mirror of
				https://github.com/drwetter/testssl.sh.git
				synced 2025-10-30 21:35:26 +01:00 
			
		
		
		
	Merge pull request #499 from dcooper16/get_full_server_response
Add option to retrieve entire server response
This commit is contained in:
		
							
								
								
									
										155
									
								
								testssl.sh
									
									
									
									
									
								
							
							
						
						
									
										155
									
								
								testssl.sh
									
									
									
									
									
								
							| @@ -5761,10 +5761,98 @@ 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 3 if the response version is TLS 1.3 and the entire ServerHello has been received, since any remaining | ||||||
|  | # portion of the response will be encrypted. | ||||||
|  | # arg1: ASCII-HEX encoded reply | ||||||
|  | check_tls_serverhellodone() { | ||||||
|  |      local tls_hello_ascii="$1" | ||||||
|  |      local tls_handshake_ascii="" tls_alert_ascii="" | ||||||
|  |      local -i i tls_hello_ascii_len tls_handshake_ascii_len tls_alert_ascii_len | ||||||
|  |      local -i msg_len remaining | ||||||
|  |      local tls_content_type tls_protocol tls_handshake_type tls_msg_type | ||||||
|  |      local tls_err_level | ||||||
|  |  | ||||||
| # arg1: name of file with socket reply |      DETECTED_TLS_VERSION="" | ||||||
|  |  | ||||||
|  |      if [[ -z "$tls_hello_ascii" ]]; then | ||||||
|  |           return 0              # no server hello received | ||||||
|  |      fi | ||||||
|  |  | ||||||
|  |      tls_hello_ascii_len=${#tls_hello_ascii} | ||||||
|  |      for (( i=0; i<tls_hello_ascii_len; i=i+msg_len )); do | ||||||
|  |           remaining=$tls_hello_ascii_len-$i | ||||||
|  |           [[ $remaining -lt 10 ]] && return 1 | ||||||
|  |  | ||||||
|  |           tls_content_type="${tls_hello_ascii:i:2}" | ||||||
|  |           [[ "$tls_content_type" != "15" ]] && [[ "$tls_content_type" != "16" ]] && \ | ||||||
|  |                [[ "$tls_content_type" != "17" ]] && return 2 | ||||||
|  |           i=$i+2 | ||||||
|  |           tls_protocol="${tls_hello_ascii:i:4}" | ||||||
|  |           [[ -z "$DETECTED_TLS_VERSION" ]] && DETECTED_TLS_VERSION=$tls_protocol | ||||||
|  |           [[ "${tls_protocol:0:2}" != "03" ]] && return 2 | ||||||
|  |           i=$i+4 | ||||||
|  |           msg_len=2*$(hex2dec "${tls_hello_ascii:i:4}") | ||||||
|  |           i=$i+4 | ||||||
|  |           remaining=$tls_hello_ascii_len-$i | ||||||
|  |           [[ $msg_len -gt $remaining ]] && return 1 | ||||||
|  |  | ||||||
|  |           if [[ "$tls_content_type" == "16" ]]; then | ||||||
|  |                tls_handshake_ascii+="${tls_hello_ascii:i:msg_len}" | ||||||
|  |                tls_handshake_ascii_len=${#tls_handshake_ascii} | ||||||
|  |                # the ServerHello MUST be the first handshake message | ||||||
|  |                [[ $tls_handshake_ascii_len -ge 2 ]] && [[ "${tls_handshake_ascii:0:2}" != "02" ]] && return 2 | ||||||
|  |                if [[ $tls_handshake_ascii_len -ge 12 ]]; then | ||||||
|  |                     DETECTED_TLS_VERSION="${tls_handshake_ascii:8:4}" | ||||||
|  |                     if [[ 0x"$DETECTED_TLS_VERSION" -ge "0x0304" ]]; then | ||||||
|  |                          tls_handshake_ascii_len=2*$(hex2dec "${tls_handshake_ascii:2:6}") | ||||||
|  |                          if [[ $tls_handshake_ascii_len+8 -gt $remaining ]]; then | ||||||
|  |                               return 1 # Not all of the ServerHello message has been received | ||||||
|  |                          else | ||||||
|  |                               return 3 | ||||||
|  |                          fi | ||||||
|  |                     fi | ||||||
|  |                fi | ||||||
|  |           elif [[ "$tls_content_type" == "15" ]]; then   # TLS ALERT | ||||||
|  |                tls_alert_ascii+="${tls_hello_ascii:i:msg_len}" | ||||||
|  |           fi | ||||||
|  |      done | ||||||
|  |  | ||||||
|  |      # If there is a fatal alert, then we are done. | ||||||
|  |      tls_alert_ascii_len=${#tls_alert_ascii} | ||||||
|  |      for (( i=0; i<tls_alert_ascii_len; i=i+4 )); do | ||||||
|  |           remaining=$tls_alert_ascii_len-$i | ||||||
|  |           [[ $remaining -lt 4 ]] && return 1 | ||||||
|  |           tls_err_level=${tls_alert_ascii:i:2}    # 1: warning, 2: fatal | ||||||
|  |           [[ $tls_err_level == "02" ]] && DETECTED_TLS_VERSION="" && return 0 | ||||||
|  |      done | ||||||
|  |  | ||||||
|  |      # If there is a serverHelloDone or Finished, then we are done. | ||||||
|  |      tls_handshake_ascii_len=${#tls_handshake_ascii} | ||||||
|  |      for (( i=0; i<tls_handshake_ascii_len; i=i+msg_len )); do | ||||||
|  |           remaining=$tls_handshake_ascii_len-$i | ||||||
|  |           [[ $remaining -lt 8 ]] && return 1 | ||||||
|  |           tls_msg_type="${tls_handshake_ascii:i:2}" | ||||||
|  |           i=$i+2 | ||||||
|  |           msg_len=2*$(hex2dec "${tls_handshake_ascii:i:6}") | ||||||
|  |           i=$i+6 | ||||||
|  |           remaining=$tls_handshake_ascii_len-$i | ||||||
|  |           [[ $msg_len -gt $remaining ]] && return 1 | ||||||
|  |  | ||||||
|  |           # For SSLv3 - TLS1.2 look for a ServerHelloDone message. | ||||||
|  |           # For TLS 1.3 look for a Finished message. | ||||||
|  |           [[ $tls_msg_type == "0E" ]] && return 0 | ||||||
|  |           [[ $tls_msg_type == "14" ]] && return 0 | ||||||
|  |      done | ||||||
|  |  | ||||||
|  |      # If we haven't encoountered a fatal alert or a server hello done, | ||||||
|  |      # then there must be more data to retrieve. | ||||||
|  |      return 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | # arg1: ASCII-HEX encoded reply | ||||||
| parse_tls_serverhello() { | parse_tls_serverhello() { | ||||||
|      local tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$1") |      local tls_hello_ascii="$1" | ||||||
|      local tls_handshake_ascii="" tls_alert_ascii="" |      local tls_handshake_ascii="" tls_alert_ascii="" | ||||||
|      local -i tls_hello_ascii_len tls_handshake_ascii_len tls_alert_ascii_len msg_len |      local -i tls_hello_ascii_len tls_handshake_ascii_len tls_alert_ascii_len msg_len | ||||||
|      local tls_serverhello_ascii="" |      local tls_serverhello_ascii="" | ||||||
| @@ -6322,12 +6410,18 @@ socksend_tls_clienthello() { | |||||||
|  |  | ||||||
| # 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 | ||||||
|  | # arg3: (optional): "all" - process full response (including Certificate and certificate_status handshake messages) | ||||||
|  | #                   "ephemeralkey" - extract the server's ephemeral key (if any) | ||||||
| tls_sockets() { | tls_sockets() { | ||||||
|      local -i ret=0 |      local -i ret=0 | ||||||
|      local -i save=0 |      local -i save=0 | ||||||
|      local lines |      local lines | ||||||
|      local tls_low_byte |      local tls_low_byte | ||||||
|      local cipher_list_2send |      local cipher_list_2send | ||||||
|  |      local sock_reply_file2 sock_reply_file3 | ||||||
|  |      local tls_hello_ascii next_packet hello_done=0 | ||||||
|  |      local process_full="$3" | ||||||
|  |  | ||||||
|      tls_low_byte="$1" |      tls_low_byte="$1" | ||||||
|      if [[ -n "$2" ]]; then             # use supplied string in arg2 if there is one |      if [[ -n "$2" ]]; then             # use supplied string in arg2 if there is one | ||||||
| @@ -6348,15 +6442,68 @@ tls_sockets() { | |||||||
|      if [[ $ret -eq 0 ]]; then |      if [[ $ret -eq 0 ]]; then | ||||||
|           sockread_serverhello 32768 |           sockread_serverhello 32768 | ||||||
|           TLS_NOW=$(LC_ALL=C date "+%s") |           TLS_NOW=$(LC_ALL=C date "+%s") | ||||||
|  |            | ||||||
|  |           tls_hello_ascii=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE") | ||||||
|  |           tls_hello_ascii="${tls_hello_ascii%%[!0-9A-F]*}" | ||||||
|  |  | ||||||
|  |           # The server's response may span more than one packet. So, | ||||||
|  |           # 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 | ||||||
|  |                check_tls_serverhellodone "$tls_hello_ascii" | ||||||
|  |                hello_done=$? | ||||||
|  |                [[ "$hello_done" -eq 3 ]] && process_full="ephemeralkey" | ||||||
|  |           fi | ||||||
|  |           for (( 1 ; hello_done==1; 1 )); do | ||||||
|  |                sock_reply_file2=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7 | ||||||
|  |                mv "$SOCK_REPLY_FILE" "$sock_reply_file2" | ||||||
|  |  | ||||||
|  |                debugme echo "requesting more server hello data..." | ||||||
|  |                socksend "" $USLEEP_SND | ||||||
|  |                sockread_serverhello 32768 | ||||||
|  |  | ||||||
|  |                next_packet=$(hexdump -v -e '16/1 "%02X"' "$SOCK_REPLY_FILE") | ||||||
|  |                next_packet="${next_packet%%[!0-9A-F]*}" | ||||||
|  |                if [[ ${#next_packet} -eq 0 ]]; then | ||||||
|  |                     # This shouldn't be necessary. However, it protects against | ||||||
|  |                     # getting into an infinite loop if the server has nothing | ||||||
|  |                     # left to send and check_tls_serverhellodone doesn't | ||||||
|  |                     # correctly catch it. | ||||||
|  |                     mv "$sock_reply_file2" "$SOCK_REPLY_FILE" | ||||||
|  |                     hello_done=0 | ||||||
|  |                else | ||||||
|  |                     tls_hello_ascii+="$next_packet" | ||||||
|  |  | ||||||
|  |                     sock_reply_file3=$(mktemp $TEMPDIR/ddreply.XXXXXX) || return 7 | ||||||
|  |                     mv "$SOCK_REPLY_FILE" "$sock_reply_file3" | ||||||
|  |                     mv "$sock_reply_file2" "$SOCK_REPLY_FILE" | ||||||
|  |                     cat "$sock_reply_file3" >> "$SOCK_REPLY_FILE" | ||||||
|  |                     rm "$sock_reply_file3" | ||||||
|  |  | ||||||
|  |                     check_tls_serverhellodone "$tls_hello_ascii" | ||||||
|  |                     hello_done=$? | ||||||
|  |                     [[ "$hello_done" -eq 3 ]] && process_full="ephemeralkey" | ||||||
|  |                fi | ||||||
|  |           done | ||||||
|  |  | ||||||
|           debugme outln "reading server hello..." |           debugme outln "reading server hello..." | ||||||
|           if [[ "$DEBUG" -ge 4 ]]; then |           if [[ "$DEBUG" -ge 4 ]]; then | ||||||
|                hexdump -C $SOCK_REPLY_FILE | head -6 |                hexdump -C $SOCK_REPLY_FILE | head -6 | ||||||
|                echo |                echo | ||||||
|           fi |           fi | ||||||
|  |  | ||||||
|           parse_tls_serverhello "$SOCK_REPLY_FILE" |           parse_tls_serverhello "$tls_hello_ascii" "$process_full" | ||||||
|           save=$? |           save=$? | ||||||
|  |  | ||||||
|  |           if [[ $save == 0 ]]; then | ||||||
|  |                debugme echo "sending close_notify..." | ||||||
|  |                if [[ "$DETECTED_TLS_VERSION" == "0300" ]]; then | ||||||
|  |                     socksend ",x15, x03, x00, x00, x02, x02, x00" 0 | ||||||
|  |                else | ||||||
|  |                     socksend ",x15, x03, x01, x00, x02, x02, x00" 0 | ||||||
|  |                fi | ||||||
|  |           fi | ||||||
|  |  | ||||||
|           # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL |           # see https://secure.wand.net.nz/trac/libprotoident/wiki/SSL | ||||||
|           lines=$(count_lines "$(hexdump -C "$SOCK_REPLY_FILE" 2>$ERRFILE)") |           lines=$(count_lines "$(hexdump -C "$SOCK_REPLY_FILE" 2>$ERRFILE)") | ||||||
|           debugme out "  (returned $lines lines)  " |           debugme out "  (returned $lines lines)  " | ||||||
| @@ -9465,7 +9612,7 @@ lets_roll() { | |||||||
|      determine_service "$1"        # any starttls service goes here |      determine_service "$1"        # any starttls service goes here | ||||||
|  |  | ||||||
|      $do_tls_sockets && [[ $TLS_LOW_BYTE -eq 22 ]] && { sslv2_sockets "" "true"; echo "$?" ; exit 0; } |      $do_tls_sockets && [[ $TLS_LOW_BYTE -eq 22 ]] && { sslv2_sockets "" "true"; echo "$?" ; exit 0; } | ||||||
|      $do_tls_sockets && [[ $TLS_LOW_BYTE -ne 22 ]] && { tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER"; echo "$?" ; exit 0; } |      $do_tls_sockets && [[ $TLS_LOW_BYTE -ne 22 ]] && { tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER" "all"; echo "$?" ; exit 0; } | ||||||
|      $do_test_just_one && test_just_one ${single_cipher} |      $do_test_just_one && test_just_one ${single_cipher} | ||||||
|  |  | ||||||
|      # all top level functions  now following have the prefix "run_" |      # all top level functions  now following have the prefix "run_" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Dirk Wetter
					Dirk Wetter