2014-07-16 19:04:15 +02:00
|
|
|
#!/usr/bin/env bash
|
2014-10-29 21:24:43 +01:00
|
|
|
# bash is needed for some distros which use dash as /bin/sh and for tcp sockets which
|
|
|
|
# this program uses a couple of times
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
# Program for spotting weak SSL encryption, ciphers, version and some vulnerablities or features
|
|
|
|
|
2014-11-20 10:46:55 +01:00
|
|
|
VERSION="2.1rc2"
|
2014-07-01 16:28:16 +02:00
|
|
|
SWURL="https://testssl.sh"
|
|
|
|
SWCONTACT="dirk aet testssl dot sh"
|
|
|
|
|
|
|
|
# Author: Dirk Wetter, copyleft: 2007-2014
|
|
|
|
#
|
|
|
|
# License: GPLv2, see http://www.fsf.org/licensing/licenses/info/GPLv2.html
|
|
|
|
# and accompanying license "LICENSE.txt". Redistribution + modification under this
|
|
|
|
# license permitted.
|
|
|
|
# If you enclose this script or parts of it in your software, it has to
|
|
|
|
# be accompanied by the same license (see link) and the place where to get
|
|
|
|
# the recent version of this program: https://testssl.sh
|
|
|
|
# Don't violate the license.
|
|
|
|
#
|
|
|
|
# USAGE WITHOUT ANY WARRANTY, THE SOFTWARE IS PROVIDED "AS IS". USE IT AT
|
|
|
|
# your OWN RISK
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
# I know reading this shell script is neither nice nor it's rocket science. However openssl
|
|
|
|
# is a such a good swiss army knife (e.g. wiki.openssl.org/index.php/Command_Line_Utilities)
|
|
|
|
# that it was difficult to resist wrapping it with some shell commandos. That's how everything
|
|
|
|
# started -- but that was (and still is) a long way to go.
|
|
|
|
#
|
|
|
|
# One can do the same in other languages and/or choose another crypto provider as openssl -- YMMV.
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
# Q: So what's the difference between https://www.ssllabs.com/ssltest or
|
|
|
|
# https://sslcheck.globalsign.com/?
|
2014-07-16 19:04:15 +02:00
|
|
|
# A: As of now ssllabs only check webservers on standard ports, reachable from
|
2014-07-01 16:28:16 +02:00
|
|
|
# the internet. And those are 3rd parties. If those four restrictions are fine
|
|
|
|
# with you, they might tell you more than this tool -- as of now.
|
|
|
|
|
|
|
|
# Note that 56Bit ciphers are disabled during compile time in $OPENSSL > 0.9.8c
|
|
|
|
# (http://rt.$OPENSSL.org/Ticket/Display.html?user=guest&pass=guest&id=1461)
|
|
|
|
# ---> TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES in ssl/tls1.h . For testing it's recommended
|
|
|
|
# to change this to 1 and recompile e.g. w/ ./config --prefix=/usr/ --openssldir=/etc/ssl .
|
|
|
|
# Also some distributions disable SSLv2. Please note: Everything which is disabled or not
|
|
|
|
# supported on the client side is not possible to test on the server side!
|
2014-07-16 19:04:15 +02:00
|
|
|
# Thus as a courtesy I provide openssl binaries for Linux which have everything you need
|
|
|
|
# enabled, see website
|
|
|
|
#
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
# following variables make use of $ENV, e.g. OPENSSL=<myprivate_path_to_openssl> ./testssl.sh <host>
|
|
|
|
|
|
|
|
#OPENSSL="${OPENSSL:-/usr/bin/openssl}" # private openssl version --> is now evaluated below
|
|
|
|
CAPATH="${CAPATH:-/etc/ssl/certs/}" # same as previous. Doing nothing yet. FC has only a CA bundle per default, ==> openssl version -d
|
|
|
|
OSSL_VER="" # openssl version, will be autodetermined
|
|
|
|
NC="" # netcat will be autodetermined
|
2014-11-22 21:15:47 +01:00
|
|
|
ECHO="/usr/bin/printf --" # works under Linux, BSD, MacOS. watch out under Solaris, not tested yet under cygwin
|
2014-11-17 18:49:56 +01:00
|
|
|
COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all
|
2014-07-01 16:28:16 +02:00
|
|
|
SHOW_LCIPHERS=no # determines whether the client side ciphers are displayed at all (makes no sense normally)
|
|
|
|
VERBERR=${VERBERR:-1} # 0 means to be more verbose (some like the errors to be dispayed so that one can tell better
|
|
|
|
# whether the handshake succeeded or not. For errors with individual ciphers you also need to have SHOW_EACH_C=1
|
2014-11-25 13:12:24 +01:00
|
|
|
LOCERR=${LOCERR:-0} # displays the local error
|
2014-07-01 16:28:16 +02:00
|
|
|
SHOW_EACH_C=${SHOW_EACH_C:-0} # where individual ciphers are tested show just the positively ones tested
|
|
|
|
SNEAKY=${SNEAKY:-1} # if zero: the referer and useragent we leave while checking the http header is just usual
|
|
|
|
#FIXME: consequently we should mute the initial netcat and openssl s_client -connect as they cause a 400 (nginx, apache)
|
|
|
|
|
|
|
|
#FIXME: still to be filled with (more) sense:
|
|
|
|
DEBUG=${DEBUG:-0} # if 1 the temp file won't be erased. Currently only keeps the last output anyway
|
|
|
|
VERBOSE=${VERBOSE:-0} # if 1 it shows what's going on. Currently only used for heartbleed and ccs injection
|
|
|
|
VERB_CLIST="" # ... and if so, "-V" shows them row by row cipher, SSL-version, KX, Au, Enc and Mac
|
|
|
|
HSTS_MIN=180 #>180 days is ok for HSTS
|
2014-10-29 21:24:43 +01:00
|
|
|
HPKP_MIN=9 #>9 days should be ok for HPKP_MIN, practical hiints?
|
2014-10-30 21:12:18 +01:00
|
|
|
MAX_WAITSOCK=10 # waiting at max 10 seconds for socket reply
|
2014-11-19 17:08:59 +01:00
|
|
|
CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS
|
2014-07-01 16:28:16 +02:00
|
|
|
NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1"
|
2014-10-30 21:12:18 +01:00
|
|
|
RUN_DIR=`dirname $0`
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-10-30 21:12:18 +01:00
|
|
|
# more global vars:
|
2014-07-01 16:28:16 +02:00
|
|
|
TLS_PROTO_OFFERED=""
|
|
|
|
SOCKREPLY=""
|
|
|
|
HEXC=""
|
|
|
|
SNI=""
|
|
|
|
IP4=""
|
|
|
|
IP6=""
|
|
|
|
OSSL_VER_MAJOR=0
|
|
|
|
OSSL_VER_MINOR=0
|
|
|
|
OSSL_VER_APPENDIX="none"
|
|
|
|
NODEIP=""
|
|
|
|
IPS=""
|
2014-10-30 21:12:18 +01:00
|
|
|
|
2014-11-18 04:30:48 +01:00
|
|
|
# make sure that temporary files are cleaned up after use
|
|
|
|
trap cleanup QUIT EXIT
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
# The various hexdump commands we need to replace xxd (BSD compatability))
|
|
|
|
HEXDUMPVIEW=(hexdump -C) # This is used in verbose mode to see what's going on
|
|
|
|
HEXDUMP=(hexdump -ve '16/1 "%02x " " \n"') # This is used to analyse the reply
|
|
|
|
HEXDUMPPLAIN=(hexdump -ve '1/1 "%.2x"') # Replaces both xxd -p and tr -cd '[:print:]'
|
|
|
|
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
out() {
|
|
|
|
$ECHO "$1"
|
|
|
|
}
|
|
|
|
|
|
|
|
outln() {
|
|
|
|
[ ! -z "$1" ] && $ECHO "$1"
|
|
|
|
$ECHO "\n"
|
|
|
|
}
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
# some functions for text (i know we could do this with tput, but what about systems having no terminfo?
|
|
|
|
# http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html
|
|
|
|
off() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" != 0 ]] && out "\033[m\c"
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
liteblue() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[0;34m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
liteblueln() { liteblue "$1"; outln; }
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
blue() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[1;34m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
blueln() { blue "$1"; outln; }
|
|
|
|
|
2014-11-17 17:43:59 +01:00
|
|
|
# idea: I have a non-color term. But it can do reverse, bold and underline. Bold
|
|
|
|
# in the result equals to an alarm, underline to s.th. not working (magenta), reverse stays
|
|
|
|
# reverse
|
|
|
|
# FIXME: What bout folks who don't want color at all
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
litered() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[0;31m$1 " || bold "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
literedln() { litered "$1"; outln; }
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
red() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[1;31m$1 " || bold "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
redln() { red "$1"; outln; }
|
|
|
|
|
|
|
|
litemagenta() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[0;35m$1 " || underline "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
litemagentaln() { litemagenta "$1"; outln; }
|
|
|
|
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
magenta() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[1;35m$1 " || underline "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
magentaln() { magenta "$1"; outln; }
|
|
|
|
|
|
|
|
litecyan() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[0;36m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
litecyanln() { litecyan "$1"; outln; }
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
cyan() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[1;36m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
cyanln() { cyan "$1"; outln; }
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
grey() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[1;30m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
greyln() { grey "$1"; outln; }
|
|
|
|
|
|
|
|
litegrey() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[0;37m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
litegreyln() { litegrey "$1"; outln; }
|
|
|
|
|
|
|
|
litegreen() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[0;32m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
litegreenln() { litegreen "$1"; outln; }
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
green() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[1;32m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
greenln() { green "$1"; outln; }
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
brown() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[0;33m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
brownln() { brown "$1"; outln; }
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
yellow() {
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$COLOR" = 2 ]] && out "\033[1;33m$1 " || out "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
off
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
yellowlnln() { yellowln "$1"; outln; }
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-25 13:12:24 +01:00
|
|
|
bold() { [[ "$COLOR" != 0 ]] && out "\033[1m$1" || out "$1" ; off; }
|
2014-07-16 19:04:15 +02:00
|
|
|
boldln() { bold "$1" ; outln; }
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-25 13:12:24 +01:00
|
|
|
underline() { [[ "$COLOR" != 0 ]] && out "\033[4m$1" || out "$1" ; off; }
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-25 13:12:24 +01:00
|
|
|
boldandunder() { [[ "$COLOR" != 0 ]] && out "\033[1m\033[4m$1" || out "$1" ; off; }
|
2014-07-16 19:04:15 +02:00
|
|
|
|
2014-11-25 13:12:24 +01:00
|
|
|
reverse() { [[ "$COLOR" != 0 ]] && out "\033[7m$1" || out "$1" ; off; }
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
|
2014-11-19 18:04:43 +01:00
|
|
|
# whether it is ok to offer/not to offer enc/cipher/version
|
2014-07-01 16:28:16 +02:00
|
|
|
ok(){
|
|
|
|
if [ "$2" -eq 1 ] ; then
|
|
|
|
case $1 in
|
2014-07-16 19:04:15 +02:00
|
|
|
1) redln "offered (NOT ok)" ;; # 1 1
|
2014-09-25 16:24:21 +02:00
|
|
|
0) greenln "not offered (OK)" ;; # 0 1
|
2014-07-01 16:28:16 +02:00
|
|
|
esac
|
|
|
|
else
|
|
|
|
case $1 in
|
2014-11-20 10:46:55 +01:00
|
|
|
7) brownln "not offered" ;; # 7 0
|
|
|
|
6) literedln "offered (NOT ok)" ;; # 6 0
|
2014-11-19 18:04:43 +01:00
|
|
|
5) litered "supported but couldn't detect a cipher"; outln "(check manually)" ;; # 5 5
|
|
|
|
4) litegreenln "offered (OK)" ;; # 4 0
|
2014-10-15 13:10:06 +02:00
|
|
|
3) brownln "offered" ;; # 3 0
|
2014-11-20 10:46:55 +01:00
|
|
|
2) outln "offered" ;; # 2 0
|
2014-09-25 16:24:21 +02:00
|
|
|
1) greenln "offered (OK)" ;; # 1 0
|
2014-07-16 19:04:15 +02:00
|
|
|
0) boldln "not offered" ;; # 0 0
|
2014-07-01 16:28:16 +02:00
|
|
|
esac
|
|
|
|
fi
|
|
|
|
return $2
|
|
|
|
}
|
|
|
|
|
|
|
|
# in a nutshell: It's HTTP-level compression & an attack which works against any cipher suite and
|
|
|
|
# is agnostic to the version of TLS/SSL, more: http://www.breachattack.com/
|
|
|
|
breach() {
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " BREACH"; out " =HTTP Compression, experimental "
|
2014-07-01 16:28:16 +02:00
|
|
|
[ -z "$1" ] && url="/"
|
|
|
|
# referers are important here!
|
|
|
|
if [ $SNEAKY -eq 0 ] ; then
|
|
|
|
referer="Referer: http://google.com/" # see https://community.qualys.com/message/20360
|
|
|
|
useragent="User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
|
|
|
|
else
|
|
|
|
referer="Referer: TLS/SSL-Tester from $SWURL"
|
|
|
|
useragent="User-Agent: Mozilla/4.0 (X11; Linux x86_64; rv:42.0) Gecko/19700101 Firefox/42.0"
|
|
|
|
fi
|
|
|
|
(
|
|
|
|
$OPENSSL s_client -quiet -connect $NODEIP:$PORT $SNI << EOF
|
|
|
|
GET $url HTTP/1.1
|
|
|
|
Host: $NODE
|
|
|
|
$useragent
|
|
|
|
Accept-Language: en-US,en
|
|
|
|
Accept-encoding: gzip,deflate,compress
|
|
|
|
$referer
|
|
|
|
Connection: close
|
|
|
|
|
|
|
|
EOF
|
|
|
|
) &>$HEADERFILE_BREACH
|
|
|
|
ret=$?
|
|
|
|
# sometimes it hangs here. Currently only kill helps
|
|
|
|
#test $DEBUG -eq 1 && \
|
|
|
|
result=`cat $HEADERFILE_BREACH | grep -a '^Content-Encoding' | sed -e 's/^Content-Encoding//' -e 's/://' -e 's/ //g'`
|
|
|
|
result=`echo $result | tr -cd '\40-\176'`
|
|
|
|
if [ -z $result ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
green "no HTTP compression "
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
litered "uses $result compression "
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
# Catch: any URL cvan be vulnerable. I am testing now only the root
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "(only \"$url\" tested)"
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
2014-10-15 13:10:06 +02:00
|
|
|
# Padding Oracle On Downgraded Legacy Encryption
|
|
|
|
poodle() {
|
|
|
|
bold " POODLE "; out "(CVE-2014-3566), experimental "
|
|
|
|
# w/o downgrade check as of now https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 | TLS_FALLBACK_SCSV
|
|
|
|
$OPENSSL s_client -ssl3 $STARTTLS -connect $NODEIP:$PORT $SNI 2>$TMPFILE >/dev/null </dev/null
|
|
|
|
ret=$?
|
|
|
|
[ "$VERBERR" -eq 0 ] && cat $TMPFILE | egrep "error|failure" | egrep -v "unable to get local|verify error"
|
|
|
|
if [ $ret -eq 0 ]; then
|
2014-10-17 22:16:37 +02:00
|
|
|
litered "VULNERABLE"; out ", uses SSLv3 (no TLS_FALLBACK_SCSV tested)"
|
2014-10-15 13:10:06 +02:00
|
|
|
else
|
2014-10-17 22:16:37 +02:00
|
|
|
green "not vulnerable (OK)"
|
2014-10-15 13:10:06 +02:00
|
|
|
fi
|
2014-10-17 22:16:37 +02:00
|
|
|
outln
|
2014-10-15 13:10:06 +02:00
|
|
|
|
|
|
|
rm $TMPFILE
|
|
|
|
return $ret
|
|
|
|
}
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
#problems not handled: chunked, 302
|
|
|
|
http_header() {
|
|
|
|
[ -z "$1" ] && url="/"
|
|
|
|
if [ $SNEAKY -eq 0 ] ; then
|
|
|
|
referer="Referer: "
|
|
|
|
useragent="User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
|
|
|
|
else
|
|
|
|
referer="Referer: TLS/SSL-Tester from $SWURL"
|
|
|
|
useragent="User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:42.0) Gecko/19700101 Firefox/42.0"
|
|
|
|
fi
|
|
|
|
(
|
|
|
|
$OPENSSL s_client -quiet -connect $NODEIP:$PORT $SNI << EOF
|
|
|
|
GET $url HTTP/1.1
|
|
|
|
Host: $NODE
|
|
|
|
$useragent
|
|
|
|
Accept-Language: en-US,en
|
|
|
|
$referer
|
|
|
|
Connection: close
|
|
|
|
|
|
|
|
EOF
|
|
|
|
) &>$HEADERFILE
|
2014-07-16 19:04:15 +02:00
|
|
|
ret=$?
|
|
|
|
# sometimes it hangs here ^^^. Currently only kill helps
|
|
|
|
test $DEBUG -eq 1 && cat $HEADERFILE
|
|
|
|
sed -e '/^<HTML/,$d' -e '/^<html/,$d' -e '/^<XML /,$d' -e '/<?XML /,$d' \
|
|
|
|
-e '/^<xml /,$d' -e '/<?xml /,$d' -e '/^<\!DOCTYPE/,$d' -e '/^<\!doctype/,$d' $HEADERFILE >$HEADERFILE.2
|
2014-07-01 16:28:16 +02:00
|
|
|
#### ^^^ Attention: the filtering for the html body only as of now, doesn't work for other content yet
|
2014-07-16 19:04:15 +02:00
|
|
|
mv $HEADERFILE.2 $HEADERFILE # sed'ing in place doesn't work with BSD and Linux simultaneously
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
2014-10-29 21:24:43 +01:00
|
|
|
includeSubDomains() {
|
|
|
|
if grep -q includeSubDomains "$1"; then
|
|
|
|
litegreen ", includeSubDomains"
|
|
|
|
else
|
|
|
|
litecyan ", just this domain"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
#FIXME: it doesn't follow a 30x. At least a path should be possible to provide
|
|
|
|
hsts() {
|
|
|
|
[ -s $HEADERFILE ] || http_header
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " HSTS "
|
2014-10-29 21:24:43 +01:00
|
|
|
grep -iw '^Strict-Transport-Security' $HEADERFILE >$TMPFILE
|
2014-07-01 16:28:16 +02:00
|
|
|
if [ $? -eq 0 ]; then
|
2014-10-29 21:24:43 +01:00
|
|
|
grep -ciw '^Strict-Transport-Security' $HEADERFILE | egrep -wq "1" || out "(two HSTS header, using 1st one) "
|
2014-10-08 01:03:14 +02:00
|
|
|
AGE_SEC=`sed -e 's/[^0-9]*//g' $TMPFILE | head -1`
|
2014-07-01 16:28:16 +02:00
|
|
|
AGE_DAYS=`expr $AGE_SEC \/ 86400`
|
|
|
|
if [ $AGE_DAYS -gt $HSTS_MIN ]; then
|
2014-10-08 01:03:14 +02:00
|
|
|
litegreen "$AGE_DAYS days \c" ; out "($AGE_SEC s)"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
|
|
|
brown "$AGE_DAYS days (<$HSTS_MIN is not good enough)"
|
|
|
|
fi
|
2014-10-29 21:24:43 +01:00
|
|
|
includeSubDomains "$TMPFILE"
|
|
|
|
else
|
|
|
|
out "no"
|
|
|
|
fi
|
|
|
|
outln
|
|
|
|
|
|
|
|
rm $TMPFILE
|
|
|
|
return $?
|
|
|
|
}
|
|
|
|
|
|
|
|
hpkp() {
|
|
|
|
[ -s $HEADERFILE ] || http_header
|
|
|
|
bold " HPKP "
|
|
|
|
egrep -iw '^Public-Key-Pins|Public-Key-Pins-Report-Only' $HEADERFILE >$TMPFILE
|
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
egrep -ciw '^Public-Key-Pins|Public-Key-Pins-Report-Only' $HEADERFILE | egrep -wq "1" || out "(two HPKP header, using 1st one) "
|
|
|
|
AGE_SEC=`sed -e 's/\r//g' -e 's/^.*max-age=//' -e 's/;.*//' $TMPFILE`
|
|
|
|
AGE_DAYS=`expr $AGE_SEC \/ 86400`
|
|
|
|
if [ $AGE_DAYS -gt $HPKP_MIN ]; then
|
|
|
|
litegreen "$AGE_DAYS days \c" ; out "($AGE_SEC s)"
|
|
|
|
else
|
|
|
|
brown "$AGE_DAYS days (<$HPKP_MIN is not good enough)"
|
|
|
|
fi
|
|
|
|
includeSubDomains "$TMPFILE"
|
|
|
|
out ", fingerprints not checked"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-10-29 21:24:43 +01:00
|
|
|
out "no"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
rm $TMPFILE
|
|
|
|
return $?
|
|
|
|
}
|
2014-10-29 21:24:43 +01:00
|
|
|
#FIXME: report-uri
|
|
|
|
#FIXME: once checkcert.sh is here: fingerprints!
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
serverbanner() {
|
|
|
|
[ -s $HEADERFILE ] || http_header
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " Server "
|
2014-07-01 16:28:16 +02:00
|
|
|
grep -i '^Server' $HEADERFILE >$TMPFILE
|
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
#out=`cat $TMPFILE | sed -e 's/^Server: //' -e 's/^server: //' -e 's/^[[:space:]]//'`
|
2014-07-16 19:04:15 +02:00
|
|
|
serverbanner=`cat $TMPFILE | sed -e 's/^Server: //' -e 's/^server: //'`
|
2014-07-01 16:28:16 +02:00
|
|
|
# if [ x"$out" == "x\n" -o x"$out" == "x\n\r" -o x"$out" == "x" ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
# outln "(line exists but empty string)"
|
2014-07-01 16:28:16 +02:00
|
|
|
# else
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "$serverbanner"
|
2014-07-01 16:28:16 +02:00
|
|
|
# fi
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "(None, interesting!)"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " Application"
|
2014-07-01 16:28:16 +02:00
|
|
|
# examples: php.net, asp.net , www.regonline.com
|
|
|
|
egrep -i '^X-Powered-By|^X-AspNet-Version|^X-Runtime|^X-Version' $HEADERFILE >$TMPFILE
|
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
#cat $TMPFILE | sed 's/^.*:/:/' | sed -e :a -e '$!N;s/\n:/ \n\ +/;ta' -e 'P;D' | sed 's/://g'
|
|
|
|
cat $TMPFILE | sed 's/^/ /'
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
litegrey " (None)"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
rm $TMPFILE
|
|
|
|
return $?
|
|
|
|
}
|
|
|
|
|
|
|
|
#dead function as of now
|
|
|
|
secure_cookie() { # ARG1: Path
|
|
|
|
[ -s $HEADERFILE ] || http_header
|
|
|
|
grep -i '^Set-Cookie' $HEADERFILE >$TMPFILE
|
|
|
|
if [ $? -eq 0 ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "Cookie issued, status: "
|
2014-07-01 16:28:16 +02:00
|
|
|
if grep -q -i secure $TMPFILE; then
|
2014-07-16 19:04:15 +02:00
|
|
|
litegreenln "Secure Flag"
|
2014-07-01 16:28:16 +02:00
|
|
|
echo $TMPFILE
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "no secure flag"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
#FIXME: Access-Control-Allow-Origin, CSP, Upgrade, X-Frame-Options, X-XSS-Protection, X-Content-Type-Options
|
|
|
|
# https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
|
|
|
|
|
|
|
|
|
|
|
|
# #1: string with 2 opensssl codes, HEXC= same in NSS/ssllab terminology
|
|
|
|
normalize_ciphercode() {
|
|
|
|
part1=`echo "$1" | awk -F',' '{ print $1 }'`
|
|
|
|
part2=`echo "$1" | awk -F',' '{ print $2 }'`
|
|
|
|
part3=`echo "$1" | awk -F',' '{ print $3 }'`
|
|
|
|
if [ "$part1" == "0x00" ] ; then # leading 0x00
|
|
|
|
HEXC=$part2
|
|
|
|
else
|
|
|
|
part2=`echo $part2 | sed 's/0x//g'`
|
|
|
|
if [ -n "$part3" ] ; then # a SSLv2 cipher has three parts
|
|
|
|
part3=`echo $part3 | sed 's/0x//g'`
|
|
|
|
fi
|
|
|
|
HEXC="$part1$part2$part3"
|
|
|
|
fi
|
2014-11-18 11:03:03 +01:00
|
|
|
HEXC=`echo $HEXC | tr 'A-Z' 'a-z' | sed 's/0x/x/'` #tolower + strip leading 0
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
prettyprint_local() {
|
2014-11-18 11:03:03 +01:00
|
|
|
blue "--> Displaying all local ciphers";
|
|
|
|
if [ ! -z "$1" ]; then
|
|
|
|
blue "matching word pattern "\"$1\"" (ignore case)";
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-11-18 11:03:03 +01:00
|
|
|
outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
neat_header
|
|
|
|
|
2014-11-18 11:03:03 +01:00
|
|
|
if [ -z "$1" ]; then
|
|
|
|
$OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode dash ciph sslvers kx auth enc mac export ; do
|
|
|
|
normalize_ciphercode $hexcode
|
|
|
|
neat_list $HEXC $ciph $kx $enc | strings
|
|
|
|
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
|
|
|
|
normalize_ciphercode $hexcode
|
|
|
|
neat_list $HEXC $ciph $kx $enc | strings | grep -wai "$arg"
|
|
|
|
done
|
|
|
|
done
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# list ciphers (and makes sure you have them locally configured)
|
|
|
|
# arg[1]: cipher list (or anything else)
|
|
|
|
listciphers() {
|
2014-11-25 13:12:24 +01:00
|
|
|
$OPENSSL ciphers "$VERB_CLIST" $1 &>$TMPFILE
|
|
|
|
ret=$?
|
|
|
|
[[ "$LOCERR" = 1 ]] && cat $TMPFILE
|
|
|
|
return $ret
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# argv[1]: cipher list to test
|
|
|
|
# argv[2]: string on console
|
|
|
|
# argv[3]: ok to offer? 0: yes, 1: no
|
|
|
|
std_cipherlists() {
|
2014-07-16 19:04:15 +02:00
|
|
|
out "$2 ";
|
2014-11-25 13:12:24 +01:00
|
|
|
if listciphers $1; then # is that locally available??
|
2014-07-16 19:04:15 +02:00
|
|
|
[ x$SHOW_LCIPHERS = "xyes" ] && out "local ciphers are: " && cat $TMPFILE | sed 's/:/, /g'
|
|
|
|
$OPENSSL s_client -cipher "$1" $STARTTLS -connect $NODEIP:$PORT $SNI 2>$TMPFILE >/dev/null </dev/null
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=$?
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ $VERBOSE -eq 1 ]] && cat $TMPFILE
|
|
|
|
case $3 in
|
|
|
|
0) # ok to offer
|
|
|
|
if [[ $ret -eq 0 ]]; then # was offered
|
|
|
|
ok 1 0 # green
|
|
|
|
else
|
|
|
|
ok 0 0 # black
|
|
|
|
fi ;;
|
|
|
|
2) # not really bad
|
|
|
|
if [[ $ret -eq 0 ]]; then
|
|
|
|
ok 2 0 # offered in bold
|
|
|
|
else
|
|
|
|
ok 0 0 # not offered also in bold
|
|
|
|
fi;;
|
|
|
|
*) # the ugly rest
|
|
|
|
if [[ $ret -eq 0 ]]; then
|
|
|
|
ok 1 1 # was offered! --> red
|
|
|
|
else
|
|
|
|
#ok 0 0 # was not offered, that's ok
|
|
|
|
ok 0 1 # was not offered --> green
|
|
|
|
fi ;;
|
|
|
|
esac
|
|
|
|
rm $TMPFILE
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-10-29 21:24:43 +01:00
|
|
|
singlespaces=`echo "$2" | sed -e 's/ \+/ /g' -e 's/^ //' -e 's/ $//g' -e 's/ //g'`
|
2014-10-23 15:52:06 +02:00
|
|
|
magentaln "Local problem: No $singlespaces configured in $OPENSSL"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
# we need lf in those cases:
|
2014-11-25 13:12:24 +01:00
|
|
|
[[ "$LOCERR" -eq 1 ]] && echo
|
|
|
|
[[ "$VERBOSE" -eq 1 ]] && echo
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
2014-09-16 22:18:09 +02:00
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
# sockets inspired by http://blog.chris007.de/?p=238
|
|
|
|
# ARG1: hexbyte, ARG2: hexode for TLS Version, ARG3: sleep
|
|
|
|
socksend() {
|
|
|
|
data=`echo $1 | sed 's/tls_version/'"$2"'/g'`
|
|
|
|
[ $VERBOSE -eq 1 ] && echo "\"$data\""
|
2014-11-19 13:22:22 +01:00
|
|
|
printf $data >&5 2>/dev/null &
|
2014-07-01 16:28:16 +02:00
|
|
|
sleep $3
|
|
|
|
}
|
2014-09-16 22:18:09 +02:00
|
|
|
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
sockread() {
|
2014-11-18 00:26:58 +01:00
|
|
|
[ "x$2" = "x" ] && maxsleep=$MAX_WAITSOCK || maxsleep=$2
|
2014-09-16 22:18:09 +02:00
|
|
|
ret=0
|
|
|
|
|
|
|
|
ddreply=`mktemp /tmp/ddreply.XXXXXX` || exit 7
|
|
|
|
dd bs=$1 of=$ddreply count=1 <&5 2>/dev/null &
|
|
|
|
pid=$!
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
if ! ps ax | grep -v grep | grep -q $pid; then
|
|
|
|
break # didn't reach maxsleep yet
|
|
|
|
kill $pid >&2 2>/dev/null
|
|
|
|
fi
|
|
|
|
sleep 1
|
|
|
|
maxsleep=`expr $maxsleep - 1`
|
|
|
|
test $maxsleep -eq 0 && break
|
|
|
|
done
|
|
|
|
if ps ax | grep -v grep | grep -q $pid; then
|
2014-10-08 14:30:31 +02:00
|
|
|
# time's up and dd is still alive --> timeout
|
|
|
|
kill $pid
|
2014-09-16 22:18:09 +02:00
|
|
|
wait $pid 2>/dev/null
|
|
|
|
ret=3 # means killed
|
|
|
|
fi
|
|
|
|
SOCKREPLY=`cat $ddreply`
|
|
|
|
rm $ddreply
|
|
|
|
|
|
|
|
return $ret
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
show_rfc_style(){
|
2014-11-17 18:49:56 +01:00
|
|
|
[ ! -r "$MAP_RFC_FNAME" ] && return 1
|
2014-11-18 01:36:29 +01:00
|
|
|
RFCname=`grep -iw $1 "$MAP_RFC_FNAME" | sed -e 's/^.*TLS/TLS/' -e 's/^.*SSL/SSL/'`
|
2014-11-17 18:49:56 +01:00
|
|
|
[ -n "$RFCname" ] && out "$RFCname"
|
|
|
|
return 0
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# header and list for all_ciphers+cipher_per_proto, and PFS+RC4
|
|
|
|
neat_header(){
|
2014-11-18 10:29:11 +01:00
|
|
|
outln "Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits${MAP_RFC_FNAME:+ Cipher Suite Name (RFC)}"
|
2014-11-18 23:14:17 +01:00
|
|
|
outln "%s-------------------------------------------------------------------------${MAP_RFC_FNAME:+----------------------------------------------}"
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
neat_list(){
|
|
|
|
kx=`echo $3 | sed 's/Kx=//g'`
|
|
|
|
enc=`echo $4 | sed 's/Enc=//g'`
|
2014-11-18 01:36:29 +01:00
|
|
|
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
|
2014-07-01 16:28:16 +02:00
|
|
|
echo "$export" | grep -iq export && strength="$strength,export"
|
2014-11-18 11:03:03 +01:00
|
|
|
$ECHO " %-7s %-30s %-10s %-11s%-11s${MAP_RFC_FNAME:+ %-48s}${SHOW_EACH_C:+ }" "$1" "$2" "$kx" "$enc" "$strength" "$(show_rfc_style $HEXC)"
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
2014-08-29 14:57:20 +02:00
|
|
|
test_just_one(){
|
2014-11-18 01:36:29 +01:00
|
|
|
blue "--> Testing single cipher with word pattern "\"$1\"" (ignore case)"; outln "\n"
|
2014-08-29 14:57:20 +02:00
|
|
|
neat_header
|
2014-11-02 23:37:17 +01:00
|
|
|
for arg in `echo $@ | sed 's/,/ /g'`; do
|
2014-11-17 18:49:56 +01:00
|
|
|
# 1st check whether openssl has cipher or not
|
2014-11-02 23:37:17 +01:00
|
|
|
$OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode dash ciph sslvers kx auth enc mac export ; do
|
|
|
|
normalize_ciphercode $hexcode
|
2014-11-18 01:36:29 +01:00
|
|
|
neat_list $HEXC $ciph $kx $enc | strings | grep -qwai "$arg"
|
2014-11-02 23:37:17 +01:00
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
$OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $SNI &>$TMPFILE </dev/null
|
|
|
|
ret=$?
|
|
|
|
neat_list $HEXC $ciph $kx $enc
|
2014-08-29 14:57:20 +02:00
|
|
|
|
|
|
|
if [ $ret -eq 0 ]; then
|
|
|
|
cyan " available"
|
|
|
|
else
|
|
|
|
out " not a/v"
|
|
|
|
fi
|
2014-11-02 23:37:17 +01:00
|
|
|
outln
|
2014-08-29 14:57:20 +02:00
|
|
|
fi
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
2014-11-02 23:37:17 +01:00
|
|
|
outln
|
|
|
|
rm $TMPFILE
|
|
|
|
|
2014-08-29 14:57:20 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
# test for all ciphers locally configured (w/o distinguishing whether they are good or bad
|
|
|
|
allciphers(){
|
|
|
|
# FIXME: e.g. OpenSSL < 1.0 doesn't understand "-V"
|
2014-07-16 19:04:15 +02:00
|
|
|
blue "--> Testing all locally available ciphers against the server"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
neat_header
|
|
|
|
$OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode n ciph sslvers kx auth enc mac export; do
|
|
|
|
$OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $SNI &>$TMPFILE </dev/null
|
|
|
|
ret=$?
|
|
|
|
if [ $ret -ne 0 ] && [ "$SHOW_EACH_C" -eq 0 ]; then
|
|
|
|
continue # no successful connect AND not verbose displaying each cipher
|
|
|
|
fi
|
|
|
|
normalize_ciphercode $hexcode
|
|
|
|
neat_list $HEXC $ciph $kx $enc
|
|
|
|
if [ "$SHOW_EACH_C" -ne 0 ]; then
|
|
|
|
if [ $ret -eq 0 ]; then
|
|
|
|
cyan " available"
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
out " not a/v"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
rm $TMPFILE
|
|
|
|
done
|
|
|
|
return 0
|
|
|
|
}
|
2014-07-16 19:04:15 +02:00
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
# test for all ciphers per protocol locally configured (w/o distinguishing whether they are good or bad
|
|
|
|
cipher_per_proto(){
|
2014-07-16 19:04:15 +02:00
|
|
|
blue "--> Testing all locally available ciphers per protocol against the server"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
neat_header
|
2014-07-16 19:04:15 +02:00
|
|
|
outln " -ssl2 SSLv2\n -ssl3 SSLv3\n -tls1 TLSv1\n -tls1_1 TLSv1.1\n -tls1_2 TLSv1.2"| while read proto prtext; do
|
2014-07-01 16:28:16 +02:00
|
|
|
locally_supported "$proto" "$prtext" || continue
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
$OPENSSL ciphers $proto -V 'ALL:COMPLEMENTOFALL:@STRENGTH' | while read hexcode n ciph sslvers kx auth enc mac export; do
|
|
|
|
$OPENSSL s_client -cipher $ciph $proto $STARTTLS -connect $NODEIP:$PORT $SNI &>$TMPFILE </dev/null
|
|
|
|
ret=$?
|
|
|
|
if [ $ret -ne 0 ] && [ "$SHOW_EACH_C" -eq 0 ]; then
|
|
|
|
continue # no successful connect AND not verbose displaying each cipher
|
|
|
|
fi
|
|
|
|
normalize_ciphercode $hexcode
|
|
|
|
neat_list $HEXC $ciph $kx $enc
|
|
|
|
if [ "$SHOW_EACH_C" -ne 0 ]; then
|
|
|
|
if [ $ret -eq 0 ]; then
|
|
|
|
cyan " available"
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
out " not a/v"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
rm $TMPFILE
|
|
|
|
done
|
|
|
|
done
|
2014-07-16 19:04:15 +02:00
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
locally_supported() {
|
2014-07-16 19:04:15 +02:00
|
|
|
out "$2 "
|
2014-07-01 16:28:16 +02:00
|
|
|
$OPENSSL s_client "$1" 2>&1 | grep -q "unknown option"
|
|
|
|
if [ $? -eq 0 ]; then
|
2014-10-23 15:40:15 +02:00
|
|
|
magentaln "Local problem: $OPENSSL doesn't support \"s_client $1\""
|
2014-11-19 17:08:59 +01:00
|
|
|
ret=7
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-11-19 17:08:59 +01:00
|
|
|
ret=0
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-11-19 17:08:59 +01:00
|
|
|
|
|
|
|
return $ret
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
testversion_new() {
|
2014-11-19 18:04:43 +01:00
|
|
|
local sni=$SNI
|
|
|
|
[ "x$1" = "x-ssl2" ] && sni="" # newer openssl throw an error if SNI with SSLv2
|
|
|
|
|
|
|
|
$OPENSSL s_client -state $1 $STARTTLS -connect $NODEIP:$PORT $sni &>$TMPFILE </dev/null
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=$?
|
|
|
|
[ "$VERBERR" -eq 0 ] && cat $TMPFILE | egrep "error|failure" | egrep -v "unable to get local|verify error"
|
2014-11-19 17:08:59 +01:00
|
|
|
|
|
|
|
if grep -q "no cipher list" $TMPFILE ; then
|
2014-11-19 18:04:43 +01:00
|
|
|
ret=5
|
2014-11-19 17:08:59 +01:00
|
|
|
fi
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
rm $TMPFILE
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
testprotohelper() {
|
|
|
|
if locally_supported "$1" "$2" ; then
|
|
|
|
testversion_new "$1" "$2"
|
|
|
|
return $?
|
|
|
|
else
|
|
|
|
return 7
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
runprotocols() {
|
2014-07-16 19:04:15 +02:00
|
|
|
blue "--> Testing Protocols"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
# e.g. ubuntu's 12.04 openssl binary + soon others don't want sslv2 anymore: bugs.launchpad.net/ubuntu/+source/openssl/+bug/955675
|
2014-11-19 17:08:59 +01:00
|
|
|
|
2014-11-19 18:04:43 +01:00
|
|
|
testprotohelper "-ssl2" " SSLv2 "
|
|
|
|
case $? in
|
|
|
|
0) ok 1 1 ;; # red
|
|
|
|
5) ok 5 5 ;; # protocol ok, but no cipher
|
|
|
|
1) ok 0 1 ;; # green "not offered (ok)"
|
|
|
|
7) ;; # no local support
|
|
|
|
esac
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 17:08:59 +01:00
|
|
|
testprotohelper "-ssl3" " SSLv3 "
|
2014-11-19 18:04:43 +01:00
|
|
|
case $? in
|
|
|
|
0) ok 6 0 ;; # poodle hack"
|
|
|
|
1) ok 0 1 ;; # green "not offered (ok)"
|
|
|
|
5) ok 5 5 ;; # protocol ok, but no cipher
|
|
|
|
7) ;; # no local support
|
|
|
|
esac
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 17:08:59 +01:00
|
|
|
testprotohelper "-tls1" " TLSv1 "
|
2014-11-19 18:04:43 +01:00
|
|
|
case $? in
|
2014-11-20 10:46:55 +01:00
|
|
|
0) ok 4 0 ;; # no GCM, thus only in litegreen
|
2014-11-19 18:04:43 +01:00
|
|
|
1) ok 0 0 ;;
|
|
|
|
5) ok 5 5 ;; # protocol ok, but no cipher
|
|
|
|
7) ;; # no local support
|
|
|
|
esac
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 17:08:59 +01:00
|
|
|
testprotohelper "-tls1_1" " TLSv1.1 "
|
2014-11-19 18:04:43 +01:00
|
|
|
case $? in
|
|
|
|
0) ok 1 0 ;;
|
2014-11-20 10:46:55 +01:00
|
|
|
1) ok 7 0 ;; # no GCM, penalty
|
2014-11-19 18:04:43 +01:00
|
|
|
5) ok 5 5 ;; # protocol ok, but no cipher
|
|
|
|
7) ;; # no local support
|
|
|
|
esac
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 17:08:59 +01:00
|
|
|
testprotohelper "-tls1_2" " TLSv1.2 "
|
2014-11-19 18:04:43 +01:00
|
|
|
case $? in
|
|
|
|
0) ok 1 0 ;;
|
2014-11-20 10:46:55 +01:00
|
|
|
1) ok 7 0 ;; # no GCM, penalty
|
2014-11-19 18:04:43 +01:00
|
|
|
5) ok 5 5 ;; # protocol ok, but no cipher
|
|
|
|
7) ;; # no local support
|
|
|
|
esac
|
2014-11-19 17:08:59 +01:00
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
run_std_cipherlists() {
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
|
|
|
blue "--> Testing standard cipher lists"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
# see man ciphers
|
|
|
|
std_cipherlists NULL:eNULL " Null Cipher " 1
|
|
|
|
std_cipherlists aNULL " Anonymous NULL Cipher " 1
|
|
|
|
std_cipherlists ADH " Anonymous DH Cipher " 1
|
|
|
|
std_cipherlists EXPORT40 " 40 Bit encryption " 1
|
|
|
|
std_cipherlists EXPORT56 " 56 Bit encryption " 1
|
|
|
|
std_cipherlists EXPORT " Export Cipher (general) " 1
|
|
|
|
std_cipherlists LOW " Low (<=64 Bit) " 1
|
|
|
|
std_cipherlists DES " DES Cipher " 1
|
|
|
|
std_cipherlists 3DES " Triple DES Cipher " 2
|
|
|
|
std_cipherlists "MEDIUM:!NULL:!aNULL:!SSLv2" " Medium grade encryption " 2
|
|
|
|
std_cipherlists "HIGH:!NULL:!aNULL" " High grade encryption " 0
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
simple_preference() {
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
|
|
|
blue "--> Testing server defaults (Server Hello)"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
# throwing every cipher/protocol at the server and displaying its pick
|
2014-08-29 14:57:20 +02:00
|
|
|
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $SNI -tlsextdebug -status </dev/null 2>/dev/null >$TMPFILE
|
2014-07-01 16:28:16 +02:00
|
|
|
localtime=`date "+%s"`
|
|
|
|
if [ $? -ne 0 ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
magentaln "This shouldn't happen. "
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=6
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
out " Negotiated protocol "
|
2014-11-20 10:46:55 +01:00
|
|
|
TLS_PROTO_OFFERED=`grep -w "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g'`
|
2014-07-01 16:28:16 +02:00
|
|
|
case "$TLS_PROTO_OFFERED" in
|
2014-07-16 19:04:15 +02:00
|
|
|
*TLSv1.2) greenln $TLS_PROTO_OFFERED ;;
|
|
|
|
*TLSv1.1) litegreenln $TLS_PROTO_OFFERED ;;
|
|
|
|
*TLSv1) outln $TLS_PROTO_OFFERED ;;
|
|
|
|
*SSLv2) redln $TLS_PROTO_OFFERED ;;
|
2014-10-15 13:10:06 +02:00
|
|
|
*SSLv3) redln $TLS_PROTO_OFFERED ;;
|
2014-07-16 19:04:15 +02:00
|
|
|
*) outln "FIXME: $TLS_PROTO_OFFERED" ;;
|
2014-07-01 16:28:16 +02:00
|
|
|
esac
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
out " Negotiated cipher "
|
2014-11-20 10:46:55 +01:00
|
|
|
default=`grep -w "Cipher" $TMPFILE | egrep -vw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g'`
|
2014-07-01 16:28:16 +02:00
|
|
|
case "$default" in
|
2014-07-16 19:04:15 +02:00
|
|
|
*NULL*|*EXP*) redln "$default" ;;
|
|
|
|
*RC4*) literedln "$default" ;;
|
|
|
|
*CBC*) literedln "$default" ;; #FIXME BEAST: We miss some CBC ciphers here, need to work w/ a list
|
2014-11-20 10:46:55 +01:00
|
|
|
*GCM*) greenln "$default" ;; # best ones
|
|
|
|
*CHACHA20*) greenln "$default" ;; # best ones
|
|
|
|
ECDHE*AES*) brownln "$default" ;; # it's CBC. so lucky13
|
2014-07-16 19:04:15 +02:00
|
|
|
*) outln "$default" ;;
|
2014-07-01 16:28:16 +02:00
|
|
|
esac
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
out " Server key size "
|
2014-07-01 16:28:16 +02:00
|
|
|
keysize=`grep -w "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //'`
|
|
|
|
if [ -z "$keysize" ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "(couldn't determine)"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
|
|
|
case "$keysize" in
|
2014-07-16 19:04:15 +02:00
|
|
|
1024*) literedln "$keysize" ;;
|
|
|
|
2048*) outln "$keysize" ;;
|
|
|
|
4096*) litegreenln "$keysize" ;;
|
|
|
|
*) outln "$keysize" ;;
|
2014-07-01 16:28:16 +02:00
|
|
|
esac
|
|
|
|
fi
|
|
|
|
|
2014-08-29 14:57:20 +02:00
|
|
|
out " TLS server extensions "
|
2014-07-01 16:28:16 +02:00
|
|
|
extensions=`grep -w "^TLS server extension" $TMPFILE | sed -e 's/^TLS server extension \"//' -e 's/\".*$/,/g'`
|
|
|
|
if [ -z "$extensions" ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "(none)"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
echo $extensions | sed 's/,$//' # remove last comma
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
out " Session Tickets RFC 5077 "
|
2014-07-01 16:28:16 +02:00
|
|
|
sessticket_str=`grep -w "session ticket" $TMPFILE | grep lifetime`
|
|
|
|
if [ -z "$sessticket_str" ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "(none)"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
|
|
|
lifetime=`echo $sessticket_str | grep lifetime | sed 's/[A-Za-z:() ]//g'`
|
|
|
|
unit=`echo $sessticket_str | grep lifetime | sed -e 's/^.*'"$lifetime"'//' -e 's/[ ()]//g'`
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "$lifetime $unit"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-08-29 14:57:20 +02:00
|
|
|
|
|
|
|
out " OCSP stapling "
|
|
|
|
if grep "OCSP response" $TMPFILE | grep -q "no response sent" ; then
|
|
|
|
out " not offered"
|
|
|
|
else
|
|
|
|
if grep "OCSP Response Status" $TMPFILE | grep -q successful; then
|
|
|
|
litegreen " OCSP stapling offered"
|
|
|
|
else
|
|
|
|
outln " not sure what's going on here, debug:"
|
|
|
|
grep -A 20 "OCSP response" $TMPFILE
|
|
|
|
ret=2
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
outln
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
#gmt_unix_time, removed since 1.0.1f
|
|
|
|
#
|
|
|
|
#remotetime=`grep -w "Start Time" $TMPFILE | sed 's/[A-Za-z:() ]//g'`
|
|
|
|
#if [ ! -z "$remotetime" ]; then
|
|
|
|
# remotetime_stdformat=`date --date="@$remotetime" "+%Y-%m-%d %r"`
|
|
|
|
# difftime=`expr $localtime - $remotetime`
|
|
|
|
# [ $difftime -gt 0 ] && difftime="+"$difftime
|
|
|
|
# difftime=$difftime" s"
|
2014-07-16 19:04:15 +02:00
|
|
|
# outln " remotetime? : $remotetime ($difftime) = $remotetime_stdformat"
|
|
|
|
# outln " $remotetime"
|
|
|
|
# outln " $localtime"
|
2014-07-01 16:28:16 +02:00
|
|
|
#fi
|
|
|
|
#http://www.moserware.com/2009/06/first-few-milliseconds-of-https.html
|
|
|
|
|
|
|
|
rm $TMPFILE
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# http://www.heise.de/security/artikel/Forward-Secrecy-testen-und-einrichten-1932806.html
|
|
|
|
pfs() {
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-10-23 15:40:15 +02:00
|
|
|
blue "--> Testing (Perfect) Forward Secrecy (P)FS)"; outln " -- omitting 3DES, RC4 and Null Encryption here"
|
2014-07-01 16:28:16 +02:00
|
|
|
# https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy
|
|
|
|
PFSOK='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH'
|
2014-10-23 15:40:15 +02:00
|
|
|
# ^^^ remark: the exclusing via ! doesn't work with libressl.
|
|
|
|
#
|
2014-07-01 16:28:16 +02:00
|
|
|
# PFSOK='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH'
|
2014-10-23 15:40:15 +02:00
|
|
|
# this catches also ECDHE-ECDSA-NULL-SHA or ECDHE-RSA-RC4-SHA
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 17:08:59 +01:00
|
|
|
$OPENSSL ciphers -V "$PFSOK" >$TMPFILE 2>/dev/null
|
|
|
|
if [ $? -ne 0 ] ; then
|
|
|
|
number_pfs=`wc -l $TMPFILE | awk '{ print $1 }'`
|
|
|
|
if [ "$number_pfs" -le "$CLIENT_MIN_PFS" ] ; then
|
|
|
|
outln
|
|
|
|
magentaln " Local problem: you have only $number_pfs client side PFS ciphers "
|
|
|
|
outln " Thus it doesn't make sense to test PFS"
|
|
|
|
[ $number_pfs -ne 0 ] && cat $TMPFILE
|
|
|
|
return 1
|
|
|
|
fi
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
savedciphers=`cat $TMPFILE`
|
|
|
|
[ x$SHOW_LCIPHERS = "xyes" ] && echo "local ciphers available for testing PFS:" && echo `cat $TMPFILE`
|
|
|
|
|
|
|
|
$OPENSSL s_client -cipher 'ECDH:DH' $STARTTLS -connect $NODEIP:$PORT $SNI &>$TMPFILE </dev/null
|
|
|
|
ret=$?
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
if [ $ret -ne 0 ] || [ `grep -c "BEGIN CERTIFICATE" $TMPFILE` -eq 0 ]; then
|
2014-09-16 22:18:09 +02:00
|
|
|
brown "No PFS available"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
litegreen "PFS seems generally available. Now testing specific ciphers ..."; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
noone=0
|
|
|
|
neat_header
|
|
|
|
$OPENSSL ciphers -V "$PFSOK" | while read hexcode n ciph sslvers kx auth enc mac; do
|
|
|
|
$OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null </dev/null
|
|
|
|
ret=$?
|
|
|
|
if [ $ret -ne 0 ] && [ "$SHOW_EACH_C" -eq 0 ] ; then
|
|
|
|
continue # no successful connect AND not verbose displaying each cipher
|
|
|
|
fi
|
|
|
|
normalize_ciphercode $hexcode
|
|
|
|
neat_list $HEXC $ciph $kx $enc $strength
|
|
|
|
if [ "$SHOW_EACH_C" -ne 0 ] ; then
|
|
|
|
if [ $ret -eq 0 ]; then
|
|
|
|
green "works"
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
out "not a/v"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
else
|
|
|
|
noone=1
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
done
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
if [ "$noone" -eq 0 ] ; then
|
2014-07-16 19:04:15 +02:00
|
|
|
out "Please note: detected PFS ciphers don't necessarily mean any client/browser will use them"
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=0
|
|
|
|
else
|
|
|
|
magenta "no PFS ciphers found"
|
|
|
|
ret=1
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
rm $TMPFILE
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rc4() {
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
|
|
|
blue "--> Checking RC4 Ciphers" ; outln
|
2014-07-01 16:28:16 +02:00
|
|
|
$OPENSSL ciphers -V 'RC4:@STRENGTH' >$TMPFILE
|
|
|
|
[ x$SHOW_LCIPHERS = "xyes" ] && echo "local ciphers available for testing RC4:" && echo `cat $TMPFILE`
|
|
|
|
$OPENSSL s_client -cipher `$OPENSSL ciphers RC4` $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null </dev/null
|
|
|
|
RC4=$?
|
|
|
|
if [ $RC4 -eq 0 ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
litered "\nRC4 seems generally available. Now testing specific ciphers..."; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
bad=1
|
|
|
|
neat_header
|
|
|
|
cat $TMPFILE | while read hexcode n ciph sslvers kx auth enc mac; do
|
|
|
|
$OPENSSL s_client -cipher $ciph $STARTTLS -connect $NODEIP:$PORT $SNI </dev/null &>/dev/null
|
|
|
|
ret=$?
|
|
|
|
if [ $ret -ne 0 ] && [ "$SHOW_EACH_C" -eq 0 ] ; then
|
|
|
|
continue # no successful connect AND not verbose displaying each cipher
|
|
|
|
fi
|
|
|
|
normalize_ciphercode $hexcode
|
|
|
|
neat_list $HEXC $ciph $kx $enc $strength
|
|
|
|
if [ "$SHOW_EACH_C" -ne 0 ]; then
|
|
|
|
if [ $ret -eq 0 ]; then
|
2014-11-17 18:49:56 +01:00
|
|
|
litered "available"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-11-17 18:49:56 +01:00
|
|
|
out "not a/v"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
else
|
|
|
|
bad=1
|
2014-07-16 19:04:15 +02:00
|
|
|
out
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
done
|
|
|
|
# https://en.wikipedia.org/wiki/Transport_Layer_Security#RC4_attacks
|
|
|
|
# http://blog.cryptographyengineering.com/2013/03/attack-of-week-rc4-is-kind-of-broken-in.html
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-11-20 10:46:55 +01:00
|
|
|
outln "RC4 is broken, for legacy support (IE6) rather consider x13 or x0a"
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-09-25 16:24:21 +02:00
|
|
|
litegreenln "no RC4 ciphers detected (OK)"
|
2014-07-01 16:28:16 +02:00
|
|
|
bad=0
|
|
|
|
fi
|
|
|
|
|
|
|
|
rm $TMPFILE
|
|
|
|
return $bad
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# good source for configuration and bugs: https://wiki.mozilla.org/Security/Server_Side_TLS
|
|
|
|
# good start to read: http://en.wikipedia.org/wiki/Transport_Layer_Security#Attacks_against_TLS.2FSSL
|
|
|
|
|
|
|
|
|
|
|
|
lucky13() {
|
|
|
|
#FIXME: to do
|
|
|
|
# CVE-2013-0169
|
|
|
|
# in a nutshell: don't offer CBC suites (again). MAC as a fix for padding oracles is not enough
|
|
|
|
# best: TLS v1.2+ AES GCM
|
|
|
|
echo "FIXME"
|
|
|
|
echo
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
spdy(){
|
2014-07-16 19:04:15 +02:00
|
|
|
out " SPDY/NPN "
|
2014-07-01 16:28:16 +02:00
|
|
|
if [ "x$STARTTLS" != "x" ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "SPDY is an HTTP protocol"
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=2
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
# first, does the current openssl support it?
|
2014-07-01 16:28:16 +02:00
|
|
|
$OPENSSL s_client help 2>&1 | grep -qw nextprotoneg
|
|
|
|
if [ $? -ne 0 ]; then
|
2014-11-19 17:08:59 +01:00
|
|
|
magenta "Local problem: $OPENSSL doesn't support SPDY"; outln
|
|
|
|
return 0
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
$OPENSSL s_client -host $NODE -port $PORT -nextprotoneg $NPN_PROTOs </dev/null 2>/dev/null >$TMPFILE
|
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
# we need -a here
|
2014-07-16 19:04:15 +02:00
|
|
|
tmpstr=`grep -a '^Protocols' $TMPFILE | sed 's/Protocols.*: //'`
|
|
|
|
if [ -z "$tmpstr" -o "$tmpstr" = " " ] ; then
|
|
|
|
out "not offered"
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=1
|
|
|
|
else
|
|
|
|
# now comes a strange thing: "Protocols advertised by server:" is empty but connection succeeded
|
|
|
|
if echo $tmpstr | egrep -q "spdy|http" ; then
|
2014-11-19 18:04:43 +01:00
|
|
|
bold "$tmpstr" ; out " (advertised)"
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=0
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
litemagenta "please check manually, response from server was ambigious ..."
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=10
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
else
|
2014-07-16 19:04:15 +02:00
|
|
|
litemagenta "handshake failed"
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=2
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
# btw: nmap can do that too http://nmap.org/nsedoc/scripts/tls-nextprotoneg.html
|
|
|
|
# nmap --script=tls-nextprotoneg #NODE -p $PORT is your friend if your openssl doesn't want to test this
|
|
|
|
rm $TMPFILE
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
fd_socket() {
|
|
|
|
# arg doesn't work here
|
|
|
|
if ! exec 5<> /dev/tcp/$NODEIP/$PORT; then
|
2014-10-07 12:04:21 +02:00
|
|
|
magenta "`basename $0`: unable to open a socket to $NODEIP:$PORT"
|
2014-07-01 16:28:16 +02:00
|
|
|
return 6
|
|
|
|
fi
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2014-10-07 12:04:21 +02:00
|
|
|
close_socket(){
|
|
|
|
exec 5<&-
|
|
|
|
exec 5>&-
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
ok_ids(){
|
|
|
|
echo
|
|
|
|
tput bold; tput setaf 2; echo "ok -- something resetted our ccs packets"; tput sgr0
|
|
|
|
echo
|
|
|
|
exit 0
|
|
|
|
}
|
|
|
|
|
|
|
|
ccs_injection(){
|
|
|
|
# see https://www.openssl.org/news/secadv_20140605.txt
|
|
|
|
# mainly adapted from Ramon de C Valle's C code from https://gist.github.com/rcvalle/71f4b027d61a78c42607
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " CCS "; out " (CVE-2014-0224), experimental "
|
2014-10-08 14:30:31 +02:00
|
|
|
ccs_message="\x14\x03\tls_version\x00\x01\x01" # ChangeCipherSpec, TLS version 2 bytes, lenght 2 bytes, payload CCS 1 byte
|
2014-11-18 00:26:58 +01:00
|
|
|
# 20/0x14=Change Ciipher Spexcc
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT &>$TMPFILE </dev/null
|
|
|
|
|
|
|
|
tls_hexcode=x01
|
|
|
|
proto_offered=`grep -w Protocol $TMPFILE | sed -e 's/^ \+Protocol \+://'`
|
|
|
|
case $tls_proto_offered in
|
|
|
|
*TLSv1.2*) tls_hexcode=x03 ;;
|
|
|
|
*TLSv1.1*) tls_hexcode=x02 ;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
client_hello="
|
|
|
|
# TLS header ( 5 bytes)
|
|
|
|
,x16, # Content type (x16 for handshake)
|
|
|
|
x03, tls_version, # TLS Version
|
|
|
|
x00, x93, # Length
|
|
|
|
# Handshake header
|
|
|
|
x01, # Type (x01 for ClientHello)
|
|
|
|
x00, x00, x8f, # Length
|
|
|
|
x03, tls_version, # TLS Version
|
|
|
|
# Random (32 byte)
|
|
|
|
x53, x43, x5b, x90, x9d, x9b, x72, x0b,
|
|
|
|
xbc, x0c, xbc, x2b, x92, xa8, x48, x97,
|
|
|
|
xcf, xbd, x39, x04, xcc, x16, x0a, x85,
|
|
|
|
x03, x90, x9f, x77, x04, x33, xd4, xde,
|
|
|
|
x00, # Session ID length
|
|
|
|
x00, x68, # Cipher suites length
|
|
|
|
# Cipher suites (51 suites)
|
|
|
|
xc0, x13, xc0, x12, xc0, x11, xc0, x10,
|
|
|
|
xc0, x0f, xc0, x0e, xc0, x0d, xc0, x0c,
|
|
|
|
xc0, x0b, xc0, x0a, xc0, x09, xc0, x08,
|
|
|
|
xc0, x07, xc0, x06, xc0, x05, xc0, x04,
|
|
|
|
xc0, x03, xc0, x02, xc0, x01, x00, x39,
|
|
|
|
x00, x38, x00, x37, x00, x36, x00, x35, x00, x34,
|
|
|
|
x00, x33, x00, x32, x00, x31, x00, x30,
|
|
|
|
x00, x2f, x00, x16, x00, x15, x00, x14,
|
|
|
|
x00, x13, x00, x12, x00, x11, x00, x10,
|
|
|
|
x00, x0f, x00, x0e, x00, x0d, x00, x0c,
|
|
|
|
x00, x0b, x00, x0a, x00, x09, x00, x08,
|
|
|
|
x00, x07, x00, x06, x00, x05, x00, x04,
|
|
|
|
x00, x03, x00, x02, x00, x01, x01, x00"
|
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
#msg=`echo "$client_hello" | grep -o '\bx[[:xdigit:]]\{2\}\b\|tls_version' | sed -e 's/x/\\\x/g' -e 's/tls_version/\\\tls_version/g' | tr -d '\n'`
|
2014-07-01 16:28:16 +02:00
|
|
|
msg=`echo "$client_hello" | sed -e 's/# .*$//g' -e 's/,/\\\/g' | sed -e 's/ //g' -e 's/[ \t]//g' | tr -d '\n'`
|
|
|
|
|
|
|
|
fd_socket 5 || return 6
|
|
|
|
|
2014-11-18 20:23:17 +01:00
|
|
|
[ $VERBOSE -eq 1 ] && out "\nsending client hello, "
|
2014-07-01 16:28:16 +02:00
|
|
|
socksend "$msg" $tls_hexcode 1
|
2014-11-18 00:26:58 +01:00
|
|
|
sockread 16384
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
if [ $VERBOSE -eq 1 ]; then
|
2014-11-18 20:23:17 +01:00
|
|
|
outln "\nserver hello:"
|
2014-11-19 13:22:22 +01:00
|
|
|
echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "[...]"
|
2014-11-18 00:26:58 +01:00
|
|
|
outln "\npayload #1 with TLS version $tls_hexcode:"
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
socksend $ccs_message $tls_hexcode 1 || ok_ids
|
2014-11-18 00:26:58 +01:00
|
|
|
sockread 2048 5 # 5 seconds
|
|
|
|
if [ $VERBOSE -eq 1 ]; then
|
|
|
|
outln "\n1st reply: "
|
2014-11-19 13:22:22 +01:00
|
|
|
out "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20
|
2014-11-18 00:26:58 +01:00
|
|
|
# ok: 15 | 0301 | 02 | 02 0a == ALERT | TLS 1.0 | Length=2 | Unexpected Message (0a)
|
|
|
|
outln
|
|
|
|
outln "payload #2 with TLS version $tls_hexcode:"
|
|
|
|
fi
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
socksend $ccs_message $tls_hexcode 2 || ok_ids
|
2014-11-18 00:26:58 +01:00
|
|
|
sockread 2048 5
|
2014-09-16 22:18:09 +02:00
|
|
|
retval=$?
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
if [ $VERBOSE -eq 1 ]; then
|
2014-11-18 00:26:58 +01:00
|
|
|
outln "\n2nd reply: "
|
2014-11-19 13:22:22 +01:00
|
|
|
out "$SOCKREPLY" | "${HEXDUMPVIEW[@]}"
|
2014-11-18 00:26:58 +01:00
|
|
|
# not ok: 15 | 0301 | 02 | 02 | 15 == ALERT | TLS 1.0 | Length=2 | Decryption failed (21)
|
|
|
|
# ok: 0a or nothing: ==> RST
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
reply_sanitized=`echo "$SOCKREPLY" | "${HEXDUMPPLAIN[@]}" | sed 's/^..........//'`
|
|
|
|
lines=`echo "$SOCKREPLY" | "${HEXDUMP[@]}" | wc -l`
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
if [ "$reply_sanitized" == "0a" ] || [ "$lines" -gt 1 ] ; then
|
2014-09-25 16:24:21 +02:00
|
|
|
green "not vulnerable (OK)"
|
2014-10-08 14:30:31 +02:00
|
|
|
ret=1
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-09-16 22:18:09 +02:00
|
|
|
red "VULNERABLE"
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=1
|
|
|
|
fi
|
2014-11-20 10:46:55 +01:00
|
|
|
[ $retval -eq 3 ] && out "(timed out)"
|
2014-09-16 22:18:09 +02:00
|
|
|
outln
|
2014-10-07 12:04:21 +02:00
|
|
|
|
|
|
|
close_socket
|
2014-07-01 16:28:16 +02:00
|
|
|
rm $TMPFILE
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
heartbleed(){
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " Heartbleed\c"; out " (CVE-2014-0160), experimental "
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
# mainly adapted from https://gist.github.com/takeshixx/10107280
|
|
|
|
heartbleed_payload="\x18\x03\tls_version\x00\x03\x01\x40\x00"
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-20 10:46:55 +01:00
|
|
|
# determine TLS versions available:
|
|
|
|
$OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT -tlsextdebug &>$TMPFILE </dev/null
|
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
tls_hexcode=x01
|
|
|
|
proto_offered=`grep -w Protocol $TMPFILE | sed -e 's/^ \+Protocol \+://'`
|
|
|
|
case $tls_proto_offered in
|
|
|
|
*TLSv1.2*) tls_hexcode=x03 ;;
|
|
|
|
*TLSv1.1*) tls_hexcode=x02 ;;
|
|
|
|
esac
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
client_hello="
|
|
|
|
# TLS header ( 5 bytes)
|
|
|
|
,x16, # Content type (x16 for handshake)
|
|
|
|
x03, tls_version, # TLS Version
|
|
|
|
x00, xdc, # Length
|
|
|
|
# Handshake header
|
|
|
|
x01, # Type (x01 for ClientHello)
|
|
|
|
x00, x00, xd8, # Length
|
|
|
|
x03, tls_version, # TLS Version
|
|
|
|
# Random (32 byte)
|
|
|
|
x53, x43, x5b, x90, x9d, x9b, x72, x0b,
|
|
|
|
xbc, x0c, xbc, x2b, x92, xa8, x48, x97,
|
|
|
|
xcf, xbd, x39, x04, xcc, x16, x0a, x85,
|
|
|
|
x03, x90, x9f, x77, x04, x33, xd4, xde,
|
|
|
|
x00, # Session ID length
|
|
|
|
x00, x66, # Cipher suites length
|
|
|
|
# Cipher suites (51 suites)
|
|
|
|
xc0, x14, xc0, x0a, xc0, x22, xc0, x21,
|
|
|
|
x00, x39, x00, x38, x00, x88, x00, x87,
|
|
|
|
xc0, x0f, xc0, x05, x00, x35, x00, x84,
|
|
|
|
xc0, x12, xc0, x08, xc0, x1c, xc0, x1b,
|
|
|
|
x00, x16, x00, x13, xc0, x0d, xc0, x03,
|
|
|
|
x00, x0a, xc0, x13, xc0, x09, xc0, x1f,
|
|
|
|
xc0, x1e, x00, x33, x00, x32, x00, x9a,
|
|
|
|
x00, x99, x00, x45, x00, x44, xc0, x0e,
|
|
|
|
xc0, x04, x00, x2f, x00, x96, x00, x41,
|
|
|
|
xc0, x11, xc0, x07, xc0, x0c, xc0, x02,
|
|
|
|
x00, x05, x00, x04, x00, x15, x00, x12,
|
|
|
|
x00, x09, x00, x14, x00, x11, x00, x08,
|
|
|
|
x00, x06, x00, x03, x00, xff,
|
|
|
|
x01, # Compression methods length
|
|
|
|
x00, # Compression method (x00 for NULL)
|
|
|
|
x00, x49, # Extensions length
|
|
|
|
# Extension: ec_point_formats
|
|
|
|
x00, x0b, x00, x04, x03, x00, x01, x02,
|
|
|
|
# Extension: elliptic_curves
|
|
|
|
x00, x0a, x00, x34, x00, x32, x00, x0e,
|
|
|
|
x00, x0d, x00, x19, x00, x0b, x00, x0c,
|
|
|
|
x00, x18, x00, x09, x00, x0a, x00, x16,
|
|
|
|
x00, x17, x00, x08, x00, x06, x00, x07,
|
|
|
|
x00, x14, x00, x15, x00, x04, x00, x05,
|
|
|
|
x00, x12, x00, x13, x00, x01, x00, x02,
|
|
|
|
x00, x03, x00, x0f, x00, x10, x00, x11,
|
|
|
|
# Extension: SessionTicket TLS
|
|
|
|
x00, x23, x00, x00,
|
|
|
|
# Extension: Heartbeat
|
|
|
|
x00, x0f, x00, x01, x01"
|
|
|
|
|
|
|
|
#msg=`echo "$client_hello" | grep -o '\bx[[:xdigit:]]\{2\}\b\|tls_version' | sed -e 's/x/\\\x/g' -e 's/tls_version/\\\tls_version/g' | tr -d '\n'`
|
|
|
|
msg=`echo "$client_hello" | sed -e 's/# .*$//g' -e 's/,/\\\/g' | sed -e 's/ //g' -e 's/[ \t]//g' | tr -d '\n'`
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
fd_socket 5 || return 6
|
|
|
|
|
|
|
|
[ $VERBOSE -eq 1 ] && out "\nsending client hello, "
|
|
|
|
socksend "$msg" $tls_hexcode 1
|
|
|
|
sockread 16384
|
|
|
|
|
|
|
|
if [ $VERBOSE -eq 1 ]; then
|
|
|
|
outln "\nserver hello:"
|
|
|
|
echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}" | head -20
|
|
|
|
outln "[...]"
|
|
|
|
outln " sending payload with TLS version $tls_hexcode:"
|
|
|
|
fi
|
|
|
|
|
|
|
|
socksend $heartbleed_payload $tls_hexcode 1
|
|
|
|
sockread 16384
|
|
|
|
retval=$?
|
|
|
|
|
|
|
|
if [ $VERBOSE -eq 1 ]; then
|
|
|
|
outln "\n heartbleed reply: "
|
|
|
|
echo "$SOCKREPLY" | "${HEXDUMPVIEW[@]}"
|
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-10-07 12:04:21 +02:00
|
|
|
|
2014-11-19 13:22:22 +01:00
|
|
|
lines_returned=`echo "$SOCKREPLY" | "${HEXDUMP[@]}" | wc -l`
|
|
|
|
if [ $lines_returned -gt 1 ]; then
|
|
|
|
red "VULNERABLE"
|
|
|
|
ret=1
|
|
|
|
else
|
|
|
|
green "not vulnerable (OK)"
|
|
|
|
ret=0
|
|
|
|
fi
|
2014-11-20 10:46:55 +01:00
|
|
|
[ $retval -eq 3 ] && out "(timed out)"
|
2014-11-19 13:22:22 +01:00
|
|
|
outln
|
|
|
|
|
2014-10-07 12:04:21 +02:00
|
|
|
close_socket
|
2014-11-20 10:46:55 +01:00
|
|
|
rm $TMPFILE
|
2014-07-01 16:28:16 +02:00
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
renego() {
|
|
|
|
ADDCMD=""
|
|
|
|
# This tests for CVE-2009-3555 / RFC5746, OSVDB: 59968-59974
|
|
|
|
case "$OSSL_VER" in
|
2014-11-18 20:23:17 +01:00
|
|
|
0.9.8*) # we need this for Mac OSX unfortunately
|
2014-07-01 16:28:16 +02:00
|
|
|
case "$OSSL_VER_APPENDIX" in
|
|
|
|
[a-l])
|
|
|
|
magenta "Your $OPENSSL $OSSL_VER cannot test the secure renegotiation vulnerability"
|
|
|
|
return 3 ;;
|
|
|
|
[m-z])
|
|
|
|
# all ok ;;
|
|
|
|
esac ;;
|
|
|
|
1.0.1*)
|
|
|
|
ADDCMD="-legacy_renegotiation" ;;
|
|
|
|
0.9.9*|1.0*)
|
|
|
|
# all ok ;;
|
|
|
|
esac
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " Renegotiation "; out "(CVE 2009-3555) "
|
2014-07-01 16:28:16 +02:00
|
|
|
echo R | $OPENSSL s_client $ADDCMD $STARTTLS -connect $NODEIP:$PORT $SNI &>/dev/null
|
|
|
|
reneg_ok=$? # 0=client is renegotiating and does not gets an error: that should not be!
|
|
|
|
NEG_STR="Secure Renegotiation IS NOT"
|
2014-07-16 19:04:15 +02:00
|
|
|
echo "R" | $OPENSSL s_client $STARTTLS -connect $NODEIP:$PORT $SNI 2>&1 | grep -iq "$NEG_STR"
|
2014-07-01 16:28:16 +02:00
|
|
|
secreg=$? # 0= Secure Renegotiation IS NOT supported
|
|
|
|
|
|
|
|
if [ $reneg_ok -eq 0 ] && [ $secreg -eq 0 ]; then
|
|
|
|
# Client side renegotiation is accepted and secure renegotiation IS NOT supported
|
2014-09-25 16:24:21 +02:00
|
|
|
redln "IS vulnerable (NOT ok)"
|
2014-07-01 16:28:16 +02:00
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
if [ $reneg_ok -eq 1 ] && [ $secreg -eq 1 ]; then
|
2014-09-25 16:24:21 +02:00
|
|
|
greenln "not vulnerable (OK)"
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
if [ $reneg_ok -eq 1 ] ; then # 1,0
|
2014-07-16 19:04:15 +02:00
|
|
|
litegreenln "got an error from the server while renegotiating on client: should be ok ($reneg_ok,$secreg)"
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
litegreenln "Patched Server detected ($reneg_ok,$secreg), probably ok" # 0,1
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
crime() {
|
2014-07-16 19:04:15 +02:00
|
|
|
# in a nutshell: don't offer TLS/SPDY compression on the server side
|
2014-07-01 16:28:16 +02:00
|
|
|
#
|
|
|
|
# This tests for CRIME Vulnerability (www.ekoparty.org/2012/juliano-rizzo.php) on HTTPS, not SPDY (yet)
|
|
|
|
# Please note that it is an attack where you need client side control, so in regular situations this
|
|
|
|
# means anyway "game over", w/wo CRIME
|
|
|
|
# www.h-online.com/security/news/item/Vulnerability-in-SSL-encryption-is-barely-exploitable-1708604.html
|
|
|
|
|
|
|
|
ADDCMD=""
|
|
|
|
case "$OSSL_VER" in
|
|
|
|
# =< 0.9.7 was weeded out before
|
|
|
|
0.9.8)
|
|
|
|
ADDCMD="-no_ssl2" ;;
|
|
|
|
0.9.9*|1.0*)
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
bold " CRIME, TLS " ; out "(CVE-2012-4929) "
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
# 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
|
2014-11-20 10:46:55 +01:00
|
|
|
magentaln "Local Problem: Your $OPENSSL lacks zlib support"
|
2014-07-01 16:28:16 +02:00
|
|
|
return 0 #FIXME
|
|
|
|
fi
|
|
|
|
|
|
|
|
STR=`$OPENSSL s_client $ADDCMD $STARTTLS -connect $NODEIP:$PORT $SNI 2>&1 </dev/null | grep Compression `
|
|
|
|
if echo $STR | grep -q NONE >/dev/null; then
|
2014-09-25 16:24:21 +02:00
|
|
|
greenln "not vulnerable (OK) "
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=0
|
|
|
|
else
|
2014-09-25 16:24:21 +02:00
|
|
|
redln "IS vulnerable (NOT ok)"
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# this needs to be re-done i order to remove the redundant check for spdy
|
|
|
|
|
|
|
|
# weed out starttls, spdy-crime is a web thingy
|
|
|
|
# if [ "x$STARTTLS" != "x" ]; then
|
|
|
|
# echo
|
|
|
|
# return $ret
|
|
|
|
# fi
|
|
|
|
|
|
|
|
# weed out non-webports, spdy-crime is a web thingy. there's a catch thoug, you see it?
|
|
|
|
# case $PORT in
|
|
|
|
# 25|465|587|80|110|143|993|995|21)
|
|
|
|
# echo
|
|
|
|
# return $ret
|
|
|
|
# esac
|
|
|
|
|
|
|
|
# $OPENSSL s_client help 2>&1 | grep -qw nextprotoneg
|
|
|
|
# if [ $? -eq 0 ]; then
|
|
|
|
# $OPENSSL s_client -host $NODE -port $PORT -nextprotoneg $NPN_PROTOs $SNI </dev/null 2>/dev/null >$TMPFILE
|
|
|
|
# if [ $? -eq 0 ]; then
|
|
|
|
# echo
|
2014-07-16 19:04:15 +02:00
|
|
|
# bold "CRIME Vulnerability, SPDY \c" ; outln "(CVE-2012-4929): \c"
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
# STR=`grep Compression $TMPFILE `
|
|
|
|
# if echo $STR | grep -q NONE >/dev/null; then
|
2014-09-25 16:24:21 +02:00
|
|
|
# green "not vulnerable (OK)"
|
2014-07-01 16:28:16 +02:00
|
|
|
# ret=`expr $ret + 0`
|
|
|
|
# else
|
2014-09-25 16:24:21 +02:00
|
|
|
# red "IS vulnerable (NOT ok)"
|
2014-07-01 16:28:16 +02:00
|
|
|
# ret=`expr $ret + 1`
|
|
|
|
# fi
|
|
|
|
# fi
|
|
|
|
# fi
|
2014-07-16 19:04:15 +02:00
|
|
|
[ $VERBERR -eq 0 ] && outln "$STR"
|
2014-07-01 16:28:16 +02:00
|
|
|
#echo
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
beast(){
|
|
|
|
#FIXME: to do
|
|
|
|
#in a nutshell: don't use CBC Ciphers in TLSv1.0
|
|
|
|
# need to provide a list with bad ciphers. Not sure though whether
|
|
|
|
# it can be fixed in the OpenSSL/NSS/whatsover stack
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
youknowwho() {
|
|
|
|
# CVE-2013-2566,
|
|
|
|
# NOT FIXME as there's no code: http://www.isg.rhul.ac.uk/tls/
|
|
|
|
# http://blog.cryptographyengineering.com/2013/03/attack-of-week-rc4-is-kind-of-broken-in.html
|
|
|
|
return 0
|
|
|
|
# in a nutshell: don't use RC4, really not!
|
|
|
|
}
|
|
|
|
|
|
|
|
old_fart() {
|
2014-07-16 19:04:15 +02:00
|
|
|
magentaln "Your $OPENSSL $OSSL_VER version is an old fart..."
|
|
|
|
magentaln "Get the precompiled bins, it doesn\'t make much sense to proceed"
|
2014-07-01 16:28:16 +02:00
|
|
|
exit 3
|
|
|
|
}
|
|
|
|
|
|
|
|
find_openssl_binary() {
|
|
|
|
# 0. check environment variable whether it's executable
|
|
|
|
if [ ! -z "$OPENSSL" ] && [ ! -x "$OPENSSL" ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
redln "\ncannot execute specified ($OPENSSL) openssl binary."
|
|
|
|
outln "continuing ..."
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
if [ -x "$OPENSSL" ]; then
|
|
|
|
# 1. check environment variable
|
|
|
|
:
|
|
|
|
else
|
|
|
|
# 2. otherwise try openssl in path of testssl.sh
|
|
|
|
OPENSSL=$RUN_DIR/openssl
|
|
|
|
if [ ! -x $OPENSSL ] ; then
|
|
|
|
# 3. with arch suffix
|
|
|
|
OPENSSL=$RUN_DIR/openssl.`uname -m`
|
|
|
|
if [ ! -x $OPENSSL ] ; then
|
|
|
|
#4. finally: didn't fiond anything, so we take the one propably from system:
|
|
|
|
OPENSSL=`which openssl`
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
# http://www.openssl.org/news/openssl-notes.html
|
|
|
|
OSSL_VER=`$OPENSSL version | awk -F' ' '{ print $2 }'`
|
|
|
|
OSSL_VER_MAJOR=`echo "$OSSL_VER" | sed 's/\..*$//'`
|
|
|
|
OSSL_VER_MINOR=`echo "$OSSL_VER" | sed -e 's/^.\.//' | sed 's/\..*.//'`
|
|
|
|
OSSL_VER_APPENDIX=`echo "$OSSL_VER" | tr -d '[0-9.]'`
|
2014-11-19 13:22:22 +01:00
|
|
|
OSSL_VER_PLATFORM=`$OPENSSL version -p | sed 's/^platform: //'`
|
2014-07-16 19:04:15 +02:00
|
|
|
OSSL_BUILD_DATE=`$OPENSSL version -a | grep '^built' | sed -e 's/built on//' -e 's/: ... //' -e 's/: //' -e 's/ UTC//' -e 's/ +0000//' -e 's/.000000000//'`
|
2014-11-19 13:22:22 +01:00
|
|
|
echo $OSSL_BUILD_DATE | grep -q "not available" && OSSL_BUILD_DATE=""
|
|
|
|
export OPENSSL OSSL_VER OSSL_BUILD_DATE OSSL_VER_PLATFORM
|
2014-07-01 16:28:16 +02:00
|
|
|
case "$OSSL_VER" in
|
|
|
|
0.9.7*|0.9.6*|0.9.5*)
|
|
|
|
# 0.9.5a was latest in 0.9.5 an released 2000/4/1, that'll NOT suffice for this test
|
|
|
|
old_fart ;;
|
|
|
|
0.9.8)
|
|
|
|
case $OSSL_VER_APPENDIX in
|
|
|
|
a|b|c|d|e) old_fart;; # no SNI!
|
2014-11-19 13:22:22 +01:00
|
|
|
# other than that we leave this for MacOSX but it's a pain and no guarantees!
|
2014-07-01 16:28:16 +02:00
|
|
|
esac
|
|
|
|
;;
|
|
|
|
esac
|
2014-10-14 16:28:18 +02:00
|
|
|
if [ $OSSL_VER_MAJOR -lt 1 ]; then ## mm: Patch for libressl
|
2014-11-19 13:22:22 +01:00
|
|
|
outln
|
2014-11-19 17:08:59 +01:00
|
|
|
magentaln " ¡¡¡ <Enter> at your own risk !!! $OPENSSL is way too old (< version 1.0)"
|
|
|
|
outln " Proceeding may likely result in false negatives or positives\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
read a
|
|
|
|
fi
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
starttls() {
|
|
|
|
protocol=`echo "$1" | sed 's/s$//'` # strip trailing s in ftp(s), smtp(s), pop3(s), imap(s)
|
|
|
|
case "$1" in
|
|
|
|
ftp|smtp|pop3|imap|xmpp|telnet)
|
|
|
|
$OPENSSL s_client -connect $NODEIP:$PORT $SNI -starttls $protocol </dev/null >$TMPFILE 2>&1
|
|
|
|
ret=$?
|
|
|
|
if [ $ret -ne 0 ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
bold "Problem: $OPENSSL couldn't estabilish STARTTLS via $protocol"; outln
|
2014-07-01 16:28:16 +02:00
|
|
|
cat $TMPFILE
|
|
|
|
return 3
|
|
|
|
else
|
|
|
|
# now, this is lame: normally this should be handled by top level. Then I need to do proper parsing
|
|
|
|
# of the cmdline e.g. with getopts.
|
|
|
|
STARTTLS="-starttls $protocol"
|
|
|
|
export STARTTLS
|
|
|
|
runprotocols ; ret=`expr $? + $ret`
|
|
|
|
run_std_cipherlists ; ret=`expr $? + $ret`
|
|
|
|
simple_preference ; ret=`expr $? + $ret`
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing specific vulnerabilities" ; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
#FIXME: heartbleed + CCS won't work this way yet
|
|
|
|
# heartbleed ; ret=`expr $? + $ret`
|
|
|
|
# ccs_injection ; ret=`expr $? + $ret`
|
|
|
|
renego ; ret=`expr $? + $ret`
|
|
|
|
crime ; ret=`expr $? + $ret`
|
|
|
|
beast ; ret=`expr $? + $ret`
|
2014-07-16 19:04:15 +02:00
|
|
|
|
|
|
|
outln
|
|
|
|
#cipher_per_proto ; ret=`expr $? + $ret`
|
|
|
|
allciphers ; ret=`expr $? + $ret`
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
rc4 ; ret=`expr $? + $ret`
|
|
|
|
pfs ; ret=`expr $? + $ret`
|
|
|
|
fi
|
|
|
|
;;
|
2014-07-16 19:04:15 +02:00
|
|
|
*) outln "momentarily only ftp, smtp, pop3, imap, xmpp and telnet allowed" >&2
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=2
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
help() {
|
|
|
|
PRG=`basename $0`
|
|
|
|
cat << EOF
|
|
|
|
|
2014-11-18 10:29:11 +01:00
|
|
|
$PRG <options>
|
|
|
|
|
|
|
|
<-h|--help> what you're looking at
|
|
|
|
<-b|--banner> displays banner + version
|
|
|
|
<-v|--version> same as above
|
|
|
|
<-V|--local> pretty print all local ciphers
|
2014-11-18 11:03:03 +01:00
|
|
|
<-V|--local> <pattern> what local cipher with <pattern> is a/v?
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-18 10:29:11 +01:00
|
|
|
$PRG <options> URI
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-18 10:29:11 +01:00
|
|
|
<-e|--each-cipher> check each local ciphers remotely
|
|
|
|
<-E|-ee|--cipher-per-proto> check those per protocol
|
|
|
|
<-f|--ciphers> check cipher suites
|
|
|
|
<-p|--protocols> check TLS/SSL protocols only
|
|
|
|
<-P|--preference> displays the servers picks: protocol+cipher
|
|
|
|
<-y|--spdy> checks for SPDY/NPN
|
|
|
|
<-x|--single-ciphers-test> <pattern> tests matched <pattern> of cipher
|
|
|
|
<-B|--heartbleed> tests only for heartbleed vulnerability
|
|
|
|
<-I|--ccs|--ccs_injection> tests only for CCS injection vulnerability
|
|
|
|
<-R|--renegotiation> tests only for renegotiation vulnerability
|
|
|
|
<-C|--compression|--crime> tests only for CRIME vulnerability
|
|
|
|
<-T|--breach> tests only for BREACH vulnerability
|
|
|
|
<-0|--poodle> tests only for POODLE vulnerability
|
|
|
|
<-s|--pfs|--fs|--nsa> checks (perfect) forward secrecy settings
|
|
|
|
<-4|--rc4|--appelbaum> which RC4 ciphers are being offered?
|
|
|
|
<-H|--header|--headers> check for HSTS, HPKP and server/application banner string
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-18 10:29:11 +01:00
|
|
|
<-t|--starttls> host:port <ftp|smtp|pop3|imap|xmpp|telnet> <SNI hostname> *)
|
2014-11-19 22:23:13 +01:00
|
|
|
*) for telnet STARTTLS support you need the supplied openssl
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 22:23:13 +01:00
|
|
|
<URI> host|host:port|URL|URL:port (port 443 is assumed unless otherwise specified)
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-11-19 22:23:13 +01:00
|
|
|
<pattern> an ignore case word pattern of cipher hexcode or any other string in the name, kx or bits
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EOF
|
|
|
|
return $?
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mybanner() {
|
|
|
|
me=`basename $0`
|
|
|
|
osslver=`$OPENSSL version`
|
|
|
|
osslpath=`which $OPENSSL`
|
|
|
|
hn=`hostname`
|
2014-11-18 10:29:11 +01:00
|
|
|
#poor man's ident (nowadays ident not neccessarily installed)
|
2014-07-16 19:04:15 +02:00
|
|
|
idtag=`grep '\$Id' $0 | grep -w Exp | grep -v grep | sed -e 's/^# //' -e 's/\$ $/\$/'`
|
2014-11-17 18:49:56 +01:00
|
|
|
[ "$COLOR" != 0 ] && idtag="\033[1;30m$idtag\033[m\033[1m"
|
2014-07-01 16:28:16 +02:00
|
|
|
bb=`cat <<EOF
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
#########################################################
|
2014-07-01 16:28:16 +02:00
|
|
|
$me v$VERSION ($SWURL)
|
2014-11-17 18:49:56 +01:00
|
|
|
($idtag)
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
This program is free software. Redistribution +
|
|
|
|
modification under GPLv2 is permitted.
|
|
|
|
USAGE w/o ANY WARRANTY. USE IT AT YOUR OWN RISK!
|
|
|
|
|
2014-11-18 10:29:11 +01:00
|
|
|
Note: you can only check the server with what is
|
|
|
|
available (ciphers/protocols) locally on your machine!
|
2014-07-16 19:04:15 +02:00
|
|
|
#########################################################
|
2014-07-01 16:28:16 +02:00
|
|
|
EOF
|
|
|
|
`
|
|
|
|
bold "$bb"
|
2014-07-16 19:04:15 +02:00
|
|
|
outln "\n"
|
2014-11-19 13:22:22 +01:00
|
|
|
outln " Using \"$osslver\" from
|
|
|
|
$hn:$osslpath
|
|
|
|
(built: \"$OSSL_BUILD_DATE\", platform: \"$OSSL_VER_PLATFORM\")\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
maketempf () {
|
|
|
|
TMPFILE=`mktemp /tmp/ssltester.$NODE.XXXXXX` || exit 6
|
|
|
|
HEADERFILE=`mktemp /tmp/ssltester.header$NODE.XXXXXX` || exit 6
|
|
|
|
HEADERFILE_BREACH=`mktemp /tmp/ssltester.header$NODE.XXXXXX` || exit 6
|
|
|
|
#LOGFILE=`mktemp /tmp/ssltester.$NODE.XXXXXX.log` || exit 6
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup () {
|
2014-11-19 22:23:13 +01:00
|
|
|
if [ "$DEBUG" -eq 1 ] ; then
|
|
|
|
[ -n "$TMPFILE" ] && [ -r ${TMPFILE} ] && cat ${TMPFILE}
|
|
|
|
[ -r "$HEADERFILE_BREACH" ] && cat ${HEADERFILE_BREACH}
|
|
|
|
[ -r "$HEADERFILE" ] && cat ${HEADERFILE}
|
|
|
|
#[ -e "$LOGFILE" ] && cat ${LOGFILE}
|
2014-07-01 16:28:16 +02:00
|
|
|
else
|
2014-11-18 04:30:48 +01:00
|
|
|
rm ${TMPFILE} ${HEADERFILE} ${HEADERFILE_BREACH} ${LOGFILE} ${GOST_CONF} 2>/dev/null
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-11-18 23:14:17 +01:00
|
|
|
[ -n "$NODE" ] && datebanner "Done" # only if running against server
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
initialize_engine(){
|
|
|
|
if uname -s | grep -q BSD || ! $OPENSSL engine gost -vvvv -t -c 2>&1 >/dev/null; then
|
|
|
|
litemagenta "No engine or GOST support via engine with your $OPENSSL"; outln "\n"
|
|
|
|
return 1
|
|
|
|
else
|
|
|
|
if [ -z "$OPENSSL_CONF" ]; then
|
|
|
|
GOST_CONF=`mktemp /tmp/ssltester.GOST.XXXXXX` || exit 6
|
|
|
|
# see https://www.mail-archive.com/openssl-users@openssl.org/msg65395.html
|
|
|
|
cat >$GOST_CONF << EOF
|
|
|
|
openssl_conf = openssl_def
|
|
|
|
|
|
|
|
[ openssl_def ]
|
|
|
|
engines = engine_section
|
|
|
|
|
|
|
|
[ engine_section ]
|
|
|
|
gost = gost_section
|
|
|
|
|
|
|
|
[ gost_section ]
|
|
|
|
engine_id = gost
|
|
|
|
default_algorithms = ALL
|
|
|
|
CRYPT_PARAMS = id-Gost28147-89-CryptoPro-A-ParamSet
|
|
|
|
|
|
|
|
EOF
|
|
|
|
export OPENSSL_CONF=$GOST_CONF
|
|
|
|
else
|
|
|
|
litemagenta "For now I am providing the config file in to have GOST support"; outln
|
|
|
|
sleep 2
|
|
|
|
outln
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ignore_no_or_lame() {
|
2014-07-01 16:28:16 +02:00
|
|
|
if [ "$WARNINGS" = "off" -o "$WARNINGS" = "false" ]; then
|
|
|
|
return 0
|
|
|
|
fi
|
2014-10-07 12:04:21 +02:00
|
|
|
#outln
|
2014-11-17 17:05:43 +01:00
|
|
|
magenta "$1 "
|
2014-07-01 16:28:16 +02:00
|
|
|
read a
|
|
|
|
case $a in
|
2014-07-16 19:04:15 +02:00
|
|
|
Y|y|Yes|YES|yes)
|
|
|
|
return 0;;
|
|
|
|
default)
|
|
|
|
;;
|
2014-07-01 16:28:16 +02:00
|
|
|
esac
|
2014-07-16 19:04:15 +02:00
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
parse_hn_port() {
|
|
|
|
PORT=443 # unless otherwise auto-determined, see below
|
|
|
|
NODE="$1"
|
|
|
|
|
|
|
|
# strip "https" and trailing urlpath supposed it was supplied additionally
|
|
|
|
echo $NODE | grep -q 'https://' && NODE=`echo $NODE | sed -e 's/https\:\/\///'`
|
|
|
|
|
|
|
|
# strip trailing urlpath
|
|
|
|
NODE=`echo $NODE | sed -e 's/\/.*$//'`
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
# was the address supplied like [AA:BB:CC::]:port ?
|
|
|
|
if echo $NODE | grep -q ']' ; then
|
|
|
|
tmp_port=`printf $NODE | sed 's/\[.*\]//' | sed 's/://'`
|
|
|
|
# determine v6 port, supposed it was supplied additionally
|
|
|
|
if [ ! -z "$tmp_port" ] ; then
|
|
|
|
PORT=$tmp_port
|
|
|
|
NODE=`printf $NODE | sed "s/:$PORT//"`
|
|
|
|
fi
|
|
|
|
NODE=`printf $NODE | sed -e 's/\[//' -e 's/\]//'`
|
|
|
|
else
|
|
|
|
# determine v4 port, supposed it was supplied additionally
|
|
|
|
echo $NODE | grep -q ':' && PORT=`echo $NODE | sed 's/^.*\://'` && NODE=`echo $NODE | sed 's/\:.*$//'`
|
|
|
|
fi
|
|
|
|
SNI="-servername $NODE"
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
#URLP=`echo $1 | sed 's/'"${PROTO}"':\/\/'"${NODE}"'//'`
|
|
|
|
#URLP=`echo $URLP | sed 's/\/\//\//g'` # // -> /
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
# now get NODEIP
|
|
|
|
get_dns_entries
|
|
|
|
|
2014-10-07 12:04:21 +02:00
|
|
|
# check if we can connect to port
|
|
|
|
if ! fd_socket; then
|
|
|
|
ignore_no_or_lame "Ignore? "
|
|
|
|
[ $? -ne 0 ] && exit 3
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
2014-10-07 12:04:21 +02:00
|
|
|
close_socket
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
if [ -z "$2" ]; then # for starttls we don't want this check
|
|
|
|
# is ssl service listening on port? FIXME: better with bash on IP!
|
2014-07-16 19:04:15 +02:00
|
|
|
$OPENSSL s_client -connect "$NODE:$PORT" $SNI </dev/null >/dev/null 2>&1
|
2014-07-01 16:28:16 +02:00
|
|
|
if [ $? -ne 0 ]; then
|
2014-11-17 17:05:43 +01:00
|
|
|
boldln "$NODE:$PORT doesn't seem a TLS/SSL enabled server or it requires a certificate";
|
|
|
|
ignore_no_or_lame "Proceed (note that the results might look ok but they are nonsense) ? "
|
2014-07-01 16:28:16 +02:00
|
|
|
[ $? -ne 0 ] && exit 3
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
datebanner "Testing"
|
|
|
|
|
|
|
|
[ "$PORT" != 443 ] && bold "A non standard port or testing no web servers might show lame reponses (then just wait)\n"
|
2014-07-16 19:04:15 +02:00
|
|
|
initialize_engine
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
get_dns_entries() {
|
2014-10-07 11:14:39 +02:00
|
|
|
test4iponly=`printf $NODE | sed -e 's/[0-9]//g' -e 's/\.//g'`
|
|
|
|
if [ "x$test4iponly" == "x" ]; then # only an IPv4 address was supplied
|
|
|
|
IP4=$NODE
|
|
|
|
SNI="" # override this as we test the IP only
|
|
|
|
else
|
|
|
|
# for security testing sometimes we have local host entries, so getent is preferred
|
2014-11-22 03:57:36 +01:00
|
|
|
if which getent &>/dev/null; then
|
2014-10-07 11:14:39 +02:00
|
|
|
getent ahostsv4 $NODE 2>/dev/null >/dev/null
|
|
|
|
if [ $? -eq 0 ]; then
|
2014-11-18 23:14:17 +01:00
|
|
|
# Linux:
|
|
|
|
IP4=`getent ahostsv4 $NODE 2>/dev/null | grep -v ':' | grep STREAM | awk '{ print $1}' | uniq`
|
|
|
|
#else
|
|
|
|
# IP4=`getent hosts $NODE 2>/dev/null | grep -v ':' | awk '{ print $1}' | uniq`
|
|
|
|
#FIXME: FreeBSD returns only one entry
|
2014-10-07 11:14:39 +02:00
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
fi
|
2014-11-18 23:14:17 +01:00
|
|
|
if [ -z "$IP4" ] ; then # getent returned nothing:
|
2014-10-07 11:14:39 +02:00
|
|
|
IP4=`host -t a $NODE | grep -v alias | sed 's/^.*address //'`
|
2014-10-09 11:22:23 +02:00
|
|
|
if echo "$IP4" | grep -q NXDOMAIN || echo "$IP4" | grep -q "no A record"; then
|
|
|
|
magenta "Can't proceed: No IP address for \"$NODE\" available"; outln "\n"
|
2014-10-07 11:14:39 +02:00
|
|
|
exit 1
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
fi
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-10-07 11:14:39 +02:00
|
|
|
# for IPv6 we often get this :ffff:IPV4 address which isn't of any use
|
|
|
|
#which getent 2>&1 >/dev/null && IP6=`getent ahostsv6 $NODE | grep $NODE | awk '{ print $1}' | grep -v '::ffff' | uniq`
|
|
|
|
if [ -z "$IP6" ] ; then
|
|
|
|
if host -t aaaa $NODE 2>&1 >/dev/null ; then
|
|
|
|
IP6=`host -t aaaa $NODE | grep -v alias | grep -v "no AAAA record" | sed 's/^.*address //'`
|
|
|
|
else
|
|
|
|
IP6=""
|
|
|
|
fi
|
2014-07-16 19:04:15 +02:00
|
|
|
fi
|
2014-10-09 11:22:23 +02:00
|
|
|
fi # test4iponly
|
2014-07-16 19:04:15 +02:00
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
IPADDRs=`echo $IP4`
|
|
|
|
[ ! -z "$IP6" ] && IPADDRs=`echo $IP4`" "`echo $IP6`
|
|
|
|
|
|
|
|
# FIXME: we could test more than one IPv4 addresses if available, same IPv6. For now we test the first IPv4:
|
|
|
|
NODEIP=`echo "$IP4" | head -1`
|
2014-07-16 19:04:15 +02:00
|
|
|
|
|
|
|
# we can't do this as some checks are not yet IPv6 safe (sorry!)
|
|
|
|
#NODEIP=`echo "$IP6" | head -1`
|
2014-07-01 16:28:16 +02:00
|
|
|
rDNS=`host -t PTR $NODEIP | grep -v "is an alias for" | sed -e 's/^.*pointer //' -e 's/\.$//'`
|
|
|
|
echo $rDNS | grep -q NXDOMAIN && rDNS=" - "
|
|
|
|
}
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
display_rdns_etc() {
|
2014-07-01 16:28:16 +02:00
|
|
|
if [ `echo "$IPADDRs" | wc -w` -gt 1 ]; then
|
2014-07-16 19:04:15 +02:00
|
|
|
out " further IP addresses: "
|
2014-07-01 16:28:16 +02:00
|
|
|
for i in $IPADDRs; do
|
|
|
|
[ "$i" == "$NODEIP" ] && continue
|
2014-07-16 19:04:15 +02:00
|
|
|
out " $i"
|
2014-07-01 16:28:16 +02:00
|
|
|
done
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
|
|
|
fi
|
|
|
|
if [ -n "$rDNS" ] ; then
|
|
|
|
out " rDNS ($NODEIP):"
|
|
|
|
out "$rDNS" 26
|
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
datebanner() {
|
|
|
|
tojour=`date +%F`" "`date +%R`
|
2014-11-18 23:14:17 +01:00
|
|
|
outln
|
2014-07-16 19:04:15 +02:00
|
|
|
reverse "$1 now ($tojour) ---> $NODEIP:$PORT ($NODE) <---"; outln
|
2014-11-18 23:14:17 +01:00
|
|
|
if [ "$1" = "Testing" ] ; then
|
2014-07-16 19:04:15 +02:00
|
|
|
outln
|
|
|
|
display_rdns_etc
|
|
|
|
outln
|
|
|
|
fi
|
|
|
|
outln
|
2014-07-01 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
################# main: #################
|
|
|
|
|
|
|
|
|
|
|
|
case "$1" in
|
|
|
|
-h|--help|-help|"")
|
|
|
|
help
|
|
|
|
exit $? ;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
# auto determine where bins are
|
|
|
|
find_openssl_binary
|
|
|
|
mybanner
|
|
|
|
|
|
|
|
#PATH_TO_TESTSSL="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"
|
|
|
|
PATH_TO_TESTSSL=`readlink "$BASH_SOURCE"` 2>/dev/null
|
|
|
|
[ -z $PATH_TO_TESTSSL ] && PATH_TO_TESTSSL="."
|
2014-11-17 18:49:56 +01:00
|
|
|
#
|
|
|
|
# next file provides a pair "keycode/ RFC style name", see the RFCs, cipher(1) and
|
|
|
|
# https://www.carbonwind.net/TLS_Cipher_Suites_Project/tls_ssl_cipher_suites_simple_table_all.htm
|
|
|
|
[ -r "$(dirname $PATH_TO_TESTSSL)/mapping-rfc.txt" ] && MAP_RFC_FNAME=`dirname $PATH_TO_TESTSSL`"/mapping-rfc.txt"
|
|
|
|
|
2014-07-01 16:28:16 +02:00
|
|
|
|
|
|
|
#FIXME: I know this sucks and getoptS is better
|
|
|
|
|
|
|
|
case "$1" in
|
|
|
|
-b|--banner|-banner|-v|--version|-version)
|
|
|
|
exit 0
|
|
|
|
;;
|
|
|
|
-V|--local)
|
2014-07-16 19:04:15 +02:00
|
|
|
initialize_engine # GOST support
|
2014-07-01 16:28:16 +02:00
|
|
|
prettyprint_local "$2"
|
|
|
|
exit $? ;;
|
2014-11-18 10:29:11 +01:00
|
|
|
-x|--single-ciphers-test)
|
2014-08-29 14:57:20 +02:00
|
|
|
parse_hn_port "$3"
|
|
|
|
maketempf
|
|
|
|
test_just_one $2
|
|
|
|
ret=$?
|
|
|
|
exit $ret ;;
|
2014-07-01 16:28:16 +02:00
|
|
|
-t|--starttls)
|
|
|
|
parse_hn_port "$2" "$3" # here comes hostname:port and protocol to signal starttls
|
|
|
|
maketempf
|
|
|
|
starttls "$3" # protocol
|
|
|
|
ret=$?
|
|
|
|
exit $ret ;;
|
|
|
|
-e|--each-cipher)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
allciphers
|
|
|
|
ret=$?
|
|
|
|
exit $ret ;;
|
|
|
|
-E|-ee|--cipher-per-proto)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
cipher_per_proto
|
|
|
|
ret=$?
|
|
|
|
exit $ret ;;
|
|
|
|
-p|--protocols)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
runprotocols ; ret=$?
|
|
|
|
spdy ; ret=`expr $? + $ret`
|
|
|
|
exit $ret ;;
|
|
|
|
-f|--ciphers)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
run_std_cipherlists
|
|
|
|
ret=$?
|
|
|
|
exit $ret ;;
|
|
|
|
-P|--preference)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
simple_preference
|
|
|
|
ret=$?
|
|
|
|
exit $ret ;;
|
|
|
|
-y|--spdy|--google)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
spdy
|
|
|
|
ret=$?
|
|
|
|
exit $? ;;
|
|
|
|
-B|--heartbleet)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing for heartbleed vulnerability"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
heartbleed
|
|
|
|
ret=$?
|
|
|
|
exit $? ;;
|
|
|
|
-I|--ccs|--ccs_injection)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing for CCS injection vulnerability"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
ccs_injection
|
|
|
|
ret=$?
|
|
|
|
exit $? ;;
|
|
|
|
-R|--renegotiation)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing for Renegotiation vulnerability"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
renego
|
|
|
|
ret=$?
|
|
|
|
exit $? ;;
|
|
|
|
-C|--compression|--crime)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing for CRIME vulnerability"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
crime
|
|
|
|
ret=$?
|
|
|
|
exit $? ;;
|
|
|
|
-T|--breach)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing for BREACH (HTTP compression) vulnerability"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
breach
|
|
|
|
ret=$?
|
|
|
|
ret=`expr $? + $ret`
|
|
|
|
exit $ret ;;
|
2014-10-15 13:10:06 +02:00
|
|
|
-0|--poodle)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
outln; blue "--> Testing for POODLE (Padding Oracle On Downgraded Legacy Encryption) vulnerability"; outln "\n"
|
|
|
|
poodle
|
|
|
|
ret=$?
|
|
|
|
ret=`expr $? + $ret`
|
|
|
|
exit $ret ;;
|
2014-07-01 16:28:16 +02:00
|
|
|
-4|--rc4|--appelbaum)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
rc4
|
|
|
|
ret=$?
|
|
|
|
exit $? ;;
|
|
|
|
-s|--pfs|--fs|--nsa)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
|
|
|
pfs
|
|
|
|
ret=$?
|
|
|
|
exit $ret ;;
|
|
|
|
-H|--header|--headers)
|
|
|
|
parse_hn_port "$2"
|
|
|
|
maketempf
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing HTTP Header response"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
hsts
|
2014-10-29 21:24:43 +01:00
|
|
|
hpkp
|
2014-07-01 16:28:16 +02:00
|
|
|
ret=$?
|
|
|
|
serverbanner
|
|
|
|
ret=`expr $? + $ret`
|
|
|
|
exit $ret ;;
|
2014-11-19 22:23:13 +01:00
|
|
|
-*) help ;; # wrong argument
|
2014-07-01 16:28:16 +02:00
|
|
|
*)
|
|
|
|
parse_hn_port "$1"
|
|
|
|
maketempf
|
|
|
|
|
|
|
|
runprotocols ; ret=$?
|
|
|
|
spdy ; ret=`expr $? + $ret`
|
|
|
|
run_std_cipherlists ; ret=`expr $? + $ret`
|
|
|
|
simple_preference ; ret=`expr $? + $ret`
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing specific vulnerabilities"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
heartbleed ; ret=`expr $? + $ret`
|
|
|
|
ccs_injection ; ret=`expr $? + $ret`
|
|
|
|
renego ; ret=`expr $? + $ret`
|
|
|
|
crime ; ret=`expr $? + $ret`
|
|
|
|
breach ; ret=`expr $? + $ret`
|
|
|
|
beast ; ret=`expr $? + $ret`
|
2014-10-15 13:10:06 +02:00
|
|
|
poodle ; ret=`expr $? + $ret`
|
2014-07-01 16:28:16 +02:00
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
outln; blue "--> Testing HTTP Header response"; outln "\n"
|
2014-07-01 16:28:16 +02:00
|
|
|
hsts ; ret=`expr $? + $ret`
|
2014-10-29 21:24:43 +01:00
|
|
|
hpkp ; ret=`expr $? + $ret`
|
2014-07-01 16:28:16 +02:00
|
|
|
serverbanner ; ret=`expr $? + $ret`
|
|
|
|
|
2014-07-16 19:04:15 +02:00
|
|
|
rc4 ; ret=`expr $? + $ret`
|
2014-07-01 16:28:16 +02:00
|
|
|
pfs ; ret=`expr $? + $ret`
|
|
|
|
exit $ret ;;
|
|
|
|
esac
|
|
|
|
|
2014-11-25 13:12:24 +01:00
|
|
|
# $Id: testssl.sh,v 1.148 2014/11/25 12:11:34 dirkw Exp $
|
2014-07-01 16:28:16 +02:00
|
|
|
# vim:ts=5:sw=5
|
|
|
|
|
|
|
|
|