mirror of
https://github.com/drwetter/testssl.sh.git
synced 2024-12-31 22:09:44 +01:00
run_allciphers() speedup
The run_allciphers() function currently works by calling "$OPENSSL s_client" once for each cipher suite supported by $OPENSSL. In the case of "OpenSSL 1.0.2-chacha (1.0.2e-dev)" that means 195 calls to "$OPENSSL s_client" even though servers tend to only support a small fraction of these cipher suites. This PR produces the same output as the current run_allciphers() with fewer calls to "$OPENSSL s_client", which results in the function running faster (usually much faster). The basic idea behind the revised function is to test cipher suites in blocks. If $OPENSSL supports 195 cipher suites, then it group these cipher suites into 4 blocks of 64 (with the final block being smaller). It makes one call to "$OPENSSL s_client" with cipher suites 1-64, and if it fails, then it knows that none of these 64 cipher suites are supported by the server and it doesn't need to perform any more tests on these 64 cipher suites. If it succeeds, then it breaks the 64 cipher suites into 4 blocks of 16 and calls "$OPENSSL s_client" with each of those blocks. The blocks of 16 that are successful are broken into blocks of 4, and for each of the successful blocks of 4 the individual cipher suites are tested. For testssl.sh and www.google.com the number of calls to "$OPENSSL s_client" is reduced from 195 to 88. For github.com the number of calls is reduced to 56! I haven't made any changes to run_cipher_per_proto yet, but if this PR is accepted I can make the same changes in that function. Thanks, David
This commit is contained in:
parent
c684ba7d9c
commit
eac2df6d81
121
testssl.sh
121
testssl.sh
@ -1570,51 +1570,102 @@ test_just_one(){
|
||||
# test for all ciphers locally configured (w/o distinguishing whether they are good or bad
|
||||
run_allciphers(){
|
||||
local tmpfile
|
||||
local nr_ciphers
|
||||
local -i sclient_success=0
|
||||
local hexcode n ciph sslvers kx auth enc mac export
|
||||
local -i nr_ciphers
|
||||
local n sslvers auth mac export
|
||||
local -a hexcode ciph kx enc export2
|
||||
local -i i j parent child end_of_bundle round_num bundle_size num_bundles mod_check
|
||||
local -a ciphers_found
|
||||
local dhlen
|
||||
local available
|
||||
local ciphers_to_test
|
||||
|
||||
# get a list of all the cipher suites to test (only need the hexcode, ciph, kx, enc, and export values
|
||||
nr_ciphers=0
|
||||
$OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>>$ERRFILE | (while read hexcode[nr_ciphers] n ciph[nr_ciphers] sslvers kx[nr_ciphers] auth enc[nr_ciphers] mac export2[nr_ciphers]; do
|
||||
nr_ciphers=$nr_ciphers+1
|
||||
done
|
||||
|
||||
nr_ciphers=$(count_ciphers "$($OPENSSL ciphers 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE)")
|
||||
outln
|
||||
pr_headlineln " Testing all $nr_ciphers locally available ciphers against the server, ordered by encryption strength "
|
||||
"$HAS_DH_BITS" || pr_warningln " (Your $OPENSSL cannot show DH/ECDH bits)"
|
||||
outln
|
||||
neat_header
|
||||
|
||||
$OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>>$ERRFILE | while read hexcode n ciph sslvers kx auth enc mac export; do
|
||||
# FIXME: e.g. OpenSSL < 1.0 doesn't understand "-V" --> we can't do anything about it!
|
||||
$OPENSSL s_client -cipher $ciph $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE </dev/null
|
||||
sclient_connect_successful "$?" "$TMPFILE"
|
||||
sclient_success=$?
|
||||
if [[ "$sclient_success" -ne 0 ]] && ! "$SHOW_EACH_C"; then
|
||||
continue # no successful connect AND not verbose displaying each cipher
|
||||
fi
|
||||
normalize_ciphercode "$hexcode"
|
||||
if [[ $kx == "Kx=ECDH" ]] || [[ $kx == "Kx=DH" ]] || [[ $kx == "Kx=EDH" ]]; then
|
||||
dhlen=$(read_dhbits_from_file "$TMPFILE" quiet)
|
||||
kx="$kx $dhlen"
|
||||
fi
|
||||
neat_list "$HEXC" "$ciph" "$kx" "$enc"
|
||||
available=""
|
||||
if "$SHOW_EACH_C"; then
|
||||
if [[ "$sclient_success" -eq 0 ]]; then
|
||||
available="available"
|
||||
pr_cyan " available"
|
||||
else
|
||||
out " not a/v"
|
||||
available="not a/v"
|
||||
fi
|
||||
fi
|
||||
if "$SHOW_SIGALGO"; then
|
||||
$OPENSSL x509 -noout -text -in $TMPFILE | awk -F':' '/Signature Algorithm/ { print $2 }' | head -1
|
||||
else
|
||||
outln
|
||||
fi
|
||||
fileout "cipher_$HEXC" "INFO" "$(neat_list "$HEXC" "$ciph" "$kx" "$enc") $available"
|
||||
tmpfile_handle $FUNCNAME.txt
|
||||
# Split ciphers into bundles of size 4**n, starting with an "n" that
|
||||
# splits the ciphers into 4 bundles, and then reduing "n" by one in each
|
||||
# round. Only test a bundle of 4**n ciphers against the server if it was
|
||||
# part of a bundle of 4**(n+1) ciphers that included a cipher supported by
|
||||
# the server. Continue until n=0.
|
||||
|
||||
# Determine bundle size that will result in their being exactly four bundles.
|
||||
for((bundle_size=1;bundle_size<nr_ciphers;bundle_size*=4)); do
|
||||
:
|
||||
done
|
||||
|
||||
# set ciphers_found[1] so that all bundles will be tested in round 0.
|
||||
ciphers_found[1]=true
|
||||
round_num=0
|
||||
|
||||
for ((bundle_size/=4;bundle_size>=1;bundle_size/=4)); do
|
||||
# Note that since the number of ciphers isn't a power of 4, the number
|
||||
# of bundles may be may be less than 4**(round_num+1), and the final
|
||||
# bundle may have fewer than bundle_size ciphers.
|
||||
num_bundles=$nr_ciphers/$bundle_size
|
||||
mod_check=$nr_ciphers%$bundle_size
|
||||
[[ $mod_check -ne 0 ]] && num_bundles=$num_bundles+1
|
||||
for ((i=0;i<num_bundles;i++)); do
|
||||
# parent=index of bundle from previous round that includes this bundle of ciphers
|
||||
parent=4**$round_num+$i/4
|
||||
# child=index for this bundle of ciphers
|
||||
child=4*4**$round_num+$i
|
||||
if ${ciphers_found[parent]}; then
|
||||
ciphers_to_test=""
|
||||
end_of_bundle=$i*$bundle_size+$bundle_size
|
||||
[[ $end_of_bundle -gt $nr_ciphers ]] && end_of_bundle=$nr_ciphers
|
||||
for ((j=i*bundle_size;j<end_of_bundle;j++)); do
|
||||
ciphers_to_test="${ciphers_to_test}:${ciph[j]}"
|
||||
done
|
||||
ciphers_found[child]=false
|
||||
$OPENSSL s_client -cipher "${ciphers_to_test:1}" $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE </dev/null
|
||||
sclient_connect_successful "$?" "$TMPFILE"
|
||||
[[ "$?" -eq 0 ]] && ciphers_found[child]=true
|
||||
else
|
||||
# No need to test, since test of parent demonstrated none of these ciphers work.
|
||||
ciphers_found[child]=false
|
||||
fi
|
||||
|
||||
# If this is a "leaf" of the test tree, then print out the results.
|
||||
if [[ $bundle_size -eq 1 ]] && ( ${ciphers_found[child]} || "$SHOW_EACH_C"); then
|
||||
export=${export2[i]}
|
||||
normalize_ciphercode "${hexcode[i]}"
|
||||
if [[ ${kx[i]} == "Kx=ECDH" ]] || [[ ${kx[i]} == "Kx=DH" ]] || [[ ${kx[i]} == "Kx=EDH" ]]; then
|
||||
if ${ciphers_found[child]}; then
|
||||
dhlen=$(read_dhbits_from_file "$TMPFILE" quiet)
|
||||
kx[i]="${kx[i]} $dhlen"
|
||||
fi
|
||||
fi
|
||||
neat_list "$HEXC" "${ciph[i]}" "${kx[i]}" "${enc[i]}"
|
||||
available=""
|
||||
if "$SHOW_EACH_C"; then
|
||||
if ${ciphers_found[child]}; then
|
||||
available="available"
|
||||
pr_cyan " available"
|
||||
else
|
||||
out " not a/v"
|
||||
available="not a/v"
|
||||
fi
|
||||
fi
|
||||
if "$SHOW_SIGALGO" && ${ciphers_found[child]}; then
|
||||
$OPENSSL x509 -noout -text -in $TMPFILE | awk -F':' '/Signature Algorithm/ { print $2 }' | head -1
|
||||
else
|
||||
outln
|
||||
fi
|
||||
fileout "cipher_$HEXC" "INFO" "$(neat_list "$HEXC" "${ciph[i]}" "${kx[i]}" "${enc[i]}") $available"
|
||||
tmpfile_handle $FUNCNAME.txt
|
||||
fi
|
||||
done
|
||||
round_num=round_num+1
|
||||
done)
|
||||
outln
|
||||
return 0
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user