@@ -4866,31 +4866,36 @@ run_server_preference() {
4866
4866
check_tls12_pref() {
4867
4867
local batchremoved="-CAMELLIA:-IDEA:-KRB5:-PSK:-SRP:-aNULL:-eNULL"
4868
4868
local batchremoved_success=false
4869
- local tested_cipher="-$1"
4870
- local order="$1"
4869
+ local tested_cipher=""
4870
+ local order=""
4871
+ local -i nr_ciphers_found_r1=0 nr_ciphers_found_r2=0
4871
4872
4872
4873
while true; do
4873
- $OPENSSL s_client $STARTTLS -tls1_2 $BUGS -cipher "ALL: $tested_cipher:$batchremoved" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
4874
+ $OPENSSL s_client $STARTTLS -tls1_2 $BUGS -cipher "ALL$tested_cipher:$batchremoved" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
4874
4875
if sclient_connect_successful $? $TMPFILE ; then
4875
4876
cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE)
4876
4877
order+=" $cipher"
4877
4878
tested_cipher="$tested_cipher:-$cipher"
4879
+ nr_ciphers_found_r1+=1
4880
+ "$FAST" && break
4878
4881
else
4879
4882
debugme outln "A: $tested_cipher"
4880
4883
break
4881
4884
fi
4882
4885
done
4883
4886
batchremoved="${batchremoved//-/}"
4884
4887
while true; do
4885
- # no ciphers from "ALL: $tested_cipher:$batchremoved" left
4888
+ # no ciphers from "ALL$tested_cipher:$batchremoved" left
4886
4889
# now we check $batchremoved, and remove the minus signs first:
4887
4890
$OPENSSL s_client $STARTTLS -tls1_2 $BUGS -cipher "$batchremoved" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
4888
4891
if sclient_connect_successful $? $TMPFILE ; then
4889
4892
batchremoved_success=true # signals that we have some of those ciphers and need to put everything together later on
4890
4893
cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE)
4891
4894
order+=" $cipher"
4892
4895
batchremoved="$batchremoved:-$cipher"
4896
+ nr_ciphers_found_r1+=1
4893
4897
debugme outln "B1: $batchremoved"
4898
+ "$FAST" && break
4894
4899
else
4895
4900
debugme outln "B2: $batchremoved"
4896
4901
break
@@ -4900,70 +4905,66 @@ check_tls12_pref() {
4900
4905
4901
4906
if "$batchremoved_success"; then
4902
4907
# now we combine the two cipher sets from both while loops
4908
+ [[ "${order:0:1}" == " " ]] && order="${order:1}"
4903
4909
combined_ciphers="${order// /:}"
4904
- $OPENSSL s_client $STARTTLS -tls1_2 $BUGS -cipher "$combined_ciphers" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
4905
- if sclient_connect_successful $? $TMPFILE ; then
4906
- # first cipher
4907
- cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE)
4908
- order="$cipher"
4909
- tested_cipher="-$cipher"
4910
- else
4911
- fixmeln "something weird happened around line $((LINENO - 6))"
4912
- return 1
4913
- fi
4910
+ order="" ; tested_cipher=""
4914
4911
while true; do
4915
- $OPENSSL s_client $STARTTLS -tls1_2 $BUGS -cipher "$combined_ciphers: $tested_cipher" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
4912
+ $OPENSSL s_client $STARTTLS -tls1_2 $BUGS -cipher "$combined_ciphers$tested_cipher" -connect $NODEIP:$PORT $PROXY $SNI </dev/null 2>>$ERRFILE >$TMPFILE
4916
4913
if sclient_connect_successful $? $TMPFILE ; then
4917
4914
cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE)
4918
4915
order+=" $cipher"
4919
4916
tested_cipher="$tested_cipher:-$cipher"
4917
+ nr_ciphers_found_r2+=1
4918
+ "$FAST" && break
4920
4919
else
4921
4920
# nothing left, we're done
4922
- out " $order"
4923
4921
break
4924
4922
fi
4925
4923
done
4926
-
4927
- else
4928
- # second cipher set didn't succeed: we can just output everything
4929
- out " $order"
4924
+ if "$FAST" && [[ $nr_ciphers_found_r2 -ne 1 ]]; then
4925
+ fixmeln "something weird happened around line $((LINENO - 14))"
4926
+ return 1
4927
+ elif ! "$FAST" && [[ $nr_ciphers_found_r2 -ne $nr_ciphers_found_r1 ]]; then
4928
+ fixmeln "something weird happened around line $((LINENO - 16))"
4929
+ return 1
4930
+ fi
4930
4931
fi
4932
+ out "$order"
4931
4933
4932
4934
tmpfile_handle $FUNCNAME.txt
4933
4935
return 0
4934
4936
}
4935
4937
4936
4938
4937
4939
cipher_pref_check() {
4938
- local p proto protos npn_protos sni
4940
+ local p proto proto_hex npn_protos sni
4939
4941
local tested_cipher cipher order
4940
4942
local overflow_probe_cipherlist="ALL:-ECDHE-RSA-AES256-GCM-SHA384:-AES128-SHA:-DES-CBC3-SHA"
4943
+ local -i i nr_ciphers nr_nonossl_ciphers num_bundles mod_check bundle_size bundle end_of_bundle success
4944
+ local hexc ciphers_to_test
4945
+ local -a rfc_ciph hexcode ciphers_found ciphers_found2
4946
+ local -a -i index
4947
+ local using_sockets=true ciphers_found_with_sockets
4948
+
4949
+ "$SSL_NATIVE" && using_sockets=false
4950
+ "$FAST" && using_sockets=false
4951
+ [[ $TLS_NR_CIPHERS == 0 ]] && using_sockets=false
4941
4952
4942
4953
pr_bold " Cipher order"
4943
4954
4944
- for p in ssl2 ssl3 tls1 tls1_1 tls1_2; do
4945
- order=""
4946
- if [[ $p == ssl2 ]] && ! "$HAS_SSL2"; then
4947
- out "\n SSLv2: "; local_problem "$OPENSSL doesn't support \"s_client -ssl2\"";
4948
- continue
4949
- fi
4950
- if [[ $p == ssl3 ]] && ! "$HAS_SSL3"; then
4955
+ outln " ssl3 00 SSLv3\n tls1 01 TLSv1\n tls1_1 02 TLSv1.1\n tls1_2 03 TLSv1.2"| while read p proto_hex proto; do
4956
+ order=""; ciphers_found_with_sockets=false
4957
+ if [[ $p == ssl3 ]] && ! "$HAS_SSL3" && ! "$using_sockets"; then
4951
4958
out "\n SSLv3: "; local_problem "$OPENSSL doesn't support \"s_client -ssl3\"";
4952
4959
continue
4953
4960
fi
4954
- # with the supplied binaries SNI works also for SSLv2 (+ SSLv3)
4955
- [[ "$p" =~ ssl ]] && sni="" || sni=$SNI
4956
- $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $sni </dev/null 2>$ERRFILE >$TMPFILE
4957
- if sclient_connect_successful $? $TMPFILE; then
4958
- tested_cipher=""
4959
- proto=$(awk '/Protocol/ { print $3 }' $TMPFILE)
4960
- cipher=$(awk '/Cipher *:/ { print $3 }' $TMPFILE)
4961
- [[ -z "$proto" ]] && continue # for early openssl versions sometimes needed
4962
- outln
4963
- printf " %-10s" "$proto: "
4964
- tested_cipher="-"$cipher
4965
- order="$cipher"
4966
- if [[ $p == tls1_2 ]]; then
4961
+ has_server_protocol "$p" || continue
4962
+
4963
+ if [[ $p != ssl3 ]] || "$HAS_SSL3"; then
4964
+ # with the supplied binaries SNI works also for SSLv3
4965
+ [[ "$p" =~ ssl ]] && sni="" || sni=$SNI
4966
+
4967
+ if [[ $p == tls1_2 ]] && ! "$SERVER_SIZE_LIMIT_BUG"; then
4967
4968
# for some servers the ClientHello is limited to 128 ciphers or the ClientHello itself has a length restriction.
4968
4969
# So far, this was only observed in TLS 1.2, affected are e.g. old Cisco LBs or ASAs, see issue #189
4969
4970
# To check whether a workaround is needed we send a laaarge list of ciphers/big client hello. If connect fails,
@@ -4975,23 +4976,144 @@ cipher_pref_check() {
4975
4976
fi
4976
4977
fi
4977
4978
if [[ $p == tls1_2 ]] && "$SERVER_SIZE_LIMIT_BUG"; then
4978
- order=$(check_tls12_pref "$cipher")
4979
- out "$order"
4979
+ order="$(check_tls12_pref)"
4980
4980
else
4981
- out " $cipher" # this is the first cipher for protocol
4982
- if ! "$FAST"; then
4983
- while true; do
4984
- $OPENSSL s_client $STARTTLS -"$p" $BUGS -cipher "ALL:$tested_cipher" -connect $NODEIP:$PORT $PROXY $sni </dev/null 2>>$ERRFILE >$TMPFILE
4985
- sclient_connect_successful $? $TMPFILE || break
4986
- cipher=$(awk '/Cipher *:/ { print $3 }' $TMPFILE)
4987
- out " $cipher"
4988
- order+=" $cipher"
4989
- tested_cipher="$tested_cipher:-$cipher"
4981
+ tested_cipher=""
4982
+ while true; do
4983
+ $OPENSSL s_client $STARTTLS -"$p" $BUGS -cipher "ALL:COMPLEMENTOFALL$tested_cipher" -connect $NODEIP:$PORT $PROXY $sni </dev/null 2>>$ERRFILE >$TMPFILE
4984
+ sclient_connect_successful $? $TMPFILE || break
4985
+ cipher=$(awk '/Cipher *:/ { print $3 }' $TMPFILE)
4986
+ [[ -z "$cipher" ]] && break
4987
+ order+=" $cipher"
4988
+ tested_cipher+=":-"$cipher
4989
+ "$FAST" && break
4990
+ done
4991
+ fi
4992
+ fi
4993
+
4994
+ nr_nonossl_ciphers=0
4995
+ if "$using_sockets"; then
4996
+ for (( i=0; i < TLS_NR_CIPHERS; i++ )); do
4997
+ ciphers_found[i]=false
4998
+ hexc="${TLS_CIPHER_HEXCODE[i]}"
4999
+ if [[ ${#hexc} -eq 9 ]]; then
5000
+ if [[ " $order " =~ " ${TLS_CIPHER_OSSL_NAME[i]} " ]]; then
5001
+ ciphers_found[i]=true
5002
+ else
5003
+ ciphers_found2[nr_nonossl_ciphers]=false
5004
+ hexcode[nr_nonossl_ciphers]="${hexc:2:2},${hexc:7:2}"
5005
+ rfc_ciph[nr_nonossl_ciphers]="${TLS_CIPHER_RFC_NAME[i]}"
5006
+ index[nr_nonossl_ciphers]=$i
5007
+ # Only test ciphers that are relevant to the protocol.
5008
+ if [[ "$p" == "tls1_3" ]]; then
5009
+ [[ "${hexc:2:2}" == "13" ]] && nr_nonossl_ciphers+=1
5010
+ elif [[ "$p" == "tls1_2" ]]; then
5011
+ [[ "${hexc:2:2}" != "13" ]] && nr_nonossl_ciphers+=1
5012
+ elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ "SHA256" ]] && \
5013
+ [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ "SHA384" ]] && \
5014
+ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *"_CCM" ]] && \
5015
+ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *"_CCM_8" ]]; then
5016
+ nr_nonossl_ciphers+=1
5017
+ fi
5018
+ fi
5019
+ fi
5020
+ done
5021
+ fi
5022
+
5023
+ if [[ $nr_nonossl_ciphers -eq 0 ]]; then
5024
+ num_bundles=0
5025
+ elif [[ $p != tls1_2 ]] || ! "$SERVER_SIZE_LIMIT_BUG"; then
5026
+ num_bundles=1
5027
+ bundle_size=$nr_nonossl_ciphers
5028
+ else
5029
+ num_bundles=$nr_nonossl_ciphers/128
5030
+ mod_check=$nr_nonossl_ciphers%128
5031
+ [[ $mod_check -ne 0 ]] && num_bundles=$num_bundles+1
5032
+
5033
+ bundle_size=$nr_nonossl_ciphers/$num_bundles
5034
+ mod_check=$nr_nonossl_ciphers%$num_bundles
5035
+ [[ $mod_check -ne 0 ]] && bundle_size+=1
5036
+ fi
5037
+
5038
+ for (( bundle=0; bundle < num_bundles; bundle++ )); do
5039
+ end_of_bundle=$bundle*$bundle_size+$bundle_size
5040
+ [[ $end_of_bundle -gt $nr_nonossl_ciphers ]] && end_of_bundle=$nr_nonossl_ciphers
5041
+ while true; do
5042
+ ciphers_to_test=""
5043
+ for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do
5044
+ ! "${ciphers_found2[i]}" && ciphers_to_test+=", ${hexcode[i]}"
5045
+ done
5046
+ [[ -z "$ciphers_to_test" ]] && break
5047
+ tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "ephemeralkey"
5048
+ [[ $? -ne 0 ]] && break
5049
+ cipher=$(awk '/Cipher *:/ { print $3 }' "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")
5050
+ for (( i=bundle*bundle_size; i < end_of_bundle; i++ )); do
5051
+ [[ "$cipher" == "${rfc_ciph[i]}" ]] && ciphers_found2[i]=true && break
5052
+ done
5053
+ i=${index[i]}
5054
+ ciphers_found[i]=true
5055
+ ciphers_found_with_sockets=true
5056
+ if [[ $p != tls1_2 ]] || ! "$SERVER_SIZE_LIMIT_BUG"; then
5057
+ # Throw out the results found so far and start over using just sockets
5058
+ bundle=$num_bundles
5059
+ for (( i=0; i < TLS_NR_CIPHERS; i++ )); do
5060
+ ciphers_found[i]=true
4990
5061
done
5062
+ break
4991
5063
fi
4992
- fi
5064
+ done
5065
+ done
5066
+
5067
+ # If additional ciphers were found using sockets and there is no
5068
+ # SERVER_SIZE_LIMIT_BUG, then just use sockets to find the cipher order.
5069
+ # If there is a SERVER_SIZE_LIMIT_BUG, then use sockets to find the cipher
5070
+ # order, but starting with the list of ciphers supported by the server.
5071
+ if "$ciphers_found_with_sockets"; then
5072
+ order=""
5073
+ nr_ciphers=0
5074
+ for (( i=0; i < TLS_NR_CIPHERS; i++ )); do
5075
+ hexc="${TLS_CIPHER_HEXCODE[i]}"
5076
+ if "${ciphers_found[i]}" && [[ ${#hexc} -eq 9 ]]; then
5077
+ ciphers_found2[nr_ciphers]=false
5078
+ hexcode[nr_ciphers]="${hexc:2:2},${hexc:7:2}"
5079
+ rfc_ciph[nr_ciphers]="${TLS_CIPHER_RFC_NAME[i]}"
5080
+ if [[ "$p" == "tls1_3" ]]; then
5081
+ [[ "${hexc:2:2}" == "13" ]] && nr_ciphers+=1
5082
+ elif [[ "$p" == "tls1_2" ]]; then
5083
+ [[ "${hexc:2:2}" != "13" ]] && nr_ciphers+=1
5084
+ elif [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ "SHA256" ]] && \
5085
+ [[ ! "${TLS_CIPHER_RFC_NAME[i]}" =~ "SHA384" ]] && \
5086
+ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *"_CCM" ]] && \
5087
+ [[ "${TLS_CIPHER_RFC_NAME[i]}" != *"_CCM_8" ]]; then
5088
+ nr_ciphers+=1
5089
+ fi
5090
+ fi
5091
+ done
5092
+ while true; do
5093
+ ciphers_to_test=""
5094
+ for (( i=0; i < nr_ciphers; i++ )); do
5095
+ ! "${ciphers_found2[i]}" && ciphers_to_test+=", ${hexcode[i]}"
5096
+ done
5097
+ [[ -z "$ciphers_to_test" ]] && break
5098
+ tls_sockets "$proto_hex" "${ciphers_to_test:2}, 00,ff" "ephemeralkey"
5099
+ [[ $? -ne 0 ]] && break
5100
+ cipher=$(awk '/Cipher *:/ { print $3 }' "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")
5101
+ for (( i=0; i < nr_ciphers; i++ )); do
5102
+ [[ "$cipher" == "${rfc_ciph[i]}" ]] && ciphers_found2[i]=true && break
5103
+ done
5104
+ cipher="$(rfc2openssl "$cipher")"
5105
+ # If there is no OpenSSL name for the cipher, then use the RFC name
5106
+ [[ -z "$cipher" ]] && cipher=$(awk '/Cipher *:/ { print $3 }' "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt")
5107
+ order+=" $cipher"
5108
+ done
5109
+ fi
5110
+
5111
+ if [[ -n "$order" ]]; then
5112
+ outln
5113
+ printf " %-10s" "$proto: "
5114
+ out "$order"
5115
+ fileout "order_$p" "INFO" "Default cipher order for protocol $p: $order"
4993
5116
fi
4994
- [[ -z "$order" ]] || fileout "order_$p" "INFO" "Default cipher order for protocol $p: $order"
4995
5117
done
4996
5118
outln
4997
5119
0 commit comments