From 9c84129ff47aef422428c4d83503aba86bf70c70 Mon Sep 17 00:00:00 2001 From: Dirk Date: Thu, 12 Sep 2019 10:38:50 +0200 Subject: [PATCH] Better usability for TLS 1.3-only servers In cases where TLS 1.3 is the only protocol supported by the server (as e.g. in #1312), testssl.sh has some limits with the supplied binary. For now (3.0) there's no perfect technical solution. This PR however improves the verbosity what's going on and recommends to use an openssl binary supporting TLS 1.3. And if the "secret" variable OSSL_SHORTCUT is set to true, it automatically chooses that if available (it's a hack to do so and not recommended. I just did it as a PoC). In the next development we should consider probing this upfront! Furthermore this PR removes some unnecessary quotes in double square brackets. --- testssl.sh | 63 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/testssl.sh b/testssl.sh index 3b88e45..ac90014 100755 --- a/testssl.sh +++ b/testssl.sh @@ -287,7 +287,9 @@ NR_HEADER_FAIL=0 # .. for HTTP_GET PROTOS_OFFERED="" # This keeps which protocol is being offered. See has_server_protocol(). CURVES_OFFERED="" # This keeps which curves have been detected. Just for error handling KNOWN_OSSL_PROB=false # We need OpenSSL a few times. This variable is an indicator if we can't connect. Eases handling -DETECTED_TLS_VERSION="" +DETECTED_TLS_VERSION="" # .. as hex string, e.g. 0300 or 0303 +TLS13_ONLY=false # Does the server support TLS 1.3 ONLY? +OSSL_SHORTCUT=${OSSL_SHORTCUT:-false} # Hack: if during the scan turns out the OpenSSL binary suports TLS 1.3 would be a better choice, this enables it. TLS_EXTENSIONS="" declare -r NPN_PROTOs="spdy/4a2,spdy/3,spdy/3.1,spdy/2,spdy/1,http/1.1" # alpn_protos needs to be space-separated, not comma-seperated, including odd ones observed @ facebook and others, old ones like h2-17 omitted as they could not be found @@ -2078,7 +2080,11 @@ service_detection() { # connectivity_problem() { if [[ $1 -lt $2 ]]; then - prln_warning " Oops: $3" + if "$TLS13_ONLY" && ! "$HAS_TLS13"; then + : + else + prln_warning " Oops: $3" + fi return 0 fi if [[ $1 -ge $2 ]]; then @@ -5437,6 +5443,34 @@ run_protocols() { ignore_no_or_lame "You should not proceed as no protocol was detected. If you still really really want to, say \"YES\"" "YES" [[ $? -ne 0 ]] && exit $ERR_CLUELESS fi + + if [[ "$PROTOS_OFFERED" =~ tls1_3:yes ]]; then + if [[ ! "${PROTOS_OFFERED//tls1_3:yes /}" =~ yes ]]; then + TLS13_ONLY=true + if ! "$HAS_TLS13"; then + pr_magenta " $NODE:$PORT appears to support TLS 1.3 ONLY. You better use --openssl=" + if [[ -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" + MAX_OSSL_FAIL=10 + else + if "$OSSL_SHORTCUT"; then + # 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 + else + outln + ignore_no_or_lame " Type \"yes\" to proceed and accept all scan problems" "yes" + MAX_OSSL_FAIL=10 + fi + fi + fi + fi + fi return $ret } @@ -5966,24 +6000,24 @@ read_dhbits_from_file() { fi return 0 fi - if [[ "$2" == "quiet" ]]; then + if [[ "$2" == quiet ]]; then tm_out "$bits" return 0 fi [[ -z "$2" ]] && [[ -n "$bits" ]] && out ", " - if [[ $what_dh == "DH" ]] || [[ $what_dh == "EDH" ]]; then + if [[ $what_dh == DH ]] || [[ $what_dh == EDH ]]; then add="bit DH" [[ -n "$curve" ]] && add+=" ($curve)" - if [[ "$2" == "string" ]]; then + if [[ "$2" == string ]]; then tm_out ", $bits $add" else pr_dh_quality "$bits" "$bits $add" fi # https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography, http://www.keylength.com/en/compare/ - elif [[ $what_dh == "ECDH" ]]; then + elif [[ $what_dh == ECDH ]]; then add="bit ECDH" [[ -n "$curve" ]] && add+=" ($curve)" - if [[ "$2" == "string" ]]; then + if [[ "$2" == string ]]; then tm_out ", $bits $add" else pr_ecdh_quality "$bits" "$bits $add" @@ -6336,12 +6370,10 @@ run_server_preference() { [[ $TLS_NR_CIPHERS == 0 ]] && using_sockets=false pr_bold " Cipher order" - while read proto_ossl proto_hex proto_txt; do cipher_pref_check "$proto_ossl" "$proto_hex" "$proto_txt" "$using_sockets" done <<< "$(tm_out " ssl3 00 SSLv3\n tls1 01 TLSv1\n tls1_1 02 TLSv1.1\n tls1_2 03 TLSv1.2\n tls1_3 04 TLSv1.3\n")" outln - outln else pr_bold " Negotiated cipher per proto"; outln " $limitedsense" @@ -9171,7 +9203,14 @@ run_server_defaults() { fi elif [[ $certs_found -eq 0 ]] && [[ -s "$HOSTCERT" ]]; then outln - generic_nonfatal "Client problem, shouldn't happen: Host certificate found but we can't continue with \"server defaults\"" + generic_nonfatal "Client problem, shouldn't happen: Host certificate found but we can't continue with \"server defaults\"." + elif [[ $certs_found -eq 0 ]]; then + outln + if $TLS13_ONLY; then + generic_nonfatal "Client problem: We need openssl supporting TLS 1.3. We can't continue with \"server defaults\" as we cannot retrieve the certificate. " + else + generic_nonfatal "Client problem, No server cerificate could be retrieved. Thus we can't continue with \"server defaults\"." + fi fi [[ $DEBUG -ge 1 ]] && [[ -e $HOSTCERT.nosni ]] && $OPENSSL x509 -in $HOSTCERT.nosni -text -noout 2>>$ERRFILE > $HOSTCERT.nosni.txt @@ -15616,8 +15655,8 @@ run_rc4() { done for proto in -no_ssl2 -tls1_1 -tls1 -ssl3; do - [[ "$proto" != "-no_ssl2" ]] && [[ $(has_server_protocol "${proto:1}") -eq 1 ]] && continue - ! "$HAS_SSL3" && [[ "$proto" == "-ssl3" ]] && continue + [[ "$proto" != -no_ssl2 ]] && [[ $(has_server_protocol "${proto:1}") -eq 1 ]] && continue + ! "$HAS_SSL3" && [[ "$proto" == -ssl3 ]] && continue while true; do ciphers_to_test="" for (( i=0; i < nr_ossl_ciphers; i++ )); do