From 7e506e5c5a2705857c61abf06fc975b4164806b5 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 13 Apr 2016 15:39:12 -0400 Subject: [PATCH 1/4] More extensions in socksend_tls_clienthello() This PR adds the signature algorithms, heartbeat, session ticket, and next protocol extensions to the client hello message created by socksend_tls_clienthello() for TLS 1.0 and above. It also adds the supported elliptic curves and ec points format extensions if the client hello message includes any ECC cipher suites. I tested this version against several servers with $EXPERIMENTAL set to true and get the same results as with the current code with $EXPERIMENTAL set to false. --- testssl.sh | 172 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 110 insertions(+), 62 deletions(-) diff --git a/testssl.sh b/testssl.sh index fb66226..b893487 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4165,41 +4165,128 @@ sslv2_sockets() { # ARG1: TLS version low byte (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) # ARG2: CIPHER_SUITES string socksend_tls_clienthello() { -#FIXME: redo this with all extensions! local tls_low_byte="$1" local tls_word_reclayer="03, 01" # the first TLS version number is the record layer and always 0301 -- except: SSLv3 local servername_hexstr len_servername len_servername_hex - local hexdump_format_str - local all_extensions + local hexdump_format_str part1 part2 + local all_extensions="" + local -i i j len_extension local len_sni_listlen len_sni_ext len_extension_hex - local cipher_suites len_ciph_suites len_ciph_suites_word + local cipher_suites len_ciph_suites len_ciph_suites_byte len_ciph_suites_word local len_client_hello_word len_all_word - - #len_servername=$(echo ${#NODE}) - len_servername=${#NODE} - hexdump_format_str="$len_servername/1 \"%02x,\"" - servername_hexstr=$(printf $NODE | hexdump -v -e "${hexdump_format_str}" | sed 's/,$//') + local ecc_cipher_suite_found=false + local extension_signature_algorithms extension_heartbeat + local extension_session_ticket extension_next_protocol extensions_ecc code2network "$2" # convert CIPHER_SUITES cipher_suites="$NW_STR" # we don't have the leading \x here so string length is two byte less, see next -#formatted example for SNI -#00 00 # extension server_name -#00 1a # length = the following +2 = server_name length + 5 -#00 18 # server_name list_length = server_name length +3 -#00 # server_name type (hostname) -#00 15 # server_name length -#66 66 66 66 66 66 2e 66 66 66 66 66 66 66 66 66 66 2e 66 66 66 target.mydomain1.tld # server_name target - - # convert lengths we need to fill in from dec to hex: - len_servername_hex=$(printf "%02x\n" $len_servername) - len_sni_listlen=$(printf "%02x\n" $((len_servername+3))) - len_sni_ext=$(printf "%02x\n" $((len_servername+5))) - len_extension_hex=$(printf "%02x\n" $((len_servername+9))) #FIXME: for TLS 1.2 and IIS servers we need extension_signature_algorithms!! - len_ciph_suites_byte=$(echo ${#cipher_suites}) let "len_ciph_suites_byte += 2" + if [[ "$tls_low_byte" != "00" ]]; then + # Add extensions + + # Check to see if any ECC cipher suites are included in cipher_suites + for (( i=0; i Date: Tue, 3 May 2016 16:48:42 -0400 Subject: [PATCH 2/4] Add padding extension RFC 7685 notes that there is at least one TLS implementation that hangs if the client sends a ClientHello with a TLSCiphertext.length between 256 and 511 bytes, and so the padding extension was defined in order to get around this bug. (OpenSSL s_client includes this extension when the -bugs option is used.) So, I changed socksend_tls_clienthello() to include the padding extension if the CLientHello would have a length between 256 and 511 bytes, making the padding extension just large enough to make the ClientHello 512 bytes. I also fixed a typo (a missing "0x") in the check for whether any ECC ciphers are included in the Client Hello. --- testssl.sh | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/testssl.sh b/testssl.sh index b893487..c0e599a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4170,13 +4170,13 @@ socksend_tls_clienthello() { local servername_hexstr len_servername len_servername_hex local hexdump_format_str part1 part2 local all_extensions="" - local -i i j len_extension - local len_sni_listlen len_sni_ext len_extension_hex + local -i i j len_extension len_padding_extension len_all + local len_sni_listlen len_sni_ext len_extension_hex len_padding_extension_hex local cipher_suites len_ciph_suites len_ciph_suites_byte len_ciph_suites_word local len_client_hello_word len_all_word local ecc_cipher_suite_found=false local extension_signature_algorithms extension_heartbeat - local extension_session_ticket extension_next_protocol extensions_ecc + local extension_session_ticket extension_next_protocol extensions_ecc extension_padding code2network "$2" # convert CIPHER_SUITES cipher_suites="$NW_STR" # we don't have the leading \x here so string length is two byte less, see next @@ -4184,6 +4184,12 @@ socksend_tls_clienthello() { len_ciph_suites_byte=$(echo ${#cipher_suites}) let "len_ciph_suites_byte += 2" + # we have additional 2 chars \x in each 2 byte string and 2 byte ciphers, so we need to divide by 4: + len_ciph_suites=$(printf "%02x\n" $(($len_ciph_suites_byte / 4 ))) + len2twobytes "$len_ciph_suites" + len_ciph_suites_word="$LEN_STR" + #[[ $DEBUG -ge 3 ]] && echo $len_ciph_suites_word + if [[ "$tls_low_byte" != "00" ]]; then # Add extensions @@ -4211,7 +4217,7 @@ socksend_tls_clienthello() { ecc_cipher_suite_found=true && break fi elif [[ "$part1" == "0xcc" ]]; then - if [[ "$part2" == "0xa8" ]] || [[ "$part2" == "0xa9" ]] || [[ "$part2" == "0xac" ]] || [[ "$part2" == "13" ]] || [[ "$part2" == "0x14" ]]; then + if [[ "$part2" == "0xa8" ]] || [[ "$part2" == "0xa9" ]] || [[ "$part2" == "0xac" ]] || [[ "$part2" == "0x13" ]] || [[ "$part2" == "0x14" ]]; then ecc_cipher_suite_found=true && break fi fi @@ -4282,16 +4288,31 @@ socksend_tls_clienthello() { len_extension+=2 len_extension=$len_extension/4 len_extension_hex=$(printf "%02x\n" $len_extension) - all_extensions=" - ,00, $len_extension_hex # first the len of all extentions. - ,$all_extensions" - fi - # we have additional 2 chars \x in each 2 byte string and 2 byte ciphers, so we need to divide by 4: - len_ciph_suites=$(printf "%02x\n" $(($len_ciph_suites_byte / 4 ))) - len2twobytes "$len_ciph_suites" - len_ciph_suites_word="$LEN_STR" - #[[ $DEBUG -ge 3 ]] && echo $len_ciph_suites_word + # If the length of the Client Hello would be between 256 and 511 bytes, + # then add a padding extension (see RFC 7685) + len_all=$((0x$len_ciph_suites + 0x2b + 0x$len_extension_hex + 0x2)) + if [[ $len_all -ge 256 ]] && [[ $len_all -le 511 ]]; then + if [[ $len_all -gt 508 ]]; then + len_padding_extension=0 + else + len_padding_extension=$((508 - 0x$len_ciph_suites - 0x2b - 0x$len_extension_hex - 0x2)) + fi + len_padding_extension_hex=$(printf "%02x\n" $len_padding_extension) + len2twobytes "$len_padding_extension_hex" + all_extensions="$all_extensions\\x00\\x15\\x${LEN_STR:0:2}\\x${LEN_STR:4:2}" + for (( i=0; i Date: Thu, 5 May 2016 17:08:40 -0400 Subject: [PATCH 3/4] Signature Algorithms extension for TLSv1.2 only Changed to only include the signature algorithms extension for TLSv1.2, since RFC 5246 says: Note: this extension is not meaningful for TLS versions prior to 1.2. Clients MUST NOT offer it if they are offering prior versions. However, even if clients do offer it, the rules specified in [TLSEXT] require servers to ignore extensions they do not understand. Inclusion of the extension for TLS 1.1 didn't seem to cause any harm, but it seems better to follow the RFC and not include it for TLSv1.0 or TLSv1.1. --- testssl.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index c0e599a..8bc6fc0 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4272,11 +4272,17 @@ socksend_tls_clienthello() { ,00 # server_name type (hostname) ,00, $len_servername_hex # server_name length. We assume len(hostname) < FF - 9 ,$servername_hexstr # server_name target - ,$extension_signature_algorithms ,$extension_heartbeat ,$extension_session_ticket ,$extension_next_protocol" + # RFC 5246 says that clients MUST NOT offer the signature algorithms + # extension if they are offering TLS versions prior to 1.2. + if [[ "$tls_low_byte" == "03" ]]; then + all_extensions="$all_extensions + ,$extension_signature_algorithms" + fi + if $ecc_cipher_suite_found; then all_extensions="$all_extensions ,$extensions_ecc" From 07a8bd3143203354f6a4b59f99d1505f83c23066 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 11 May 2016 09:24:07 -0400 Subject: [PATCH 4/4] Support version negotiation test The new test in PR #346 sends a TLSv1.4 ClientHello, so socksend_tls_clienthello() needs to include the signature algorithms extension if $tls_low_byte >= 3 rather than only if it is equal to 3. --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index 8bc6fc0..83a05f6 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4278,7 +4278,7 @@ socksend_tls_clienthello() { # RFC 5246 says that clients MUST NOT offer the signature algorithms # extension if they are offering TLS versions prior to 1.2. - if [[ "$tls_low_byte" == "03" ]]; then + if [[ "0x$tls_low_byte" -ge "0x03" ]]; then all_extensions="$all_extensions ,$extension_signature_algorithms" fi