Leapcell: The Best of Serverless Web Hosting
Explanation of the TLS Handshake Process
The TLS (Transport Layer Security) handshake is a vital procedure that enables secure communication between a client (such as a web browser) and a server (such as a web server). Below is a detailed breakdown of the entire TLS handshake process:
-
Client Hello
- The client starts the handshake by sending a "Client Hello" message to the server.
- This message contains:
- The TLS versions supported by the client.
- A list of cipher suites (encryption algorithms) it supports.
- A random byte string (referred to as Client Random).
-
Server Hello
- The server replies with a "Server Hello" message.
- This message includes:
- The selected TLS version.
- The chosen cipher suite.
- A random byte string (known as Server Random).
- The server's digital certificate (issued by a trusted Certificate Authority, CA).
-
Certificate Verification
- The client verifies the server's certificate through the certificate authority (CA) chain.
- It ensures that the certificate is valid, not expired, and issued to the correct domain.
-
Pre - Master Secret Generation
- The client generates a "Pre - Master Secret" using the server's public key (extracted from the certificate).
- This secret is encrypted and sent to the server.
-
Master Secret Derivation
- Both the client and the server generate the "Master Secret" using the following:
- The Client Random.
- The Server Random.
- The Pre - Master Secret.
- The Master Secret is used to derive session keys for encryption and integrity checks.
- Both the client and the server generate the "Master Secret" using the following:
-
Session Keys Creation
- Using the Master Secret, both parties create:
- Encryption keys for symmetric encryption.
- MAC (Message Authentication Code) keys for integrity checks.
- Using the Master Secret, both parties create:
-
Client Finished
- The client sends a "Finished" message, which is encrypted with the session keys.
- This confirms that the handshake was successful and that future messages will be encrypted.
-
Server Finished
- The server sends its own "Finished" message, encrypted with the session keys.
- This marks the end of the handshake and the start of encrypted communication.
-
Data Transfer
- All subsequent communication is encrypted using the derived session keys.
- Data is sent in encrypted packets with integrity checks.
Diagram of the TLS Handshake Process
+----------------------------------------+ +----------------------------------------+
| Client | | Server |
+----------------------------------------+ +----------------------------------------+
| | | |
| ClientHello |----->| |
| [TLS Version, Cipher Suites, Random] | | |
| | | |
| | | ServerHello |
| |<-----| [TLS Version, Cipher Suite, Random] |
| | | |
| |<-----| Certificate |
| | | [Server's Public Key] |
| | | |
| |<-----| ServerHelloDone |
| | | |
| CertificateVerify | | |
| [Verify Server's Certificate] | | |
| | | |
| ClientKeyExchange |----->| |
| [Encrypted Pre-Master Secret] | | |
| | | |
| ChangeCipherSpec |----->| |
| [Start Using Encryption] | | |
| | | |
| Finished |----->| |
| [Verifies Handshake Integrity] | | |
| | | |
| |<-----| ChangeCipherSpec |
| | | [Start Using Encryption] |
| | | |
| |<-----| Finished |
| | | [Verifies Handshake Integrity] |
| | | |
| Secure Communication |<--->| Secure Communication |
| [Encrypted Data Transfer] | | [Encrypted Data Transfer] |
+----------------------------------------+ +----------------------------------------+
Obtaining the TLS Client Hello Message with GoLang
Here's how to implement a server that captures all ClientHello messages using GoLang:
Certificate Generation
First, generate the necessary SSL certificates:
# Generate a private key
openssl genrsa -out server.key 2048
# Generate a public key (certificate)
openssl req -new -x509 -key server.key -out server.pem -days 3650
Server Implementation
The following is the complete server code for capturing ClientHello information:
package main
import (
"bufio"
"crypto/tls"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"sync"
"time"
)
type CollectInfos struct {
ClientHellos []*tls.ClientHelloInfo
sync.Mutex
}
var collectInfos CollectInfos
var currentClientHello *tls.ClientHelloInfo
func (c *CollectInfos) collectClientHello(clientHello *tls.ClientHelloInfo) {
c.Lock()
defer c.Unlock()
c.ClientHellos = append(c.ClientHellos, clientHello)
}
func (c *CollectInfos) DumpInfo() {
c.Lock()
defer c.Unlock()
data, err := json.Marshal(c.ClientHellos)
if err != nil {
log.Fatal(err)
}
ioutil.WriteFile("hello.json", data, os.ModePerm)
}
func getCert() *tls.Certificate {
cert, err := tls.LoadX509KeyPair("server.pem", "server.key")
if err != nil {
log.Println(err)
return nil
}
return &cert
}
func buildTlsConfig(cert *tls.Certificate) *tls.Config {
cfg := &tls.Config{
Certificates: []tls.Certificate{*cert},
GetConfigForClient: func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
collectInfos.collectClientHello(clientHello)
currentClientHello = clientHello
return nil, nil
},
}
return cfg
}
func serve(cfg *tls.Config) {
ln, err := tls.Listen("tcp", ":443", cfg)
if err != nil {
log.Println(err)
return
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
continue
}
go handler(conn)
}
}
func handler(conn net.Conn) {
defer conn.Close()
r := bufio.NewReader(conn)
for {
msg, err := r.ReadString('\n')
if err != nil {
log.Println(err)
return
}
fmt.Println(msg)
data, err := json.Marshal(currentClientHello)
if err != nil {
log.Fatal(err)
}
_, err = conn.Write(data)
if err != nil {
log.Println(err)
return
}
}
}
func main() {
go func() {
for {
collectInfos.DumpInfo()
time.Sleep(10 * time.Second)
}
}()
cert := getCert()
if cert != nil {
serve(buildTlsConfig(cert))
}
}
Client Implementation
The corresponding client code is as follows:
func main() {
conn, err := tls.Dial("tcp", "localhost:443", &tls.Config{InsecureSkipVerify: true})
if err != nil {
log.Fatal(err)
}
defer conn.Close()
_, err = conn.Write([]byte("hello\n"))
if err != nil {
log.Fatal(err)
}
buf := make([]byte, 1000)
n, err := conn.Read(buf)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(buf[:n]))
}
This implementation enables you to capture detailed information from ClientHello messages during the TLS handshake process. The server periodically exports this information to a JSON file for analysis.
Leapcell: The Best of Serverless Web Hosting
Finally, recommend a platform that is most suitable for deploying Go services: Leapcell
🚀 Build with Your Favorite Language
Develop effortlessly in JavaScript, Python, Go, or Rust.
🌍 Deploy Unlimited Projects for Free
Only pay for what you use—no charges when there are no requests.
⚡ Pay - as - You - Go, No Hidden Costs
No idle fees, just seamless scalability.
🔹 Follow us on Twitter: @LeapcellHQ
Top comments (0)