Lately I have started implementing TLS for the sport as a fun project and I'm currently trying to self make and send locally a client hello TLS packet (a minimal one).
When observed via the loopback interface in Wireshark it appears as pure data instead of a tls layer with all of the various fields and after lots of trying I decided to ask here the following questions:
Here is my server and client that send basically my c code output (remember that they are not made for real TLS handling but just to show the packet in Wireshark):
server.py
import socket
TCP_IP = '0.0.0.0'
TCP_PORT = 2004
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpServer.bind((TCP_IP, TCP_PORT))
tcpServer.listen(4)
(conn, (ip,port)) = tcpServer.accept()
client.py
import socket
host = "127.0.0.1"
port = 2004
BUFFER_SIZE = 2000
tcpClientA = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientA.connect((host, port))
tcpClientA.send(b"\x16\x03\x01\x00\xa5\x01\xa1\x00\x00\x03\x03\x31\x32\x33\x34\x35\x36\x37\x38\x39\x61\x73\x64\x66\x67\x68\x6a\x6b\x6c\x7a\x78\x63\x76\x62\x6e\x6d\x61\x73\x64\x66\x67\x68\x6a\x00\x20\x00\xcc\xa8\xcc\xa9\xc0\x2f\xc0\x30\xc0\x2b\xc0\x2c\xc0\x13\xc0\x09\xc0\x14\xc0\x0a\x00\x9c\x00\x9d\x00\x2f\x00\x35\xc0\x12\x00\x0a")
this is my c code for creating the packet it shows that I have set all of the necessary client hello TLS fields for Wireshark to present (In addition I used the following site as guidance https://tls.ulfheim.net/) :
#include <stdint.h>
#include <stdio.h>
#include <string.h>
struct __attribute__((__packed__)) record {
// record layer
uint8_t record_type;
uint16_t version;
uint16_t length;
// handshake layer
uint8_t handshake_type;
char hello_length[3];
// client version
uint16_t tls_version;
// client random
char client_random[32];
// session id
uint8_t session_id;
// cipher suites
uint16_t suites_length;
uint16_t suites[1000];
};
void print_struct(struct record r)
{
unsigned char packet[sizeof(r)] = {0x00};
memcpy(packet, &r, sizeof(r));
for(int i = 0; i < sizeof(packet); i++) {
if(packet[i] != 0xff) {
printf("%02x", packet[i]);
}
}
}
int main()
{
struct record client_hello = {0};
client_hello.record_type = 0x16;
client_hello.version = 0x0103;
client_hello.length = 0xA500;
client_hello.handshake_type = 0x01;
client_hello.hello_length[0] = 0xA1;
client_hello.hello_length[1] = 0x00;
client_hello.hello_length[2] = 0x00;
client_hello.tls_version = 0x0303;
memcpy(client_hello.client_random, "123456789asdfghjklzxcvbnmasdfghj", 32);
client_hello.session_id = 0x00;
client_hello.suites_length = 32;
uint16_t arr[] = {0xa8cc, 0xa9cc, 0x2fc0, 0x30c0, 0x2bc0, 0x2cc0, 0x13c0, 0x09c0, 0x14c0, 0x0ac0, 0x9c00, 0x9d00, 0x2f00, 0x3500, 0x12c0, 0x0a00};
memset(client_hello.suites, 0xffff, sizeof(client_hello.suites));
memcpy(client_hello.suites, arr, sizeof(arr));
print_struct(client_hello);
return 0;
}
This is how Wireshark presents the sent self crafted TLS client hello packet:
0000 02 00 00 00 45 00 00 76 74 c5 40 00 80 06 00 00 ....E..vt.@.....
0010 7f 00 00 01 7f 00 00 01 d9 2f 07 d4 7f 69 9a d9 ........./...i..
0020 99 2a 47 85 50 18 27 f9 03 da 00 00 16 03 01 00 .*G.P.'.........
0030 a5 01 a1 00 00 03 03 31 32 33 34 35 36 37 38 39 .......123456789
0040 61 73 64 66 67 68 6a 6b 6c 7a 78 63 76 62 6e 6d asdfghjklzxcvbnm
0050 61 73 64 66 67 68 6a 00 20 00 cc a8 cc a9 c0 2f asdfghj. ....../
0060 c0 30 c0 2b c0 2c c0 13 c0 09 c0 14 c0 0a 00 9c .0.+.,..........
0070 00 9d 00 2f 00 35 c0 12 00 0a .../.5....
This is a screen shot of how I want it to be shown:
For starters, the TLS length field is wrong. Wireshark's TCP dissector indicates that the TCP payload length is 78 bytes; yet the TLS length is 165 (0x00a5), and thus can't be correct. Also, the handshake length is wrong too. Try changing this:
0030 a5 01 a1 00 00 03 03 31 32 33 34 35 36 37 38 39 .......123456789
to this:
0030 49 01 00 00 45 03 03 31 32 33 34 35 36 37 38 39 I...-..123456789
After that, you'll have to fix the Cipher Suites Length field, which is currently set to 8192 (0x2000) and is also bogus. At most it's 32 (0x0020), so you could try changing this:
0050 61 73 64 66 67 68 6a 00 20 00 cc a8 cc a9 c0 2f asdfghj. ....../
to this:
0050 61 73 64 66 67 68 6a 00 00 20 cc a8 cc a9 c0 2f asdfghj. ....../
This should get you closer but you'll have to continue tweaking the data from there. And for anyone looking to test this, you can save the following data to a text file and then use text2pcap
to convert it to a pcap file that Wireshark can load:
0000 02 00 00 00 45 00 00 76 74 c5 40 00 80 06 00 00 ....E..vt.@..... 0010 7f 00 00 01 7f 00 00 01 d9 2f 01 bb 7f 69 9a d9 ........./...i.. 0020 99 2a 47 85 50 18 27 f9 03 da 00 00 16 03 01 00 .*G.P.'......... 0030 49 01 00 00 45 03 03 31 32 33 34 35 36 37 38 39 I...-..123456789 0040 61 73 64 66 67 68 6a 6b 6c 7a 78 63 76 62 6e 6d asdfghjklzxcvbnm 0050 61 73 64 66 67 68 6a 00 00 20 cc a8 cc a9 c0 2f asdfghj. ....../ 0060 c0 30 c0 2b c0 2c c0 13 c0 09 c0 14 c0 0a 00 9c .0.+.,.......... 0070 00 9d 00 2f 00 35 c0 12 00 0a .../.5....
Run text2pcap
as follows:
text2pcap.exe -l0 file.txt file.pcap