Skip to content

Commit 6ecdde3

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 11add0d commit 6ecdde3

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
@@ -10139,12 +10139,30 @@ code2network() {
1013910139
# sockets inspired by http://blog.chris007.de/?p=238
1014010140
# ARG1: hexbytes separated by commas, with a leading comma
1014110141
# ARG2: seconds to sleep
10142+
# ARG3: the size of the first message fragment to send
1014210143
socksend_clienthello() {
1014310144
local data=""
10144-
10145+
local -i i first_fragment_size=0
10146+
local first_fragment
10147+
10148+
[[ -n "$3" ]] && first_fragment_size="$3"
1014510149
code2network "$1"
1014610150
data="$NW_STR"
1014710151
[[ "$DEBUG" -ge 4 ]] && echo && echo "\"$data\""
10152+
if [[ $first_fragment_size -ne 0 ]]; then
10153+
for (( i=1; i < ${#data}; i++ )); do
10154+
[[ "${data:i:1}" == '\' ]] && first_fragment_size=$first_fragment_size-1
10155+
[[ $first_fragment_size -eq 0 ]] && break
10156+
done
10157+
first_fragment="${data:0:i}"
10158+
data="${data:i}"
10159+
if [[ -z "$PRINTF" ]] ;then
10160+
# We could also use "dd ibs=1M obs=1M" here but is seems to be at max 3% slower
10161+
printf -- "$first_fragment" | cat >&5 2>/dev/null &
10162+
else
10163+
$PRINTF -- "$first_fragment" 2>/dev/null >&5 2>/dev/null &
10164+
fi
10165+
fi
1014810166
if [[ -z "$PRINTF" ]] ;then
1014910167
# We could also use "dd ibs=1M obs=1M" here but is seems to be at max 3% slower
1015010168
printf -- "$data" | cat >&5 2>/dev/null &
@@ -12663,7 +12681,7 @@ generate_key_share_extension() {
1266312681
# ARG4: (optional) additional request extensions
1266412682
# ARG5: (optional): "true" if ClientHello should advertise compression methods other than "NULL"
1266512683
# ARG6: (optional): "false" if prepare_tls_clienthello() should not open a new socket
12666-
#
12684+
# ARG7: (optional): the size of the first message fragment to send.
1266712685
prepare_tls_clienthello() {
1266812686
local tls_low_byte="$1" tls_legacy_version="$1"
1266912687
local process_full="$3"
@@ -12684,6 +12702,7 @@ prepare_tls_clienthello() {
1268412702
local extensions_key_share="" extn_type supported_groups_c2n="" extn_psk_mode=""
1268512703
local extra_extensions extra_extensions_list="" extension_supported_versions=""
1268612704
local offer_compression=false compression_methods
12705+
local first_fragment_size="$7"
1268712706

1268812707
# TLSv1.3 ClientHello messages MUST specify only the NULL compression method.
1268912708
[[ "$5" == true ]] && [[ "0x$tls_low_byte" -le "0x03" ]] && offer_compression=true
@@ -13062,7 +13081,7 @@ prepare_tls_clienthello() {
1306213081
fi
1306313082

1306413083
debugme echo -n "sending client hello... "
13065-
socksend_clienthello "$TLS_CLIENT_HELLO$all_extensions" $USLEEP_SND
13084+
socksend_clienthello "$TLS_CLIENT_HELLO$all_extensions" $USLEEP_SND $first_fragment_size
1306613085

1306713086
if [[ "$tls_low_byte" -gt 0x03 ]]; then
1306813087
TLS_CLIENT_HELLO="$(tolower "$NW_STR")"
@@ -13280,6 +13299,7 @@ resend_if_hello_retry_request() {
1328013299
# arg4: (optional) additional request extensions
1328113300
# arg5: (optional) "true" if ClientHello should advertise compression methods other than "NULL"
1328213301
# arg6: (optional) "false" if the connection should not be closed before the function returns.
13302+
# arg7: (optional) the size of the first message fragment to send.
1328313303
# return: 0: successful connect | 1: protocol or cipher not available | 2: as (0) but downgraded
1328413304
# 6: couldn't open socket | 7: couldn't open temp file
1328513305
tls_sockets() {
@@ -13312,7 +13332,7 @@ tls_sockets() {
1331213332
cipher_list_2send="$NW_STR"
1331313333

1331413334
debugme echo -en "\nsending client hello... "
13315-
prepare_tls_clienthello "$tls_low_byte" "$cipher_list_2send" "$process_full" "$4" "$offer_compression"
13335+
prepare_tls_clienthello "$tls_low_byte" "$cipher_list_2send" "$process_full" "$4" "$offer_compression" "" "$7"
1331613336
ret=$? # 6 means opening socket didn't succeed, e.g. timeout
1331713337

1331813338
# if sending didn't succeed we don't bother
@@ -15931,6 +15951,21 @@ run_grease() {
1593115951
fi
1593215952
fi
1593315953

15954+
if "$normal_hello_ok"; then
15955+
for i in 5 6 7 8 5 6 7 8; do
15956+
debugme echo -e "\nSending ClientHello with first message fragment of length $i bytes."
15957+
tls_sockets "$proto" "$cipher_list" "" "" "" "" $i
15958+
success=$?
15959+
[[ $success -eq 0 ]] || [[ $success -eq 2 ]] && break
15960+
debugme tm_svrty_low "\nConnection failed on ClientHello with first message fragment of length $i bytes."
15961+
done
15962+
if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then
15963+
prln_svrty_low " Server fails if ClientHello sent with first message fragment less than 9 bytes."
15964+
fileout "$jsonID" "LOW" "Server fails if ClientHello sent with first message fragment less than 9 bytes."
15965+
bug_found=true
15966+
fi
15967+
fi
15968+
1593415969
# Check that server ignores unrecognized cipher suite values
1593515970
# see https://datatracker.ietf.org/doc/draft-ietf-tls-grease
1593615971
if "$normal_hello_ok"; then

0 commit comments

Comments
 (0)