- LibreSSL compatibility: recent pull spits out an error if cnf file isn't found (oh well) ==> introduction of #ERRFILE, good idea anyway

- commented what I wanted to achieve with the colors
- code cleanups
This commit is contained in:
Dirk Wetter 2015-08-24 23:50:03 +02:00
parent aa91990fb3
commit 838112e6d2

View File

@ -74,7 +74,7 @@ echo $VERSION | egrep -q "dev|rc" && \
readonly PROG_NAME=$(basename "$0") readonly PROG_NAME=$(basename "$0")
readonly RUN_DIR=$(dirname $0) readonly RUN_DIR=$(dirname $0)
INSTALL_DIR="" INSTALL_DIR=""
MAP_RFC_FNAME="" MAPPING_FILE_RFC=""
which git &>/dev/null && readonly GIT_REL=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $1" "$2" "$3 }') which git &>/dev/null && readonly GIT_REL=$(git log --format='%h %ci' -1 2>/dev/null | awk '{ print $1" "$2" "$3 }')
readonly CVS_REL=$(tail -5 $0 | awk '/dirkw Exp/ { print $4" "$5" "$6}') readonly CVS_REL=$(tail -5 $0 | awk '/dirkw Exp/ { print $4" "$5" "$6}')
@ -93,8 +93,6 @@ TERM_CURRPOS=0 # ^^^ we also need to find out the length or current pos in
# following variables make use of $ENV, e.g. OPENSSL=<myprivate_path_to_openssl> ./testssl.sh <host> # following variables make use of $ENV, e.g. OPENSSL=<myprivate_path_to_openssl> ./testssl.sh <host>
# 0 means (normally) true here. Some of the variables are also accessible with a command line switch # 0 means (normally) true here. Some of the variables are also accessible with a command line switch
# we have tab indentation with 5 virtual chars!
declare -x OPENSSL declare -x OPENSSL
COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all
SHOW_EACH_C=${SHOW_EACH_C:-0} # where individual ciphers are tested show just the positively ones tested #FIXME: upside down value SHOW_EACH_C=${SHOW_EACH_C:-0} # where individual ciphers are tested show just the positively ones tested #FIXME: upside down value
@ -128,10 +126,11 @@ readonly CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS
DAYS2WARN1=${DAYS2WARN1:-60} # days to warn before cert expires, threshold 1 DAYS2WARN1=${DAYS2WARN1:-60} # days to warn before cert expires, threshold 1
DAYS2WARN2=${DAYS2WARN2:-30} # days to warn before cert expires, threshold 2 DAYS2WARN2=${DAYS2WARN2:-30} # days to warn before cert expires, threshold 2
# furher vars needed to follow # further vars needed to follow
readonly NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1" readonly NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1"
TEMPDIR="" TEMPDIR=""
TMPFILE="" TMPFILE=""
ERRFILE=""
HOSTCERT="" HOSTCERT=""
HEADERFILE="" HEADERFILE=""
HEADERFILE_BREACH="" HEADERFILE_BREACH=""
@ -252,24 +251,24 @@ outln() { out "$1\n"; }
#TODO: Still no shell injection safe but if just run it from the cmd line: that's fine #TODO: Still no shell injection safe but if just run it from the cmd line: that's fine
# color print functions, see also http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html # color print functions, see also http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
pr_liteblue() { [[ "$COLOR" -eq 2 ]] && out "\033[0;34m$1" || out "$1"; pr_off; } pr_liteblue() { [[ "$COLOR" -eq 2 ]] && out "\033[0;34m$1" || out "$1"; pr_off; } # not yet used
pr_liteblueln() { pr_liteblue "$1"; outln; } pr_liteblueln() { pr_liteblue "$1"; outln; }
pr_blue() { [[ "$COLOR" -eq 2 ]] && out "\033[1;34m$1" || out "$1"; pr_off; } pr_blue() { [[ "$COLOR" -eq 2 ]] && out "\033[1;34m$1" || out "$1"; pr_off; } # used for head lines of single tests
pr_blueln() { pr_blue "$1"; outln; } pr_blueln() { pr_blue "$1"; outln; }
pr_litered() { [[ "$COLOR" -eq 2 ]] && out "\033[0;31m$1" || pr_bold "$1"; pr_off; } pr_litered() { [[ "$COLOR" -eq 2 ]] && out "\033[0;31m$1" || pr_bold "$1"; pr_off; } # this is bad
pr_literedln() { pr_litered "$1"; outln; } pr_literedln() { pr_litered "$1"; outln; }
pr_red() { [[ "$COLOR" -eq 2 ]] && out "\033[1;31m$1" || pr_bold "$1"; pr_off; } pr_red() { [[ "$COLOR" -eq 2 ]] && out "\033[1;31m$1" || pr_bold "$1"; pr_off; } # oh, this is really bad
pr_redln() { pr_red "$1"; outln; } pr_redln() { pr_red "$1"; outln; }
pr_litemagenta() { [[ "$COLOR" -eq 2 ]] && out "\033[0;35m$1" || pr_underline "$1"; pr_off; } pr_litemagenta() { [[ "$COLOR" -eq 2 ]] && out "\033[0;35m$1" || pr_underline "$1"; pr_off; } # local problem: one test acconot be done
pr_litemagentaln() { pr_litemagenta "$1"; outln; } pr_litemagentaln() { pr_litemagenta "$1"; outln; }
pr_magenta() { [[ "$COLOR" -eq 2 ]] && out "\033[1;35m$1" || pr_underline "$1"; pr_off; } pr_magenta() { [[ "$COLOR" -eq 2 ]] && out "\033[1;35m$1" || pr_underline "$1"; pr_off; } # Fatal error: quitting because of this
pr_magentaln() { pr_magenta "$1"; outln; } pr_magentaln() { pr_magenta "$1"; outln; }
pr_litecyan() { [[ "$COLOR" -eq 2 ]] && out "\033[0;36m$1" || out "$1"; pr_off; } pr_litecyan() { [[ "$COLOR" -eq 2 ]] && out "\033[0;36m$1" || out "$1"; pr_off; } # not yet used
pr_litecyanln() { pr_litecyan "$1"; outln; } pr_litecyanln() { pr_litecyan "$1"; outln; }
pr_cyan() { [[ "$COLOR" -eq 2 ]] && out "\033[1;36m$1" || out "$1"; pr_off; } pr_cyan() { [[ "$COLOR" -eq 2 ]] && out "\033[1;36m$1" || out "$1"; pr_off; } # additional hint
pr_cyanln() { pr_cyan "$1"; outln; } pr_cyanln() { pr_cyan "$1"; outln; }
pr_litegreyln() { pr_litegrey "$1"; outln; } pr_litegreyln() { pr_litegrey "$1"; outln; }
@ -277,14 +276,14 @@ pr_litegrey() { [[ "$COLOR" -eq 2 ]] && out "\033[0;37m$1" || out "$1"; pr_off
pr_grey() { [[ "$COLOR" -eq 2 ]] && out "\033[1;30m$1" || out "$1"; pr_off; } pr_grey() { [[ "$COLOR" -eq 2 ]] && out "\033[1;30m$1" || out "$1"; pr_off; }
pr_greyln() { pr_grey "$1"; outln; } pr_greyln() { pr_grey "$1"; outln; }
pr_litegreen() { [[ "$COLOR" -eq 2 ]] && out "\033[0;32m$1" || out "$1"; pr_off; } pr_litegreen() { [[ "$COLOR" -eq 2 ]] && out "\033[0;32m$1" || out "$1"; pr_off; } # This is good
pr_litegreenln() { pr_litegreen "$1"; outln; } pr_litegreenln() { pr_litegreen "$1"; outln; }
pr_green() { [[ "$COLOR" -eq 2 ]] && out "\033[1;32m$1" || out "$1"; pr_off; } pr_green() { [[ "$COLOR" -eq 2 ]] && out "\033[1;32m$1" || out "$1"; pr_off; } # This is the best
pr_greenln() { pr_green "$1"; outln; } pr_greenln() { pr_green "$1"; outln; }
pr_yellow() { [[ "$COLOR" -eq 2 ]] && out "\033[1;33m$1" || out "$1"; pr_off; } pr_yellow() { [[ "$COLOR" -eq 2 ]] && out "\033[1;33m$1" || out "$1"; pr_off; } # academic or minor problem
pr_yellowln() { pr_yellow "$1"; outln; } pr_yellowln() { pr_yellow "$1"; outln; }
pr_brown() { [[ "$COLOR" -eq 2 ]] && out "\033[0;33m$1" || out "$1"; pr_off; } pr_brown() { [[ "$COLOR" -eq 2 ]] && out "\033[0;33m$1" || out "$1"; pr_off; } # it is not a bad problem but you shouldn't do this
pr_brownln() { pr_brown "$1"; outln; } pr_brownln() { pr_brown "$1"; outln; }
@ -376,6 +375,15 @@ count_words() {
echo "$1" | wc -w | sed 's/ //g' echo "$1" | wc -w | sed 's/ //g'
} }
count_ciphers() {
printf "$1" | sed 's/:/ /g' | wc -w | sed 's/ //g'
}
actually_supported_ciphers() {
$OPENSSL ciphers "$1" 2>/dev/null || echo ""
}
newline_to_spaces() { newline_to_spaces() {
echo "$1" | tr '\n' ' ' | sed 's/ $//' echo "$1" | tr '\n' ' ' | sed 's/ $//'
} }
@ -405,9 +413,11 @@ out_row_aligned() {
tmpfile_handle() { tmpfile_handle() {
if [[ "$DEBUG" -eq 0 ]] ; then if [[ "$DEBUG" -eq 0 ]] ; then
rm $TMPFILE rm $TMPFILE 2>/dev/null
[[ $ERRFILE =~ "dev/null" ]] || rm $ERRFILE
else else
mv $TMPFILE "$TEMPDIR/$NODEIP.$1" mv $TMPFILE "$TEMPDIR/$NODEIP.$1" 2>/dev/null
mv $ERRFILE "$TEMPDIR/$NODEIP.$(sed 's/\.txt//g' <<<$1).errorlog" 2>/dev/null
fi fi
} }
@ -465,7 +475,7 @@ runs_HTTP() {
out " -- ASSUMING_HTTP set though" out " -- ASSUMING_HTTP set though"
ret=0 ret=0
else else
out ", assuming no HTTP service, skipping HTTP checks" out ", assuming no HTTP service => skipping HTTP checks"
ret=1 ret=1
fi fi
;; ;;
@ -519,15 +529,15 @@ EOF
ret=0 ret=0
else else
#TODO: attention: if this runs into a timeout, we're dead. Try again differently: #TODO: attention: if this runs into a timeout, we're dead. Try again differently:
printf "$GET_REQ11" | $OPENSSL s_client $OPTIMAL_PROTO -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI 1>$HEADERFILE 2>/dev/null printf "$GET_REQ11" | $OPENSSL s_client $OPTIMAL_PROTO -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI 1>$HEADERFILE 2>$ERRFILE
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
pr_litemagentaln " failed (1st request stalled, 2nd erroneous)" pr_litemagentaln " failed (1st request stalled, 2nd erroneous)"
return 3 return 3
#ret=3 #ret=3
fi fi
fi fi
status_code=$(awk '/^HTTP\// { print $2 }' $HEADERFILE 2>/dev/null) status_code=$(awk '/^HTTP\// { print $2 }' $HEADERFILE 2>>$ERRFILE)
msg_thereafter=$(awk -F"$status_code" '/^HTTP\// { print $2 }' $HEADERFILE 2>/dev/null) # dirty trick to use the status code as a msg_thereafter=$(awk -F"$status_code" '/^HTTP\// { print $2 }' $HEADERFILE 2>>$ERRFILE) # dirty trick to use the status code as a
msg_thereafter=$(strip_lf "$msg_thereafter") # field separator, otherwise we need a loop with awk msg_thereafter=$(strip_lf "$msg_thereafter") # field separator, otherwise we need a loop with awk
debugme echo "Status/MSG: $status_code $msg_thereafter" debugme echo "Status/MSG: $status_code $msg_thereafter"
@ -571,7 +581,7 @@ run_http_date() {
if $HAS_GNUDATE ; then if $HAS_GNUDATE ; then
HTTP_TIME=$(date --date="$HTTP_TIME" "+%s") HTTP_TIME=$(date --date="$HTTP_TIME" "+%s")
else else
HTTP_TIME=$(date -j -f "%a, %d %b %Y %T %Z" "$HTTP_TIME" "+%s" 2>/dev/null) # the trailing \r confuses BSD flavors otherwise HTTP_TIME=$(date -j -f "%a, %d %b %Y %T %Z" "$HTTP_TIME" "+%s" 2>>$ERRFILE) # the trailing \r confuses BSD flavors otherwise
fi fi
difftime=$(($HTTP_TIME - $now)) difftime=$(($HTTP_TIME - $now))
@ -824,6 +834,8 @@ run_rp_banner() {
emphasize_stuff_in_headers "$line" emphasize_stuff_in_headers "$line"
done done
fi fi
outln
tmpfile_handle $FUNCNAME.txt tmpfile_handle $FUNCNAME.txt
return 0 return 0
@ -991,14 +1003,14 @@ prettyprint_local() {
neat_header neat_header
if [[ -z "$1" ]]; then if [[ -z "$1" ]]; then
$OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode dash ciph sslvers kx auth enc mac export ; do # -V doesn't work with openssl < 1.0 $OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE | while read hexcode dash ciph sslvers kx auth enc mac export ; do # -V doesn't work with openssl < 1.0
normalize_ciphercode $hexcode normalize_ciphercode $hexcode
neat_list $HEXC $ciph $kx $enc neat_list $HEXC $ciph $kx $enc
outln outln
done done
else 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 # -V doesn't work with openssl < 1.0 $OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE | while read hexcode dash ciph sslvers kx auth enc mac export ; do # -V doesn't work with openssl < 1.0
normalize_ciphercode $hexcode normalize_ciphercode $hexcode
# for numbers we don't do word matching: # for numbers we don't do word matching:
[[ $arg =~ $re ]] && \ [[ $arg =~ $re ]] && \
@ -1015,7 +1027,7 @@ prettyprint_local() {
# list ciphers (and makes sure you have them locally configured) # list ciphers (and makes sure you have them locally configured)
# arg[1]: cipher list (or anything else) # arg[1]: cipher list (or anything else)
listciphers() { listciphers() {
local ret local -i ret
local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< $1)" local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< $1)"
$OPENSSL ciphers "$1" &>$TMPFILE $OPENSSL ciphers "$1" &>$TMPFILE
@ -1031,15 +1043,15 @@ listciphers() {
# argv[2]: string on console # argv[2]: string on console
# argv[3]: ok to offer? 0: yes, 1: no # argv[3]: ok to offer? 0: yes, 1: no
std_cipherlists() { std_cipherlists() {
local ret local -i ret
local singlespaces local singlespaces
local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< $1)" local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< $1)"
pr_bold "$2 " # indent in order to be in the same row as server preferences pr_bold "$2 " # indent in order to be in the same row as server preferences
if listciphers "$1"; then # is that locally available?? if listciphers "$1"; then # is that locally available??
$OPENSSL s_client -cipher "$1" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI 2>$TMPFILE.2 >$TMPFILE </dev/null $OPENSSL s_client -cipher "$1" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI 2>$ERRFILE >$TMPFILE </dev/null
ret=$? ret=$?
debugme cat $TMPFILE.2 debugme cat $ERRFILE
case $3 in case $3 in
0) # ok to offer 0) # ok to offer
[[ $ret -eq 0 ]] && \ [[ $ret -eq 0 ]] && \
@ -1060,11 +1072,10 @@ std_cipherlists() {
*) # we shouldn't reach this *) # we shouldn't reach this
pr_litemagenta "? (please report this)" ;; pr_litemagenta "? (please report this)" ;;
esac esac
debugme cat $TMPFILE.2 >>$TMPFILE
tmpfile_handle $FUNCNAME.$debugname.txt tmpfile_handle $FUNCNAME.$debugname.txt
else 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" local_problem "No $singlespaces configured in $OPENSSL"
fi fi
# we need lf in those cases: # we need lf in those cases:
[[ $DEBUG -ge 2 ]] && echo [[ $DEBUG -ge 2 ]] && echo
@ -1089,8 +1100,10 @@ socksend() {
#FIXME: This is only for HB and CCS, others use still sockread_serverhello() #FIXME: This is only for HB and CCS, others use still sockread_serverhello()
sockread() { sockread() {
local -i ret=0
local ddreply
[[ "x$2" == "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2 [[ "x$2" == "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2
ret=0
ddreply=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7 ddreply=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7
dd bs=$1 of=$ddreply count=1 <&5 2>/dev/null & dd bs=$1 of=$ddreply count=1 <&5 2>/dev/null &
@ -1098,21 +1111,22 @@ sockread() {
ret=$? ret=$?
SOCKREPLY=$(cat $ddreply) SOCKREPLY=$(cat $ddreply)
rm $ddreply rm $ddreply
return $ret return $ret
} }
show_rfc_style(){ show_rfc_style(){
[ ! -r "$MAP_RFC_FNAME" ] && return 1 local rfcname
RFCname=$(grep -iw "$1" "$MAP_RFC_FNAME" | sed -e 's/^.*TLS/TLS/' -e 's/^.*SSL/SSL/')
[[ -n "$RFCname" ]] && out "$RFCname" [[ -z "$MAPPING_FILE_RFC" ]] && return 1
rfcname=$(grep -iw "$1" "$MAPPING_FILE_RFC" | sed -e 's/^.*TLS/TLS/' -e 's/^.*SSL/SSL/')
[[ -n "$rfcname" ]] && out "$rfcname"
return 0 return 0
} }
neat_header(){ neat_header(){
outln "Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits${MAP_RFC_FNAME:+ Cipher Suite Name (RFC)}" printf -- "Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits${MAPPING_FILE_RFC:+ Cipher Suite Name (RFC)}\n"
outln "%s-------------------------------------------------------------------------${MAP_RFC_FNAME:+----------------------------------------------}" printf -- "%s-------------------------------------------------------------------------${MAPPING_FILE_RFC:+----------------------------------------------}\n"
} }
@ -1121,11 +1135,15 @@ neat_header(){
# arg3: keyexchange # arg3: keyexchange
# arg4: encryption (maybe included "export") # arg4: encryption (maybe included "export")
neat_list(){ neat_list(){
kx=$(echo "$3" | sed 's/Kx=//g') local hexcode="$1"
enc=$(echo "$4" | sed 's/Enc=//g') local ossl_cipher="$2"
strength=$(echo $enc | sed -e 's/.*(//' -e 's/)//') # strength = encryption bits local kx enc strength
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=$(sed 's/Kx=//g' <<< "$3")
enc=$(sed 's/Enc=//g' <<< "$4")
strength=$(sed -e 's/.*(//' -e 's/)//' <<< "$enc") # strength = encryption bits
strength=$(sed -e 's/ChaCha20-Poly1305/ly1305/g' <<< "$strength") # workaround for empty bits ChaCha20-Poly1305
enc=$(sed -e 's/(.*)//g' -e 's/ChaCha20-Poly1305/ChaCha20-Po/g' <<< "$enc") # workaround for empty bits ChaCha20-Poly1305
echo "$export" | grep -iq export && strength="$strength,export" echo "$export" | grep -iq export && strength="$strength,export"
# workaround for color escape codes: # workaround for color escape codes:
if printf -- "$kx" | "${HEXDUMPVIEW[@]}" | grep -q 33 ; then # here's a color code if printf -- "$kx" | "${HEXDUMPVIEW[@]}" | grep -q 33 ; then # here's a color code
@ -1134,11 +1152,11 @@ neat_list(){
[[ "${#kx}" -eq 19 ]] && kx="$kx " # 19 means DH, colored >=1000. Add another space [[ "${#kx}" -eq 19 ]] && kx="$kx " # 19 means DH, colored >=1000. Add another space
#echo ${#kx} # should be always 20 #echo ${#kx} # should be always 20
fi fi
if [[ -r "$MAP_RFC_FNAME" ]]; then #if [[ -r "$MAPPING_FILE_RFC" ]]; then
printf -- " %-7s %-30s %-10s %-11s%-11s${MAP_RFC_FNAME:+ %-48s}${SHOW_EACH_C:+ }" "$1" "$2" "$kx" "$enc" "$strength" "$(show_rfc_style $HEXC)" printf -- " %-7s %-30s %-10s %-11s%-11s${MAPPING_FILE_RFC:+ %-48s}${SHOW_EACH_C:+ }" "$hexcode" "$ossl_cipher" "$kx" "$enc" "$strength" "$(show_rfc_style $HEXC)"
else #else
printf -- " %-7s %-30s %-10s %-11s%-11s${SHOW_EACH_C:+ }" "$1" "$2" "$kx" "$enc" "$strength" # printf -- " %-7s %-30s %-10s %-11s%-11s${SHOW_EACH_C:+ }" "$1" "$2" "$kx" "$enc" "$strength"
fi #fi
} }
test_just_one(){ test_just_one(){
@ -1157,7 +1175,7 @@ test_just_one(){
neat_header 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 # 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 $OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE | while read hexcode dash ciph sslvers kx auth enc mac export ; do
# FIXME: e.g. OpenSSL < 1.0 doesn't understand "-V" --> we can't do anything about it! # FIXME: e.g. OpenSSL < 1.0 doesn't understand "-V" --> we can't do anything about it!
normalize_ciphercode $hexcode normalize_ciphercode $hexcode
# is argument a number? # is argument a number?
@ -1202,13 +1220,13 @@ run_allciphers(){
local hexcode n ciph sslvers kx auth enc mac export local hexcode n ciph sslvers kx auth enc mac export
local dhlen local dhlen
nr_ciphers=$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' | sed 's/:/ /g' | wc -w) nr_ciphers=$(count_ciphers "$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE)")
pr_blue "--> Testing all locally available $nr_ciphers ciphers against the server"; outln ", ordered by encryption strength" pr_blue "--> Testing all locally available $nr_ciphers ciphers against the server"; outln ", ordered by encryption strength"
! $HAS_DH_BITS && pr_litemagentaln " (Your $OPENSSL cannot show DH/ECDH bits)" ! $HAS_DH_BITS && pr_litemagentaln " (Your $OPENSSL cannot show DH/ECDH bits)"
outln outln
neat_header neat_header
$OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode n ciph sslvers kx auth enc mac export; do $OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>>$ERRFILE | while read hexcode n ciph sslvers kx auth enc mac export; do
# FIXME: e.g. OpenSSL < 1.0 doesn't understand "-V" --> we can't do anything about it! # FIXME: e.g. OpenSSL < 1.0 doesn't understand "-V" --> we can't do anything about it!
$OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI &>$TMPFILE </dev/null $OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI &>$TMPFILE </dev/null
ret=$? ret=$?
@ -1249,7 +1267,7 @@ run_cipher_per_proto(){
outln " -ssl2 SSLv2\n -ssl3 SSLv3\n -tls1 TLS 1\n -tls1_1 TLS 1.1\n -tls1_2 TLS 1.2"| while read proto proto_text; do outln " -ssl2 SSLv2\n -ssl3 SSLv3\n -tls1 TLS 1\n -tls1_1 TLS 1.1\n -tls1_2 TLS 1.2"| while read proto proto_text; do
locally_supported "$proto" "$proto_text" || continue locally_supported "$proto" "$proto_text" || continue
outln outln
$OPENSSL ciphers $proto -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode n ciph sslvers kx auth enc mac export; do # -V doesn't work with openssl < 1.0 $OPENSSL ciphers $proto -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE | while read hexcode n ciph sslvers kx auth enc mac export; do # -V doesn't work with openssl < 1.0
$OPENSSL s_client -cipher $ciph $proto $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI &>$TMPFILE </dev/null $OPENSSL s_client -cipher $ciph $proto $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI &>$TMPFILE </dev/null
ret=$? ret=$?
if [[ $ret -ne 0 ]] && [[ "$SHOW_EACH_C" -eq 0 ]]; then if [[ $ret -ne 0 ]] && [[ "$SHOW_EACH_C" -eq 0 ]]; then
@ -1276,15 +1294,13 @@ run_cipher_per_proto(){
} }
locally_supported() { locally_supported() {
local ret local -i ret=0
[ -n "$2" ] && out "$2 " [[ -n "$2" ]] && out "$2 "
$OPENSSL s_client "$1" 2>&1 | grep -aq "unknown option" $OPENSSL s_client "$1" 2>&1 | grep -aq "unknown option"
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
pr_magentaln "Local problem: $OPENSSL doesn't support \"s_client $1\"" local_problem "$OPENSSL doesn't support \"s_client $1\""
ret=7 ret=7
else
ret=0
fi fi
return $ret return $ret
} }
@ -1292,7 +1308,7 @@ locally_supported() {
run_prototest_openssl() { run_prototest_openssl() {
local sni="$SNI" local sni="$SNI"
local ret local -i ret=0
$OPENSSL s_client -state $1 $STARTTLS -connect $NODEIP:$PORT $PROXY $sni &>$TMPFILE </dev/null $OPENSSL s_client -state $1 $STARTTLS -connect $NODEIP:$PORT $PROXY $sni &>$TMPFILE </dev/null
ret=$? ret=$?
@ -1300,7 +1316,7 @@ run_prototest_openssl() {
$VERBERR && egrep "error|failure" $TMPFILE | egrep -av "unable to get local|verify error" $VERBERR && egrep "error|failure" $TMPFILE | egrep -av "unable to get local|verify error"
if ! locally_supported "$1" "$2" ; then if ! locally_supported "$1" "$2" ; then
return 7 ret=7
else # we remove SNI for SSLv2 and v3: else # we remove SNI for SSLv2 and v3:
[[ "$1" =~ "ssl" ]] && sni="" # newer openssl throw an error if SNI is supplied with SSLv2, [[ "$1" =~ "ssl" ]] && sni="" # newer openssl throw an error if SNI is supplied with SSLv2,
# SSLv3 doesn't have SNI (openssl doesn't complain though -- yet) # SSLv3 doesn't have SNI (openssl doesn't complain though -- yet)
@ -1495,21 +1511,27 @@ read_dhbits_from_file() {
run_server_preference() { run_server_preference() {
local -i ret=0
local cipher1 cipher2
local list_fwd="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: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-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-DSS-AES256-GCM-SHA384:AES256-SHA256" local list_fwd="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: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-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-DSS-AES256-GCM-SHA384:AES256-SHA256"
local list_reverse="AES256-SHA256:DHE-DSS-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA:ECDH-RSA-AES128-SHA:ECDH-RSA-DES-CBC3-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA256:AES128-SHA:RC4-SHA:DES-CBC-SHA:RC4-MD5:DES-CBC3-SHA" # offline via tac, see https://github.com/thomassa/testssl.sh/commit/7a4106e839b8c3033259d66697893765fc468393 local list_reverse="AES256-SHA256:DHE-DSS-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA:ECDH-RSA-AES128-SHA:ECDH-RSA-DES-CBC3-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA256:AES128-SHA:RC4-SHA:DES-CBC-SHA:RC4-MD5:DES-CBC3-SHA" # offline via tac, see https://github.com/thomassa/testssl.sh/commit/7a4106e839b8c3033259d66697893765fc468393
local remark4default_cipher
local default_cipher default_proto
local -a cipher proto
local p i
outln; outln;
pr_blue "--> Testing server preferences"; outln "\n" pr_blue "--> Testing server preferences"; outln "\n"
pr_bold " Has server cipher order? " pr_bold " Has server cipher order? "
$OPENSSL s_client $STARTTLS -cipher $list_fwd -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -cipher $list_fwd -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>$ERRFILE >$TMPFILE
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
pr_magenta "no matching cipher in this list found (pls report this): " pr_magenta "no matching cipher in this list found (pls report this): "
outln "$list_fwd . " outln "$list_fwd . "
ret=6 ret=6
else else
cipher1=$(grep -wa Cipher $TMPFILE | egrep -avw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') cipher1=$(grep -wa Cipher $TMPFILE | egrep -avw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g')
$OPENSSL s_client $STARTTLS -cipher $list_reverse -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -cipher $list_reverse -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
cipher2=$(grep -wa Cipher $TMPFILE | egrep -avw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') cipher2=$(grep -wa Cipher $TMPFILE | egrep -avw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g')
if [[ "$cipher1" != "$cipher2" ]]; then if [[ "$cipher1" != "$cipher2" ]]; then
@ -1522,7 +1544,7 @@ run_server_preference() {
[[ $DEBUG -ge 2 ]] && out " $cipher1 | $cipher2" [[ $DEBUG -ge 2 ]] && out " $cipher1 | $cipher2"
outln outln
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
pr_bold " Negotiated protocol " pr_bold " Negotiated protocol "
default_proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') default_proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g')
case "$default_proto" in case "$default_proto" in
@ -1556,7 +1578,7 @@ run_server_preference() {
for p in ssl2 ssl3 tls1 tls1_1 tls1_2; do for p in ssl2 ssl3 tls1 tls1_1 tls1_2; do
#locally_supported -"$p" " " || continue #locally_supported -"$p" " " || continue
locally_supported -"$p" || continue locally_supported -"$p" || continue
$OPENSSL s_client $STARTTLS -"$p" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -"$p" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
proto[i]=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') proto[i]=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g')
cipher[i]=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') cipher[i]=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g')
@ -1572,7 +1594,7 @@ run_server_preference() {
[[ -n "$PROXY" ]] && arg=" SPDY/NPN is" [[ -n "$PROXY" ]] && arg=" SPDY/NPN is"
[[ -n "$STARTTLS" ]] && arg=" " [[ -n "$STARTTLS" ]] && arg=" "
if spdy_pre " $arg"; then # is NPN/SPDY supported and is this no STARTTLS? / no PROXY if spdy_pre " $arg"; then # is NPN/SPDY supported and is this no STARTTLS? / no PROXY
$OPENSSL s_client -host $NODE -port $PORT -nextprotoneg "$NPN_PROTOs" </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client -host $NODE -port $PORT -nextprotoneg "$NPN_PROTOs" </dev/null 2>>$ERRFILE >$TMPFILE
if [[ $? -eq 0 ]]; then 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 if [[ -z "${proto[i]}" ]]; then
@ -1621,7 +1643,7 @@ cipher_pref_check() {
pr_bold " Cipher order" pr_bold " Cipher order"
for p in ssl2 ssl3 tls1 tls1_1 tls1_2; do for p in ssl2 ssl3 tls1 tls1_1 tls1_2; do
$OPENSSL s_client $STARTTLS -"$p" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -"$p" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>$ERRFILE >$TMPFILE
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
tested_cipher="" tested_cipher=""
proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g')
@ -1631,7 +1653,7 @@ cipher_pref_check() {
printf " %-10s %s " "$proto:" "$cipher" printf " %-10s %s " "$proto:" "$cipher"
tested_cipher="-"$cipher tested_cipher="-"$cipher
while true; do while true; do
$OPENSSL s_client $STARTTLS -"$p" -cipher "ALL:$tested_cipher" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -"$p" -cipher "ALL:$tested_cipher" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
[[ $? -ne 0 ]] && break [[ $? -ne 0 ]] && break
cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g')
out "$cipher " out "$cipher "
@ -1644,14 +1666,14 @@ cipher_pref_check() {
if ! spdy_pre " SPDY/NPN: " ; then # is NPN/SPDY supported and is this no STARTTLS? if ! spdy_pre " SPDY/NPN: " ; then # is NPN/SPDY supported and is this no STARTTLS?
outln outln
else else
protos=$($OPENSSL s_client -host $NODE -port $PORT -nextprotoneg \"\" </dev/null 2>/dev/null | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g') protos=$($OPENSSL s_client -host $NODE -port $PORT -nextprotoneg \"\" </dev/null 2>>$ERRFILE | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g')
for p in $protos; do for p in $protos; do
$OPENSSL s_client -host $NODE -port $PORT -nextprotoneg "$p" $PROXY </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client -host $NODE -port $PORT -nextprotoneg "$p" $PROXY </dev/null 2>>$$ERRFILE >$TMPFILE
cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g')
printf " %-10s %s " "$p:" "$cipher" printf " %-10s %s " "$p:" "$cipher"
tested_cipher="-"$cipher tested_cipher="-"$cipher
while true; do while true; do
$OPENSSL s_client -cipher "ALL:$tested_cipher" -host $NODE -port $PORT -nextprotoneg "$p" $PROXY </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client -cipher "ALL:$tested_cipher" -host $NODE -port $PORT -nextprotoneg "$p" $PROXY </dev/null 2>>$ERRFILE >$TMPFILE
[[ $? -ne 0 ]] && break [[ $? -ne 0 ]] && break
cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g')
out "$cipher " out "$cipher "
@ -1670,15 +1692,15 @@ get_host_cert() {
# arg1 is proto or empty # arg1 is proto or empty
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI $1 2>/dev/null </dev/null | \ $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI $1 2>/dev/null </dev/null | \
awk '/-----BEGIN/,/-----END/ { print $0 }' >$HOSTCERT awk '/-----BEGIN/,/-----END/ { print $0 }' >$HOSTCERT
return $? return $((${PIPESTATUS[0]} + ${PIPESTATUS[1]}))
} }
get_all_certs() { get_all_certs() {
local savedir local savedir
local nrsaved local nrsaved
local ret local -i ret
$OPENSSL s_client -showcerts $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI 2>/dev/null </dev/null >$TEMPDIR/allcerts.txt $OPENSSL s_client -showcerts $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI 2>$ERRFILE </dev/null >$TEMPDIR/allcerts.txt
ret=$? ret=$?
savedir=$(pwd); cd $TEMPDIR savedir=$(pwd); cd $TEMPDIR
# http://backreference.org/2010/05/09/ocsp-verification-with-openssl/ # http://backreference.org/2010/05/09/ocsp-verification-with-openssl/
@ -1732,7 +1754,7 @@ run_server_defaults() {
#TLS extensions follow now #TLS extensions follow now
# throwing 1st every cipher/protocol at the server to know what works # throwing 1st every cipher/protocol at the server to know what works
for proto in tls1_2 tls1_1 tls1 ssl3; do for proto in tls1_2 tls1_1 tls1 ssl3; do
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug -status </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug -status </dev/null 2>$ERRFILE >$TMPFILE
ret=$? ret=$?
get_host_cert "-$proto" get_host_cert "-$proto"
[ $? -eq 0 ] && [ $ret -eq 0 ] && break [ $? -eq 0 ] && [ $ret -eq 0 ] && break
@ -1740,7 +1762,7 @@ run_server_defaults() {
done # this loop is needed for IIS/6 done # this loop is needed for IIS/6
if [ $ret -eq 7 ]; then if [ $ret -eq 7 ]; then
# "-status" kills GOST only servers, so we do another test without it and see whether that works then: # "-status" kills GOST only servers, so we do another test without it and see whether that works then:
if ! $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug </dev/null 2>/dev/null >$TMPFILE; then if ! $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug </dev/null 2>>$ERRFILE >$TMPFILE; then
pr_magentaln "$OPENSSL returned an error around line $LINENO". pr_magentaln "$OPENSSL returned an error around line $LINENO".
tmpfile_handle tlsextdebug+status.txt tmpfile_handle tlsextdebug+status.txt
return 7 # this is ugly, I know return 7 # this is ugly, I know
@ -1748,7 +1770,7 @@ run_server_defaults() {
gost_status_problem=true gost_status_problem=true
fi fi
fi fi
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY -$proto 2>/dev/null </dev/null | awk '/-----BEGIN/,/-----END/ { print $0 }' >$HOSTCERT.nosni $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY -$proto 2>>$ERRFILE </dev/null | awk '/-----BEGIN/,/-----END/ { print $0 }' >$HOSTCERT.nosni
pr_bold " TLS server extensions " pr_bold " TLS server extensions "
extensions=$(grep -aw "^TLS server extension" $TMPFILE | sed -e 's/^TLS server extension \"//' -e 's/\".*$/,/g') extensions=$(grep -aw "^TLS server extension" $TMPFILE | sed -e 's/^TLS server extension \"//' -e 's/\".*$/,/g')
if [ -z "$extensions" ]; then if [ -z "$extensions" ]; then
@ -1769,8 +1791,8 @@ run_server_defaults() {
pr_bold " Server key size " pr_bold " Server key size "
keysize=$(grep -aw "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //' -e 's/bit//' -e 's/ //') keysize=$(grep -aw "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //' -e 's/bit//' -e 's/ //')
sig_algo=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep "Signature Algorithm" | sed 's/^.*Signature Algorithm: //' | sort -u ) sig_algo=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep "Signature Algorithm" | sed 's/^.*Signature Algorithm: //' | sort -u )
key_algo=$($OPENSSL x509 -in $HOSTCERT -noout -text | awk -F':' '/Public Key Algorithm:/ { print $2 }' | sort -u ) key_algo=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | awk -F':' '/Public Key Algorithm:/ { print $2 }' | sort -u )
if [ -z "$keysize" ]; then if [ -z "$keysize" ]; then
outln "(couldn't determine)" outln "(couldn't determine)"
@ -1805,12 +1827,12 @@ run_server_defaults() {
# old, but interesting: https://blog.hboeck.de/archives/754-Playing-with-the-EFF-SSL-Observatory.html # old, but interesting: https://blog.hboeck.de/archives/754-Playing-with-the-EFF-SSL-Observatory.html
pr_bold " Fingerprint / Serial " pr_bold " Fingerprint / Serial "
outln "$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha1 | sed 's/Fingerprint=//' | sed 's/://g' ) / $($OPENSSL x509 -noout -in $HOSTCERT -serial | sed 's/serial=//')" outln "$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha1 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g' ) / $($OPENSSL x509 -noout -in $HOSTCERT -serial 2>>$ERRFILE | sed 's/serial=//')"
outln "$spaces$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256 | sed 's/Fingerprint=//' | sed 's/://g' )" outln "$spaces$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g' )"
pr_bold " Common Name (CN) " pr_bold " Common Name (CN) "
if $OPENSSL x509 -in $HOSTCERT -noout -subject | grep -wq CN; then if $OPENSSL x509 -in $HOSTCERT -noout -subject 2>>$ERRFILE | grep -wq CN; then
cn=$($OPENSSL x509 -in $HOSTCERT -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//') cn=$($OPENSSL x509 -in $HOSTCERT -noout -subject 2>>$ERRFILE | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//')
pr_underline "$cn" pr_underline "$cn"
else else
cn="(no CN field in subject)" cn="(no CN field in subject)"
@ -1819,8 +1841,8 @@ run_server_defaults() {
cn_nosni="" cn_nosni=""
if [[ -s $HOSTCERT.nosni ]] ; then if [[ -s $HOSTCERT.nosni ]] ; then
if $OPENSSL x509 -in $HOSTCERT.nosni -noout -subject | grep -wq CN; then if $OPENSSL x509 -in $HOSTCERT.nosni -noout -subject 2>>$ERRFILE | grep -wq CN; then
cn_nosni=$($OPENSSL x509 -in $HOSTCERT.nosni -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//') cn_nosni=$($OPENSSL x509 -in $HOSTCERT.nosni -noout -subject 2>>$ERRFILE | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//')
else else
cn_nosni="no CN field in subject" cn_nosni="no CN field in subject"
fi fi
@ -1846,7 +1868,7 @@ run_server_defaults() {
fi fi
fi fi
sans=$($OPENSSL x509 -in $HOSTCERT -noout -text | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ sans=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \
sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername:<unsupported>//g') sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername:<unsupported>//g')
# ^^^ CACert # ^^^ CACert
@ -1860,10 +1882,10 @@ run_server_defaults() {
fi fi
outln outln
pr_bold " Issuer " pr_bold " Issuer "
issuer=$($OPENSSL x509 -in $HOSTCERT -noout -issuer | sed -e 's/^.*CN=//g' -e 's/\/.*$//g') issuer=$($OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE| sed -e 's/^.*CN=//g' -e 's/\/.*$//g')
issuer_o=$($OPENSSL x509 -in $HOSTCERT -noout -issuer | sed 's/^.*O=//g' | sed 's/\/.*$//g') issuer_o=$($OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE | sed 's/^.*O=//g' | sed 's/\/.*$//g')
if $OPENSSL x509 -in $HOSTCERT -noout -issuer | grep -q 'C=' ; then if $OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE | 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 2>>$ERRFILE | sed 's/^.*C=//g' | sed 's/\/.*$//g')
else else
issuer_c="" # CACert would have 'issuer= ' here otherwise issuer_c="" # CACert would have 'issuer= ' here otherwise
fi fi
@ -1877,7 +1899,7 @@ run_server_defaults() {
# http://events.ccc.de/congress/2010/Fahrplan/attachments/1777_is-the-SSLiverse-a-safe-place.pdf, see page 40pp # http://events.ccc.de/congress/2010/Fahrplan/attachments/1777_is-the-SSLiverse-a-safe-place.pdf, see page 40pp
pr_bold " EV cert"; out " (experimental) " pr_bold " EV cert"; out " (experimental) "
policy_oid=$($OPENSSL x509 -in $HOSTCERT -text | awk '/ .Policy: / { print $2 }') policy_oid=$($OPENSSL x509 -in $HOSTCERT -text 2>>$ERRFILE | awk '/ .Policy: / { print $2 }')
if echo $issuer | egrep -q 'Extended Validation|Extended Validated|EV SSL|EV CA' || \ if echo $issuer | egrep -q 'Extended Validation|Extended Validated|EV SSL|EV CA' || \
[[ "2.16.840.1.114028.10.1.2" == "$policy_oid" ]] || \ [[ "2.16.840.1.114028.10.1.2" == "$policy_oid" ]] || \
[[ "1.3.6.1.4.1.17326.10.14.2.1.2" == "$policy_oid" ]] || \ [[ "1.3.6.1.4.1.17326.10.14.2.1.2" == "$policy_oid" ]] || \
@ -1896,15 +1918,15 @@ run_server_defaults() {
# https://certs.opera.com/03/ev-oids.xml # https://certs.opera.com/03/ev-oids.xml
pr_bold " Certificate Expiration " pr_bold " Certificate Expiration "
expire=$($OPENSSL x509 -in $HOSTCERT -checkend 0) expire=$($OPENSSL x509 -in $HOSTCERT -checkend 0 2>>$ERRFILE)
if ! echo $expire | grep -qw not; then if ! echo $expire | grep -qw not; then
pr_red "expired!" pr_red "expired!"
else else
secs2warn=$((24 * 60 * 60 * $DAYS2WARN2)) # low threshold first secs2warn=$((24 * 60 * 60 * $DAYS2WARN2)) # low threshold first
expire=$($OPENSSL x509 -in $HOSTCERT -checkend $secs2warn) expire=$($OPENSSL x509 -in $HOSTCERT -checkend $secs2warn 2>>$ERRFILE)
if echo "$expire" | grep -qw not; then if echo "$expire" | grep -qw not; then
secs2warn=$((24 * 60 * 60 * $DAYS2WARN1)) secs2warn=$((24 * 60 * 60 * $DAYS2WARN1))
expire=$($OPENSSL x509 -in $HOSTCERT -checkend $secs2warn) expire=$($OPENSSL x509 -in $HOSTCERT -checkend $secs2warn 2>>$ERRFILE)
if echo "$expire" | grep -qw not; then if echo "$expire" | grep -qw not; then
pr_litegreen ">= $DAYS2WARN1 days" pr_litegreen ">= $DAYS2WARN1 days"
else else
@ -1916,11 +1938,11 @@ run_server_defaults() {
fi fi
if $HAS_GNUDATE ; then if $HAS_GNUDATE ; then
enddate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") enddate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -enddate 2>>$ERRFILE | cut -d= -f 2)" +"%F %H:%M %z")
startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate | cut -d= -f 2)" +"%F %H:%M") startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate 2>>$ERRFILE | cut -d= -f 2)" +"%F %H:%M")
else else
enddate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -enddate | cut -d= -f 2)" +"%F %H:%M %z") enddate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -enddate 2>>$ERRFILE | 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") startdate=$(date -j -f "%b %d %T %Y %Z" "$($OPENSSL x509 -in $HOSTCERT -noout -startdate 2>>$ERRFILE | cut -d= -f 2)" +"%F %H:%M")
fi fi
outln " ($startdate --> $enddate)" outln " ($startdate --> $enddate)"
@ -1929,7 +1951,7 @@ run_server_defaults() {
pr_bold " # of certificates provided"; outln " $(get_all_certs)" pr_bold " # of certificates provided"; outln " $(get_all_certs)"
pr_bold " Certificate Revocation List " pr_bold " 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 2>>$ERRFILE | grep -A 4 "CRL Distribution" | grep URI | sed 's/^.*URI://')"
case $(count_lines "$crl") in case $(count_lines "$crl") in
0) pr_literedln "--" ;; 0) pr_literedln "--" ;;
1) outln "$crl" ;; 1) outln "$crl" ;;
@ -1937,7 +1959,7 @@ run_server_defaults() {
esac esac
pr_bold " OCSP URI " pr_bold " OCSP URI "
ocsp_uri=$($OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri) ocsp_uri=$($OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri 2>>$ERRFILE)
[ x"$ocsp_uri" == "x" ] && pr_literedln "--" || echo "$ocsp_uri" [ x"$ocsp_uri" == "x" ] && pr_literedln "--" || echo "$ocsp_uri"
pr_bold " OCSP stapling " pr_bold " OCSP stapling "
@ -1963,7 +1985,7 @@ run_server_defaults() {
# already -- and that was a different one -- means that would get overwritten anyway # already -- and that was a different one -- means that would get overwritten anyway
tmpfile_handle tlsextdebug+status.txt tmpfile_handle tlsextdebug+status.txt
tls_time tls_time
return $ret return $ret
} }
@ -1994,7 +2016,7 @@ run_pfs() {
no_supported_ciphers=$(count_ciphers $(actually_supported_ciphers $pfs_cipher_list)) no_supported_ciphers=$(count_ciphers $(actually_supported_ciphers $pfs_cipher_list))
if [ "$no_supported_ciphers" -le "$CLIENT_MIN_PFS" ] ; then if [ "$no_supported_ciphers" -le "$CLIENT_MIN_PFS" ] ; then
outln outln
pr_magentaln " Local problem: you only have $number_pfs PFS ciphers on the client side " local_problem "You only have $number_pfs PFS ciphers on the client side "
return 1 return 1
fi fi
@ -2005,12 +2027,12 @@ run_pfs() {
pr_brownln "Not OK: No ciphers supporting Forward Secrecy offered" pr_brownln "Not OK: No ciphers supporting Forward Secrecy offered"
else else
pfs_offered=0 pfs_offered=0
pr_litegreen " PFS is offered (OK)"
if $WIDE; then if $WIDE; then
pr_litegreen " PFS ciphers (OK): " outln ", ciphers follow (client/browser support is here specially important) \n"
outln ", cipher follow (client/browser support is here specially important) \n"
neat_header neat_header
else else
pr_litegreen " PFS is offered (OK) " out " "
fi fi
while read hexcode dash pfs_cipher sslvers kx auth enc mac; do while read hexcode dash pfs_cipher sslvers kx auth enc mac; do
tmpfile=$TMPFILE.$hexcode tmpfile=$TMPFILE.$hexcode
@ -2038,7 +2060,7 @@ run_pfs() {
else else
out "$pfs_cipher " out "$pfs_cipher "
fi fi
done < <($OPENSSL ciphers -V "$pfs_cipher_list") # -V doesn't work with openssl < 1.0 done < <($OPENSSL ciphers -V "$pfs_cipher_list" 2>$ERRFILE) # -V doesn't work with openssl < 1.0
# ^^^^^ posix redirect as shopt will either segfault or doesn't work with old bash versions # ^^^^^ posix redirect as shopt will either segfault or doesn't work with old bash versions
debugme echo $pfs_offered debugme echo $pfs_offered
@ -2075,19 +2097,22 @@ spdy_pre(){
# first, does the current openssl support it? # first, does the current openssl support it?
$OPENSSL s_client help 2>&1 | grep -qw nextprotoneg $OPENSSL s_client help 2>&1 | grep -qw nextprotoneg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
pr_magentaln "Local problem: $OPENSSL doesn't support SPDY/NPN"; local_problem "$OPENSSL doesn't support SPDY/NPN";
return 7 return 7
fi fi
return 0 return 0
} }
run_spdy() { run_spdy() {
local tmpstr
local -i ret=0
pr_bold " SPDY/NPN " pr_bold " SPDY/NPN "
if ! spdy_pre ; then if ! spdy_pre ; then
echo echo
return 0 return 0
fi fi
$OPENSSL s_client -host $NODE -port $PORT -nextprotoneg $NPN_PROTOs </dev/null 2>/dev/null >$TMPFILE $OPENSSL s_client -host $NODE -port $PORT -nextprotoneg $NPN_PROTOs </dev/null 2>$ERRFILE >$TMPFILE
tmpstr=$(grep -a '^Protocols' $TMPFILE | sed 's/Protocols.*: //') tmpstr=$(grep -a '^Protocols' $TMPFILE | sed 's/Protocols.*: //')
if [ -z "$tmpstr" -o "$tmpstr" == " " ] ; then if [ -z "$tmpstr" -o "$tmpstr" == " " ] ; then
out "not offered" out "not offered"
@ -2657,7 +2682,7 @@ tls_sockets() {
save=$? save=$?
# see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL
lines=$(hexdump -C "$SOCK_REPLY_FILE" 2>/dev/null | wc -l | sed 's/ //g') lines=$(count_lines "$(hexdump -C "$SOCK_REPLY_FILE" 2>$ERRFILE)")
[[ "$DEBUG" -ge 2 ]] && out " (returned $lines lines) " [[ "$DEBUG" -ge 2 ]] && out " (returned $lines lines) "
# determine the return value for higher level, so that they can tell what the result is # determine the return value for higher level, so that they can tell what the result is
@ -2922,6 +2947,10 @@ run_ccs_injection(){
return $ret return $ret
} }
local_problem() {
pr_litemagentaln "Local problem: $1"
}
run_renego() { run_renego() {
# no SNI here. Not needed as there won't be two different SSL stacks for one IP # no SNI here. Not needed as there won't be two different SSL stacks for one IP
local legacycmd="" local legacycmd=""
@ -2951,7 +2980,7 @@ run_renego() {
case "$OSSL_VER" in case "$OSSL_VER" in
0.9.8*) # we need this for Mac OSX unfortunately 0.9.8*) # we need this for Mac OSX unfortunately
case "$OSSL_VER_APPENDIX" in case "$OSSL_VER_APPENDIX" in
[a-l]) pr_magentaln "Local Problem: $OPENSSL cannot test this secure renegotiation vulnerability" [a-l]) local_problem "$OPENSSL cannot test this secure renegotiation vulnerability"
return 3 ;; return 3 ;;
[m-z]) ;; # all ok [m-z]) ;; # all ok
esac ;; esac ;;
@ -2998,7 +3027,7 @@ run_crime() {
# first we need to test whether OpenSSL binary has zlib support # first we need to test whether OpenSSL binary has zlib support
$OPENSSL zlib -e -a -in /dev/stdin &>/dev/stdout </dev/null | grep -q zlib $OPENSSL zlib -e -a -in /dev/stdin &>/dev/stdout </dev/null | grep -q zlib
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
pr_magentaln "Local Problem: Your $OPENSSL lacks zlib support" local_problem "$OPENSSL lacks zlib support"
return 7 return 7
fi fi
@ -3117,15 +3146,6 @@ EOF
return $ret return $ret
} }
### two helper functions for vulnerabilities follow
count_ciphers() {
printf "$1" | sed 's/:/ /g' | wc -w | sed 's/ //g'
}
actually_supported_ciphers() {
$OPENSSL ciphers "$1" 2>/dev/null || echo ""
}
# Padding Oracle On Downgraded Legacy Encryption, in a nutshell: don't use CBC Ciphers in SSLv3 # Padding Oracle On Downgraded Legacy Encryption, in a nutshell: don't use CBC Ciphers in SSLv3
run_ssl_poodle() { run_ssl_poodle() {
local -i ret=0 local -i ret=0
@ -3135,7 +3155,7 @@ run_ssl_poodle() {
[ $VULN_COUNT -le $VULN_THRESHLD ] && outln && pr_blue "--> Testing for SSLv3 POODLE (Padding Oracle On Downgraded Legacy Encryption)" && outln "\n" [ $VULN_COUNT -le $VULN_THRESHLD ] && outln && pr_blue "--> Testing for SSLv3 POODLE (Padding Oracle On Downgraded Legacy Encryption)" && outln "\n"
pr_bold " POODLE, SSL"; out " (CVE-2014-3566) " pr_bold " POODLE, SSL"; out " (CVE-2014-3566) "
cbc_ciphers=$($OPENSSL ciphers -v 'ALL:eNULL' | awk '/CBC/ { print $1 }' | tr '\n' ':') cbc_ciphers=$($OPENSSL ciphers -v 'ALL:eNULL' 2>$ERRFILE | awk '/CBC/ { print $1 }' | tr '\n' ':')
#FIXME: even with worst openssl client (FreeBSD9) we have 17 reasonable ciphers but is that enough to check?? #FIXME: even with worst openssl client (FreeBSD9) we have 17 reasonable ciphers but is that enough to check??
debugme echo $cbc_ciphers debugme echo $cbc_ciphers
$OPENSSL s_client -ssl3 $STARTTLS -cipher $cbc_ciphers -connect $NODEIP:$PORT $PROXY $SNI &>$TMPFILE </dev/null $OPENSSL s_client -ssl3 $STARTTLS -cipher $cbc_ciphers -connect $NODEIP:$PORT $PROXY $SNI &>$TMPFILE </dev/null
@ -3170,7 +3190,7 @@ run_tls_fallback_scsv() {
# First check we have support for TLS_FALLBACK_SCSV in our local OpenSSL # First check we have support for TLS_FALLBACK_SCSV in our local OpenSSL
$OPENSSL s_client -h 2>&1 | grep -q "\-fallback_scsv" $OPENSSL s_client -h 2>&1 | grep -q "\-fallback_scsv"
if [ $? -gt 0 ]; then if [ $? -gt 0 ]; then
pr_magentaln "Local Problem: Your $OPENSSL lacks TLS_FALLBACK_SCSV support" local_problem "$OPENSSL lacks TLS_FALLBACK_SCSV support"
return 4 return 4
fi fi
@ -3220,7 +3240,7 @@ run_freak() {
#echo "========= ${PIPESTATUS[*]} #echo "========= ${PIPESTATUS[*]}
case $no_supported_ciphers in case $no_supported_ciphers in
0) pr_magentaln "Local problem: your $OPENSSL doesn't have any EXPORT RSA ciphers configured" 0) local_problem "$OPENSSL doesn't have any EXPORT RSA ciphers configured"
return 7 ;; return 7 ;;
1|2|3) 1|2|3)
addtl_warning=" ($magenta""tested only with $no_supported_ciphers out of 9 ciphers only!$off)" ;; addtl_warning=" ($magenta""tested only with $no_supported_ciphers out of 9 ciphers only!$off)" ;;
@ -3260,7 +3280,7 @@ run_logjam() {
no_supported_ciphers=$(count_ciphers $(actually_supported_ciphers $exportdhe_cipher_list)) no_supported_ciphers=$(count_ciphers $(actually_supported_ciphers $exportdhe_cipher_list))
case $no_supported_ciphers in case $no_supported_ciphers in
0) pr_magentaln "Local problem: your $OPENSSL doesn't have any DHE EXPORT ciphers configured" 0) local_problem "$OPENSSL doesn't have any DHE EXPORT ciphers configured"
return 3 ;; return 3 ;;
1|2) addtl_warning=" ($magenta""tested w/ $no_supported_ciphers/4 ciphers only!$off)" ;; 1|2) addtl_warning=" ($magenta""tested w/ $no_supported_ciphers/4 ciphers only!$off)" ;;
3) addtl_warning=" (tested w/ $no_supported_ciphers/4 ciphers)" ;; 3) addtl_warning=" (tested w/ $no_supported_ciphers/4 ciphers)" ;;
@ -3309,9 +3329,10 @@ run_beast(){
pr_bold " BEAST"; out " (CVE-2011-3389) " pr_bold " BEAST"; out " (CVE-2011-3389) "
$WIDE && outln $WIDE && outln
>$ERRFILE
# 2) test handfull of common CBC ciphers # 2) test handfull of common CBC ciphers
for proto in ssl3 tls1; do for proto in ssl3 tls1; do
$OPENSSL s_client -"$proto" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>/dev/null </dev/null $OPENSSL s_client -"$proto" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>>$ERRFILE </dev/null
if [[ $? -ne 0 ]]; then # protocol supported? if [[ $? -ne 0 ]]; then # protocol supported?
if $continued; then # second round: we hit TLS1: if $continued; then # second round: we hit TLS1:
pr_litegreenln "no SSL3 or TLS1" pr_litegreenln "no SSL3 or TLS1"
@ -3328,7 +3349,7 @@ run_beast(){
neat_header # NOTTHATNICE: we display the header also if in the end no cbc cipher is available on the client side neat_header # NOTTHATNICE: we display the header also if in the end no cbc cipher is available on the client side
fi fi
while read hexcode dash cbc_cipher sslvers kx auth enc mac; do while read hexcode dash cbc_cipher sslvers kx auth enc mac; do
$OPENSSL s_client -cipher "$cbc_cipher" -"$proto" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>/dev/null </dev/null $OPENSSL s_client -cipher "$cbc_cipher" -"$proto" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>>$ERRFILE </dev/null
openssl_ret=$? openssl_ret=$?
[[ $openssl_ret -eq 0 ]] && vuln_beast=true [[ $openssl_ret -eq 0 ]] && vuln_beast=true
if $WIDE; then if $WIDE; then
@ -3349,7 +3370,7 @@ run_beast(){
vuln_beast=true vuln_beast=true
fi fi
fi fi
done < <($OPENSSL ciphers -V 'ALL:eNULL' | grep -a CBC) # -V doesn't work with openssl < 1.0 done < <($OPENSSL ciphers -V 'ALL:eNULL' 2>>$ERRFILE | grep -a CBC) # -V doesn't work with openssl < 1.0
# ^^^^^ process substitution as shopt will either segfault or doesn't work with old bash versions # ^^^^^ process substitution as shopt will either segfault or doesn't work with old bash versions
if ! $WIDE; then if ! $WIDE; then
@ -3371,7 +3392,7 @@ run_beast(){
# 2) support for TLS 1.1+1.2? # 2) support for TLS 1.1+1.2?
for proto in tls1_1 tls1_2; do for proto in tls1_1 tls1_2; do
$OPENSSL s_client -state -"$proto" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI 2>/dev/null >$TMPFILE </dev/null $OPENSSL s_client -state -"$proto" $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI 2>>$ERRFILE >$TMPFILE </dev/null
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
higher_proto_supported="$higher_proto_supported ""$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol .*://' -e 's/ //g')" higher_proto_supported="$higher_proto_supported ""$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol .*://' -e 's/ //g')"
fi fi
@ -3416,7 +3437,7 @@ run_rc4() {
fi fi
pr_bold " RC4"; out " (CVE-2013-2566, CVE-2015-2808) " pr_bold " RC4"; out " (CVE-2013-2566, CVE-2015-2808) "
$OPENSSL ciphers -V 'RC4:@STRENGTH' >$TMPFILE # -V doesn't work with openssl < 1.0, feeding this into the while loop below $OPENSSL ciphers -V 'RC4:@STRENGTH' >$TMPFILE 2>$ERRFILE # -V doesn't work with openssl < 1.0, feeding this into the while loop below
$OPENSSL s_client -cipher $rc4_ciphers_list $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI &>/dev/null </dev/null $OPENSSL s_client -cipher $rc4_ciphers_list $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI &>/dev/null </dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
# FF >=39 won't connect to them unless it's in this white list: http://mxr.mozilla.org/mozilla-central/source/security/manager/ssl/IntolerantFallbackList.inc # FF >=39 won't connect to them unless it's in this white list: http://mxr.mozilla.org/mozilla-central/source/security/manager/ssl/IntolerantFallbackList.inc
@ -3487,27 +3508,27 @@ get_install_dir() {
#INSTALL_DIR=$(cd "$(dirname "$0")" && pwd)/$(basename "$0") #INSTALL_DIR=$(cd "$(dirname "$0")" && pwd)/$(basename "$0")
INSTALL_DIR=$(dirname ${BASH_SOURCE[0]}) INSTALL_DIR=$(dirname ${BASH_SOURCE[0]})
[ -r "$RUN_DIR/mapping-rfc.txt" ] && MAP_RFC_FNAME="$RUN_DIR/mapping-rfc.txt" [ -r "$RUN_DIR/mapping-rfc.txt" ] && MAPPING_FILE_RFC="$RUN_DIR/mapping-rfc.txt"
[ -r "$INSTALL_DIR/mapping-rfc.txt" ] && MAP_RFC_FNAME="$INSTALL_DIR/mapping-rfc.txt" [ -r "$INSTALL_DIR/mapping-rfc.txt" ] && MAPPING_FILE_RFC="$INSTALL_DIR/mapping-rfc.txt"
# we haven't found the mapping file yet... # we haven't found the mapping file yet...
if [ ! -r "$MAP_RFC_FNAME" ] && which readlink &>/dev/null ; then if [ ! -r "$MAPPING_FILE_RFC" ] && which readlink &>/dev/null ; then
readlink -f ls &>/dev/null && \ readlink -f ls &>/dev/null && \
INSTALL_DIR=$(readlink -f $(basename ${BASH_SOURCE[0]})) || \ INSTALL_DIR=$(readlink -f $(basename ${BASH_SOURCE[0]})) || \
INSTALL_DIR=$(readlink $(basename ${BASH_SOURCE[0]})) INSTALL_DIR=$(readlink $(basename ${BASH_SOURCE[0]}))
# not sure whether Darwin has -f # not sure whether Darwin has -f
INSTALL_DIR=$(dirname $INSTALL_DIR 2>/dev/null) INSTALL_DIR=$(dirname $INSTALL_DIR 2>/dev/null)
[ -r "$INSTALL_DIR/mapping-rfc.txt" ] && MAP_RFC_FNAME="$INSTALL_DIR/mapping-rfc.txt" [ -r "$INSTALL_DIR/mapping-rfc.txt" ] && MAPPING_FILE_RFC="$INSTALL_DIR/mapping-rfc.txt"
fi fi
# still no mapping file: # still no mapping file:
if [ ! -r "$MAP_RFC_FNAME" ] && which realpath &>/dev/null ; then if [ ! -r "$MAPPING_FILE_RFC" ] && which realpath &>/dev/null ; then
INSTALL_DIR=$(dirname $(realpath ${BASH_SOURCE[0]})) INSTALL_DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))
MAP_RFC_FNAME="$INSTALL_DIR/mapping-rfc.txt" MAPPING_FILE_RFC="$INSTALL_DIR/mapping-rfc.txt"
fi fi
[ ! -r "$MAP_RFC_FNAME" ] && pr_litemagentaln "\nNo mapping file found" [ ! -r "$MAPPING_FILE_RFC" ] && unset MAPPING_FILE_RFC && pr_litemagentaln "\nNo mapping file found"
debugme echo "$MAP_RFC_FNAME" debugme echo "$MAPPING_FILE_RFC"
} }
@ -3555,13 +3576,14 @@ find_openssl_binary() {
: # 5. we tried hard and failed, so now we use the system binaries : # 5. we tried hard and failed, so now we use the system binaries
fi fi
# no ERRFILE initialized yet
$OPENSSL version -a 2>/dev/null >/dev/null $OPENSSL version -a 2>/dev/null >/dev/null
if [ $? -ne 0 ] || [ ! -x "$OPENSSL" ]; then if [ $? -ne 0 ] || [ ! -x "$OPENSSL" ]; then
fatal "cannot exec or find any openssl binary" -1 fatal "cannot exec or find any openssl binary" -1
fi fi
# http://www.openssl.org/news/openssl-notes.html # http://www.openssl.org/news/openssl-notes.html
OSSL_VER=$($OPENSSL version 2>/dev/null| awk -F' ' '{ print $2 }') OSSL_VER=$($OPENSSL version 2>/dev/null | awk -F' ' '{ print $2 }')
OSSL_VER_MAJOR=$(echo "$OSSL_VER" | sed 's/\..*$//') OSSL_VER_MAJOR=$(echo "$OSSL_VER" | sed 's/\..*$//')
OSSL_VER_MINOR=$(echo "$OSSL_VER" | sed -e 's/^.\.//' | tr -d '[a-zA-Z]-') OSSL_VER_MINOR=$(echo "$OSSL_VER" | sed -e 's/^.\.//' | tr -d '[a-zA-Z]-')
OSSL_VER_APPENDIX=$(echo "$OSSL_VER" | tr -d '[0-9.]') OSSL_VER_APPENDIX=$(echo "$OSSL_VER" | tr -d '[0-9.]')
@ -3700,7 +3722,7 @@ mybanner() {
local cwd="" local cwd=""
$QUIET && return $QUIET && return
nr_ciphers=$(count_ciphers $($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH')) nr_ciphers=$(count_ciphers $($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>/dev/null))
[ -z "$GIT_REL" ] && \ [ -z "$GIT_REL" ] && \
idtag="$CVS_REL" || \ idtag="$CVS_REL" || \
idtag="$GIT_REL -- $CVS_REL_SHORT" idtag="$GIT_REL -- $CVS_REL_SHORT"
@ -3742,6 +3764,12 @@ EOF
maketempf() { maketempf() {
TEMPDIR=$(mktemp -d /tmp/ssltester.XXXXXX) || exit -6 TEMPDIR=$(mktemp -d /tmp/ssltester.XXXXXX) || exit -6
TMPFILE=$TEMPDIR/tempfile.txt || exit -6 TMPFILE=$TEMPDIR/tempfile.txt || exit -6
if [[ "$DEBUG" -eq 0 ]]; then
ERRFILE="/dev/null"
else
ERRFILE=$TEMPDIR/errorfile.txt || exit -6
>$ERRFILE
fi
HOSTCERT=$TEMPDIR/host_certificate.txt HOSTCERT=$TEMPDIR/host_certificate.txt
HEADERFILE=$TEMPDIR/http_header.txt HEADERFILE=$TEMPDIR/http_header.txt
HEADERFILE_BREACH=$TEMPDIR/http_header_breach.txt HEADERFILE_BREACH=$TEMPDIR/http_header_breach.txt
@ -3774,7 +3802,7 @@ PATH: $PATH
PROG_NAME: $PROG_NAME PROG_NAME: $PROG_NAME
INSTALL_DIR: $INSTALL_DIR INSTALL_DIR: $INSTALL_DIR
RUN_DIR: $RUN_DIR RUN_DIR: $RUN_DIR
MAP_RFC_FNAME: $MAP_RFC_FNAME MAPPING_FILE_RFC: $MAPPING_FILE_RFC
CAPATH: $CAPATH CAPATH: $CAPATH
@ -3825,11 +3853,17 @@ cleanup () {
outln outln
} }
fatal() {
pr_magentaln "Fatal error: $1"
exit $2
}
# for now only GOST engine # for now only GOST engine
initialize_engine(){ initialize_engine(){
grep -q '^# testssl config file' "$OPENSSL_CONF" 2>/dev/null && return 0 # have been here already grep -q '^# testssl config file' "$OPENSSL_CONF" 2>/dev/null && return 0 # have been here already
if ! $OPENSSL engine gost -vvvv -t -c >/dev/null 2>&1; then if ! $OPENSSL engine gost -vvvv -t -c 2>/dev/null >/dev/null; then
outln outln
pr_litemagenta "No engine or GOST support via engine with your $OPENSSL"; outln pr_litemagenta "No engine or GOST support via engine with your $OPENSSL"; outln
return 1 return 1
@ -3837,7 +3871,7 @@ initialize_engine(){
outln outln
pr_litemagenta "No engine or GOST support via engine with your $OPENSSL"; outln pr_litemagenta "No engine or GOST support via engine with your $OPENSSL"; outln
return 1 return 1
else # we have engine support else # we have engine support
if [[ -n "$OPENSSL_CONF" ]]; then if [[ -n "$OPENSSL_CONF" ]]; then
pr_litemagentaln "For now I am providing the config file in to have GOST support" pr_litemagentaln "For now I am providing the config file in to have GOST support"
else else
@ -3863,12 +3897,13 @@ EOF
export OPENSSL_CONF export OPENSSL_CONF
fi fi
fi fi
return 0 return 0
} }
ignore_no_or_lame() { ignore_no_or_lame() {
local a
[[ "$WARNINGS" == "off" ]] && return 0 [[ "$WARNINGS" == "off" ]] && return 0
[[ "$WARNINGS" == "false" ]] && return 0 [[ "$WARNINGS" == "false" ]] && return 0
[[ "$WARNINGS" == "batch" ]] && return 1 [[ "$WARNINGS" == "batch" ]] && return 1
@ -3884,8 +3919,9 @@ ignore_no_or_lame() {
# arg1: URI # arg1: URI
# arg2: protocol # arg2: protocol
parse_hn_port() { parse_hn_port() {
NODE="$1" local tmp_port
NODE="$1"
# strip "https" and trailing urlpath supposed it was supplied additionally # strip "https" and trailing urlpath supposed it was supplied additionally
echo "$NODE" | grep -q 'https://' && NODE=$(echo "$NODE" | sed -e 's/^https\:\/\///') echo "$NODE" | grep -q 'https://' && NODE=$(echo "$NODE" | sed -e 's/^https\:\/\///')
@ -3913,10 +3949,10 @@ parse_hn_port() {
URL_PATH=$(echo $URL_PATH | sed 's/\/\//\//g') # we rather want // -> / URL_PATH=$(echo $URL_PATH | sed 's/\/\//\//g') # we rather want // -> /
[[ -z "$URL_PATH" ]] && URL_PATH="/" [[ -z "$URL_PATH" ]] && URL_PATH="/"
debugme echo $URL_PATH debugme echo $URL_PATH
return 0 # NODE, URL_PATH, PORT is set now return 0 # NODE, URL_PATH, PORT is set now
} }
is_ipv4addr() { is_ipv4addr() {
local octet="(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])" local octet="(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
local ipv4address="$octet\\.$octet\\.$octet\\.$octet" local ipv4address="$octet\\.$octet\\.$octet\\.$octet"
@ -3936,8 +3972,8 @@ is_ipv6addr() {
# less than 2x ":" # less than 2x ":"
[[ $(count_lines "$(echo -n "$1" | tr ':' '\n')") -le 1 ]] && \ [[ $(count_lines "$(echo -n "$1" | tr ':' '\n')") -le 1 ]] && \
return 1 return 1
#check on char we allow: #check on chars allowed:
[[ -n "$(echo -n | tr -d '0-9:a-fA-F ' | sed -e '/^$/d')" ]] && \ [[ -n "$(tr -d '0-9:a-fA-F ' <<< "$1" | sed -e '/^$/d')" ]] && \
return 1 return 1
return 0 return 0
} }
@ -4087,7 +4123,7 @@ determine_rdns() {
elif which host &> /dev/null; then elif which host &> /dev/null; then
rDNS=$(host -t PTR $NODEIP 2>/dev/null | awk '/pointer/ { print $NF }') rDNS=$(host -t PTR $NODEIP 2>/dev/null | awk '/pointer/ { print $NF }')
elif which nslookup &> /dev/null; then elif which nslookup &> /dev/null; then
rDNS=$(nslookup -type=PTR $NODEIP 2> /dev/null | grep -v 'canonical name =' | grep 'name = ' | awk '{ print $NF }' | sed 's/\.$//') rDNS=$(nslookup -type=PTR $NODEIP 2>/dev/null | grep -v 'canonical name =' | grep 'name = ' | awk '{ print $NF }' | sed 's/\.$//')
fi fi
OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134 OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134
rDNS=$(echo $rDNS) rDNS=$(echo $rDNS)
@ -4101,25 +4137,18 @@ get_mx_record() {
OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134
if which host &> /dev/null; then if which host &> /dev/null; then
mxs=$(host -t MX "$1" 2>/dev/null| grep 'handled by' | sed -e 's/^.*by //g' -e 's/\.$//') mxs=$(host -t MX "$1" 2>/dev/null | grep 'handled by' | sed -e 's/^.*by //g' -e 's/\.$//')
elif which dig &> /dev/null; then elif which dig &> /dev/null; then
mxs=$(dig +short -t MX "$1" 2>/dev/null) mxs=$(dig +short -t MX "$1" 2>/dev/null)
elif which nslookup &> /dev/null; then 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 else
pr_magentaln 'No dig, host or nslookup' fatal "No dig, host or nslookup" -3
exit -3
fi fi
OPENSSL_CONF="$saved_openssl_conf" OPENSSL_CONF="$saved_openssl_conf"
echo "$mxs" echo "$mxs"
} }
fatal() {
pr_magentaln "Fatal error: $1"
exit $2
}
# We need to get the IP address of the proxy so we can use it in fd_socket # We need to get the IP address of the proxy so we can use it in fd_socket
check_proxy(){ check_proxy(){
local save_LOCAL_A=$LOCAL_A local save_LOCAL_A=$LOCAL_A
@ -4196,7 +4225,7 @@ determine_service() {
# see http://xmpp.org/rfcs/rfc3920.html # see http://xmpp.org/rfcs/rfc3920.html
fi fi
fi fi
$OPENSSL s_client -connect $NODEIP:$PORT $PROXY $STARTTLS 2>/dev/null >$TMPFILE </dev/null $OPENSSL s_client -connect $NODEIP:$PORT $PROXY $STARTTLS 2>$ERRFILE >$TMPFILE </dev/null
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
pr_magentaln " $OPENSSL couldn't establish STARTTLS via $protocol to $NODEIP:$PORT" pr_magentaln " $OPENSSL couldn't establish STARTTLS via $protocol to $NODEIP:$PORT"
debugme cat $TMPFILE debugme cat $TMPFILE
@ -4236,7 +4265,8 @@ display_rdns_etc() {
} }
datebanner() { datebanner() {
tojour=$(date +%F)" "$(date +%R) local tojour="$(date +%F) $(date +%R)"
outln outln
pr_reverse "$1 now ($tojour) ---> $NODEIP:$PORT ($NODE) <---"; outln "\n" pr_reverse "$1 now ($tojour) ---> $NODEIP:$PORT ($NODE) <---"; outln "\n"
if [[ "$1" == "Testing" ]]; then if [[ "$1" == "Testing" ]]; then
@ -4764,4 +4794,4 @@ fi
exit $ret exit $ret
# $Id: testssl.sh,v 1.357 2015/08/24 12:09:44 dirkw Exp $ # $Id: testssl.sh,v 1.358 2015/08/24 21:50:01 dirkw Exp $