diff --git a/doc/testssl.1 b/doc/testssl.1 index a8e8626..460996d 100644 --- a/doc/testssl.1 +++ b/doc/testssl.1 @@ -46,10 +46,10 @@ Any OpenSSL or LibreSSL version is needed as a helper\. Unlike previous versions 2) standard cipher categories to give you upfront an idea for the ciphers supported . .P -3) checks forward secrecy: ciphers and elliptical curves +3) server's cipher preferences (server order) . .P -4) server preferences (server order) +4) forward secrecy: ciphers and elliptical curves . .P 5) server defaults (certificate info, TLS extensions, session information) @@ -61,10 +61,7 @@ Any OpenSSL or LibreSSL version is needed as a helper\. Unlike previous versions 7) vulnerabilities . .P -8) testing each of 370 preconfigured ciphers -. -.P -9) client simulation +8) client simulation . .SH "OPTIONS AND PARAMETERS" Options are either short or long options\. Any long or short option requiring a value can be called with or without an equal sign\. E\.g\. \fBtestssl\.sh \-t=smtp \-\-wide \-\-openssl=/usr/bin/openssl \fR (short options with equal sign) is equivalent to \fBtestssl\.sh \-\-starttls smtp \-\-wide \-\-openssl /usr/bin/openssl \fR (long option without equal sign)\. Some command line options can also be preset via ENV variables\. \fBWIDE=true OPENSSL=/usr/bin/openssl testssl\.sh \-\-starttls=smtp \fR would be the equivalent to the aforementioned examples\. Preference has the command line over any environment variables\. diff --git a/doc/testssl.1.html b/doc/testssl.1.html index 5a6c392..4746b25 100644 --- a/doc/testssl.1.html +++ b/doc/testssl.1.html @@ -123,9 +123,9 @@ linked OpenSSL binaries for major operating systems are supplied in ./bin/

2) standard cipher categories to give you upfront an idea for the ciphers supported

-

3) checks forward secrecy: ciphers and elliptical curves

+

3) server's cipher preferences (server order)

-

4) server preferences (server order)

+

4) forward secrecy: ciphers and elliptical curves

5) server defaults (certificate info, TLS extensions, session information)

@@ -133,9 +133,7 @@ linked OpenSSL binaries for major operating systems are supplied in ./bin/

7) vulnerabilities

-

8) testing each of 370 preconfigured ciphers

- -

9) client simulation

+

8) client simulation

OPTIONS AND PARAMETERS

diff --git a/doc/testssl.1.md b/doc/testssl.1.md index 8f29a92..ac54ec4 100644 --- a/doc/testssl.1.md +++ b/doc/testssl.1.md @@ -42,9 +42,9 @@ linked OpenSSL binaries for major operating systems are supplied in `./bin/`. 2) standard cipher categories to give you upfront an idea for the ciphers supported -3) checks forward secrecy: ciphers and elliptical curves +3) server's cipher preferences (server order?) -4) server preferences (server order) +4) forward secrecy: ciphers and elliptical curves 5) server defaults (certificate info, TLS extensions, session information) @@ -52,9 +52,7 @@ linked OpenSSL binaries for major operating systems are supplied in `./bin/`. 7) vulnerabilities -8) testing each of 370 preconfigured ciphers - -9) client simulation +8) client simulation ## OPTIONS AND PARAMETERS diff --git a/testssl.sh b/testssl.sh index 938eea2..995196f 100755 --- a/testssl.sh +++ b/testssl.sh @@ -259,6 +259,7 @@ APP_TRAF_KEY_INFO="" # Information about the application traf 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="" +V2_HELLO_CIPHERSPEC_LENGTH=0 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 declare -r ALPN_PROTOs="h2 spdy/3.1 http/1.1 grpc-exp h2-fb spdy/1 spdy/2 spdy/3 stun.turn stun.nat-discovery webrtc c-webrtc ftp" @@ -3970,7 +3971,7 @@ run_allciphers() { # are good or bad) and list them in order to encryption strength. ciphers_by_strength() { local proto="$1" proto_hex="$2" proto_text="$3" - local using_sockets="$4" + local using_sockets="$4" wide="$5" local ossl_ciphers_proto local -i nr_ciphers nr_ossl_ciphers nr_nonossl_ciphers success local n sslvers auth mac hexc sslv2_ciphers="" cipher @@ -3983,15 +3984,18 @@ ciphers_by_strength() { local id local has_dh_bits="$HAS_DH_BITS" - pr_underline "$(printf -- "%b" "$proto_text")" # for local problem if it happens - out " " + "$wide" || out " " if ! "$using_sockets" && ! locally_supported "$proto"; then + pr_local_problem "Your $OPENSSL does not support $proto" + "$wide" && outln return 0 fi - outln - [[ $(has_server_protocol "${proto:1}") -eq 1 ]] && return 0 + if [[ $(has_server_protocol "${proto:1}") -eq 1 ]]; then + "$wide" && outln " - " + return 0 + fi # get a list of all the cipher suites to test nr_ciphers=0 @@ -4006,7 +4010,8 @@ ciphers_by_strength() { ciphers_found[nr_ciphers]=false sigalg[nr_ciphers]="" ossl_supported[nr_ciphers]=${TLS_CIPHER_OSSL_SUPPORTED[i]} - if "$using_sockets" && ! "$has_dh_bits" && ( [[ ${kx[nr_ciphers]} == "Kx=ECDH" ]] || [[ ${kx[nr_ciphers]} == "Kx=DH" ]] || [[ ${kx[nr_ciphers]} == "Kx=EDH" ]] ); then + if "$using_sockets" && "$wide" && ! "$has_dh_bits" && \ + ( [[ ${kx[nr_ciphers]} == "Kx=ECDH" ]] || [[ ${kx[nr_ciphers]} == "Kx=DH" ]] || [[ ${kx[nr_ciphers]} == "Kx=EDH" ]] ); then ossl_supported[nr_ciphers]=false fi if [[ ${#hexc} -eq 9 ]]; then @@ -4022,16 +4027,16 @@ ciphers_by_strength() { normalized_hexcode[nr_ciphers]="x${hexc:2:2}${hexc:7:2}${hexc:12:2}" fi if ( "$using_sockets" || "${TLS_CIPHER_OSSL_SUPPORTED[i]}" ); then - if [[ ${#hexc} -eq 9 ]] && [[ "$proto_text" != SSLv2 ]]; then - if [[ "$proto_text" == TLS\ 1.3 ]]; then + if [[ ${#hexc} -eq 9 ]] && [[ "$proto" != -ssl2 ]]; then + if [[ "$proto" == -tls1_3 ]]; then [[ "${hexc:2:2}" == 13 ]] && nr_ciphers+=1 - elif [[ "$proto_text" == TLS\ 1.2 ]]; then + elif [[ "$proto" == -tls1_2 ]]; then [[ "${hexc:2:2}" != 13 ]] && nr_ciphers+=1 elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA256 ]] && [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA384 ]] && \ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *_CCM ]] && [[ "${TLS_CIPHER_RFC_NAME[i]}" != *_CCM_8 ]]; then nr_ciphers+=1 fi - elif [[ ${#hexc} -eq 14 ]] && [[ "$proto_text" == SSLv2 ]]; then + elif [[ ${#hexc} -eq 14 ]] && [[ "$proto" == -ssl2 ]]; then sslv2_ciphers+=", ${hexcode[nr_ciphers]}" nr_ciphers+=1 fi @@ -4041,7 +4046,7 @@ ciphers_by_strength() { # The OpenSSL ciphers function, prior to version 1.1.0, could only understand -ssl2, -ssl3, and -tls1. if [[ "$OSSL_NAME" =~ LibreSSL ]]; then ossl_ciphers_proto="" - elif [[ "$proto" == -ssl2 ]] || [[ "$proto" == -ssl3 ]] || \ + elif [[ $proto == -ssl2 ]] || [[ $proto == -ssl3 ]] || \ [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == 1.1.0* ]] || [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == 1.1.1* ]] || \ [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == 3.0.0* ]]; then ossl_ciphers_proto="$proto" @@ -4049,9 +4054,9 @@ ciphers_by_strength() { ossl_ciphers_proto="-tls1" fi while read hexc n ciph[nr_ciphers] sslvers kx[nr_ciphers] auth enc[nr_ciphers] mac export2[nr_ciphers]; do - if [[ "$proto_text" == TLS\ 1.3 ]]; then + if [[ "$proto" == -tls1_3 ]]; then [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]] || continue - elif [[ "$proto_text" == "TLS 1.2" ]]; then + elif [[ "$proto" == -tls1_2 ]]; then if [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]]; then continue fi @@ -4068,31 +4073,43 @@ ciphers_by_strength() { done < <(actually_supported_osslciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 'ALL' "$ossl_ciphers_proto -V") fi - if [[ "$proto" == -ssl2 ]]; then + if [[ $proto == -ssl2 ]]; then if "$using_sockets"; then sslv2_sockets "${sslv2_ciphers:2}" "true" - if [[ $? -eq 3 ]] && [[ "$V2_HELLO_CIPHERSPEC_LENGTH" -ne 0 ]]; then - supported_sslv2_ciphers="$(grep "Supported cipher: " "$TEMPDIR/$NODEIP.parse_sslv2_serverhello.txt")" - "$SHOW_SIGALGO" && s="$(read_sigalg_from_file "$HOSTCERT")" - for (( i=0 ; i$TMPFILE 2>$ERRFILE comes from run_prototest_openssl fileout "$jsonID" "HIGH" "$supported_no_ciph1" - add_tls_offered ssl3 yes + add_proto_offered ssl3 yes ;; 7) if "$using_sockets" ; then # can only happen in debug mode @@ -5107,10 +5153,10 @@ run_protocols() { fileout "$jsonID" "LOW" "offered (deprecated)" latest_supported="0301" latest_supported_string="TLSv1.0" - add_tls_offered tls1 yes + add_proto_offered tls1 yes ;; # nothing wrong with it -- per se 1) out "not offered" - add_tls_offered tls1 no + add_proto_offered tls1 no if [[ -z $latest_supported ]]; then outln fileout "$jsonID" "INFO" "not offered" # neither good or bad @@ -5120,7 +5166,7 @@ run_protocols() { fi ;; 2) pr_svrty_medium "not offered" - add_tls_offered tls1 no + add_proto_offered tls1 no if [[ "$DETECTED_TLS_VERSION" == 0300 ]]; then [[ $DEBUG -ge 1 ]] && tm_out " -- downgraded" outln @@ -5141,19 +5187,19 @@ run_protocols() { ;; 3) out "not offered, " fileout "$jsonID" "OK" "not offered" - add_tls_offered tls1 no + add_proto_offered tls1 no pr_warning "TLS downgraded to STARTTLS plaintext"; outln fileout "$jsonID" "WARN" "TLS downgraded to STARTTLS plaintext" ;; 4) out "likely not offered, " fileout "$jsonID" "INFO" "likely not offered" - add_tls_offered tls1 no + add_proto_offered tls1 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" fileout "$jsonID" "WARN" "received 4xx/5xx after STARTTLS handshake${debug_recomm}" ;; 5) outln "$supported_no_ciph1" # protocol detected but no cipher --> comes from run_prototest_openssl fileout "$jsonID" "INFO" "$supported_no_ciph1" - add_tls_offered tls1 yes + add_proto_offered tls1 yes ;; 7) if "$using_sockets" ; then # can only happen in debug mode @@ -5185,10 +5231,10 @@ run_protocols() { fileout "$jsonID" "LOW" "offered (deprecated)" latest_supported="0302" latest_supported_string="TLSv1.1" - add_tls_offered tls1_1 yes + add_proto_offered tls1_1 yes ;; # nothing wrong with it 1) out "not offered" - add_tls_offered tls1_1 no + add_proto_offered tls1_1 no if [[ -z $latest_supported ]]; then outln fileout "$jsonID" "INFO" "is not offered" # neither good or bad @@ -5198,7 +5244,7 @@ run_protocols() { fi ;; 2) out "not offered" - add_tls_offered tls1_1 no + add_proto_offered tls1_1 no if [[ "$DETECTED_TLS_VERSION" == "$latest_supported" ]]; then [[ $DEBUG -ge 1 ]] && tm_out " -- downgraded" outln @@ -5222,19 +5268,19 @@ run_protocols() { ;; 3) out "not offered, " fileout "$jsonID" "OK" "not offered" - add_tls_offered tls1_1 no + add_proto_offered tls1_1 no pr_warning "TLS downgraded to STARTTLS plaintext"; outln fileout "$jsonID" "WARN" "TLS downgraded to STARTTLS plaintext" ;; 4) out "likely not offered, " fileout "$jsonID" "INFO" "is not offered" - add_tls_offered tls1_1 no + add_proto_offered tls1_1 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" fileout "$jsonID" "WARN" "received 4xx/5xx after STARTTLS handshake${debug_recomm}" ;; 5) outln "$supported_no_ciph1" # protocol detected but no cipher --> comes from run_prototest_openssl fileout "$jsonID" "INFO" "$supported_no_ciph1" - add_tls_offered tls1_1 yes + add_proto_offered tls1_1 yes ;; 7) if "$using_sockets" ; then # can only happen in debug mode @@ -5296,9 +5342,9 @@ run_protocols() { fileout "$jsonID" "OK" "offered" latest_supported="0303" latest_supported_string="TLSv1.2" - add_tls_offered tls1_2 yes + add_proto_offered tls1_2 yes ;; # GCM cipher in TLS 1.2: very good! - 1) add_tls_offered tls1_2 no + 1) add_proto_offered tls1_2 no if "$offers_tls13"; then out "not offered" else @@ -5316,7 +5362,7 @@ run_protocols() { fileout "$jsonID" "CRITICAL" "connection failed rather than downgrading to $latest_supported_string" fi ;; - 2) add_tls_offered tls1_2 no + 2) add_proto_offered tls1_2 no pr_svrty_medium "not offered and downgraded to a weaker protocol" if [[ "$tls12_detected_version" == 0300 ]]; then detected_version_string="SSLv3" @@ -5344,19 +5390,19 @@ run_protocols() { ;; 3) out "not offered, " fileout "$jsonID" "INFO" "not offered" - add_tls_offered tls1_2 no + add_proto_offered tls1_2 no pr_warning "TLS downgraded to STARTTLS plaintext"; outln fileout "$jsonID" "WARN" "TLS downgraded to STARTTLS plaintext" ;; 4) out "likely "; pr_svrty_medium "not offered, " fileout "$jsonID" "MEDIUM" "not offered" - add_tls_offered tls1_2 no + add_proto_offered tls1_2 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" fileout "$jsonID" "WARN" "received 4xx/5xx after STARTTLS handshake${debug_recomm}" ;; 5) outln "$supported_no_ciph1" # protocol detected, but no cipher --> comes from run_prototest_openssl fileout "$jsonID" "INFO" "$supported_no_ciph1" - add_tls_offered tls1_2 yes + add_proto_offered tls1_2 yes ;; 7) if "$using_sockets" ; then # can only happen in debug mode @@ -5450,7 +5496,7 @@ run_protocols() { fi latest_supported="0304" latest_supported_string="TLSv1.3" - add_tls_offered tls1_3 yes + add_proto_offered tls1_3 yes ;; 1) pr_svrty_low "not offered" if [[ -z $latest_supported ]]; then @@ -5460,7 +5506,7 @@ run_protocols() { prln_svrty_critical " -- connection failed rather than downgrading to $latest_supported_string" fileout "$jsonID" "CRITICAL" "connection failed rather than downgrading to $latest_supported_string" fi - add_tls_offered tls1_3 no + add_proto_offered tls1_3 no ;; 2) if [[ "$DETECTED_TLS_VERSION" == 0300 ]]; then detected_version_string="SSLv3" @@ -5483,23 +5529,23 @@ run_protocols() { prln_svrty_critical " -- server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" fileout "$jsonID" "CRITICAL" "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" fi - add_tls_offered tls1_3 no + add_proto_offered tls1_3 no ;; 3) out "not offered " fileout "$jsonID" "INFO" "not offered" - add_tls_offered tls1_3 no + add_proto_offered tls1_3 no pr_warning "TLS downgraded to STARTTLS plaintext"; outln fileout "$jsonID" "WARN" "TLS downgraded to STARTTLS plaintext" ;; 4) out "likely not offered, " fileout "$jsonID" "INFO" "not offered" - add_tls_offered tls1_3 no + add_proto_offered tls1_3 no pr_warning "received 4xx/5xx after STARTTLS handshake"; outln "$debug_recomm" fileout "$jsonID" "WARN" "received 4xx/5xx after STARTTLS handshake${debug_recomm}" ;; 5) outln "$supported_no_ciph1" # protocol detected but no cipher --> comes from run_prototest_openssl fileout "$jsonID" "INFO" "$supported_no_ciph1" - add_tls_offered tls1_3 yes + add_proto_offered tls1_3 yes ;; 7) if "$using_sockets" ; then # can only happen in debug mode @@ -6238,7 +6284,7 @@ sub_session_resumption() { run_server_preference() { local cipher1="" cipher2="" tls13_cipher1="" tls13_cipher2="" default_proto="" - local prev_cipher="" default_cipher="" + local default_cipher="" local limitedsense="" supported_sslv2_ciphers local -a offered_cipher offered_proto local proto_ossl proto_txt proto_hex cipherlist i @@ -6259,7 +6305,7 @@ run_server_preference() { "$SSL_NATIVE" && using_sockets=false outln - pr_headlineln " Testing server preferences " + pr_headlineln " Testing server's cipher preferences " outln pr_bold " Has server cipher order? " @@ -6284,14 +6330,14 @@ run_server_preference() { "ephemeralkey" sclient_success=$? if [[ $sclient_success -eq 0 ]]; then - add_tls_offered tls1_3 yes + add_proto_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 ;; + 0303) add_proto_offered tls1_2 yes ;; + 0302) add_proto_offered tls1_1 yes ;; + 0301) add_proto_offered tls1 yes ;; + 0300) add_proto_offered ssl3 yes ;; esac fi if [[ $sclient_success -eq 0 ]] ; then @@ -6504,131 +6550,41 @@ run_server_preference() { outln "$limitedsense" fi - if "$has_cipher_order"; then - "$FAST" && using_sockets=false - [[ $TLS_NR_CIPHERS == 0 ]] && using_sockets=false + "$FAST" && using_sockets=false + [[ $TLS_NR_CIPHERS == 0 ]] && using_sockets=false - pr_bold " Cipher order" - "$WIDE" && outln && neat_header - while read proto_ossl proto_hex proto_txt; do - [[ "$proto_ossl" == tls1_3 ]] && ! "$has_tls13_cipher_order" && continue - "$WIDE" && pr_underline "$proto_txt" - 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" - i=1 - for proto_ossl in ssl2 ssl3 tls1 tls1_1 tls1_2 tls1_3; do - if [[ $proto_ossl == ssl2 ]] && ! "$HAS_SSL2"; then - if ! "$using_sockets" || [[ $TLS_NR_CIPHERS -eq 0 ]]; then - out " (SSLv2: "; pr_local_problem "$OPENSSL doesn't support \"s_client -ssl2\""; outln ")"; - continue - else - sslv2_sockets "" "true" - if [[ $? -eq 3 ]] && [[ "$V2_HELLO_CIPHERSPEC_LENGTH" -ne 0 ]]; then - # Just arbitrarily pick the first cipher in the cipher-mapping.txt list. - offered_proto[i]="SSLv2" - supported_sslv2_ciphers="$(grep "Supported cipher: " "$TEMPDIR/$NODEIP.parse_sslv2_serverhello.txt")" - for (( j=0; j < TLS_NR_CIPHERS; j++ )); do - if [[ "${TLS_CIPHER_SSLVERS[j]}" == "SSLv2" ]]; then - cipher1="${TLS_CIPHER_HEXCODE[j]}" - cipher1="$(tolower "x${cipher1:2:2}${cipher1:7:2}${cipher1:12:2}")" - if [[ "$supported_sslv2_ciphers" =~ $cipher1 ]]; then - if ( [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]] && [[ "${TLS_CIPHER_OSSL_NAME[j]}" != "-" ]] ) || [[ "${TLS_CIPHER_RFC_NAME[j]}" == "-" ]]; then - offered_cipher[i]="${TLS_CIPHER_OSSL_NAME[j]}" - else - offered_cipher[i]="${TLS_CIPHER_RFC_NAME[j]}" - fi - break - fi - fi - done - [[ $DEBUG -ge 2 ]] && tmln_out "Default cipher for ${offered_proto[i]}: ${offered_cipher[i]}" - else - offered_proto[i]="" - offered_cipher[i]="" - fi - fi - elif ( [[ $proto_ossl == ssl3 ]] && ! "$HAS_SSL3" ) || ( [[ $proto_ossl == tls1_3 ]] && ! "$HAS_TLS13" ); then - if [[ $proto_ossl == ssl3 ]]; then - proto_txt="SSLv3" ; proto_hex="00" ; cipherlist="$TLS_CIPHER" - else - proto_txt="TLSv1.3" ; proto_hex="04" ; cipherlist="$TLS13_CIPHER" - fi - if ! "$using_sockets"; then - out " ($proto_txt: "; pr_local_problem "$OPENSSL doesn't support \"s_client -$proto_ossl\"" ; outln ")"; - continue - else - tls_sockets "$proto_hex" "$cipherlist" - if [[ $? -eq 0 ]]; then - offered_proto[i]="$proto_txt" - cipher1=$(get_cipher "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt") - offered_cipher[i]="$cipher1" - if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]] && [[ $TLS_NR_CIPHERS -ne 0 ]]; then - offered_cipher[i]="$(rfc2openssl "$cipher1")" - [[ -z "${offered_cipher[i]}" ]] && offered_cipher[i]="$cipher1" - fi - [[ $DEBUG -ge 2 ]] && tmln_out "Default cipher for ${offered_proto[i]}: ${offered_cipher[i]}" - else - offered_proto[i]="" - offered_cipher[i]="" - fi - fi + pr_bold " Cipher per protocol" + outln "\n" && neat_header + while read proto_ossl proto_hex proto_txt; do + pr_underline "$(printf -- "%b" "$proto_txt")" + # TODO: If there's no cipher we should consider not displaying the text in the round brackets) + # the following takes care of that but only if we know the protocol is not supported + if [[ $(has_server_protocol "$proto_ossl") -eq 1 ]]; then + outln "\n - " + continue + fi + # TODO: Also the fact that a protocol is not supported seems not to be saved by cipher_pref_check() + # (./testssl.sh --wide -p -P -E vs ./testssl.sh --wide -P -E ) + if [[ $proto_ossl == ssl2 ]] || \ + ( [[ $proto_ossl != tls1_3 ]] && ! "$has_cipher_order" ]] ) || \ + ( [[ $proto_ossl == tls1_3 ]] && ! "$has_tls13_cipher_order" ]] ); then + if [[ $proto_ossl == ssl2 ]]; then + outln " (listed by strength)" + elif [[ $proto_ossl == tls1_3 ]]; then + outln " (no server order, thus listed by strength)" else - $OPENSSL s_client $(s_client_options "$STARTTLS -"$proto_ossl" $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$ERRFILE >$TMPFILE - if sclient_connect_successful $? $TMPFILE; then - offered_proto[i]=$(get_protocol $TMPFILE) - offered_cipher[i]=$(get_cipher $TMPFILE) - [[ ${offered_cipher[i]} == "0000" ]] && offered_cipher[i]="" # Hack! - if [[ "$DISPLAY_CIPHERNAMES" =~ rfc ]] && [[ -n "${offered_cipher[i]}" ]]; then - offered_cipher[i]="$(openssl2rfc "${offered_cipher[i]}")" - [[ -z "${offered_cipher[i]}" ]] && offered_cipher[i]=$(get_cipher $TMPFILE) - fi - [[ $DEBUG -ge 2 ]] && tmln_out "Default cipher for ${offered_proto[i]}: ${offered_cipher[i]}" - else - offered_proto[i]="" - offered_cipher[i]="" - fi + prln_svrty_high " (no server order, thus listed by strength)" fi - [[ -n "${offered_cipher[i]}" ]] && add_tls_offered "$proto_ossl" yes - i=$((i + 1)) - done + ciphers_by_strength "-$proto_ossl" "$proto_hex" "$proto_txt" "$using_sockets" "true" + else + outln " (server order)" + cipher_pref_check "$proto_ossl" "$proto_hex" "$proto_txt" "$using_sockets" "true" + fi + done <<< "$(tm_out " ssl2 22 SSLv2\n 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 - for i in 1 2 3 4 5 6; do - if [[ -n "${offered_cipher[i]}" ]]; then # cipher not empty - if [[ -z "$prev_cipher" ]] || [[ "$prev_cipher" != "${offered_cipher[i]}" ]]; then - [[ -n "$prev_cipher" ]] && outln - str_len=${#offered_cipher[i]} - out " " - if [[ "$COLOR" -le 2 ]]; then - out "${offered_cipher[i]}" - else - pr_cipher_quality "${offered_cipher[i]}" - fi - out ":" - if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]]; then - for (( 1; str_len < 30; str_len++ )); do - out " " - done - else - for (( 1; str_len < 51; str_len++ )); do - out " " - done - fi - else - out ", " # same cipher --> only print out protocol behind it - fi - out "${offered_proto[i]}" - prev_cipher="${offered_cipher[i]}" - fi - fileout "cipher_order_${offered_proto[i]}" "INFO" "${offered_cipher[i]} at ${offered_proto[i]} $limitedsense" - done - outln "\n No further cipher order check has been done as order is determined by the client" - outln - fi return $ret + # end of run_server_preference() } # arg1: true if the list that is returned does not need to be ordered by preference. @@ -6709,10 +6665,11 @@ check_tls12_pref() { return 0 } - +# At the moment only called from run_server_preference() cipher_pref_check() { - local p="$1" proto_hex="$2" proto="$3" + local proto="$1" proto_hex="$2" proto_text="$3" local using_sockets="$4" + local wide="$5" # at the moment always = true local tested_cipher cipher order rfc_cipher rfc_order local overflow_probe_cipherlist="ALL:-ECDHE-RSA-AES256-GCM-SHA384:-AES128-SHA:-DES-CBC3-SHA" local -i i nr_ciphers nr_nonossl_ciphers num_bundles bundle_size bundle end_of_bundle success @@ -6724,27 +6681,25 @@ cipher_pref_check() { local ciphers_found_with_sockets order=""; ciphers_found_with_sockets=false - if [[ $p == ssl3 ]] && ! "$HAS_SSL3" && ! "$using_sockets"; then + if [[ $proto == ssl3 ]] && ! "$HAS_SSL3" && ! "$using_sockets"; then out "\n SSLv3: "; pr_local_problem "$OPENSSL doesn't support \"s_client -ssl3\""; return 0 fi - if [[ $p == tls1_3 ]] && ! "$HAS_TLS13" && ! "$using_sockets"; then + if [[ $proto == tls1_3 ]] && ! "$HAS_TLS13" && ! "$using_sockets"; then out "\n TLSv1.3 "; pr_local_problem "$OPENSSL doesn't support \"s_client -tls1_3\""; return 0 fi - [[ $(has_server_protocol "$p") -eq 1 ]] && return 0 - - if ( [[ $p != tls1_3 ]] || "$HAS_TLS13" ) && ( [[ $p != ssl3 ]] || "$HAS_SSL3" ); then - if [[ $p == tls1_2 ]] && "$SERVER_SIZE_LIMIT_BUG"; then - order="$(check_tls12_pref "$WIDE")" + if ( [[ $proto != tls1_3 ]] || "$HAS_TLS13" ) && ( [[ $proto != ssl3 ]] || "$HAS_SSL3" ); then + if [[ $proto == tls1_2 ]] && "$SERVER_SIZE_LIMIT_BUG"; then + order="$(check_tls12_pref "$wide")" [[ "${order:0:1}" == \ ]] && order="${order:1}" ciphers_found="$order" fi - if "$WIDE" || [[ -z "$order" ]]; then + if "$wide" || [[ -z "$order" ]]; then tested_cipher=""; order=""; nr_ciphers_found=0 while true; do - if [[ $p != tls1_3 ]]; then + if [[ $proto != tls1_3 ]]; then if [[ -n "$ciphers_found" ]]; then ciphers_to_test="" for cipher in $ciphers_found; do @@ -6763,14 +6718,14 @@ cipher_pref_check() { [[ -z "$ciphers_to_test" ]] && break ciphers_to_test="-ciphersuites ${ciphers_to_test:1}" fi - $OPENSSL s_client $(s_client_options "$STARTTLS -"$p" $BUGS $ciphers_to_test -connect $NODEIP:$PORT $PROXY $SNI") >$ERRFILE >$TMPFILE + $OPENSSL s_client $(s_client_options "$STARTTLS -"$proto" $BUGS $ciphers_to_test -connect $NODEIP:$PORT $PROXY $SNI") >$ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE || break cipher=$(get_cipher $TMPFILE) [[ -z "$cipher" ]] && break order+="$cipher " tested_cipher+=":-"$cipher "$FAST" && break - if "$WIDE"; then + if "$wide"; then for (( i=0; i < TLS_NR_CIPHERS; i++ )); do [[ "$cipher" == ${TLS_CIPHER_OSSL_NAME[i]} ]] && break done @@ -6778,7 +6733,7 @@ cipher_pref_check() { normalized_hexcode[nr_ciphers_found]="$(normalize_ciphercode "${TLS_CIPHER_HEXCODE[i]}")" ciph[nr_ciphers_found]="${TLS_CIPHER_OSSL_NAME[i]}" kx[nr_ciphers_found]="${TLS_CIPHER_KX[i]}" - [[ "$p" == tls1_3 ]] && kx[nr_ciphers_found]="$(read_dhtype_from_file $TMPFILE)" + [[ $proto == tls1_3 ]] && kx[nr_ciphers_found]="$(read_dhtype_from_file $TMPFILE)" if ( [[ ${kx[nr_ciphers_found]} == Kx=ECDH ]] || [[ ${kx[nr_ciphers_found]} == Kx=DH ]] || [[ ${kx[nr_ciphers_found]} == Kx=EDH ]] ); then kx[nr_ciphers_found]+=" $(read_dhbits_from_file "$TMPFILE" quiet)" fi @@ -6807,9 +6762,9 @@ cipher_pref_check() { rfc_ciph[nr_nonossl_ciphers]="${TLS_CIPHER_RFC_NAME[i]}" index[nr_nonossl_ciphers]=$i # Only test ciphers that are relevant to the protocol. - if [[ "$p" == tls1_3 ]]; then - [[ "${hexc:2:2}" == "13" ]] && nr_nonossl_ciphers+=1 - elif [[ "$p" == tls1_2 ]]; then + if [[ $proto == tls1_3 ]]; then + [[ "${hexc:2:2}" == 13 ]] && nr_nonossl_ciphers+=1 + elif [[ $proto == tls1_2 ]]; then [[ "${hexc:2:2}" != 13 ]] && nr_nonossl_ciphers+=1 elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA256 ]] && \ [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA384 ]] && \ @@ -6824,7 +6779,7 @@ cipher_pref_check() { if [[ $nr_nonossl_ciphers -eq 0 ]]; then num_bundles=0 - elif [[ $p != tls1_2 ]] || ! "$SERVER_SIZE_LIMIT_BUG"; then + elif [[ $proto != tls1_2 ]] || ! "$SERVER_SIZE_LIMIT_BUG"; then num_bundles=1 bundle_size=$nr_nonossl_ciphers else @@ -6853,7 +6808,7 @@ cipher_pref_check() { i=${index[i]} ciphers_found[i]=true ciphers_found_with_sockets=true - if [[ $p != tls1_2 ]] || ! "$SERVER_SIZE_LIMIT_BUG"; then + if [[ $proto != tls1_2 ]] || ! "$SERVER_SIZE_LIMIT_BUG"; then # Throw out the results found so far and start over using just sockets bundle=$num_bundles for (( i=0; i < TLS_NR_CIPHERS; i++ )); do @@ -6876,9 +6831,9 @@ cipher_pref_check() { ciphers_found2[nr_ciphers]=false hexcode[nr_ciphers]="${hexc:2:2},${hexc:7:2}" rfc_ciph[nr_ciphers]="${TLS_CIPHER_RFC_NAME[i]}" - if [[ "$p" == "tls1_3" ]]; then + if [[ $proto == tls1_3 ]]; then [[ "${hexc:2:2}" == "13" ]] && nr_ciphers+=1 - elif [[ "$p" == "tls1_2" ]]; then + elif [[ $proto == tls1_2 ]]; then [[ "${hexc:2:2}" != "13" ]] && nr_ciphers+=1 elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA256 ]] && \ [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ SHA384 ]] && \ @@ -6900,7 +6855,7 @@ cipher_pref_check() { for (( i=0; i < nr_ciphers; i++ )); do [[ "$cipher" == ${rfc_ciph[i]} ]] && ciphers_found2[i]=true && break done - if "$WIDE"; then + if "$wide"; then for (( i=0; i < TLS_NR_CIPHERS; i++ )); do [[ "$cipher" == ${TLS_CIPHER_RFC_NAME[i]} ]] && break done @@ -6908,7 +6863,7 @@ cipher_pref_check() { normalized_hexcode[nr_ciphers_found]="$(normalize_ciphercode "${TLS_CIPHER_HEXCODE[i]}")" ciph[nr_ciphers_found]="${TLS_CIPHER_OSSL_NAME[i]}" kx[nr_ciphers_found]="${TLS_CIPHER_KX[i]}" - [[ "$p" == tls1_3 ]] && kx[nr_ciphers_found]="$(read_dhtype_from_file "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")" + [[ $proto == tls1_3 ]] && kx[nr_ciphers_found]="$(read_dhtype_from_file "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")" if ( [[ ${kx[nr_ciphers_found]} == Kx=ECDH ]] || [[ ${kx[nr_ciphers_found]} == Kx=DH ]] || [[ ${kx[nr_ciphers_found]} == Kx=EDH ]] ); then kx[nr_ciphers_found]+=" $(read_dhbits_from_file "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" quiet)" fi @@ -6939,29 +6894,32 @@ cipher_pref_check() { order="$rfc_order" fi - "$WIDE" && outln if [[ -n "$order" ]]; then - add_tls_offered "$p" yes - if "$WIDE"; then + add_proto_offered "$proto" yes + if "$wide"; then for (( i=0 ; i$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE /dev/null)") debugme tm_out " ($lines lines) " - add_tls_offered ssl2 yes + add_proto_offered ssl2 yes if [[ "$lines" -gt 1 ]]; then nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3)) if [[ 0 -eq "$nr_ciphers_detected" ]]; then @@ -16724,7 +16682,7 @@ run_beast(){ $OPENSSL s_client $(s_client_options "-state -"${proto}" $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") 2>>$ERRFILE >$TMPFILE $TMPFILE 2>>$ERRFILE if sclient_auth $? $TMPFILE; then all_failed=false - add_tls_offered "${proto/-/}" yes + add_proto_offered "${proto/-/}" yes break fi done @@ -19519,11 +19477,11 @@ determine_optimal_proto() { tmp=${tmp/\./_} tmp=${tmp/v/} tmp="$(tolower $tmp)" - add_tls_offered "${tmp}" yes + add_proto_offered "${tmp}" yes debugme echo "one proto determined: $tmp" OPTIMAL_PROTO="" else - add_tls_offered "${proto/-/}" yes + add_proto_offered "${proto/-/}" yes OPTIMAL_PROTO="$proto" fi all_failed=false @@ -20404,7 +20362,7 @@ initialize_globals() { # Set default scanning options for the boolean global do_* variables. set_scanning_defaults() { - do_allciphers=true + do_allciphers=false do_vulnerabilities=true do_beast=true do_lucky13=true @@ -21154,11 +21112,11 @@ lets_roll() { fileout_section_header $section_number true && ((section_number++)) "$do_cipherlists" && { run_cipherlists; ret=$(($? + ret)); stopwatch run_cipherlists; } - fileout_section_header $section_number true && ((section_number++)) - "$do_fs" && { run_fs; ret=$(($? + ret)); stopwatch run_fs; } + fileout_section_header $section_number true && ((section_number++)) + "$do_server_preference" && { run_server_preference; ret=$(($? + ret)); stopwatch run_server_preference; } fileout_section_header $section_number true && ((section_number++)) - "$do_server_preference" && { run_server_preference; ret=$(($? + ret)); stopwatch run_server_preference; } + "$do_fs" && { run_fs; ret=$(($? + ret)); stopwatch run_fs; } fileout_section_header $section_number true && ((section_number++)) "$do_server_defaults" && { run_server_defaults; ret=$(($? + ret)); stopwatch run_server_defaults; }