Merge pull request #842 from dcooper16/tls13_part1

Initial support for TLSv1.3
This commit is contained in:
Dirk Wetter 2017-10-09 14:53:32 +02:00 committed by GitHub
commit 1758d18672
2 changed files with 540 additions and 94 deletions

View File

@ -1,3 +1,5 @@
0x13,0x02 - TLS13-AES-256-GCM-SHA384 TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
0x13,0x03 - TLS13-CHACHA20-POLY1305-SHA256 TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=ChaCha20(256) Mac=AEAD
0xCC,0x14 - ECDHE-ECDSA-CHACHA20-POLY1305-OLD TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD TLSv1.2 Kx=ECDH Au=ECDSA Enc=ChaCha20(256) Mac=AEAD 0xCC,0x14 - ECDHE-ECDSA-CHACHA20-POLY1305-OLD TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD TLSv1.2 Kx=ECDH Au=ECDSA Enc=ChaCha20(256) Mac=AEAD
0xCC,0x13 - ECDHE-RSA-CHACHA20-POLY1305-OLD TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD TLSv1.2 Kx=ECDH Au=RSA Enc=ChaCha20(256) Mac=AEAD 0xCC,0x13 - ECDHE-RSA-CHACHA20-POLY1305-OLD TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD TLSv1.2 Kx=ECDH Au=RSA Enc=ChaCha20(256) Mac=AEAD
0xCC,0x15 - DHE-RSA-CHACHA20-POLY1305-OLD TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD TLSv1.2 Kx=DH Au=RSA Enc=ChaCha20(256) Mac=AEAD 0xCC,0x15 - DHE-RSA-CHACHA20-POLY1305-OLD TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD TLSv1.2 Kx=DH Au=RSA Enc=ChaCha20(256) Mac=AEAD
@ -134,6 +136,9 @@
0x16,0xB8 - - TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLSv1.2 Kx=CECPQ1 Au=ECDSA Enc=ChaCha20(256) Mac=AEAD 0x16,0xB8 - - TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLSv1.2 Kx=CECPQ1 Au=ECDSA Enc=ChaCha20(256) Mac=AEAD
0x16,0xB9 - - TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384 TLSv1.2 Kx=CECPQ1 Au=RSA Enc=AESGCM(256) Mac=AEAD 0x16,0xB9 - - TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384 TLSv1.2 Kx=CECPQ1 Au=RSA Enc=AESGCM(256) Mac=AEAD
0x16,0xBA - - TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384 TLSv1.2 Kx=CECPQ1 Au=ECDSA Enc=AESGCM(256) Mac=AEAD 0x16,0xBA - - TLS_CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384 TLSv1.2 Kx=CECPQ1 Au=ECDSA Enc=AESGCM(256) Mac=AEAD
0x13,0x01 - TLS13-AES-128-GCM-SHA256 TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
0x13,0x04 - TLS13-AES-128-CCM-SHA256 TLS_AES_128_CCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESCCM(128) Mac=AEAD
0x13,0x05 - TLS13-AES-128-CCM-8-SHA256 TLS_AES_128_CCM_8_SHA256 TLSv1.3 Kx=any Au=any Enc=AESCCM8(128) Mac=AEAD
0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD 0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256

View File

@ -3641,8 +3641,21 @@ client_simulation_sockets() {
tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE") tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE")
tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}" tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}"
# Check if the response is a HelloRetryRequest.
resend_if_hello_retry_request "$tls_hello_ascii" "$cipher_list_2send" "$4" "$process_full"
ret=$?
if [[ $ret -eq 2 ]]; then
tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE")
tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}"
elif [[ $ret -eq 1 ]] || [[ $ret -eq 6 ]]; then
close_socket
TMPFILE=$SOCK_REPLY_FILE
tmpfile_handle $FUNCNAME.dd
return $ret
fi
if [[ "${tls_hello_ascii:0:1}" != "8" ]]; then if [[ "${tls_hello_ascii:0:1}" != "8" ]]; then
check_tls_serverhellodone "$tls_hello_ascii" check_tls_serverhellodone "$tls_hello_ascii" "ephemeralkey"
hello_done=$? hello_done=$?
fi fi
@ -3671,7 +3684,7 @@ client_simulation_sockets() {
cat "$sock_reply_file3" >> "$SOCK_REPLY_FILE" cat "$sock_reply_file3" >> "$SOCK_REPLY_FILE"
rm "$sock_reply_file3" rm "$sock_reply_file3"
check_tls_serverhellodone "$tls_hello_ascii" check_tls_serverhellodone "$tls_hello_ascii" "ephemeralkey"
hello_done=$? hello_done=$?
fi fi
done done
@ -7912,15 +7925,21 @@ parse_sslv2_serverhello() {
return $ret return $ret
} }
# Return 0 if arg1 contains the entire server response, 1 if it does not, and 2 if the response is malformed. # Return:
# Return 3 if the response version is TLS 1.3 and the entire ServerHello has been received, since any remaining # 0 if arg1 contains the entire server response.
# portion of the response will be encrypted. # 1 if arg1 does not contain the entire server response.
# 2 if the response is malformed.
# 3 if (a) the response version is TLSv1.3;
# (b) arg1 contains the entire ServerHello (and appears to contain the entire response); and
# (c) the entire response is supposed to be parsed
# arg1: ASCII-HEX encoded reply # arg1: ASCII-HEX encoded reply
# arg2: whether to process the full request ("all") or just the basic request plus the ephemeral key if any ("ephemeralkey").
check_tls_serverhellodone() { check_tls_serverhellodone() {
local tls_hello_ascii="$1" local tls_hello_ascii="$1"
local process_full="$2"
local tls_handshake_ascii="" tls_alert_ascii="" local tls_handshake_ascii="" tls_alert_ascii=""
local -i i tls_hello_ascii_len tls_handshake_ascii_len tls_alert_ascii_len local -i i tls_hello_ascii_len tls_handshake_ascii_len tls_alert_ascii_len
local -i msg_len remaining local -i msg_len remaining tls_serverhello_ascii_len
local tls_content_type tls_protocol tls_handshake_type tls_msg_type local tls_content_type tls_protocol tls_handshake_type tls_msg_type
local tls_err_level local tls_err_level
@ -7940,7 +7959,7 @@ check_tls_serverhellodone() {
[[ "$tls_content_type" != "17" ]] && return 2 [[ "$tls_content_type" != "17" ]] && return 2
i=$i+2 i=$i+2
tls_protocol="${tls_hello_ascii:i:4}" tls_protocol="${tls_hello_ascii:i:4}"
[[ -z "$DETECTED_TLS_VERSION" ]] && DETECTED_TLS_VERSION=$tls_protocol [[ -z "$DETECTED_TLS_VERSION" ]] && DETECTED_TLS_VERSION="$tls_protocol"
[[ "${tls_protocol:0:2}" != "03" ]] && return 2 [[ "${tls_protocol:0:2}" != "03" ]] && return 2
i=$i+4 i=$i+4
msg_len=2*$(hex2dec "${tls_hello_ascii:i:4}") msg_len=2*$(hex2dec "${tls_hello_ascii:i:4}")
@ -7955,12 +7974,12 @@ check_tls_serverhellodone() {
[[ $tls_handshake_ascii_len -ge 2 ]] && [[ "${tls_handshake_ascii:0:2}" != "02" ]] && return 2 [[ $tls_handshake_ascii_len -ge 2 ]] && [[ "${tls_handshake_ascii:0:2}" != "02" ]] && return 2
if [[ $tls_handshake_ascii_len -ge 12 ]]; then if [[ $tls_handshake_ascii_len -ge 12 ]]; then
DETECTED_TLS_VERSION="${tls_handshake_ascii:8:4}" DETECTED_TLS_VERSION="${tls_handshake_ascii:8:4}"
if [[ 0x"$DETECTED_TLS_VERSION" -ge "0x0304" ]]; then # A version of {0x7F, xx} represents an implementation of a draft version of TLS 1.3
tls_handshake_ascii_len=2*$(hex2dec "${tls_handshake_ascii:2:6}") [[ "${DETECTED_TLS_VERSION:0:2}" == "7F" ]] && DETECTED_TLS_VERSION="0304"
if [[ $tls_handshake_ascii_len+8 -gt $remaining ]]; then if [[ 0x$DETECTED_TLS_VERSION -ge 0x0304 ]] && [[ "$process_full" == "ephemeralkey" ]]; then
return 1 # Not all of the ServerHello message has been received tls_serverhello_ascii_len=2*$(hex2dec "${tls_handshake_ascii:2:6}")
else if [[ $tls_handshake_ascii_len -ge $tls_serverhello_ascii_len+8 ]]; then
return 3 return 0 # The entire ServerHello message has been received (and the rest isn't needed)
fi fi
fi fi
fi fi
@ -7995,7 +8014,12 @@ check_tls_serverhellodone() {
[[ $tls_msg_type == "0E" ]] && return 0 [[ $tls_msg_type == "0E" ]] && return 0
[[ $tls_msg_type == "14" ]] && return 0 [[ $tls_msg_type == "14" ]] && return 0
done done
# If the response is TLSv1.3 and the full response is to be processed,
# then return 3 if the entire ServerHello has been received.
if [[ "$DETECTED_TLS_VERSION" == "0304" ]] && [[ "$process_full" == "all" ]] && \
[[ $tls_handshake_ascii_len -gt 0 ]]; then
return 3
fi
# If we haven't encoountered a fatal alert or a server hello done, # If we haven't encoountered a fatal alert or a server hello done,
# then there must be more data to retrieve. # then there must be more data to retrieve.
return 1 return 1
@ -8021,15 +8045,15 @@ parse_tls_serverhello() {
local -i tls_sid_len offset extns_offset nr_certs=0 local -i tls_sid_len offset extns_offset nr_certs=0
local tls_msg_type tls_content_type tls_protocol tls_protocol2 tls_hello_time local tls_msg_type tls_content_type tls_protocol tls_protocol2 tls_hello_time
local tls_err_level tls_err_descr tls_cipher_suite rfc_cipher_suite tls_compression_method local tls_err_level tls_err_descr tls_cipher_suite rfc_cipher_suite tls_compression_method
local tls_extensions="" extension_type named_curve_str="" local tls_extensions="" extension_type named_curve_str="" named_curve_oid
local -i i j extension_len tls_extensions_len ocsp_response_len ocsp_response_list_len local -i i j extension_len tls_extensions_len ocsp_response_len ocsp_response_list_len
local -i certificate_list_len certificate_len cipherlist_len local -i certificate_list_len certificate_len cipherlist_len
local -i curve_type named_curve local -i curve_type named_curve
local -i dh_bits=0 msb mask local -i dh_bits=0 msb mask
local tmp_der_certfile tmp_pem_certfile hostcert_issuer="" ocsp_response="" local tmp_der_certfile tmp_pem_certfile hostcert_issuer="" ocsp_response=""
local key_bitstring="" local len1 len2 len3 key_bitstring="" tmp_der_key_file
local dh_p ephemeral_param rfc7919_param local dh_p dh_param ephemeral_param rfc7919_param
local -i dh_p_len local -i dh_p_len dh_param_len
TLS_TIME="" TLS_TIME=""
DETECTED_TLS_VERSION="" DETECTED_TLS_VERSION=""
@ -8122,7 +8146,6 @@ parse_tls_serverhello() {
debugme tm_out " tls_err_descr: 0x${tls_err_descr} / = $(hex2dec ${tls_err_descr})" debugme tm_out " tls_err_descr: 0x${tls_err_descr} / = $(hex2dec ${tls_err_descr})"
case $tls_err_descr in case $tls_err_descr in
00) tls_alert_descrip="close notify" ;; 00) tls_alert_descrip="close notify" ;;
01) tls_alert_descrip="end of early data" ;;
0A) tls_alert_descrip="unexpected message" ;; 0A) tls_alert_descrip="unexpected message" ;;
14) tls_alert_descrip="bad record mac" ;; 14) tls_alert_descrip="bad record mac" ;;
15) tls_alert_descrip="decryption failed" ;; 15) tls_alert_descrip="decryption failed" ;;
@ -8212,7 +8235,8 @@ parse_tls_serverhello() {
01) tmln_out " (client_hello)" ;; 01) tmln_out " (client_hello)" ;;
02) tmln_out " (server_hello)" ;; 02) tmln_out " (server_hello)" ;;
03) tmln_out " (hello_verify_request)" ;; 03) tmln_out " (hello_verify_request)" ;;
04) tmln_out " (NewSessionTicket)" ;; 04) tmln_out " (new_session_ticket)" ;;
05) tmln_out " (end_of_early_data)" ;;
06) tmln_out " (hello_retry_request)" ;; 06) tmln_out " (hello_retry_request)" ;;
08) tmln_out " (encrypted_extensions)" ;; 08) tmln_out " (encrypted_extensions)" ;;
0B) tmln_out " (certificate)" ;; 0B) tmln_out " (certificate)" ;;
@ -8226,6 +8250,7 @@ parse_tls_serverhello() {
16) tmln_out " (certificate_status)" ;; 16) tmln_out " (certificate_status)" ;;
17) tmln_out " (supplemental_data)" ;; 17) tmln_out " (supplemental_data)" ;;
18) tmln_out " (key_update)" ;; 18) tmln_out " (key_update)" ;;
FE) tmln_out " (message_hash)" ;;
*) tmln_out ;; *) tmln_out ;;
esac esac
echo " msg_len: $((msg_len/2))" echo " msg_len: $((msg_len/2))"
@ -8299,6 +8324,7 @@ parse_tls_serverhello() {
# byte 37+sid-len: compression method: 00: none, 01: deflate, 64: LZS # byte 37+sid-len: compression method: 00: none, 01: deflate, 64: LZS
# byte 38+39+sid-len: extension length # byte 38+39+sid-len: extension length
tls_protocol2="${tls_serverhello_ascii:0:4}" tls_protocol2="${tls_serverhello_ascii:0:4}"
[[ "${tls_protocol2:0:2}" == "7F" ]] && tls_protocol2="0304"
if [[ "${tls_protocol2:0:2}" != "03" ]]; then if [[ "${tls_protocol2:0:2}" != "03" ]]; then
debugme tmln_warning "server_version.major in ServerHello is not 03." debugme tmln_warning "server_version.major in ServerHello is not 03."
return 1 return 1
@ -8403,13 +8429,81 @@ parse_tls_serverhello() {
0018) tls_extensions+="TLS server extension \"token binding\" (id=24), len=$extension_len\n" ;; 0018) tls_extensions+="TLS server extension \"token binding\" (id=24), len=$extension_len\n" ;;
0019) tls_extensions+="TLS server extension \"cached info\" (id=25), len=$extension_len\n" ;; 0019) tls_extensions+="TLS server extension \"cached info\" (id=25), len=$extension_len\n" ;;
0023) tls_extensions+="TLS server extension \"session ticket\" (id=35), len=$extension_len\n" ;; 0023) tls_extensions+="TLS server extension \"session ticket\" (id=35), len=$extension_len\n" ;;
0028) tls_extensions+="TLS server extension \"key share\" (id=40), len=$extension_len\n" ;; 0028) tls_extensions+="TLS server extension \"key share\" (id=40), len=$extension_len\n"
if [[ $extension_len -lt 4 ]]; then
debugme tmln_warning "Malformed key share extension."
return 1
fi
let offset=$extns_offset+12+$i
named_curve=$(hex2dec "${tls_serverhello_ascii:offset:4}")
let offset=$extns_offset+16+$i
msg_len=2*"$(hex2dec "${tls_serverhello_ascii:offset:4}")"
if [[ $msg_len -ne $extension_len-8 ]]; then
debugme tmln_warning "Malformed key share extension."
return 1
fi
case $named_curve in
23) dh_bits=256 ; named_curve_str="P-256" ; named_curve_oid="06082a8648ce3d030107" ;;
24) dh_bits=384 ; named_curve_str="P-384" ; named_curve_oid="06052b81040022" ;;
25) dh_bits=521 ; named_curve_str="P-521" ; named_curve_oid="06052b81040023" ;;
29) dh_bits=253 ; named_curve_str="X25519" ;;
30) dh_bits=448 ; named_curve_str="X448" ;;
256) dh_bits=2048 ; named_curve_str="ffdhe2048" ;;
257) dh_bits=3072 ; named_curve_str="ffdhe3072" ;;
258) dh_bits=4096 ; named_curve_str="ffdhe4096" ;;
259) dh_bits=6144 ; named_curve_str="ffdhe6144" ;;
260) dh_bits=8192 ; named_curve_str="ffdhe8192" ;;
*) named_curve_str="" ; named_curve_oid="" ;;
esac
let offset=$extns_offset+20+$i
if [[ $named_curve -eq 29 ]]; then
key_bitstring="302a300506032b656e032100${tls_serverhello_ascii:offset:msg_len}"
elif [[ $named_curve -eq 30 ]]; then
key_bitstring="3042300506032b656f033900${tls_serverhello_ascii:offset:msg_len}"
elif [[ $named_curve -lt 256 ]] && [[ -n "$named_curve_oid" ]]; then
len1="$(printf "%02x" $(($msg_len/2+1)))"
[[ "0x${len1}" -ge "0x80" ]] && len1="81${len1}"
key_bitstring="03${len1}00${tls_serverhello_ascii:offset:msg_len}"
len2="$(printf "%02x" $((${#named_curve_oid}/2+9)))"
len3="$(printf "%02x" $((${#named_curve_oid}/2+${#key_bitstring}/2+11)))"
[[ "0x${len3}" -ge "0x80" ]] && len3="81${len3}"
key_bitstring="30${len3}30${len2}06072a8648ce3d0201${named_curve_oid}${key_bitstring}"
elif [[ "$named_curve_str" =~ "ffdhe" ]] && [[ "${TLS13_KEY_SHARES[named_curve]}" =~ "BEGIN" ]]; then
dh_param="$($OPENSSL pkey -pubout -outform DER <<< "${TLS13_KEY_SHARES[named_curve]}" | hexdump -v -e '16/1 "%02X"')"
# First is the length of the public-key SEQUENCE, and it is always encoded in four bytes (3082xxxx)
# Next is the length of the parameters SEQUENCE, and it is also always encoded in four bytes (3082xxxx)
dh_param_len=8+2*"$(hex2dec "${dh_param:12:4}")"
dh_param="${dh_param:8:dh_param_len}"
if [[ "0x${tls_serverhello_ascii:offset:2}" -ge 0x80 ]]; then
key_bitstring="00${tls_serverhello_ascii:offset:msg_len}"
msg_len+=2
else
key_bitstring="${tls_serverhello_ascii:offset:msg_len}"
fi
len1="$(printf "%04x" $(($msg_len/2)))"
key_bitstring="0282${len1}$key_bitstring"
len1="$(printf "%04x" $((${#key_bitstring}/2+1)))"
key_bitstring="${dh_param}0382${len1}00$key_bitstring"
len1="$(printf "%04x" $((${#key_bitstring}/2)))"
key_bitstring="3082${len1}$key_bitstring"
fi
if [[ -n "$key_bitstring" ]]; then
tmp_der_key_file=$(mktemp $TEMPDIR/pub_key_der.XXXXXX) || return 1
asciihex_to_binary_file "$key_bitstring" "$tmp_der_key_file"
key_bitstring="$($OPENSSL pkey -pubin -in $tmp_der_key_file -inform DER 2>$ERRFILE)"
rm $tmp_der_key_file
fi
;;
0029) tls_extensions+="TLS server extension \"pre-shared key\" (id=41), len=$extension_len\n" ;; 0029) tls_extensions+="TLS server extension \"pre-shared key\" (id=41), len=$extension_len\n" ;;
002A) tls_extensions+="TLS server extension \"early data\" (id=42), len=$extension_len\n" ;; 002A) tls_extensions+="TLS server extension \"early data\" (id=42), len=$extension_len\n" ;;
002B) tls_extensions+="TLS server extension \"supported versions\" (id=43), len=$extension_len\n" ;; 002B) tls_extensions+="TLS server extension \"supported versions\" (id=43), len=$extension_len\n" ;;
002C) tls_extensions+="TLS server extension \"cookie\" (id=44), len=$extension_len\n" ;; 002C) tls_extensions+="TLS server extension \"cookie\" (id=44), len=$extension_len\n" ;;
002D) tls_extensions+="TLS server extension \"psk key exchange modes\" (id=45), len=$extension_len\n" ;; 002D) tls_extensions+="TLS server extension \"psk key exchange modes\" (id=45), len=$extension_len\n" ;;
002E) tls_extensions+="TLS server extension \"ticket early data info\" (id=46), len=$extension_len\n" ;; 002E) tls_extensions+="TLS server extension \"ticket early data info\" (id=46), len=$extension_len\n" ;;
002F) tls_extensions+="TLS server extension \"certificate authorities\" (id=47), len=$extension_len\n" ;;
0030) tls_extensions+="TLS server extension \"oid filters\" (id=48), len=$extension_len\n" ;;
0031) tls_extensions+="TLS server extension \"post handshake auth\" (id=49), len=$extension_len\n" ;;
3374) tls_extensions+="TLS server extension \"next protocol\" (id=13172), len=$extension_len\n" 3374) tls_extensions+="TLS server extension \"next protocol\" (id=13172), len=$extension_len\n"
local -i protocol_len local -i protocol_len
echo -n "Protocols advertised by server: " >> $TMPFILE echo -n "Protocols advertised by server: " >> $TMPFILE
@ -8454,6 +8548,21 @@ parse_tls_serverhello() {
rfc_cipher_suite="$($OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL' | grep -i " 0x${tls_cipher_suite:0:2},0x${tls_cipher_suite:2:2} " | awk '{ print $3 }')" rfc_cipher_suite="$($OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL' | grep -i " 0x${tls_cipher_suite:0:2},0x${tls_cipher_suite:2:2} " | awk '{ print $3 }')"
fi fi
echo "Cipher : $rfc_cipher_suite" >> $TMPFILE echo "Cipher : $rfc_cipher_suite" >> $TMPFILE
if [[ $dh_bits -ne 0 ]]; then
if [[ "$named_curve_str" =~ "ffdhe" ]]; then
echo "Server Temp Key: DH, $named_curve_str, $dh_bits bits" >> $TMPFILE
elif [[ "$named_curve_str" == "X25519" ]] || [[ "$named_curve_str" == "X448" ]]; then
echo "Server Temp Key: $named_curve_str, $dh_bits bits" >> $TMPFILE
else
echo "Server Temp Key: ECDH, $named_curve_str, $dh_bits bits" >> $TMPFILE
fi
fi
if [[ -n "$key_bitstring" ]]; then
echo "$key_bitstring" >> $TMPFILE
[[ "${TLS13_KEY_SHARES[named_curve]}" =~ "BEGIN" ]] && \
echo "${TLS13_KEY_SHARES[named_curve]}" >> $TMPFILE
fi
echo "===============================================================================" >> $TMPFILE
if [[ "0x${tls_protocol2:2:2}" -le "0x03" ]]; then if [[ "0x${tls_protocol2:2:2}" -le "0x03" ]]; then
case $tls_compression_method in case $tls_compression_method in
00) echo "Compression: NONE" >> $TMPFILE ;; 00) echo "Compression: NONE" >> $TMPFILE ;;
@ -8475,7 +8584,21 @@ parse_tls_serverhello() {
echo -n " tls_hello_time: 0x$tls_hello_time " echo -n " tls_hello_time: 0x$tls_hello_time "
parse_date "$TLS_TIME" "+%Y-%m-%d %r" "%s" parse_date "$TLS_TIME" "+%Y-%m-%d %r" "%s"
fi fi
echo " tls_cipher_suite: 0x$tls_cipher_suite" echo -n " tls_cipher_suite: 0x$tls_cipher_suite"
if [[ -n "$rfc_cipher_suite" ]]; then
echo " ($rfc_cipher_suite)"
else
echo ""
fi
if [[ $dh_bits -ne 0 ]]; then
if [[ "$named_curve_str" =~ "ffdhe" ]]; then
echo " dh_bits: DH, $named_curve_str, $dh_bits bits"
elif [[ "$named_curve_str" == "X25519" ]] || [[ "$named_curve_str" == "X448" ]]; then
echo " dh_bits: $named_curve_str, $dh_bits bits"
else
echo " dh_bits: ECDH, $named_curve_str, $dh_bits bits"
fi
fi
if [[ "0x${tls_protocol2:2:2}" -le "0x03" ]]; then if [[ "0x${tls_protocol2:2:2}" -le "0x03" ]]; then
echo -n " tls_compression_method: 0x$tls_compression_method " echo -n " tls_compression_method: 0x$tls_compression_method "
case $tls_compression_method in case $tls_compression_method in
@ -8866,13 +8989,71 @@ sslv2_sockets() {
return $ret return $ret
} }
# arg1: supported groups extension
# arg2: "all" - process full response (including Certificate and certificate_status handshake messages)
# "ephemeralkey" - extract the server's ephemeral key (if any)
# Given the supported groups extension, create a key_share extension that includes a key share for
# each group listed in the supported groups extension.
generate_key_share_extension() {
local supported_groups
local -i i len supported_groups_len group
local extn_len list_len
local key_share key_shares=""
supported_groups="${1//\\x/}"
[[ "${supported_groups:0:4}" != "000a" ]] && return 1
supported_groups_len=${#supported_groups}
[[ $supported_groups_len -lt 16 ]] && return 1
len=2*$(hex2dec "${supported_groups:4:4}")
[[ $len+8 -ne $supported_groups_len ]] && return 1
len=2*$(hex2dec "${supported_groups:8:4}")
[[ $len+12 -ne $supported_groups_len ]] && return 1
for (( i=12; i<supported_groups_len; i=i+4 )); do
group=$(hex2dec "${supported_groups:i:4}")
# If the Supported groups extensions lists more than one group,
# then don't include the larger key shares in the extension.
[[ $i -gt 12 ]] && [[ $group -gt 256 ]] && continue
# Versions of OpenSSL prior to 1.1.0 cannot perform operations
# with X25519 keys, so don't include the X25519 key share
# if the server's response needs to be decrypted and an
# older version of OpenSSL is being used.
[[ $i -gt 12 ]] && [[ $group -eq 29 ]] && [[ "$2" == "all" ]] && \
[[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != "1.1.0"* ]] && \
[[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != "1.1.1"* ]] && \
continue
# NOTE: The public keys could be extracted from the private keys
# (TLS13_KEY_SHARES) using $OPENSSL, but only OpenSSL 1.1.0 can
# extract the public key from an X25519 private key.
key_share="${TLS13_PUBLIC_KEY_SHARES[group]}"
if [[ ${#key_share} -gt 4 ]]; then
key_shares+=",$key_share"
fi
done
[[ -z "$key_shares" ]] && tm_out "" && return 0
len=${#key_shares}/3
list_len="$(printf "%04x" "$len")"
len+=2
extn_len="$(printf "%04x" "$len")"
tm_out "00,28,${extn_len:0:2},${extn_len:2:2},${list_len:0:2},${list_len:2:2}$key_shares"
return 0
}
# ARG1: TLS version low byte (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) # ARG1: TLS version low byte (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2)
# ARG2: CIPHER_SUITES string (lowercase, and in the format output by code2network()) # ARG2: CIPHER_SUITES string (lowercase, and in the format output by code2network())
# ARG3: (optional) additional request extensions # ARG3: "all" - process full response (including Certificate and certificate_status handshake messages)
# ARG4: (optional): "true" if ClientHello should advertise compression methods other than "NULL" # "ephemeralkey" - extract the server's ephemeral key (if any)
# ARG4: (optional) additional request extensions
# ARG5: (optional): "true" if ClientHello should advertise compression methods other than "NULL"
socksend_tls_clienthello() { socksend_tls_clienthello() {
local tls_low_byte="$1" local tls_low_byte="$1" tls_legacy_version="$1"
local process_full="$3"
local tls_word_reclayer="03, 01" # the first TLS version number is the record layer and always 0301 -- except: SSLv3 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 servername_hexstr len_servername len_servername_hex
local hexdump_format_str part1 part2 local hexdump_format_str part1 part2
@ -8885,11 +9066,12 @@ socksend_tls_clienthello() {
local extension_signature_algorithms extension_heartbeat local extension_signature_algorithms extension_heartbeat
local extension_session_ticket extension_next_protocol extension_padding local extension_session_ticket extension_next_protocol extension_padding
local extension_supported_groups="" extension_supported_point_formats="" local extension_supported_groups="" extension_supported_point_formats=""
local extra_extensions extra_extensions_list="" local extensions_key_share="" extn_type supported_groups_c2n=""
local extra_extensions extra_extensions_list="" extension_supported_versions=""
local offer_compression=false compression_methods local offer_compression=false compression_methods
# TLSv1.3 ClientHello messages MUST specify only the NULL compression method. # TLSv1.3 ClientHello messages MUST specify only the NULL compression method.
[[ "$4" == "true" ]] && [[ "0x$tls_low_byte" -le "0x03" ]] && offer_compression=true [[ "$5" == "true" ]] && [[ "0x$tls_low_byte" -le "0x03" ]] && offer_compression=true
cipher_suites="$2" # we don't have the leading \x here so string length is two byte less, see next cipher_suites="$2" # we don't have the leading \x here so string length is two byte less, see next
len_ciph_suites_byte=${#cipher_suites} len_ciph_suites_byte=${#cipher_suites}
@ -8905,6 +9087,8 @@ socksend_tls_clienthello() {
# Add extensions # Add extensions
# Check to see if any ECC cipher suites are included in cipher_suites # Check to see if any ECC cipher suites are included in cipher_suites
# (not needed for TLSv1.3)
if [[ "0x$tls_low_byte" -le "0x03" ]]; then
for (( i=0; i<len_ciph_suites_byte; i=i+8 )); do for (( i=0; i<len_ciph_suites_byte; i=i+8 )); do
j=$i+4 j=$i+4
part1="0x${cipher_suites:$i:2}" part1="0x${cipher_suites:$i:2}"
@ -8928,11 +9112,14 @@ socksend_tls_clienthello() {
ecc_cipher_suite_found=true && break ecc_cipher_suite_found=true && break
fi fi
elif [[ "$part1" == "0xcc" ]]; then elif [[ "$part1" == "0xcc" ]]; then
if [[ "$part2" == "0xa8" ]] || [[ "$part2" == "0xa9" ]] || [[ "$part2" == "0xac" ]] || [[ "$part2" == "0x13" ]] || [[ "$part2" == "0x14" ]]; then if [[ "$part2" == "0xa8" ]] || [[ "$part2" == "0xa9" ]] || \
[[ "$part2" == "0xac" ]] || [[ "$part2" == "0x13" ]] || \
[[ "$part2" == "0x14" ]]; then
ecc_cipher_suite_found=true && break ecc_cipher_suite_found=true && break
fi fi
fi fi
done done
fi
if [[ -n "$SNI" ]]; then if [[ -n "$SNI" ]]; then
#formatted example for SNI #formatted example for SNI
@ -8951,11 +9138,19 @@ socksend_tls_clienthello() {
len_sni_ext=$(printf "%02x\n" $((len_servername+5))) len_sni_ext=$(printf "%02x\n" $((len_servername+5)))
fi fi
if [[ 0x$tls_low_byte -le 0x03 ]]; then
extension_signature_algorithms=" extension_signature_algorithms="
00, 0d, # Type: signature_algorithms , see RFC 5246 00, 0d, # Type: signature_algorithms , see RFC 5246
00, 20, # len 00, 20, 00,1e, # lengths
00,1e, 06,01, 06,02, 06,03, 05,01, 05,02, 05,03, 06,01, 06,02, 06,03, 05,01, 05,02, 05,03, 04,01, 04,02, 04,03,
04,01, 04,02, 04,03, 03,01, 03,02, 03,03, 02,01, 02,02, 02,03" 03,01, 03,02, 03,03, 02,01, 02,02, 02,03"
else
extension_signature_algorithms="
00, 0d, # Type: signature_algorithms , see draft-ietf-tls-tls13
00, 1c, 00, 1a, # lengths
04,03, 05,03, 06,03, 08,04, 08,05, 08,06,
04,01, 05,01, 06,01, 08,07, 08,08, 02,01, 02,03"
fi
extension_heartbeat=" extension_heartbeat="
00, 0f, 00, 01, 01" 00, 0f, 00, 01, 01"
@ -8975,7 +9170,32 @@ socksend_tls_clienthello() {
00, 18, 00, 09, 00, 0a, 00, 1a, 00, 16, 00, 17, 00, 1d, 00, 08, 00, 18, 00, 09, 00, 0a, 00, 1a, 00, 16, 00, 17, 00, 1d, 00, 08,
00, 06, 00, 07, 00, 14, 00, 15, 00, 04, 00, 05, 00, 12, 00, 13, 00, 06, 00, 07, 00, 14, 00, 15, 00, 04, 00, 05, 00, 12, 00, 13,
00, 01, 00, 02, 00, 03, 00, 0f, 00, 10, 00, 11" 00, 01, 00, 02, 00, 03, 00, 0f, 00, 10, 00, 11"
# Supported Point Formats Extension elif [[ 0x$tls_low_byte -gt 0x03 ]]; then
# Supported Groups Extension
if [[ "$process_full" != "all" ]] || \
[[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0"* ]] || \
[[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.1"* ]]; then
extension_supported_groups="
00,0a, # Type: Supported Groups, see draft-ietf-tls-tls13
00,0e, 00,0c, # lengths
00,1d, 00,17, 00,18, 00,19,
01,00, 01,01"
else
# OpenSSL prior to 1.1.0 does not support X25519, so list it as the least
# preferred option if the response needs to be decrypted.
extension_supported_groups="
00,0a, # Type: Supported Groups, see draft-ietf-tls-tls13
00,0e, 00,0c, # lengths
00,17, 00,18, 00,19,
01,00, 01,01, 00,1d"
fi
code2network "$extension_supported_groups"
supported_groups_c2n="$NW_STR"
fi
if "$ecc_cipher_suite_found" || [[ 0x$tls_low_byte -gt 0x03 ]]; then
# Supported Point Formats Extension.
extension_supported_point_formats=" extension_supported_point_formats="
00, 0b, # Type: Supported Point Formats , see RFC 4492 00, 0b, # Type: Supported Point Formats , see RFC 4492
00, 02, # len 00, 02, # len
@ -8985,16 +9205,25 @@ socksend_tls_clienthello() {
# Each extension should appear in the ClientHello at most once. So, # Each extension should appear in the ClientHello at most once. So,
# find out what extensions were provided as an argument and only use # find out what extensions were provided as an argument and only use
# the provided values for those extensions. # the provided values for those extensions.
extra_extensions="$(tolower "$3")" extra_extensions="$(tolower "$4")"
code2network "$extra_extensions" code2network "$extra_extensions"
len_all=${#extra_extensions} len_all=${#extra_extensions}
for (( i=0; i < len_all; i=i+16+4*0x$len_extension_hex )); do for (( i=0; i < len_all; i=i+16+4*0x$len_extension_hex )); do
part2=$i+4 part2=$i+4
extra_extensions_list+=" ${NW_STR:i:2}${NW_STR:part2:2} " extn_type="${NW_STR:i:2}${NW_STR:part2:2}"
extra_extensions_list+=" $extn_type "
j=$i+8 j=$i+8
part2=$j+4 part2=$j+4
len_extension_hex="${NW_STR:j:2}${NW_STR:part2:2}" len_extension_hex="${NW_STR:j:2}${NW_STR:part2:2}"
if [[ "$extn_type" == "000a" ]] && [[ 0x$tls_low_byte -gt 0x03 ]]; then
j=14+4*0x$len_extension_hex
supported_groups_c2n="${NW_STR:i:j}"
fi
done done
if [[ 0x$tls_low_byte -gt 0x03 ]]; then
extensions_key_share="$(generate_key_share_extension "$supported_groups_c2n" "$process_full")"
[[ $? -ne 0 ]] && return 1
fi
if [[ -n "$SNI" ]] && [[ ! "$extra_extensions_list" =~ " 0000 " ]]; then if [[ -n "$SNI" ]] && [[ ! "$extra_extensions_list" =~ " 0000 " ]]; then
all_extensions=" all_extensions="
@ -9005,6 +9234,24 @@ socksend_tls_clienthello() {
,00, $len_servername_hex # server_name length. We assume len(hostname) < FF - 9 ,00, $len_servername_hex # server_name length. We assume len(hostname) < FF - 9
,$servername_hexstr" # server_name target ,$servername_hexstr" # server_name target
fi fi
if [[ 0x$tls_low_byte -ge 0x04 ]] && [[ ! "$extra_extensions_list" =~ " 002b " ]]; then
# Add supported_versions extension listing all TLS/SSL versions
# from the one specified in $tls_low_byte to SSLv3.
for (( i=0x$tls_low_byte; i >=0; i=i-1 )); do
if [[ 0x$i -eq 4 ]]; then
# FIXME: The ClientHello currently indicates support
# for drafts 18, 19, 20, and 21 of TLSv1.3 in addition
# to the final version of TLSv1.3. In the future, the
# draft versions should be removed.
extension_supported_versions+=", 03, 04, 7f, 15, 7f, 14, 7f, 13, 7f, 12"
else
extension_supported_versions+=", 03, $(printf "%02x" $i)"
fi
done
[[ -n "$all_extensions" ]] && all_extensions+=","
# FIXME: Adjust the lengths ("+11" and "+9") when the draft versions of TLSv1.3 are removed.
all_extensions+="00, 2b, 00, $(printf "%02x" $((2*0x$tls_low_byte+11))), $(printf "%02x" $((2*0x$tls_low_byte+10)))$extension_supported_versions"
fi
if [[ ! "$extra_extensions_list" =~ " 0023 " ]]; then if [[ ! "$extra_extensions_list" =~ " 0023 " ]]; then
[[ -n "$all_extensions" ]] && all_extensions+="," [[ -n "$all_extensions" ]] && all_extensions+=","
@ -9028,6 +9275,12 @@ socksend_tls_clienthello() {
[[ -n "$all_extensions" ]] && all_extensions+="," [[ -n "$all_extensions" ]] && all_extensions+=","
all_extensions+="$extension_supported_groups" all_extensions+="$extension_supported_groups"
fi fi
if [[ -n "$extensions_key_share" ]] && [[ ! "$extra_extensions_list" =~ " 0028 " ]]; then
[[ -n "$all_extensions" ]] && all_extensions+=","
all_extensions+="$extensions_key_share"
fi
if [[ -n "$extension_supported_point_formats" ]] && [[ ! "$extra_extensions_list" =~ " 000b " ]]; then if [[ -n "$extension_supported_point_formats" ]] && [[ ! "$extra_extensions_list" =~ " 000b " ]]; then
[[ -n "$all_extensions" ]] && all_extensions+="," [[ -n "$all_extensions" ]] && all_extensions+=","
all_extensions+="$extension_supported_point_formats" all_extensions+="$extension_supported_point_formats"
@ -9102,6 +9355,8 @@ socksend_tls_clienthello() {
# if we have SSLv3, the first occurence of TLS protocol -- record layer -- is SSLv3, otherwise TLS 1.0 # if we have SSLv3, the first occurence of TLS protocol -- record layer -- is SSLv3, otherwise TLS 1.0
[[ $tls_low_byte == "00" ]] && tls_word_reclayer="03, 00" [[ $tls_low_byte == "00" ]] && tls_word_reclayer="03, 00"
[[ 0x$tls_legacy_version -ge 0x04 ]] && tls_legacy_version="03"
if "$offer_compression"; then if "$offer_compression"; then
# See http://www.iana.org/assignments/comp-meth-ids/comp-meth-ids.xhtml#comp-meth-ids-2 # See http://www.iana.org/assignments/comp-meth-ids/comp-meth-ids.xhtml#comp-meth-ids-2
compression_methods="03,01,40,00" # Offer NULL, DEFLATE, and LZS compression compression_methods="03,01,40,00" # Offer NULL, DEFLATE, and LZS compression
@ -9116,7 +9371,7 @@ socksend_tls_clienthello() {
# Handshake header: # Handshake header:
,01 # Type (x01 for ClientHello) ,01 # Type (x01 for ClientHello)
,00, $len_client_hello_word # Length ClientHello ,00, $len_client_hello_word # Length ClientHello
,03, $tls_low_byte # TLS version ClientHello ,03, $tls_legacy_version # TLS version ClientHello
,54, 51, 1e, 7a # Unix time since see www.moserware.com/2009/06/first-few-milliseconds-of-https.html ,54, 51, 1e, 7a # Unix time since see www.moserware.com/2009/06/first-few-milliseconds-of-https.html
,de, ad, be, ef # Random 28 bytes ,de, ad, be, ef # Random 28 bytes
,31, 33, 07, 00, 00, 00, 00, 00 ,31, 33, 07, 00, 00, 00, 00, 00
@ -9138,6 +9393,172 @@ socksend_tls_clienthello() {
return 0 return 0
} }
# arg1: The server's response
# arg2: CIPHER_SUITES string (lowercase, and in the format output by code2network())
# arg3: (optional) additional request extensions
# arg4: "all" - process full response (including Certificate and certificate_status handshake messages)
# "ephemeralkey" - extract the server's ephemeral key (if any)
# Return 0 if the response is not a HelloRetryRequest.
# Return 1 if the response is a malformed HelloRetryRequest or if a new ClientHello cannot be sent.
# Return 2 if the response is a HelloRetryRequest, and sending a new ClientHello succeeded.
# Return 6 if the response is a HelloRetryRequest, and sending a new ClientHello failed.
resend_if_hello_retry_request() {
local tls_hello_ascii="$1"
local cipher_list_2send="$2"
local process_full="$4"
local tls_low_byte server_version cipher_suite rfc_cipher_suite
local -i i j msg_len tls_hello_ascii_len
local -i extns_offset hrr_extns_len extra_extensions_len len_extn
local extra_extensions extn_type part2 new_extra_extns="" new_key_share temp
tls_hello_ascii_len=${#tls_hello_ascii}
# A HelloRetryRequest is at least 13 bytes long
[[ $tls_hello_ascii_len -lt 26 ]] && return 0
# A HelloRetryRequest is a handshake message (16) with a major record version of 03.
[[ "${tls_hello_ascii:0:4}" != "1603" ]] && return 0
# The handshake type for hello_retry_request is 06.
[[ "${tls_hello_ascii:10:2}" != "06" ]] && return 0
# This appears to be a HelloRetryRequest messsage.
debugme echo "reading hello retry request... "
if [[ "$DEBUG" -ge 4 ]]; then
hexdump -C $SOCK_REPLY_FILE | head -6
echo
fi
# Check the length of the handshake message
msg_len=2*$(hex2dec "${tls_hello_ascii:6:4}")
if [[ $msg_len -ne $tls_hello_ascii_len-10 ]]; then
debugme echo "malformed HelloRetryRequest"
return 1
fi
# Check the length of the HelloRetryRequest message.
msg_len=2*$(hex2dec "${tls_hello_ascii:12:6}")
if [[ $msg_len -ne $tls_hello_ascii_len-18 ]]; then
debugme echo "malformed HelloRetryRequest"
return 1
fi
server_version="${tls_hello_ascii:18:4}"
if [[ "$server_version" == "0304" ]] || [[ 0x$server_version -ge 0x7f13 ]]; then
# Starting with TLSv1.3 draft 19, a HelloRetryRequest is at least 15 bytes long
[[ $tls_hello_ascii_len -lt 30 ]] && return 0
cipher_suite="${tls_hello_ascii:22:2},${tls_hello_ascii:24:2}"
extns_offset=26
else
extns_offset=22
fi
# Check the length of the extensions.
hrr_extns_len=2*$(hex2dec "${tls_hello_ascii:extns_offset:4}")
if [[ $hrr_extns_len -ne $tls_hello_ascii_len-$extns_offset-4 ]]; then
debugme echo "malformed HelloRetryRequest"
return 1
fi
if [[ "${server_version:0:2}" == "7F" ]]; then
tls_low_byte="04"
else
tls_low_byte="${server_version:2:2}"
fi
if [[ $DEBUG -ge 3 ]]; then
echo "TLS message fragments:"
echo " tls_protocol (reclyr): 0x${tls_hello_ascii:2:4}"
echo " tls_content_type: 0x16 (handshake)"
echo " msg_len: $(hex2dec "${tls_hello_ascii:6:4}")"
echo
echo "TLS handshake message:"
echo " handshake type: 0x06 (hello_retry_request)"
echo " msg_len: $(hex2dec "${tls_hello_ascii:12:6}")"
echo
echo "TLS hello retry request message:"
echo " server version: $server_version"
if [[ "$server_version" == "0304" ]] || [[ 0x$server_version -ge 0x7f13 ]]; then
echo -n " cipher suite: $cipher_suite"
if [[ $TLS_NR_CIPHERS -ne 0 ]]; then
if [[ "${cipher_suite:0:2}" == "00" ]]; then
rfc_cipher_suite="$(show_rfc_style "x${cipher_suite:3:2}")"
else
rfc_cipher_suite="$(show_rfc_style "x${cipher_suite:0:2}${cipher_suite:3:2}")"
fi
else
rfc_cipher_suite="$($OPENSSL ciphers -V 'ALL:COMPLEMENTOFALL' | grep -i " 0x${cipher_suite:0:2},0x${cipher_suite:3:2} " | awk '{ print $3 }')"
fi
if [[ -n "$rfc_cipher_suite" ]]; then
echo " ($rfc_cipher_suite)"
else
echo ""
fi
fi
fi
# Parse HelloRetryRequest extensions
for (( i=extns_offset+4; i < tls_hello_ascii_len; i=i+8+$len_extn )); do
extn_type="${tls_hello_ascii:i:4}"
j=$i+4
len_extn=2*$(hex2dec "${tls_hello_ascii:j:4}")
j+=4
if [[ $len_extn -gt $tls_hello_ascii_len-$j ]]; then
debugme echo "malformed HelloRetryRequest"
return 1
fi
# If the HRR includes a cookie extension, then it needs to be
# included in the next ClientHello.
if [[ "$extn_type" == "002C" ]]; then
j=8+$len_extn
new_extra_extns+="${tls_hello_ascii:i:j}"
fi
# If the HRR includes a key_share extension, then it specifies the
# group to be used in the next ClientHello. So, create a key_share
# extension that specifies this group.
if [[ "$extn_type" == "0028" ]]; then
if [[ $len_extn -ne 4 ]]; then
debugme echo "malformed key share extension in HelloRetryRequest"
return 1
fi
[[ $DEBUG -ge 3 ]] && echo " key share: 0x${tls_hello_ascii:j:4}"
new_key_share="$(generate_key_share_extension "000a00040002${tls_hello_ascii:j:4}" "$process_full")"
new_extra_extns+="${new_key_share//,/}"
fi
done
debugme echo ""
if [[ -n "$new_extra_extns" ]]; then
temp="$new_extra_extns"
extra_extensions_len=${#temp}
new_extra_extns=""
for (( i=0 ; i < extra_extensions_len; i=i+2 )); do
new_extra_extns+=",${temp:i:2}"
done
new_extra_extns="${new_extra_extns:1}"
fi
# Include any extra extensions that were included in the first ClientHello,
# except key_share and cookie.
extra_extensions="$(strip_spaces "$(tolower "$3")")"
extra_extensions_len=${#extra_extensions}
for (( i=0; i < extra_extensions_len; i=i+12+$len_extn )); do
part2=$i+3
extn_type="${extra_extensions:i:2}${extra_extensions:part2:2}"
j=$i+6
part2=$j+3
len_extn=3*$(hex2dec "${extra_extensions:j:2}${extra_extensions:part2:2}")
if [[ "$extn_type" != "0028" ]] && [[ "$extn_type" != "002c" ]]; then
j=12+$len_extn
new_extra_extns+=",${extra_extensions:i:j}"
fi
done
debugme echo -en "\nsending second client hello... "
socksend_tls_clienthello "$tls_low_byte" "$cipher_list_2send" "$process_full" "$new_extra_extns"
if [[ $? -ne 0 ]]; then
debugme echo "stuck on sending: $ret"
return 6
fi
sockread_serverhello 32768
return 2
}
# arg1: TLS version low byte # arg1: TLS version low byte
# (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) # (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2)
# arg2: (optional) list of cipher suites # arg2: (optional) list of cipher suites
@ -9154,8 +9575,9 @@ tls_sockets() {
local tls_low_byte local tls_low_byte
local cipher_list_2send local cipher_list_2send
local sock_reply_file2 sock_reply_file3 local sock_reply_file2 sock_reply_file3
local tls_hello_ascii next_packet hello_done=0 local tls_hello_ascii next_packet
local process_full="$3" offer_compression=false local process_full="$3" offer_compression=false skip=false
local -i hello_done=0
[[ "$5" == "true" ]] && offer_compression=true [[ "$5" == "true" ]] && offer_compression=true
tls_low_byte="$1" tls_low_byte="$1"
@ -9172,7 +9594,7 @@ tls_sockets() {
cipher_list_2send="$NW_STR" cipher_list_2send="$NW_STR"
debugme echo -en "\nsending client hello... " debugme echo -en "\nsending client hello... "
socksend_tls_clienthello "$tls_low_byte" "$cipher_list_2send" "$4" "$offer_compression" socksend_tls_clienthello "$tls_low_byte" "$cipher_list_2send" "$process_full" "$4" "$offer_compression"
ret=$? # 6 means opening socket didn't succeed, e.g. timeout ret=$? # 6 means opening socket didn't succeed, e.g. timeout
# if sending didn't succeed we don't bother # if sending didn't succeed we don't bother
@ -9183,15 +9605,30 @@ tls_sockets() {
tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE") tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE")
tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}" tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}"
# The server's response may span more than one packet. So, # Check if the response is a HelloRetryRequest.
# check if response appears to be complete, and if it isn't resend_if_hello_retry_request "$tls_hello_ascii" "$cipher_list_2send" "$4" "$process_full"
# then try to get another packet from the server. ret=$?
if [[ $ret -eq 2 ]]; then
tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE")
tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}"
elif [[ $ret -eq 1 ]] || [[ $ret -eq 6 ]]; then
close_socket
TMPFILE=$SOCK_REPLY_FILE
tmpfile_handle $FUNCNAME.dd
return $ret
fi
# The server's response may span more than one packet. If only the
# first part of the response needs to be processed, this isn't an
# issue. However, if the entire response needs to be processed or
# if the ephemeral key is needed (which comes last for TLS 1.2 and
# below), then we need to check if response appears to be complete,
# and if it isn't then try to get another packet from the server.
if [[ "$process_full" == "all" ]] || [[ "$process_full" == "ephemeralkey" ]]; then if [[ "$process_full" == "all" ]] || [[ "$process_full" == "ephemeralkey" ]]; then
check_tls_serverhellodone "$tls_hello_ascii" hello_done=1; skip=true
hello_done=$?
[[ "$hello_done" -eq 3 ]] && process_full="ephemeralkey"
fi fi
for (( 1 ; hello_done==1; 1 )); do for (( 1 ; hello_done==1; 1 )); do
if ! "$skip"; then
sock_reply_file2=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7 sock_reply_file2=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7
mv "$SOCK_REPLY_FILE" "$sock_reply_file2" mv "$SOCK_REPLY_FILE" "$sock_reply_file2"
@ -9201,6 +9638,7 @@ tls_sockets() {
next_packet=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE") next_packet=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE")
next_packet="${next_packet%%[!0-9A-F]*}" next_packet="${next_packet%%[!0-9A-F]*}"
if [[ ${#next_packet} -eq 0 ]]; then if [[ ${#next_packet} -eq 0 ]]; then
# This shouldn't be necessary. However, it protects against # This shouldn't be necessary. However, it protects against
# getting into an infinite loop if the server has nothing # getting into an infinite loop if the server has nothing
@ -9216,8 +9654,11 @@ tls_sockets() {
mv "$sock_reply_file2" "$SOCK_REPLY_FILE" mv "$sock_reply_file2" "$SOCK_REPLY_FILE"
cat "$sock_reply_file3" >> "$SOCK_REPLY_FILE" cat "$sock_reply_file3" >> "$SOCK_REPLY_FILE"
rm "$sock_reply_file3" rm "$sock_reply_file3"
fi
check_tls_serverhellodone "$tls_hello_ascii" fi
skip=false
if [[ $hello_done -eq 1 ]]; then
check_tls_serverhellodone "$tls_hello_ascii" "$process_full"
hello_done=$? hello_done=$?
[[ "$hello_done" -eq 3 ]] && process_full="ephemeralkey" [[ "$hello_done" -eq 3 ]] && process_full="ephemeralkey"
fi fi