- 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 RUN_DIR=$(dirname $0)
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 }')
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>
# 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
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
@ -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
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"
TEMPDIR=""
TMPFILE=""
ERRFILE=""
HOSTCERT=""
HEADERFILE=""
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
# 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_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_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_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_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_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_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_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_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_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_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_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_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; }
@ -376,6 +375,15 @@ count_words() {
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() {
echo "$1" | tr '\n' ' ' | sed 's/ $//'
}
@ -405,9 +413,11 @@ out_row_aligned() {
tmpfile_handle() {
if [[ "$DEBUG" -eq 0 ]] ; then
rm $TMPFILE
rm $TMPFILE 2>/dev/null
[[ $ERRFILE =~ "dev/null" ]] || rm $ERRFILE
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
}
@ -465,7 +475,7 @@ runs_HTTP() {
out " -- ASSUMING_HTTP set though"
ret=0
else
out ", assuming no HTTP service, skipping HTTP checks"
out ", assuming no HTTP service => skipping HTTP checks"
ret=1
fi
;;
@ -519,15 +529,15 @@ EOF
ret=0
else
#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
pr_litemagentaln " failed (1st request stalled, 2nd erroneous)"
return 3
#ret=3
fi
fi
status_code=$(awk '/^HTTP\// { print $2 }' $HEADERFILE 2>/dev/null)
msg_thereafter=$(awk -F"$status_code" '/^HTTP\// { print $2 }' $HEADERFILE 2>/dev/null) # dirty trick to use the status code as a
status_code=$(awk '/^HTTP\// { print $2 }' $HEADERFILE 2>>$ERRFILE)
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
debugme echo "Status/MSG: $status_code $msg_thereafter"
@ -571,7 +581,7 @@ run_http_date() {
if $HAS_GNUDATE ; then
HTTP_TIME=$(date --date="$HTTP_TIME" "+%s")
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
difftime=$(($HTTP_TIME - $now))
@ -824,6 +834,8 @@ run_rp_banner() {
emphasize_stuff_in_headers "$line"
done
fi
outln
tmpfile_handle $FUNCNAME.txt
return 0
@ -991,14 +1003,14 @@ prettyprint_local() {
neat_header
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
neat_list $HEXC $ciph $kx $enc
outln
done
else
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
# for numbers we don't do word matching:
[[ $arg =~ $re ]] && \
@ -1015,7 +1027,7 @@ prettyprint_local() {
# list ciphers (and makes sure you have them locally configured)
# arg[1]: cipher list (or anything else)
listciphers() {
local ret
local -i ret
local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< $1)"
$OPENSSL ciphers "$1" &>$TMPFILE
@ -1031,15 +1043,15 @@ listciphers() {
# argv[2]: string on console
# argv[3]: ok to offer? 0: yes, 1: no
std_cipherlists() {
local ret
local -i ret
local singlespaces
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
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=$?
debugme cat $TMPFILE.2
debugme cat $ERRFILE
case $3 in
0) # ok to offer
[[ $ret -eq 0 ]] && \
@ -1060,11 +1072,10 @@ std_cipherlists() {
*) # we shouldn't reach this
pr_litemagenta "? (please report this)" ;;
esac
debugme cat $TMPFILE.2 >>$TMPFILE
tmpfile_handle $FUNCNAME.$debugname.txt
else
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
# we need lf in those cases:
[[ $DEBUG -ge 2 ]] && echo
@ -1089,8 +1100,10 @@ socksend() {
#FIXME: This is only for HB and CCS, others use still sockread_serverhello()
sockread() {
local -i ret=0
local ddreply
[[ "x$2" == "x" ]] && maxsleep=$MAX_WAITSOCK || maxsleep=$2
ret=0
ddreply=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7
dd bs=$1 of=$ddreply count=1 <&5 2>/dev/null &
@ -1098,21 +1111,22 @@ sockread() {
ret=$?
SOCKREPLY=$(cat $ddreply)
rm $ddreply
return $ret
}
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/')
[[ -n "$RFCname" ]] && out "$RFCname"
local 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
}
neat_header(){
outln "Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits${MAP_RFC_FNAME:+ Cipher Suite Name (RFC)}"
outln "%s-------------------------------------------------------------------------${MAP_RFC_FNAME:+----------------------------------------------}"
printf -- "Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits${MAPPING_FILE_RFC:+ Cipher Suite Name (RFC)}\n"
printf -- "%s-------------------------------------------------------------------------${MAPPING_FILE_RFC:+----------------------------------------------}\n"
}
@ -1121,11 +1135,15 @@ neat_header(){
# arg3: keyexchange
# arg4: encryption (maybe included "export")
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
local hexcode="$1"
local ossl_cipher="$2"
local kx enc strength
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"
# workaround for color escape codes:
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
#echo ${#kx} # should be always 20
fi
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)"
else
printf -- " %-7s %-30s %-10s %-11s%-11s${SHOW_EACH_C:+ }" "$1" "$2" "$kx" "$enc" "$strength"
fi
#if [[ -r "$MAPPING_FILE_RFC" ]]; then
printf -- " %-7s %-30s %-10s %-11s%-11s${MAPPING_FILE_RFC:+ %-48s}${SHOW_EACH_C:+ }" "$hexcode" "$ossl_cipher" "$kx" "$enc" "$strength" "$(show_rfc_style $HEXC)"
#else
# printf -- " %-7s %-30s %-10s %-11s%-11s${SHOW_EACH_C:+ }" "$1" "$2" "$kx" "$enc" "$strength"
#fi
}
test_just_one(){
@ -1157,7 +1175,7 @@ test_just_one(){
neat_header
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
$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!
normalize_ciphercode $hexcode
# is argument a number?
@ -1202,13 +1220,13 @@ run_allciphers(){
local hexcode n ciph sslvers kx auth enc mac export
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"
! $HAS_DH_BITS && pr_litemagentaln " (Your $OPENSSL cannot show DH/ECDH bits)"
outln
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!
$OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI &>$TMPFILE </dev/null
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
locally_supported "$proto" "$proto_text" || continue
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
ret=$?
if [[ $ret -ne 0 ]] && [[ "$SHOW_EACH_C" -eq 0 ]]; then
@ -1276,15 +1294,13 @@ run_cipher_per_proto(){
}
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"
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
else
ret=0
fi
return $ret
}
@ -1292,7 +1308,7 @@ locally_supported() {
run_prototest_openssl() {
local sni="$SNI"
local ret
local -i ret=0
$OPENSSL s_client -state $1 $STARTTLS -connect $NODEIP:$PORT $PROXY $sni &>$TMPFILE </dev/null
ret=$?
@ -1300,7 +1316,7 @@ run_prototest_openssl() {
$VERBERR && egrep "error|failure" $TMPFILE | egrep -av "unable to get local|verify error"
if ! locally_supported "$1" "$2" ; then
return 7
ret=7
else # we remove SNI for SSLv2 and v3:
[[ "$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)
@ -1495,21 +1511,27 @@ read_dhbits_from_file() {
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_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;
pr_blue "--> Testing server preferences"; outln "\n"
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
pr_magenta "no matching cipher in this list found (pls report this): "
outln "$list_fwd . "
ret=6
else
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')
if [[ "$cipher1" != "$cipher2" ]]; then
@ -1522,7 +1544,7 @@ run_server_preference() {
[[ $DEBUG -ge 2 ]] && out " $cipher1 | $cipher2"
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 "
default_proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g')
case "$default_proto" in
@ -1556,7 +1578,7 @@ run_server_preference() {
for p in ssl2 ssl3 tls1 tls1_1 tls1_2; do
#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
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')
@ -1572,7 +1594,7 @@ run_server_preference() {
[[ -n "$PROXY" ]] && arg=" SPDY/NPN is"
[[ -n "$STARTTLS" ]] && arg=" "
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
proto[i]=$(grep -aw "Next protocol" $TMPFILE | sed -e 's/^Next protocol://' -e 's/(.)//' -e 's/ //g')
if [[ -z "${proto[i]}" ]]; then
@ -1621,7 +1643,7 @@ cipher_pref_check() {
pr_bold " Cipher order"
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
tested_cipher=""
proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g')
@ -1631,7 +1653,7 @@ cipher_pref_check() {
printf " %-10s %s " "$proto:" "$cipher"
tested_cipher="-"$cipher
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
cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g')
out "$cipher "
@ -1644,14 +1666,14 @@ cipher_pref_check() {
if ! spdy_pre " SPDY/NPN: " ; then # is NPN/SPDY supported and is this no STARTTLS?
outln
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
$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')
printf " %-10s %s " "$p:" "$cipher"
tested_cipher="-"$cipher
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
cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g')
out "$cipher "
@ -1670,15 +1692,15 @@ get_host_cert() {
# arg1 is proto or empty
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI $1 2>/dev/null </dev/null | \
awk '/-----BEGIN/,/-----END/ { print $0 }' >$HOSTCERT
return $?
return $((${PIPESTATUS[0]} + ${PIPESTATUS[1]}))
}
get_all_certs() {
local savedir
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=$?
savedir=$(pwd); cd $TEMPDIR
# http://backreference.org/2010/05/09/ocsp-verification-with-openssl/
@ -1732,7 +1754,7 @@ run_server_defaults() {
#TLS extensions follow now
# throwing 1st every cipher/protocol at the server to know what works
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=$?
get_host_cert "-$proto"
[ $? -eq 0 ] && [ $ret -eq 0 ] && break
@ -1740,7 +1762,7 @@ run_server_defaults() {
done # this loop is needed for IIS/6
if [ $ret -eq 7 ]; 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".
tmpfile_handle tlsextdebug+status.txt
return 7 # this is ugly, I know
@ -1748,7 +1770,7 @@ run_server_defaults() {
gost_status_problem=true
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 "
extensions=$(grep -aw "^TLS server extension" $TMPFILE | sed -e 's/^TLS server extension \"//' -e 's/\".*$/,/g')
if [ -z "$extensions" ]; then
@ -1769,8 +1791,8 @@ run_server_defaults() {
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/ //')
sig_algo=$($OPENSSL x509 -in $HOSTCERT -noout -text | 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 )
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 2>>$ERRFILE | awk -F':' '/Public Key Algorithm:/ { print $2 }' | sort -u )
if [ -z "$keysize" ]; then
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
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 "$spaces$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256 | sed 's/Fingerprint=//' | sed 's/://g' )"
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 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g' )"
pr_bold " Common Name (CN) "
if $OPENSSL x509 -in $HOSTCERT -noout -subject | grep -wq CN; then
cn=$($OPENSSL x509 -in $HOSTCERT -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//')
if $OPENSSL x509 -in $HOSTCERT -noout -subject 2>>$ERRFILE | grep -wq CN; then
cn=$($OPENSSL x509 -in $HOSTCERT -noout -subject 2>>$ERRFILE | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//')
pr_underline "$cn"
else
cn="(no CN field in subject)"
@ -1819,8 +1841,8 @@ run_server_defaults() {
cn_nosni=""
if [[ -s $HOSTCERT.nosni ]] ; then
if $OPENSSL x509 -in $HOSTCERT.nosni -noout -subject | grep -wq CN; then
cn_nosni=$($OPENSSL x509 -in $HOSTCERT.nosni -noout -subject | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//')
if $OPENSSL x509 -in $HOSTCERT.nosni -noout -subject 2>>$ERRFILE | grep -wq CN; then
cn_nosni=$($OPENSSL x509 -in $HOSTCERT.nosni -noout -subject 2>>$ERRFILE | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//')
else
cn_nosni="no CN field in subject"
fi
@ -1846,7 +1868,7 @@ run_server_defaults() {
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')
# ^^^ CACert
@ -1860,10 +1882,10 @@ run_server_defaults() {
fi
outln
pr_bold " 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')
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=$($OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE| sed -e 's/^.*CN=//g' -e '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 2>>$ERRFILE | grep -q 'C=' ; then
issuer_c=$($OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE | sed 's/^.*C=//g' | sed 's/\/.*$//g')
else
issuer_c="" # CACert would have 'issuer= ' here otherwise
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
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' || \
[[ "2.16.840.1.114028.10.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
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
pr_red "expired!"
else
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
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
pr_litegreen ">= $DAYS2WARN1 days"
else
@ -1916,11 +1938,11 @@ run_server_defaults() {
fi
if $HAS_GNUDATE ; then
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 2>>$ERRFILE | cut -d= -f 2)" +"%F %H:%M %z")
startdate=$(date --date="$($OPENSSL x509 -in $HOSTCERT -noout -startdate 2>>$ERRFILE | cut -d= -f 2)" +"%F %H:%M")
else
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 -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 2>>$ERRFILE | cut -d= -f 2)" +"%F %H:%M")
fi
outln " ($startdate --> $enddate)"
@ -1929,7 +1951,7 @@ run_server_defaults() {
pr_bold " # of certificates provided"; outln " $(get_all_certs)"
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
0) pr_literedln "--" ;;
1) outln "$crl" ;;
@ -1937,7 +1959,7 @@ run_server_defaults() {
esac
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"
pr_bold " OCSP stapling "
@ -1963,7 +1985,7 @@ run_server_defaults() {
# already -- and that was a different one -- means that would get overwritten anyway
tmpfile_handle tlsextdebug+status.txt
tls_time
tls_time
return $ret
}
@ -1994,7 +2016,7 @@ run_pfs() {
no_supported_ciphers=$(count_ciphers $(actually_supported_ciphers $pfs_cipher_list))
if [ "$no_supported_ciphers" -le "$CLIENT_MIN_PFS" ] ; then
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
fi
@ -2005,12 +2027,12 @@ run_pfs() {
pr_brownln "Not OK: No ciphers supporting Forward Secrecy offered"
else
pfs_offered=0
pr_litegreen " PFS is offered (OK)"
if $WIDE; then
pr_litegreen " PFS ciphers (OK): "
outln ", cipher follow (client/browser support is here specially important) \n"
outln ", ciphers follow (client/browser support is here specially important) \n"
neat_header
else
pr_litegreen " PFS is offered (OK) "
out " "
fi
while read hexcode dash pfs_cipher sslvers kx auth enc mac; do
tmpfile=$TMPFILE.$hexcode
@ -2038,7 +2060,7 @@ run_pfs() {
else
out "$pfs_cipher "
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
debugme echo $pfs_offered
@ -2075,19 +2097,22 @@ spdy_pre(){
# first, does the current openssl support it?
$OPENSSL s_client help 2>&1 | grep -qw nextprotoneg
if [ $? -ne 0 ]; then
pr_magentaln "Local problem: $OPENSSL doesn't support SPDY/NPN";
local_problem "$OPENSSL doesn't support SPDY/NPN";
return 7
fi
return 0
}
run_spdy() {
local tmpstr
local -i ret=0
pr_bold " SPDY/NPN "
if ! spdy_pre ; then
echo
return 0
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.*: //')
if [ -z "$tmpstr" -o "$tmpstr" == " " ] ; then
out "not offered"
@ -2657,7 +2682,7 @@ tls_sockets() {
save=$?
# 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) "
# 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
}
local_problem() {
pr_litemagentaln "Local problem: $1"
}
run_renego() {
# no SNI here. Not needed as there won't be two different SSL stacks for one IP
local legacycmd=""
@ -2951,7 +2980,7 @@ run_renego() {
case "$OSSL_VER" in
0.9.8*) # we need this for Mac OSX unfortunately
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 ;;
[m-z]) ;; # all ok
esac ;;
@ -2998,7 +3027,7 @@ run_crime() {
# 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
if [ $? -eq 0 ]; then
pr_magentaln "Local Problem: Your $OPENSSL lacks zlib support"
local_problem "$OPENSSL lacks zlib support"
return 7
fi
@ -3117,15 +3146,6 @@ EOF
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
run_ssl_poodle() {
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"
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??
debugme echo $cbc_ciphers
$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
$OPENSSL s_client -h 2>&1 | grep -q "\-fallback_scsv"
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
fi
@ -3220,7 +3240,7 @@ run_freak() {
#echo "========= ${PIPESTATUS[*]}
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 ;;
1|2|3)
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))
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 ;;
1|2) addtl_warning=" ($magenta""tested w/ $no_supported_ciphers/4 ciphers only!$off)" ;;
3) addtl_warning=" (tested w/ $no_supported_ciphers/4 ciphers)" ;;
@ -3309,9 +3329,10 @@ run_beast(){
pr_bold " BEAST"; out " (CVE-2011-3389) "
$WIDE && outln
>$ERRFILE
# 2) test handfull of common CBC ciphers
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 $continued; then # second round: we hit 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
fi
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 -eq 0 ]] && vuln_beast=true
if $WIDE; then
@ -3349,7 +3370,7 @@ run_beast(){
vuln_beast=true
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
if ! $WIDE; then
@ -3371,7 +3392,7 @@ run_beast(){
# 2) support for TLS 1.1+1.2?
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
higher_proto_supported="$higher_proto_supported ""$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol .*://' -e 's/ //g')"
fi
@ -3416,7 +3437,7 @@ run_rc4() {
fi
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
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
@ -3487,27 +3508,27 @@ get_install_dir() {
#INSTALL_DIR=$(cd "$(dirname "$0")" && pwd)/$(basename "$0")
INSTALL_DIR=$(dirname ${BASH_SOURCE[0]})
[ -r "$RUN_DIR/mapping-rfc.txt" ] && MAP_RFC_FNAME="$RUN_DIR/mapping-rfc.txt"
[ -r "$INSTALL_DIR/mapping-rfc.txt" ] && MAP_RFC_FNAME="$INSTALL_DIR/mapping-rfc.txt"
[ -r "$RUN_DIR/mapping-rfc.txt" ] && MAPPING_FILE_RFC="$RUN_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...
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 && \
INSTALL_DIR=$(readlink -f $(basename ${BASH_SOURCE[0]})) || \
INSTALL_DIR=$(readlink $(basename ${BASH_SOURCE[0]}))
# not sure whether Darwin has -f
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
# 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]}))
MAP_RFC_FNAME="$INSTALL_DIR/mapping-rfc.txt"
MAPPING_FILE_RFC="$INSTALL_DIR/mapping-rfc.txt"
fi
[ ! -r "$MAP_RFC_FNAME" ] && pr_litemagentaln "\nNo mapping file found"
debugme echo "$MAP_RFC_FNAME"
[ ! -r "$MAPPING_FILE_RFC" ] && unset MAPPING_FILE_RFC && pr_litemagentaln "\nNo mapping file found"
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
fi
# no ERRFILE initialized yet
$OPENSSL version -a 2>/dev/null >/dev/null
if [ $? -ne 0 ] || [ ! -x "$OPENSSL" ]; then
fatal "cannot exec or find any openssl binary" -1
fi
# 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_MINOR=$(echo "$OSSL_VER" | sed -e 's/^.\.//' | tr -d '[a-zA-Z]-')
OSSL_VER_APPENDIX=$(echo "$OSSL_VER" | tr -d '[0-9.]')
@ -3700,7 +3722,7 @@ mybanner() {
local cwd=""
$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" ] && \
idtag="$CVS_REL" || \
idtag="$GIT_REL -- $CVS_REL_SHORT"
@ -3742,6 +3764,12 @@ EOF
maketempf() {
TEMPDIR=$(mktemp -d /tmp/ssltester.XXXXXX) || 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
HEADERFILE=$TEMPDIR/http_header.txt
HEADERFILE_BREACH=$TEMPDIR/http_header_breach.txt
@ -3774,7 +3802,7 @@ PATH: $PATH
PROG_NAME: $PROG_NAME
INSTALL_DIR: $INSTALL_DIR
RUN_DIR: $RUN_DIR
MAP_RFC_FNAME: $MAP_RFC_FNAME
MAPPING_FILE_RFC: $MAPPING_FILE_RFC
CAPATH: $CAPATH
@ -3825,11 +3853,17 @@ cleanup () {
outln
}
fatal() {
pr_magentaln "Fatal error: $1"
exit $2
}
# for now only GOST engine
initialize_engine(){
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
pr_litemagenta "No engine or GOST support via engine with your $OPENSSL"; outln
return 1
@ -3837,7 +3871,7 @@ initialize_engine(){
outln
pr_litemagenta "No engine or GOST support via engine with your $OPENSSL"; outln
return 1
else # we have engine support
else # we have engine support
if [[ -n "$OPENSSL_CONF" ]]; then
pr_litemagentaln "For now I am providing the config file in to have GOST support"
else
@ -3863,12 +3897,13 @@ EOF
export OPENSSL_CONF
fi
fi
return 0
}
ignore_no_or_lame() {
local a
[[ "$WARNINGS" == "off" ]] && return 0
[[ "$WARNINGS" == "false" ]] && return 0
[[ "$WARNINGS" == "batch" ]] && return 1
@ -3884,8 +3919,9 @@ ignore_no_or_lame() {
# arg1: URI
# arg2: protocol
parse_hn_port() {
NODE="$1"
local tmp_port
NODE="$1"
# strip "https" and trailing urlpath supposed it was supplied additionally
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 // -> /
[[ -z "$URL_PATH" ]] && URL_PATH="/"
debugme echo $URL_PATH
return 0 # NODE, URL_PATH, PORT is set now
}
is_ipv4addr() {
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"
@ -3936,8 +3972,8 @@ is_ipv6addr() {
# less than 2x ":"
[[ $(count_lines "$(echo -n "$1" | tr ':' '\n')") -le 1 ]] && \
return 1
#check on char we allow:
[[ -n "$(echo -n | tr -d '0-9:a-fA-F ' | sed -e '/^$/d')" ]] && \
#check on chars allowed:
[[ -n "$(tr -d '0-9:a-fA-F ' <<< "$1" | sed -e '/^$/d')" ]] && \
return 1
return 0
}
@ -4087,7 +4123,7 @@ determine_rdns() {
elif which host &> /dev/null; then
rDNS=$(host -t PTR $NODEIP 2>/dev/null | awk '/pointer/ { print $NF }')
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
OPENSSL_CONF="$saved_openssl_conf" # see https://github.com/drwetter/testssl.sh/issues/134
rDNS=$(echo $rDNS)
@ -4101,25 +4137,18 @@ get_mx_record() {
OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134
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
mxs=$(dig +short -t MX "$1" 2>/dev/null)
elif which nslookup &> /dev/null; then
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
fatal "No dig, host or nslookup" -3
fi
OPENSSL_CONF="$saved_openssl_conf"
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
check_proxy(){
local save_LOCAL_A=$LOCAL_A
@ -4196,7 +4225,7 @@ determine_service() {
# see http://xmpp.org/rfcs/rfc3920.html
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
pr_magentaln " $OPENSSL couldn't establish STARTTLS via $protocol to $NODEIP:$PORT"
debugme cat $TMPFILE
@ -4236,7 +4265,8 @@ display_rdns_etc() {
}
datebanner() {
tojour=$(date +%F)" "$(date +%R)
local tojour="$(date +%F) $(date +%R)"
outln
pr_reverse "$1 now ($tojour) ---> $NODEIP:$PORT ($NODE) <---"; outln "\n"
if [[ "$1" == "Testing" ]]; then
@ -4764,4 +4794,4 @@ fi
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 $