From 3ea1b1b884b1b4f3c3c55f4eb05d081acce799d7 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 26 Feb 2019 14:43:37 -0500 Subject: [PATCH 1/6] WIP: Separate server preference test (cipher order) for TLS 1.3 This PR is an attempt to fix #1163 by running separate tests for a server cipher order preference to TLSv1.3 and for SSLv3 - TLSv1.2. If the server supports TLSv1.3, then a test is performed to determine whether the server enforces a cipher order to TLSv1.3. A separate test is performed for SSLv3 - TLSv1.2 unless it is known that the server does not support any of these protocols. If the server enforces a cipher order for SSLv3 - TLSv1.2, but not for TLSv1.3, then cipher_pref_check() is not called for TLSv1.3, since cipher_pref_check() is intended to show the cipher order that the server enforces. As TLSv1.3 will be the negotiated protocol if it is supported, the negotiated cipher for TLSv1.3 will already be presented. This PR still has one major flaw, which may create a problem when testing a TLSv1.3-only server. If run_protocols() is run before run_server_preference(), then everything will be okay, as run_server_preference() will be able to determine that SSLv3 - TLSv1.2 are not supported. However, if run_server_preference() is run by itself, run_server_preference() will not know that SSLv3 - TLSv1.2 are not supported and so it will try to determine whether the server enforces a cipher preference order for these protocols. The attempt to connect to the server will fail, but at the moment run_server_preference() doesn't know whether the failure is because the server does not support SSLv3 - TLSv1.2 or because the server supports at least one of these protocols, but does not support any ciphers in $list_fwd. At the moment, run_server_preference() incorrectly flags an error. One option would be to perform additional tests against the server in this case to determine the reason for the connection failure. Another option would be to have some code that is always run earlier, such as determine_optimal_proto(), test whether a server that supports TLSv1.3 supports any earlier protocols (SSLv3 - TLSv1.2). --- testssl.sh | 83 +++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/testssl.sh b/testssl.sh index a5c5695..7f765e0 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6140,13 +6140,11 @@ run_server_preference() { local -i ret=0 j sclient_success str_len local list_fwd="DHE-RSA-SEED-SHA:SEED-SHA:DES-CBC3-SHA:RC4-MD5:DES-CBC-SHA:RC4-SHA:AES128-SHA:AES128-SHA256:AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-RSA-AES128-SHA:ECDH-RSA-AES256-SHA:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:AES256-SHA256:ECDHE-RSA-DES-CBC3-SHA:ECDHE-RSA-AES128-SHA256:AES256-GCM-SHA384:AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:ADH-AES256-GCM-SHA384:AECDH-AES128-SHA:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-AES128-SHA" local list_reverse="ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-RC4-SHA:AECDH-AES128-SHA:ADH-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-DES-CBC3-SHA:AES256-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA:ECDH-RSA-AES128-SHA:ECDH-RSA-DES-CBC3-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA256:AES128-SHA:RC4-SHA:DES-CBC-SHA:RC4-MD5:DES-CBC3-SHA:SEED-SHA:DHE-RSA-SEED-SHA" - tls13_list_fwd="TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256" - tls13_list_reverse="TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384" tls_list_fwd="c0,2c, c0,30, 00,9f, cc,a9, cc,a8, cc,aa, c0,2b, c0,2f, 00,9e, c0,24, c0,28, 00,6b, c0,23, c0,27, 00,67, c0,0a, 00,04, 00,05, 00,09, 00,0a, 00,9a, 00,96, c0,14, 00,39, c0,09, c0,13, 00,33, 00,9d, 00,9c, 13,01, 13,02, 13,03, 13,04, 13,05, 00,3d, 00,3c, 00,35, 00,2f, 00,ff" tls_list_rev="00,2f, 00,35, 00,3c, 00,3d, 13,05, 13,04, 13,03, 13,02, 13,01, 00,9c, 00,9d, 00,33, c0,13, c0,09, 00,39, c0,14, 00,96, 00,9a, 00,0a, 00,09, 00,05, 00,04, c0,0a, 00,67, c0,27, c0,23, 00,6b, c0,28, c0,24, 00,9e, c0,2f, c0,2b, cc,aa, cc,a8, cc,a9, 00,9f, c0,30, c0,2c, 00,ff" - local has_cipher_order=false + local has_cipher_order=false has_tls13_cipher_order=false local addcmd="" addcmd2="" local using_sockets=true local jsonID="cipher_order" @@ -6180,7 +6178,17 @@ run_server_preference() { 13,03, 13,01, 13,04, 13,05, 00,3d, 00,3c, 00,35, 00,2f, 00,ff" \ "ephemeralkey" sclient_success=$? - [[ $sclient_success -eq 2 ]] && sclient_success=0 # 2: downgraded + if [[ $sclient_success -eq 0 ]]; then + add_tls_offered tls1_3 yes + elif [[ $sclient_success -eq 2 ]]; then + sclient_success=0 # 2: downgraded + case $DETECTED_TLS_VERSION in + 0303) add_tls_offered tls1_2 yes ;; + 0302) add_tls_offered tls1_1 yes ;; + 0301) add_tls_offered tls1 yes ;; + 0300) add_tls_offered ssl3 yes ;; + esac + fi if [[ $sclient_success -eq 0 ]] ; then cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" "$TEMPDIR/$NODEIP.parse_tls13_serverhello.txt" @@ -6217,66 +6225,58 @@ run_server_preference() { cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE tls13_cipher2=$(get_cipher $TMPFILE) debugme tm_out "TLS 1.3: --> $tls13_cipher2\n" + + [[ $tls13_cipher1 == $tls13_cipher2 ]] && has_tls13_cipher_order=true + fi + # Check whether the server has a cipher order for SSLv3 - TLSv1.2 + if [[ $(has_server_protocol "tls1_2") -eq 1 ]] && [[ $(has_server_protocol "tls1_1") -eq 1 ]] && \ + [[ $(has_server_protocol "tls1") -eq 1 ]] && [[ $(has_server_protocol "ssl3") -eq 1 ]]; then + # It is known that SSLv3 - TLSv1.2 are not offered. + has_cipher_order="$has_tls13_cipher_order" elif [[ "$OPTIMAL_PROTO" != -ssl2 ]]; then - [[ $DEBUG -ge 4 ]] && echo -e "\n Forward: ${list_fwd}\n ${tls13_list_fwd}" - $OPENSSL s_client $(s_client_options "$STARTTLS -cipher $list_fwd -ciphersuites $tls13_list_fwd $BUGS -connect $NODEIP:$PORT $PROXY $addcmd") $ERRFILE >$TMPFILE - if ! sclient_connect_successful $? $TMPFILE && [[ -z "$STARTTLS_PROTOCOL" ]]; then - list_fwd="$(actually_supported_ciphers $list_fwd $tls13_list_fwd '-tls1')" + if [[ -n "$STARTTLS_OPTIMAL_PROTO" ]]; then + [[ ! "$STARTTLS_OPTIMAL_PROTO" =~ ssl ]] && addcmd2="$SNI" + [[ ! "$STARTTLS_OPTIMAL_PROTO" == -tls1_3 ]] && addcmd2+=" $STARTTLS_OPTIMAL_PROTO" + else + addcmd2="-no_ssl2 $SNI" + fi + [[ $DEBUG -ge 4 ]] && echo -e "\n Forward: ${list_fwd}" + $OPENSSL s_client $(s_client_options "$STARTTLS -cipher $list_fwd $BUGS -connect $NODEIP:$PORT $PROXY $addcmd2") $ERRFILE >$TMPFILE + if ! sclient_connect_successful $? $TMPFILE; then + list_fwd="$(actually_supported_ciphers $list_fwd '' '-tls1')" pr_warning "no matching cipher in this list found (pls report this): " outln "$list_fwd . " fileout "$jsonID" "WARN" "Could not determine server cipher order, no matching cipher in list found (pls report this): $list_fwd" tmpfile_handle ${FUNCNAME[0]}.txt return 1 # we assume the problem is with testing here but it could be also the server side - elif [[ -n "$STARTTLS_PROTOCOL" ]]; then - # now it still could be that we hit this bug: https://github.com/drwetter/testssl.sh/issues/188 - # workaround is to connect with a protocol - [[ ! "$STARTTLS_OPTIMAL_PROTO" =~ ssl ]] && addcmd2="$SNI" - $OPENSSL s_client $(s_client_options "$STARTTLS $STARTTLS_OPTIMAL_PROTO -cipher $list_fwd -ciphersuites $tls13_list_fwd $BUGS -connect $NODEIP:$PORT $PROXY $addcmd2") $ERRFILE >$TMPFILE - if ! sclient_connect_successful $? $TMPFILE; then - list_fwd="$(actually_supported_ciphers $list_fwd $tls13_list_fwd '-tls1')" - pr_warning "no matching cipher in this list found (pls report this): " - outln "$list_fwd . " - fileout "$jsonID" "WARN" "Could not determine cipher order, no matching cipher in list found (pls report this): $list_fwd" - tmpfile_handle ${FUNCNAME[0]}.txt - return 1 - fi fi cipher1=$(get_cipher $TMPFILE) # cipher1 from 1st serverhello debugme tm_out "1 --> $cipher1\n" - if [[ -n "$STARTTLS_OPTIMAL_PROTO" ]]; then - addcmd2="$STARTTLS_OPTIMAL_PROTO $SNI" - else - if [[ "$OPTIMAL_PROTO" == -ssl2 ]]; then - addcmd2="$OPTIMAL_PROTO" - else - addcmd2="-no_ssl2 $SNI" - fi - fi - # second client hello with reverse list - [[ $DEBUG -ge 4 ]] && echo -e "\n Reverse: ${list_reverse}\n ${tls13_list_reverse}" - $OPENSSL s_client $(s_client_options "$STARTTLS -cipher $list_reverse -ciphersuites $tls13_list_reverse $BUGS -connect $NODEIP:$PORT $PROXY $addcmd2") >$ERRFILE >$TMPFILE + [[ $DEBUG -ge 4 ]] && echo -e "\n Reverse: ${list_reverse}" + $OPENSSL s_client $(s_client_options "$STARTTLS -cipher $list_reverse $BUGS -connect $NODEIP:$PORT $PROXY $addcmd2") >$ERRFILE >$TMPFILE # first handshake worked above so no error handling here cipher2=$(get_cipher $TMPFILE) # cipher2 from 2nd serverhello debugme tm_out "2 --> $cipher2\n" + + [[ $cipher1 == $cipher2 ]] && has_cipher_order=true fi - if [[ "$default_proto" == TLSv1.3 ]] && [[ $tls13_cipher1 != $tls13_cipher2 ]]; then - pr_svrty_good "yes (OK)"; out " -- only for < TLS 1.3" - has_cipher_order=true - fileout "$jsonID" "OK" "server -- TLS 1.3 client determined" - cipher1="$tls13_cipher1" - cipher2="$tls13_cipher2" - elif [[ "$OPTIMAL_PROTO" == -ssl2 ]] || [[ "$cipher1" != $cipher2 ]]; then + if ! "$has_cipher_order" && ! "$has_tls13_cipher_order"; then # server used the different ends (ciphers) from the client hello pr_svrty_high "nope (NOT ok)" limitedsense=" (limited sense as client will pick)" fileout "$jsonID" "HIGH" "NOT a cipher order configured" + elif "$has_cipher_order" && ! "$has_tls13_cipher_order" && [[ "$default_proto" == TLSv1.3 ]]; then + pr_svrty_good "yes (OK)"; out " -- only for < TLS 1.3" + fileout "$jsonID" "OK" "server -- TLS 1.3 client determined" + elif ! "$has_cipher_order" && "$has_tls13_cipher_order"; then + pr_svrty_good "yes (OK)"; out " -- only for TLS 1.3" + fileout "$jsonID" "OK" "server -- < TLS 1.3 client determined" else pr_svrty_best "yes (OK)" - has_cipher_order=true fileout "$jsonID" "OK" "server" fi outln @@ -6385,6 +6385,7 @@ run_server_preference() { pr_bold " Cipher order" while read proto_ossl proto_hex proto_txt; do + [[ "$proto_ossl" == tls1_3 ]] && ! "$has_tls13_cipher_order" && continue 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 From beec1a7e1e265bdd6a690858d921f252fbaa9f2d Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 24 Sep 2019 14:12:02 -0400 Subject: [PATCH 2/6] Use results of determine_optimal_sockets_params() --- testssl.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 7f765e0..c96bbc6 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6229,14 +6229,15 @@ run_server_preference() { [[ $tls13_cipher1 == $tls13_cipher2 ]] && has_tls13_cipher_order=true fi # Check whether the server has a cipher order for SSLv3 - TLSv1.2 - if [[ $(has_server_protocol "tls1_2") -eq 1 ]] && [[ $(has_server_protocol "tls1_1") -eq 1 ]] && \ - [[ $(has_server_protocol "tls1") -eq 1 ]] && [[ $(has_server_protocol "ssl3") -eq 1 ]]; then - # It is known that SSLv3 - TLSv1.2 are not offered. + if [[ $(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 + # Based on testing performed by determine_optimal_sockets_params(), it is believed that + # this server does not offer SSLv3 - TLSv1.2. has_cipher_order="$has_tls13_cipher_order" elif [[ "$OPTIMAL_PROTO" != -ssl2 ]]; then if [[ -n "$STARTTLS_OPTIMAL_PROTO" ]]; then [[ ! "$STARTTLS_OPTIMAL_PROTO" =~ ssl ]] && addcmd2="$SNI" - [[ ! "$STARTTLS_OPTIMAL_PROTO" == -tls1_3 ]] && addcmd2+=" $STARTTLS_OPTIMAL_PROTO" + [[ "$STARTTLS_OPTIMAL_PROTO" != -tls1_3 ]] && addcmd2+=" $STARTTLS_OPTIMAL_PROTO" else addcmd2="-no_ssl2 $SNI" fi From 2810c70163e82776f922112c6800106c1b9b9e67 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 28 Oct 2019 16:15:38 -0400 Subject: [PATCH 3/6] Address comments in #1205 This commit addresses the comments in #1205. If a server only supports TLS 1.3, then it is not considered an issue if the server does not enforce a cipher order. However, if the server does not support a cipher order for TLS 1.2 and below, then that is an issue, even if the server does support a cipher order for TLS 1.3. --- testssl.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index c96bbc6..6f809ad 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6264,8 +6264,14 @@ run_server_preference() { [[ $cipher1 == $cipher2 ]] && has_cipher_order=true fi + debugme echo "has_cipher_order: $has_cipher_order" + debugme echo "has_tls13_cipher_order: $has_tls13_cipher_order" - if ! "$has_cipher_order" && ! "$has_tls13_cipher_order"; then + if "$TLS13_ONLY" && ! "$has_tls13_cipher_order"; then + out "nope" + limitedsense=" (limited sense as client will pick)" + fileout "$jsonID" "INFO" "NOT a cipher order configured" + elif ! "$has_cipher_order" && ! "$has_tls13_cipher_order"; then # server used the different ends (ciphers) from the client hello pr_svrty_high "nope (NOT ok)" limitedsense=" (limited sense as client will pick)" @@ -6274,10 +6280,11 @@ run_server_preference() { pr_svrty_good "yes (OK)"; out " -- only for < TLS 1.3" fileout "$jsonID" "OK" "server -- TLS 1.3 client determined" elif ! "$has_cipher_order" && "$has_tls13_cipher_order"; then - pr_svrty_good "yes (OK)"; out " -- only for TLS 1.3" - fileout "$jsonID" "OK" "server -- < TLS 1.3 client determined" + pr_svrty_high "nope (NOT ok)"; out " -- only for TLS 1.3" + fileout "$jsonID" "HIGH" "server -- < TLS 1.3 client determined" else pr_svrty_best "yes (OK)" + "$has_tls13_cipher_order" && out " -- TLS 1.3 and below" fileout "$jsonID" "OK" "server" fi outln From 0f40e85f62bbfa798241e6f42354e2791352da79 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Tue, 29 Oct 2019 17:32:50 +0100 Subject: [PATCH 4/6] TLS 1.3 and cipher order If a server offers TLS 1.3 only and the cipher order is server side this commit changes the severity level to INFO. Also it changes nope to no in two places --- testssl.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/testssl.sh b/testssl.sh index 6f809ad..1635b4e 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6268,12 +6268,12 @@ run_server_preference() { debugme echo "has_tls13_cipher_order: $has_tls13_cipher_order" if "$TLS13_ONLY" && ! "$has_tls13_cipher_order"; then - out "nope" + out "no (TLS 1.3 only)" limitedsense=" (limited sense as client will pick)" - fileout "$jsonID" "INFO" "NOT a cipher order configured" + fileout "$jsonID" "INFO" "not a cipher order for TLS 1.3 configured" elif ! "$has_cipher_order" && ! "$has_tls13_cipher_order"; then # server used the different ends (ciphers) from the client hello - pr_svrty_high "nope (NOT ok)" + pr_svrty_high "no (NOT ok)" limitedsense=" (limited sense as client will pick)" fileout "$jsonID" "HIGH" "NOT a cipher order configured" elif "$has_cipher_order" && ! "$has_tls13_cipher_order" && [[ "$default_proto" == TLSv1.3 ]]; then @@ -6283,9 +6283,16 @@ run_server_preference() { pr_svrty_high "nope (NOT ok)"; out " -- only for TLS 1.3" fileout "$jsonID" "HIGH" "server -- < TLS 1.3 client determined" else - pr_svrty_best "yes (OK)" - "$has_tls13_cipher_order" && out " -- TLS 1.3 and below" - fileout "$jsonID" "OK" "server" + if "$has_tls13_cipher_order"; then + if "$TLS13_ONLY"; then + out "yes (TLS 1.3 only)" + fileout "$jsonID" "INFO" "server (TLS 1.3)" + else + pr_svrty_best "yes (OK)" + out " -- TLS 1.3 and below" + fileout "$jsonID" "OK" "server" + fi + fi fi outln From 2f9bcea5e63697cc91043d7ae11a3b9773a6d5e0 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Tue, 29 Oct 2019 17:36:08 +0100 Subject: [PATCH 5/6] change another nope to no --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index 1635b4e..848c3f8 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6280,7 +6280,7 @@ run_server_preference() { pr_svrty_good "yes (OK)"; out " -- only for < TLS 1.3" fileout "$jsonID" "OK" "server -- TLS 1.3 client determined" elif ! "$has_cipher_order" && "$has_tls13_cipher_order"; then - pr_svrty_high "nope (NOT ok)"; out " -- only for TLS 1.3" + pr_svrty_high "no (NOT ok)"; out " -- only for TLS 1.3" fileout "$jsonID" "HIGH" "server -- < TLS 1.3 client determined" else if "$has_tls13_cipher_order"; then From 9a5c8c08d56171c39727be9f17fc1ea95c9e4881 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Tue, 29 Oct 2019 19:03:36 +0100 Subject: [PATCH 6/6] Add case in cipher order for TLS != 1.3 --- testssl.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testssl.sh b/testssl.sh index 848c3f8..94bdf4a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6292,6 +6292,10 @@ run_server_preference() { out " -- TLS 1.3 and below" fileout "$jsonID" "OK" "server" fi + else + # we don't have TLS 1.3 at all + pr_svrty_best "yes (OK)" + fileout "$jsonID" "OK" "server" fi fi outln