TLS Packet Analysis
Reference
Previously, we looked at the TCP 3-way handshake.
In this post, we will examine TLS communication. Since many blogs have already covered the basics of TLS, I will write this for personal study, comparing it with the RFC documentation.
In the next post, I will cover decrypting the encrypted application layer data.
Remember, TLS is also a stateful, connection-oriented protocol.
Communication Details
TCP
The client sends to the server with the Push flag set to 1.
PSH means to push to the upper layer immediately upon arrival.
Let’s look at the TCP payload.
TLS values are listed in order.
TLS Record Layer
https://datatracker.ietf.org/doc/html/rfc5246#section-6.2
This layer receives raw (uninterpreted) data from higher layers. The data is classified into three types:
- ProtocolVersion
- ContentType
- TLSPlaintext

The structure is as follows:
|
|
TLSPlaintext
https://datatracker.ietf.org/doc/html/rfc5246#section-6.2
The structure is as follows:
|
|
ContentType

Looking at the memory, the value 16 in hexadecimal is 22 in decimal, which corresponds to handshake(22)
in the ContentType enum. This is a packet requesting a handshake.
Version

The value at the version index is 03 01
, which the RFC says represents TLS 1.0. This is the version of the Record Layer, not the Client Hello. The ClientHello determines the version. It seems to be sent as 1.0 arbitrarily. Note that while the TLSPlaintext version is marked as 1.0, the client_version in the following fragment is 1.2. The client_version should be the latest version supported by the client, so the tls version in TLSPlaintext can be understood as the minimum supported version.
Length
The length of the TLSPlaintext fragment. Here, it is 512 bytes.
Fragment
This means application data. All the values below are application data!

HandShake Protocol in Fragment
From here, you can see data like Client Hello and Server Hello.
https://datatracker.ietf.org/doc/html/rfc5246#section-7.4
Handshake Type
If the value is 1, it is client_hello. The body type varies by HandShakeType. Let’s look at the body of ClientHello first.
Length
3 bytes are allocated to indicate the length of the body.
TLS Full HandShake

tls session management is done with session tickets, so the flow proceeds as TLS FullHandShake described in RFC 5077.
Client Hello
The structure is as follows:
|
|
You can check the following items:
client_version
The TLS version the client wants to use.

Random
The random structure generated by the client:
|
|

Session ID
|
|

A variable length vector, so the length and actual value follow. 0~32 can be expressed in 1 byte, so it’s represented as 33 bytes in total. If this value is not empty, it means the client wants to reuse the session. Here, since the session id exists, it means the client wants to reuse it.
Cipher Suites
The client lists the supported encryption algorithms in order of preference.
|
|

The first is Reserved (GREASE), defined in RFC 8701. It’s a value to prevent the TLS echo system from malfunctioning. In the end, the client wants to use TLS_AES_128_GCM_SHA256
.
Compression Method
The compression algorithms supported by the client.

Extensions
The client can request extensions from the server. The structure is:
|
|

You can see the structure of the Extension in the third line of server_name. After Client Hello, an Ack is sent, then the Server Hello packet is delivered.

Server Hello
HandShake type (2), the structure of the Server Hello message:
|
|

The fields are similar to Client Hello, so I’ll skip the Wireshark details.
Version
The highest version supported by the server among the versions supported by the client.
Random
The random structure generated by the server. It must be generated independently from the client.
SessionID
The session id corresponding to this connection. If the session id sent in clientHello is not empty, the server will look it up in the session cache. If found, it will use the session state to create a new connection and send Finished messages. If empty, it means the session cannot be reused. Here, the session length is 0, so the session id sent by the client cannot be reused.
cipherSuite
The cipher suite chosen by the server from those sent by the client. If reusing a session, it must be the same as before. Here, the server chose TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
.
Compression Method
The compression algorithm chosen by the server from those sent by the client.
Extensions
The list of extensions. Only those provided by the client are listed.
💡 If the packet size is large, the same ack may be sent for multiple packets. This is not a problem; it just means the data was received.
Certificate
Multiple Packets!
The Certificate is completed over three packets due to its large size.

The Application data size of the Certificate Handshake Protocol is 3877 bytes. Considering the maximum segment size (1460 bytes with a 20-byte header), it’s understandable that it is split.
Handshake Type: Certificate Structure
|
|
Checking Certificate with Java
You can check the certificate using Java and the following three things:
- HexEncoded Certificate value
- bouncycastle library (cryptography library)
- JCA (Java Cryptography Architecture)
Hex Encoding can be easily obtained from Wireshark.
|
|
|
|
You can then open the generated file with openssl:
|
|
You will see the certificate details.
Multiple Certificates
The server provides two certificates.

One is for the domain support.microsoft.com
.

The subject is the owner of the certificate (common name is support.microsoft.com
). The issuer is the issuing authority (Microsoft RSA TLS CA 02). The other is the intermediate CA certificate.
According to the Chain of Trust, the issuing authority’s certificate is also provided for recursive verification.

So the subject of this certificate is Microsoft RSA TLS CA 02, which was the issuer of the server certificate. The issuer of this certificate is Baltimore CyberTrust Root, a RootCA. Where is the RootCA certificate? For security reasons, the RootCA certificate is managed by the OS. On Mac, you can check it in the System Keychain under System Roots.

During the handshake, the Certificate step provides the server’s certificate and ends. The public key is also included in this certificate.
|
|
The modulus and exponent, which are components of the public key, are provided in the certificate.
Now, let’s look at the Server Key Exchange.
Server Key Exchange
https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.3

According to the RFC, this message is sent right after the Server Certificate message. Wireshark shows the same. If the server did not send the premaster secret exchange method in the Certificate message, this message is sent.
Structure
|
|
|
|
If the client provided the signature_algorithms
extension in Client Hello, the signature algorithm and hash algorithm pair must be present in the extension.
EC Diffie-Hellman Server Params
Curve Type: named_curve
https://datatracker.ietf.org/doc/html/rfc4492#section-5.4
|
|
If the curve_type is named_curve (0x03), the following structure appears:
|
|
According to the RFC, namedcurve specifies a recommended set of elliptic curve domain parameters. Only values referring to a specific curve are allowed here.
|
|
Wireshark shows:

ECParameters: Named Curve: secp256r1 ECPoint: Publickey Length: 65, PubKey: 048….
The server chose the algorithm rsa_pss_rsae_sha256
in Server Key Exchange.

Client Request
Optionally, the server can request a certificate from the client (used in mTLS). Generally, this is omitted for public internet services.
Server Hello Done

After ServerHello and related messages are finished, this message is sent. After this, the server waits for the client’s response. This means:
- The server has finished sending messages needed for key exchange.
- The client can now process its part of the key exchange.
The client should:
- Verify the certificate is valid.
- Check if it can accept the server hello parameters.
Client Certificate
If the server requested a certificate from the client, this message would be sent. In this case, it was not requested.
Client Key Exchange Message
https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.7

Here, the premaster secret is set. The client sends either an RSA-encrypted secret or Diffie-Hellman parameters to share the same premaster secret.
Structure
|
|

https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.7.2
Wireshark shows the type as ClientDiffieHellmanPublic.
|
|
Change Cipher Spec
https://datatracker.ietf.org/doc/html/rfc5246#section-7.1
The Change Cipher Spec message is used to notify a change in encryption strategy. The value is 1, indicating a change. From this point, Handshake Messages are encrypted.
https://datatracker.ietf.org/doc/html/rfc5246#section-6.1
TLS connection state refers to the operating environment of the TLS Record Protocol, such as compression, encryption, and MAC algorithms. Connection states are logically divided into:
- current read state
- current write state
- pending read state
- pending write state
While in the pending state, security parameters are set, and ChangeCipherSpec
changes the pending states to current states. After all handshake steps (certificates, key exchange, signatures, etc.) are decided, the ChangeCipherSpec
message is sent, meaning that from now on, messages will be encrypted.

From the next message, everything is encrypted.

Now, Wireshark no longer shows the payload values, just that the Handshake Message is encrypted. The encrypted HandShake message is the preMasterSecret.
New Session Ticket
https://datatracker.ietf.org/doc/html/rfc5077
The server sent a handshake type called New Session Ticket. If the client sets the Session Ticket extension to an empty value in ClientHello, the server supports this. The purpose is to let the client remember the session state, reducing the server’s session state maintenance cost. If the session id is used, the server must maintain the session state, which is burdensome.

Change Cipher Spec Message, Encrypted Handshake Message
The server also changes to the current state with the Change Cipher Spec message and then sends encrypted messages (likely the Finished message).
Encrypted Transmission
After all these steps, both sides use the same master secret to encrypt messages.

The Application Data received by the Transport Layer Security Record Layer is now marked as encrypted.
End!
This post became quite long as I went into detail. I wanted to cover decryption as well, but that will be in the next post. I will continue to update this post as I learn more. If you find any mistakes, please refer to the RFC links above. See you in the next post about encryption and decryption!