From 8fdb388dc3e05e54a533085e046fc042234c6a1d Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 12 Feb 2019 12:50:24 -0500 Subject: [PATCH] Reorganize run_cipher_per_proto() This PR reorganizes run_cipher_per_proto(). Currently run_cipher_per_proto() runs a for loop, which loops over each protocol and prints the set of supported ciphers for each protocol. This PR simply places the body of the for loop in a separate function from the loop itself. This allows the body of the loop to be called for just a single protocol. While this PR does not change the way that testssl.sh functions, it would allow for a future change in which run_server_preferences() called cipher_pref_check() for protocols in which the server enforces a cipher order and calls ciphers_by_strength() for protocols in which the server does not enforce a cipher order. --- testssl.sh | 538 +++++++++++++++++++++++++++-------------------------- 1 file changed, 276 insertions(+), 262 deletions(-) diff --git a/testssl.sh b/testssl.sh index c8ab76a..e3b40d3 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3955,8 +3955,12 @@ run_allciphers() { } # test for all ciphers per protocol locally configured (w/o distinguishing whether they are good or bad) -run_cipher_per_proto() { - local proto proto_hex proto_text ossl_ciphers_proto +# for the specified protocol, test for all ciphers locally configured (w/o distinguishing whether they +# 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 ossl_ciphers_proto local -i nr_ciphers nr_ossl_ciphers nr_nonossl_ciphers success local n sslvers auth mac export hexc sslv2_ciphers="" cipher local -a hexcode normalized_hexcode ciph rfc_ciph kx enc export2 @@ -3967,6 +3971,275 @@ run_cipher_per_proto() { local available local id local has_dh_bits="$HAS_DH_BITS" + + pr_underline "$(printf "%s" "$proto_text")" + # for local problem if it happens + out " " + if ! "$using_sockets" && ! locally_supported "$proto"; then + return 0 + fi + outln + + [[ $(has_server_protocol "${proto:1}") -eq 1 ]] && return 0 + + # get a list of all the cipher suites to test + nr_ciphers=0 + if "$using_sockets" || [[ $OSSL_VER_MAJOR -lt 1 ]]; then + for (( i=0; i < TLS_NR_CIPHERS; i++ )); do + hexc="${TLS_CIPHER_HEXCODE[i]}" + ciph[nr_ciphers]="${TLS_CIPHER_OSSL_NAME[i]}" + rfc_ciph[nr_ciphers]="${TLS_CIPHER_RFC_NAME[i]}" + kx[nr_ciphers]="${TLS_CIPHER_KX[i]}" + enc[nr_ciphers]="${TLS_CIPHER_ENC[i]}" + export2[nr_ciphers]="${TLS_CIPHER_EXPORT[i]}" + 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 + ossl_supported[nr_ciphers]=false + fi + if [[ ${#hexc} -eq 9 ]]; then + hexcode[nr_ciphers]="${hexc:2:2},${hexc:7:2}" + if [[ "${hexc:2:2}" == "00" ]]; then + normalized_hexcode[nr_ciphers]="x${hexc:7:2}" + else + normalized_hexcode[nr_ciphers]="x${hexc:2:2}${hexc:7:2}" + fi + else + hexc="$(tolower "$hexc")" + hexcode[nr_ciphers]="${hexc:2:2},${hexc:7:2},${hexc:12:2}" + 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 + [[ "${hexc:2:2}" == "13" ]] && nr_ciphers+=1 + elif [[ "$proto_text" == "TLS 1.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 + sslv2_ciphers+=", ${hexcode[nr_ciphers]}" + nr_ciphers+=1 + fi + fi + done + else # no sockets, openssl! + # The OpenSSL ciphers function, prior to version 1.1.0, could only understand -ssl2, -ssl3, and -tls1. + if [[ "$proto" == "-ssl2" ]] || [[ "$proto" == "-ssl3" ]] || \ + [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0"* ]] || [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.1"* ]]; then + ossl_ciphers_proto="$proto" + else + 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 + [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]] || continue + elif [[ "$proto_text" == "TLS 1.2" ]]; then + if [[ "${ciph[nr_ciphers]}" == TLS13* ]] || [[ "${ciph[nr_ciphers]}" == TLS_* ]]; then + continue + fi + elif [[ "${ciph[nr_ciphers]}" == *"-SHA256" ]] || [[ "${ciph[nr_ciphers]}" == *"-SHA384" ]] || \ + [[ "${ciph[nr_ciphers]}" == *"-CCM" ]] || [[ "${ciph[nr_ciphers]}" == *"-CCM8" ]] || \ + [[ "${ciph[nr_ciphers]}" =~ CHACHA20-POLY1305 ]]; then + continue + fi + ciphers_found[nr_ciphers]=false + normalized_hexcode[nr_ciphers]="$(normalize_ciphercode "$hexc")" + sigalg[nr_ciphers]="" + ossl_supported[nr_ciphers]=true + nr_ciphers+=1 + done < <(actually_supported_ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 'ALL' "$ossl_ciphers_proto -V") + fi + + 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 = 128 ciphers. So, + # test cipher suites in bundles of 128 or less. + num_bundles=$nr_ossl_ciphers/128 + mod_check=$nr_ossl_ciphers%128 + [[ $mod_check -ne 0 ]] && num_bundles=$num_bundles+1 + + bundle_size=$nr_ossl_ciphers/$num_bundles + mod_check=$nr_ossl_ciphers%$num_bundles + [[ $mod_check -ne 0 ]] && bundle_size+=1 + fi + + for (( bundle=0; bundle < num_bundles; bundle++ )); do + end_of_bundle=$bundle*$bundle_size+$bundle_size + [[ $end_of_bundle -gt $nr_ossl_ciphers ]] && end_of_bundle=$nr_ossl_ciphers + for (( success=0; success==0 ; 1 )); do + ciphers_to_test="" + tls13_ciphers_to_test="" + for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do + if ! "${ciphers_found2[i]}"; then + if [[ "$proto" == "-tls1_3" ]]; then + tls13_ciphers_to_test+=":${ciph2[i]}" + else + ciphers_to_test+=":${ciph2[i]}" + fi + fi + done + success=1 + if [[ -n "$ciphers_to_test" ]] || [[ -n "$tls13_ciphers_to_test" ]]; then + $OPENSSL s_client $(s_client_options "-cipher "\'${ciphers_to_test:1}\'" -ciphersuites "\'${tls13_ciphers_to_test:1}\'" $proto $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>$ERRFILE = 128 ciphers. So, + # test cipher suites in bundles of 128 or less. + num_bundles=$nr_nonossl_ciphers/128 + mod_check=$nr_nonossl_ciphers%128 + [[ $mod_check -ne 0 ]] && num_bundles=$num_bundles+1 + + bundle_size=$nr_nonossl_ciphers/$num_bundles + mod_check=$nr_nonossl_ciphers%$num_bundles + [[ $mod_check -ne 0 ]] && bundle_size+=1 + fi + + for (( bundle=0; bundle < num_bundles; bundle++ )); do + end_of_bundle=$bundle*$bundle_size+$bundle_size + [[ $end_of_bundle -gt $nr_nonossl_ciphers ]] && end_of_bundle=$nr_nonossl_ciphers + for (( success=0; success==0 ; 1 )); do + ciphers_to_test="" + for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do + ! "${ciphers_found2[i]}" && ciphers_to_test+=", ${hexcode2[i]}" + done + success=1 + if [[ -n "$ciphers_to_test" ]]; then + if "$SHOW_SIGALGO"; then + tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "all" + else + tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "ephemeralkey" + fi + if [[ $? -eq 0 ]]; then + success=0 + cipher=$(get_cipher "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt") + for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do + [[ "$cipher" == "${rfc_ciph2[i]}" ]] && ciphers_found2[i]=true && break + done + i=${index[i]} + ciphers_found[i]=true + [[ "$proto_text" == "TLS 1.3" ]] && kx[i]="$(read_dhtype_from_file "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")" + if [[ ${kx[i]} == "Kx=ECDH" ]] || [[ ${kx[i]} == "Kx=DH" ]] || [[ ${kx[i]} == "Kx=EDH" ]]; then + dhlen=$(read_dhbits_from_file "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" quiet) + kx[i]="${kx[i]} $dhlen" + fi + "$SHOW_SIGALGO" && [[ -r "$HOSTCERT" ]] && \ + sigalg[i]="$(read_sigalg_from_file "$HOSTCERT")" + fi + fi + done + done + fi + + for (( i=0 ; i$TMPFILE 2>$ERRFILE = 128 ciphers. So, - # test cipher suites in bundles of 128 or less. - num_bundles=$nr_ossl_ciphers/128 - mod_check=$nr_ossl_ciphers%128 - [[ $mod_check -ne 0 ]] && num_bundles=$num_bundles+1 - - bundle_size=$nr_ossl_ciphers/$num_bundles - mod_check=$nr_ossl_ciphers%$num_bundles - [[ $mod_check -ne 0 ]] && bundle_size+=1 - fi - - for (( bundle=0; bundle < num_bundles; bundle++ )); do - end_of_bundle=$bundle*$bundle_size+$bundle_size - [[ $end_of_bundle -gt $nr_ossl_ciphers ]] && end_of_bundle=$nr_ossl_ciphers - for (( success=0; success==0 ; 1 )); do - ciphers_to_test="" - tls13_ciphers_to_test="" - for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do - if ! "${ciphers_found2[i]}"; then - if [[ "$proto" == "-tls1_3" ]]; then - tls13_ciphers_to_test+=":${ciph2[i]}" - else - ciphers_to_test+=":${ciph2[i]}" - fi - fi - done - success=1 - if [[ -n "$ciphers_to_test" ]] || [[ -n "$tls13_ciphers_to_test" ]]; then - $OPENSSL s_client $(s_client_options "-cipher "\'${ciphers_to_test:1}\'" -ciphersuites "\'${tls13_ciphers_to_test:1}\'" $proto $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>$ERRFILE = 128 ciphers. So, - # test cipher suites in bundles of 128 or less. - num_bundles=$nr_nonossl_ciphers/128 - mod_check=$nr_nonossl_ciphers%128 - [[ $mod_check -ne 0 ]] && num_bundles=$num_bundles+1 - - bundle_size=$nr_nonossl_ciphers/$num_bundles - mod_check=$nr_nonossl_ciphers%$num_bundles - [[ $mod_check -ne 0 ]] && bundle_size+=1 - fi - - for (( bundle=0; bundle < num_bundles; bundle++ )); do - end_of_bundle=$bundle*$bundle_size+$bundle_size - [[ $end_of_bundle -gt $nr_nonossl_ciphers ]] && end_of_bundle=$nr_nonossl_ciphers - for (( success=0; success==0 ; 1 )); do - ciphers_to_test="" - for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do - ! "${ciphers_found2[i]}" && ciphers_to_test+=", ${hexcode2[i]}" - done - success=1 - if [[ -n "$ciphers_to_test" ]]; then - if "$SHOW_SIGALGO"; then - tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "all" - else - tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "ephemeralkey" - fi - if [[ $? -eq 0 ]]; then - success=0 - cipher=$(get_cipher "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt") - for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do - [[ "$cipher" == "${rfc_ciph2[i]}" ]] && ciphers_found2[i]=true && break - done - i=${index[i]} - ciphers_found[i]=true - [[ "$proto_text" == "TLS 1.3" ]] && kx[i]="$(read_dhtype_from_file "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")" - if [[ ${kx[i]} == "Kx=ECDH" ]] || [[ ${kx[i]} == "Kx=DH" ]] || [[ ${kx[i]} == "Kx=EDH" ]]; then - dhlen=$(read_dhbits_from_file "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" quiet) - kx[i]="${kx[i]} $dhlen" - fi - "$SHOW_SIGALGO" && [[ -r "$HOSTCERT" ]] && \ - sigalg[i]="$(read_sigalg_from_file "$HOSTCERT")" - fi - fi - done - done - fi - - for (( i=0 ; i