Merge pull request #1336 from dcooper16/ossl_determine_optimal_proto

Use OpenSSL for determine_optimal_proto()
This commit is contained in:
Dirk Wetter 2019-10-18 21:07:15 +02:00 committed by GitHub
commit 3389d84103
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 96 additions and 136 deletions

View File

@ -380,6 +380,7 @@ OPTIMAL_PROTO="" # Need this for IIS6 (sigh) + OpenSSL 1.
# https://github.com/PeterMosmans/openssl/issues/19#issuecomment-100897892 # https://github.com/PeterMosmans/openssl/issues/19#issuecomment-100897892
STARTTLS_OPTIMAL_PROTO="" # Same for STARTTLS, see https://github.com/drwetter/testssl.sh/issues/188 STARTTLS_OPTIMAL_PROTO="" # Same for STARTTLS, see https://github.com/drwetter/testssl.sh/issues/188
OPTIMAL_SOCKETS_PROTO="" # Same for tls_sockets(). -- not yet used OPTIMAL_SOCKETS_PROTO="" # Same for tls_sockets(). -- not yet used
ALL_FAILED_SOCKETS=true # Set to true if all attempts to connect to server using tls_sockets/sslv2_sockets failed
TLS_TIME="" # To keep the value of TLS server timestamp TLS_TIME="" # To keep the value of TLS server timestamp
TLS_NOW="" # Similar TLS_NOW="" # Similar
TLS_DIFFTIME_SET=false # Tells TLS functions to measure the TLS difftime or not TLS_DIFFTIME_SET=false # Tells TLS functions to measure the TLS difftime or not
@ -17943,74 +17944,10 @@ determine_optimal_sockets_params() {
sslv2_sockets sslv2_sockets
[[ $? -eq 3 ]] && all_failed=false && add_tls_offered ssl2 yes [[ $? -eq 3 ]] && all_failed=false && add_tls_offered ssl2 yes
fi fi
if [[ -n "$OPTIMAL_SOCKETS_PROTO" ]]; then ALL_FAILED_SOCKETS="$all_failed"
prln_warning " $NODEIP:$PORT doesn't seem to handle version negotiation correctly. This may lead to some false positives and/or false negatives."
fi
return 0 return 0
} }
# This is a helper function for determine_optimal_proto() below. It sets the
# the global STARTTLS_OPTIMAL_PROTO / OPTIMAL_PROTO accordingly and returns 1
# if no protocol could be determined and 0 if this was possible.
#
determine_optimal_proto_sockets_helper() {
local all_failed=true
local proto=""
local optimal_proto=""
local starttls="$1"
local -i ret
for proto in 03 01 04 00 02 22; do
case $proto in
03) tls_sockets "$proto" "$TLS12_CIPHER"
ret=$?
if [[ $ret -eq 0 ]] || [[ $ret -eq 2 ]]; then
case $DETECTED_TLS_VERSION in
0303) add_tls_offered tls1_2 yes; optimal_proto="-tls1_2" ;;
0302) add_tls_offered tls1_1 yes; optimal_proto="-tls1_1" ;;
0301) add_tls_offered tls1 yes; optimal_proto="-tls1" ;;
0300) add_tls_offered ssl3 yes; optimal_proto="-ssl3" ;;
esac
all_failed=false
break
fi ;;
04) tls_sockets "$proto" "$TLS13_CIPHER"
if [[ $? -eq 0 ]]; then
add_tls_offered tls1_3 yes; optimal_proto="-tls1_3"
all_failed=false
break
fi ;;
01|00|02) tls_sockets "$proto" "$TLS_CIPHER" "" "" "true"
ret=$?
if [[ $ret -eq 0 ]] || [[ $ret -eq 2 ]]; then
case $DETECTED_TLS_VERSION in
0302) add_tls_offered tls1_1 yes; optimal_proto="-tls1_1" ;;
0301) add_tls_offered tls1 yes; optimal_proto="-tls1" ;;
0300) add_tls_offered ssl3 yes; optimal_proto="-ssl3" ;;
esac
all_failed=false
break
fi ;;
22) sslv2_sockets
[[ $? -eq 3 ]] && all_failed=false && add_tls_offered ssl2 yes && optimal_proto="-ssl2"
;;
esac
done
[[ "$proto" != 22 ]] && cp $TEMPDIR/$NODEIP.parse_tls_serverhello.txt $TMPFILE
debugme echo "proto: $proto"
if [[ -n "$starttls" ]]; then
STARTTLS_OPTIMAL_PROTO="$optimal_proto"
else
OPTIMAL_PROTO="$optimal_proto"
fi
if "$all_failed"; then
return 1
else
return 0
fi
}
# This function determines (STARTTLS_)OPTIMAL_PROTO. It is basically a workaround function as under certain # This function determines (STARTTLS_)OPTIMAL_PROTO. It is basically a workaround function as under certain
# circumstances a ClientHello without specifying a protocol will fail. # circumstances a ClientHello without specifying a protocol will fail.
@ -18023,20 +17960,12 @@ determine_optimal_proto_sockets_helper() {
determine_optimal_proto() { determine_optimal_proto() {
local all_failed=true local all_failed=true
local tmp="" local tmp=""
local using_sockets=true local proto optimal_proto
"$do_tls_sockets" && return 0 "$do_tls_sockets" && return 0
>$ERRFILE >$ERRFILE
"$SSL_NATIVE" && using_sockets=false
if [[ -n "$1" ]]; then if [[ -n "$1" ]]; then
# STARTTLS
if "$using_sockets"; then
determine_optimal_proto_sockets_helper "$1"
[[ $? -eq 1 ]] && all_failed=true || all_failed=false
else
# No sockets
# STARTTLS workaround needed see https://github.com/drwetter/testssl.sh/issues/188 -- kind of odd # STARTTLS workaround needed see https://github.com/drwetter/testssl.sh/issues/188 -- kind of odd
for STARTTLS_OPTIMAL_PROTO in -tls1_2 -tls1 -ssl3 -tls1_1 -tls1_3 -ssl2; do for STARTTLS_OPTIMAL_PROTO in -tls1_2 -tls1 -ssl3 -tls1_1 -tls1_3 -ssl2; do
case $STARTTLS_OPTIMAL_PROTO in case $STARTTLS_OPTIMAL_PROTO in
@ -18045,69 +17974,91 @@ determine_optimal_proto() {
-ssl2) "$HAS_SSL2" || continue ;; -ssl2) "$HAS_SSL2" || continue ;;
*) ;; *) ;;
esac esac
#FIXME: to be replaced / added by socket ( if "$using_sockets" ...)
$OPENSSL s_client $(s_client_options "$STARTTLS_OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" $PROXY -msg -starttls $1" $SNI) </dev/null >$TMPFILE 2>>$ERRFILE $OPENSSL s_client $(s_client_options "$STARTTLS_OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" $PROXY -msg -starttls $1" $SNI) </dev/null >$TMPFILE 2>>$ERRFILE
if sclient_auth $? $TMPFILE; then if sclient_auth $? $TMPFILE; then
all_failed=false all_failed=false
add_tls_offered "${proto/-/}" yes
break break
fi fi
all_failed=true
done done
"$all_failed" && STARTTLS_OPTIMAL_PROTO="" "$all_failed" && STARTTLS_OPTIMAL_PROTO=""
fi optimal_proto="$STARTTLS_OPTIMAL_PROTO"
debugme echo "STARTTLS_OPTIMAL_PROTO: $STARTTLS_OPTIMAL_PROTO" debugme echo "STARTTLS_OPTIMAL_PROTO: $STARTTLS_OPTIMAL_PROTO"
else else
# No STARTTLS # No STARTTLS
if "$using_sockets"; then for proto in '' -tls1_2 -tls1 -tls1_3 -ssl3 -tls1_1 -ssl2; do
determine_optimal_proto_sockets_helper case $proto in
[[ $? -eq 1 ]] && all_failed=true || all_failed=false
else
# no sockets
for OPTIMAL_PROTO in '' -tls1_2 -tls1 -tls1_3 -ssl3 -tls1_1 -ssl2; do
case $OPTIMAL_PROTO in
-tls1_3) "$HAS_TLS13" || continue ;; -tls1_3) "$HAS_TLS13" || continue ;;
-ssl3) "$HAS_SSL3" || continue ;; -ssl3) "$HAS_SSL3" || continue ;;
-ssl2) "$HAS_SSL2" || continue ;; -ssl2) "$HAS_SSL2" || continue ;;
*) ;; *) ;;
esac esac
$OPENSSL s_client $(s_client_options "$OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" -msg $PROXY $SNI") </dev/null >$TMPFILE 2>>$ERRFILE $OPENSSL s_client $(s_client_options "$proto $BUGS -connect "$NODEIP:$PORT" -msg $PROXY $SNI") </dev/null >$TMPFILE 2>>$ERRFILE
if sclient_auth $? $TMPFILE; then if sclient_auth $? $TMPFILE; then
# we use the successful handshake at least to get one valid protocol supported -- it saves us time later # we use the successful handshake at least to get one valid protocol supported -- it saves us time later
if [[ -z "$OPTIMAL_PROTO" ]]; then if [[ -z "$proto" ]]; then
# convert to openssl terminology # convert to openssl terminology
tmp=$(get_protocol $TMPFILE) tmp=$(get_protocol $TMPFILE)
tmp=${tmp/\./_} tmp=${tmp/\./_}
tmp=${tmp/v/} tmp=${tmp/v/}
tmp="$(tolower $tmp)" tmp="$(tolower $tmp)"
add_tls_offered "${tmp}" yes add_tls_offered "${tmp}" yes
case $tmp in
tls1) OPTIMAL_PROTO="-tls1" ;;
tls1_1) OPTIMAL_PROTO="-tls1_1" ;;
tls1_2) OPTIMAL_PROTO="-tls1_2" ;;
tls1_3) OPTIMAL_PROTO="-tls1_3" ;;
ssl2) OPTIMAL_PROTO="-ssl2" ;;
esac
else
add_tls_offered "${OPTIMAL_PROTO/-/}" yes
fi
debugme echo "one proto determined: $tmp" debugme echo "one proto determined: $tmp"
OPTIMAL_PROTO=""
else
add_tls_offered "${proto/-/}" yes
OPTIMAL_PROTO="$proto"
fi
all_failed=false all_failed=false
break break
fi fi
all_failed=true
done done
fi
"$all_failed" && OPTIMAL_PROTO="" "$all_failed" && OPTIMAL_PROTO=""
if [[ "$OPTIMAL_PROTO" == -ssl2 ]]; then optimal_proto="$OPTIMAL_PROTO"
debugme echo "OPTIMAL_PROTO: $OPTIMAL_PROTO"
fi
[[ "$optimal_proto" != -ssl2 ]] && ! "$all_failed" && grep -q '^Server Temp Key' $TMPFILE && HAS_DH_BITS=true # FIX #190
if [[ "$(has_server_protocol "tls1_3")" -eq 0 ]] && [[ "$(has_server_protocol "tls1_2")" -ne 0 ]] &&
[[ "$(has_server_protocol "tls1_1")" -ne 0 ]] && [[ "$(has_server_protocol "tls1")" -ne 0 ]] &&
[[ "$(has_server_protocol "ssl3")" -ne 0 ]]; then
TLS13_ONLY=true
fi
if [[ "$optimal_proto" == -ssl2 ]]; then
prln_magenta "$NODEIP:$PORT appears to only support SSLv2." prln_magenta "$NODEIP:$PORT appears to only support SSLv2."
ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes" ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes"
[[ $? -ne 0 ]] && exit $ERR_CLUELESS [[ $? -ne 0 ]] && exit $ERR_CLUELESS
elif "$all_failed" && ! "$ALL_FAILED_SOCKETS"; then
if ! "$HAS_TLS13" && "$TLS13_ONLY"; then
pr_magenta " $NODE:$PORT appears to support TLS 1.3 ONLY. You better use --openssl=<path_to_openssl_supporting_TLS_1.3>"
if ! "$OSSL_SHORTCUT" || [[ ! -x /usr/bin/openssl ]] || /usr/bin/openssl s_client -tls1_3 -connect x 2>&1 | grep -aq "unknown option"; then
outln
ignore_no_or_lame " Type \"yes\" to proceed and accept all scan problems" "yes"
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
MAX_OSSL_FAIL=10
else
# dirty hack but an idea for the future to be implemented upfront: Now we know, we'll better off
# with the OS supplied openssl binary. We need to inittialize variables / arrays again though.
# And the service detection can't be made up for now
outln ", proceeding with /usr/bin/openssl"
OPENSSL=/usr/bin/openssl
find_openssl_binary
prepare_arrays
fi fi
debugme echo "OPTIMAL_PROTO: $OPTIMAL_PROTO" elif ! "$HAS_SSL3" && [[ "$(has_server_protocol "ssl3")" -eq 0 ]] && [[ "$(has_server_protocol "tls1_3")" -ne 0 ]] && \
[[ "$(has_server_protocol "tls1_2")" -ne 0 ]] && [[ "$(has_server_protocol "tls1_1")" -ne 0 ]] &&
[[ "$(has_server_protocol "tls1")" -ne 0 ]]; then
prln_magenta " $NODE:$PORT appears to support SSLv3 ONLY. You better use --openssl=<path_to_openssl_supporting_SSL_3>"
ignore_no_or_lame " Type \"yes\" to proceed and accept all scan problems" "yes"
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
MAX_OSSL_FAIL=10
else
prln_bold " Your $OPENSSL cannot connect to $NODEIP:$PORT"
ignore_no_or_lame " The results might look ok but they could be nonsense. Really proceed ? (\"yes\" to continue)" "yes"
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
fi fi
[[ "$OPTIMAL_PROTO" != -ssl2 ]] && ! "$all_failed" && grep -q '^Server Temp Key' $TMPFILE && HAS_DH_BITS=true # FIX #190 elif "$all_failed"; then
if "$all_failed"; then
outln outln
if "$HAS_IPv6"; then if "$HAS_IPv6"; then
pr_bold " Your $OPENSSL is not IPv6 aware, or $NODEIP:$PORT " pr_bold " Your $OPENSSL is not IPv6 aware, or $NODEIP:$PORT "
@ -18118,6 +18069,14 @@ determine_optimal_proto() {
prln_bold "doesn't seem to be a TLS/SSL enabled server"; prln_bold "doesn't seem to be a TLS/SSL enabled server";
ignore_no_or_lame " The results might look ok but they could be nonsense. Really proceed ? (\"yes\" to continue)" "yes" ignore_no_or_lame " The results might look ok but they could be nonsense. Really proceed ? (\"yes\" to continue)" "yes"
[[ $? -ne 0 ]] && exit $ERR_CLUELESS [[ $? -ne 0 ]] && exit $ERR_CLUELESS
elif ! "$all_failed" && "$ALL_FAILED_SOCKETS"; then
# For some reason connecting with tls_sockets/sslv2_sockets didn't work, but connecting
# with $OPENSSL s_client did.
# FIXME: Should we include some sort of "please report" note here?
prln_magenta " Testing with $NODE:$PORT only worked using $OPENSSL."
"$SSL_NATIVE" || prln_magenta " Test results may be somewhat better if the --ssl-native option is used."
ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes"
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
fi fi
tmpfile_handle ${FUNCNAME[0]}.txt tmpfile_handle ${FUNCNAME[0]}.txt
@ -19564,6 +19523,7 @@ reset_hostdepended_vars() {
PROTOS_OFFERED="" PROTOS_OFFERED=""
CURVES_OFFERED="" CURVES_OFFERED=""
OPTIMAL_PROTO="" OPTIMAL_PROTO=""
ALL_FAILED_SOCKETS=true
SERVER_SIZE_LIMIT_BUG=false SERVER_SIZE_LIMIT_BUG=false
} }