Skip to content

Commit 88c2ecf

Browse files
author
David Cooper
committed
ClientHello with small first TCP fragment
Some servers will reject a ClientHello if when sent the first TCP fragment is less than 9 bytes. This commit adds a test for that problem by sending ClientHello messages such such short TCP fragments. It tries initial fragments lengths of 5, 6, 7, and 8 bytes, and tries each of these lengths twice, and reports a problem only if the connection fails only every attempt. The reason for the repeated attempts is that some servers will occasionally fail these tests, and the goal is to only report a problem if testssl#1113 would have reported a problem.
1 parent 9599a56 commit 88c2ecf

1 file changed

Lines changed: 39 additions & 4 deletions

File tree

testssl.sh

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9996,12 +9996,30 @@ code2network() {
99969996
# sockets inspired by http://blog.chris007.de/?p=238
99979997
# ARG1: hexbytes separated by commas, with a leading comma
99989998
# ARG2: seconds to sleep
9999+
# ARG3: the size of the first message fragment to send
999910000
socksend_clienthello() {
1000010001
local data=""
10001-
10002+
local -i i first_fragment_size=0
10003+
local first_fragment
10004+
10005+
[[ -n "$3" ]] && first_fragment_size="$3"
1000210006
code2network "$1"
1000310007
data="$NW_STR"
1000410008
[[ "$DEBUG" -ge 4 ]] && echo && echo "\"$data\""
10009+
if [[ $first_fragment_size -ne 0 ]]; then
10010+
for (( i=1; i < ${#data}; i++ )); do
10011+
[[ "${data:i:1}" == '\' ]] && first_fragment_size=$first_fragment_size-1
10012+
[[ $first_fragment_size -eq 0 ]] && break
10013+
done
10014+
first_fragment="${data:0:i}"
10015+
data="${data:i}"
10016+
if [[ -z "$PRINTF" ]] ;then
10017+
# We could also use "dd ibs=1M obs=1M" here but is seems to be at max 3% slower
10018+
printf -- "$first_fragment" | cat >&5 2>/dev/null &
10019+
else
10020+
$PRINTF -- "$first_fragment" 2>/dev/null >&5 2>/dev/null &
10021+
fi
10022+
fi
1000510023
if [[ -z "$PRINTF" ]] ;then
1000610024
# We could also use "dd ibs=1M obs=1M" here but is seems to be at max 3% slower
1000710025
printf -- "$data" | cat >&5 2>/dev/null &
@@ -12489,7 +12507,7 @@ generate_key_share_extension() {
1248912507
# ARG4: (optional) additional request extensions
1249012508
# ARG5: (optional): "true" if ClientHello should advertise compression methods other than "NULL"
1249112509
# ARG6: (optional): "false" if prepare_tls_clienthello() should not open a new socket
12492-
#
12510+
# ARG7: (optional): the size of the first message fragment to send.
1249312511
prepare_tls_clienthello() {
1249412512
local tls_low_byte="$1" tls_legacy_version="$1"
1249512513
local process_full="$3"
@@ -12510,6 +12528,7 @@ prepare_tls_clienthello() {
1251012528
local extensions_key_share="" extn_type supported_groups_c2n="" extn_psk_mode=""
1251112529
local extra_extensions extra_extensions_list="" extension_supported_versions=""
1251212530
local offer_compression=false compression_methods
12531+
local first_fragment_size="$7"
1251312532

1251412533
# TLSv1.3 ClientHello messages MUST specify only the NULL compression method.
1251512534
[[ "$5" == true ]] && [[ "0x$tls_low_byte" -le "0x03" ]] && offer_compression=true
@@ -12888,7 +12907,7 @@ prepare_tls_clienthello() {
1288812907
fi
1288912908

1289012909
debugme echo -n "sending client hello... "
12891-
socksend_clienthello "$TLS_CLIENT_HELLO$all_extensions" $USLEEP_SND
12910+
socksend_clienthello "$TLS_CLIENT_HELLO$all_extensions" $USLEEP_SND $first_fragment_size
1289212911

1289312912
if [[ "$tls_low_byte" -gt 0x03 ]]; then
1289412913
TLS_CLIENT_HELLO="$(tolower "$NW_STR")"
@@ -13106,6 +13125,7 @@ resend_if_hello_retry_request() {
1310613125
# arg4: (optional) additional request extensions
1310713126
# arg5: (optional) "true" if ClientHello should advertise compression methods other than "NULL"
1310813127
# arg6: (optional) "false" if the connection should not be closed before the function returns.
13128+
# arg7: (optional) the size of the first message fragment to send.
1310913129
# return: 0: successful connect | 1: protocol or cipher not available | 2: as (0) but downgraded
1311013130
# 6: couldn't open socket | 7: couldn't open temp file
1311113131
tls_sockets() {
@@ -13138,7 +13158,7 @@ tls_sockets() {
1313813158
cipher_list_2send="$NW_STR"
1313913159

1314013160
debugme echo -en "\nsending client hello... "
13141-
prepare_tls_clienthello "$tls_low_byte" "$cipher_list_2send" "$process_full" "$4" "$offer_compression"
13161+
prepare_tls_clienthello "$tls_low_byte" "$cipher_list_2send" "$process_full" "$4" "$offer_compression" "" "$7"
1314213162
ret=$? # 6 means opening socket didn't succeed, e.g. timeout
1314313163

1314413164
# if sending didn't succeed we don't bother
@@ -15738,6 +15758,21 @@ run_grease() {
1573815758
fi
1573915759
fi
1574015760

15761+
if "$normal_hello_ok"; then
15762+
for i in 5 6 7 8 5 6 7 8; do
15763+
debugme echo -e "\nSending ClientHello with first message fragment of length $i bytes."
15764+
tls_sockets "$proto" "$cipher_list" "" "" "" "" $i
15765+
success=$?
15766+
[[ $success -eq 0 ]] || [[ $success -eq 2 ]] && break
15767+
debugme tm_svrty_low "\nConnection failed on ClientHello with first message fragment of length $i bytes."
15768+
done
15769+
if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then
15770+
prln_svrty_low " Server fails if ClientHello sent with first message fragment less than 9 bytes."
15771+
fileout "$jsonID" "LOW" "Server fails if ClientHello sent with first message fragment less than 9 bytes."
15772+
bug_found=true
15773+
fi
15774+
fi
15775+
1574115776
# Check that server ignores unrecognized cipher suite values
1574215777
# see https://datatracker.ietf.org/doc/draft-ietf-tls-grease
1574315778
if "$normal_hello_ok"; then

0 commit comments

Comments
 (0)