Re-add curve fallback detection

This commit is contained in:
Julien Vehent 2015-04-01 12:50:01 -04:00
parent 04314bffdc
commit 4d7e1cb05a
1 changed files with 94 additions and 20 deletions

View File

@ -63,6 +63,8 @@ CAPATH=""
SAVECRT=""
TEST_CURVES="False"
has_curves="False"
# openssl formated list of curves that will cause server to select ECC suite
ecc_ciphers=""
unset known_certs
declare -A known_certs
unset cert_checksums
@ -458,7 +460,11 @@ test_cipher_on_target() {
if [[ $pfs =~ ECDH ]]; then
has_curves="True"
if [ $TEST_CURVES == "True" ]; then
test_ecc_curves
test_curves
if [ "$ecc_ciphers" != "" ]; then
ecc_ciphers+=":"
fi
ecc_ciphers+="$cipher"
else
# resolve the openssl curve to the proper IANA name
current_curves="$(get_curve_name $(echo $pfs|cut -d ',' -f2))"
@ -622,6 +628,7 @@ display_results_in_terminal() {
fi
if [ $TEST_CURVES == "True" ]; then
echo "Curves ordering: $curvesordering"
echo "Curves fallback: $fallback_supported"
fi
}
@ -656,7 +663,11 @@ display_results_in_json() {
echo -n "}"
ctr=$((ctr+1))
done
echo ']}'
echo -n ']'
if [ $TEST_CURVES == "True" ]; then
echo -n ",\"curves_fallback\":\"$fallback_supported\""
fi
echo '}'
}
test_serverside_ordering() {
@ -712,9 +723,7 @@ test_serverside_ordering() {
fi
}
test_ecc_curves() {
# openssl formated list of curves that will cause server to select ECC suite
local ecc_ciphers=""
test_curves() {
# "True" if server supports ciphers that don't use ECC at a lower priority
local fallback_available="False"
@ -817,8 +826,7 @@ test_ecc_curves() {
local tmp=$(echo Q | $sslcommand -curves $test_curves 2>/dev/null)
parse_openssl_output <<<"$tmp"
if [[ -z $current_protocol || $current_cipher == "(NONE)" \
|| $current_cipher == '0000' ]]; then
if [[ -z $current_protocol || $current_cipher == "(NONE)" || $current_cipher == '0000' ]]; then
fallback_supported="order-specific"
verbose "Server aborted connection"
else
@ -829,18 +837,14 @@ test_ecc_curves() {
if [[ ${ephem_data[0]} =~ ECDH ]]; then
verbose "Server did select ${ephem_data[1]} curve"
curves_ordering="inconclusive-${ephem_data[1]}"
for id in "${!curve_names[@]}"; do
if [[ ${curve_names[$id]} =~ ${ephem_data[1]} ]]; then
local canonic_name=(${curve_names[$id]})
if [[ ${canonic_name[0]} == $most_wanted ]]; then
curves_ordering="client"
break
else
curves_ordering="server"
break
fi
fi
done
local cname="$(get_curve_name ${ephem_data[1]})"
if [ "$cname" == "$most_wanted" ]; then
curves_ordering="client"
break
else
curves_ordering="server"
break
fi
else
# some servers downgrade to non ECDH when curve order is changed
curves_ordering="inconclusive-noecc"
@ -849,6 +853,76 @@ test_ecc_curves() {
fi
}
test_curves_fallback() {
# "True" if server supports ciphers that don't use ECC at a lower priority
local fallback_available="False"
# return variable: whatever a server will fall back to non ECC suite when
# client doesn't advertise support for curves the server needs
fallback_supported="False"
# prepare the ssl command we'll be using
local sslcommand=""
sslcommand="$TIMEOUTBIN $TIMEOUT $OPENSSLBIN s_client"
if [ -n "$CAPATH" ]; then
sslcommand+=" -CApath $CAPATH -showcerts"
elif [ -e "$CACERTS" ]; then
sslcommand+=" -CAfile $CACERTS"
fi
sslcommand+=" -status $SCLIENTARGS -connect $TARGET -cipher $ecc_ciphers"
# force the TLS to send a TLS1.0 client hello at least, as with SSLv2
# ciphers present it will try to send a SSLv2 compatible client hello
sslcommand+=" -no_ssl2 -no_ssl3"
#
# here we use the same logic as with detecting cipher suites: first
# advertise all curves as supported, then remove curves one by one until we
# either get a fallback to a non ECC cipher, we run of curves or server
# tries to negotiate a curve we didn't advertise
#
local curves=(${CURVES[*]})
while [[ ${#curves[@]} -gt 0 ]]; do
OLDIFS="$IFS"
IFS=':'
local test_curves="${curves[*]}"
IFS="$OLDIFS"
verbose "Testing $test_curves"
ratelimit
local tmp=$(echo Q | $sslcommand -curves $test_curves 2>/dev/null)
parse_openssl_output <<<"$tmp"
if [[ -z $current_protocol || $current_cipher == "(NONE)" || $current_cipher == '0000' ]]; then
# server aborted connection
if [[ $fallback_available == "True" ]]; then
fallback_supported="False"
else
fallback_supported="unknown"
fi
break
else
# server accepted connection
local ephem_data=(${current_pfs//,/ })
if [[ ${ephem_data[0]} =~ ECDH ]]; then
# we got an ecc connection, remove the curve from the list of testable curves
local cname="$(get_curve_name ${ephem_data[1]})"
verbose "Server selected curve $cname"
for id in "${!curves[@]}"; do
if [ "${curves[id]}" == "$cname" ]; then
unset curves[$id]
break
fi
done
else
verbose "Server fell back to $current_cipher"
# ok, we got a fallback
fallback_supported="True"
break
fi
fi
done
}
# If no options are given, give usage information and exit (with error code)
if [ $# -eq 0 ]; then
usage;
@ -979,7 +1053,7 @@ get_cipher_pref $CIPHERSUITE
test_serverside_ordering
if [[ $TEST_CURVES == "True" ]]; then
test_ecc_curves
test_curves_fallback
fi
if [ "$OUTPUTFORMAT" == "json" ]; then