3

I wanted to implement RFC 8446 to learn more about TLS. I've worked some with text based protocols like HTTP and SMTP. TLS is my first binary encoding to attempt implementing sections of.

I'm sending a very malformed ClientHello to google.com:443:

let client_hello: Vec<u8> = [3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0]

I found The Illustrated TLS1.3 Connection: Every Byte Explained which should help a lot in correcting my message, but I'm having a very hard time figuring out why google.com:443 responds to me, and what the response is:

let google_response: Vec<u8> = [21, 3, 1, 0, 2, 2, 10]

I think it might be an alert? If I just take the right most bytes [2,10] then it's an unexpected_message, but this doesn't explain the rest of the bits which are consistently returned.

What is this message? Is there a better way to debug SSL Client implementations? Something with openssl?

1 Answer 1

4

The data exchanged on a TLS connection is a series of records. RFC 8446 §5 describes the record protocol. The format of a record is:

  • [1 byte] record content type;
  • [2 bytes] protocol version, always 0x0303 for TLS 1.2 and TLS 1.3 (don't worry about exceptions for now);
  • [2 bytes] length N of the following data (big-endian a.k.a. network-endian; all multi-byte integers are encoded in big-endian order unless otherwise specified);
  • [N bytes] data, depending on the record content type.

What you send is a record of invalid type and version with a 0-byte payload, followed by more garbage. Google's response is a record with type=21 (alert), protocol version [3,1] meaning TLS 1.0 (presumably the oldest version the server supports, since you didn't give any indication of supporting a more recent version), and 2 bytes of content [2, 10]. Decoding this alert (RFC 8446 §7.2), it's level 2 “fatal” and description 10 “unexpected message”.

Start by constructing valid records, before worrying about the contents of those records. TLS distinguishes records and messages, and allows messages to span multiple records, but don't worry about that for now: treat a record as one message, either a handshake message or a fragment of application data. TLS is a stream protocol so you can break application data into messages however you like.

For debugging, use a local server with debugging facilities rather than a remote server that you don't control. For example:

openssl s_server -debug -trace -www -accept 4433 -psk_identity whoiam -psk 73776f726466697368

or

openssl genrsa -out mykey.pem 2048
openssl req -new -x509 -key mykey.pem -out mycert.crt -days 360
openssl s_server -debug -trace -www -accept 4433 -cert mycert.crt -key mykey.pem

Wireshark is also useful to see what you're sending or trying to parse.

1
  • I think the most helpful part was just you picking apart the message bytes. I wasn't very confident if it were big endian, little endian, or even which way those formats flow :). I probably needed to read the spec more and organize that information better.
    – Breedly
    Nov 8, 2022 at 12:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .