DEV Community

Cover image for Complete TLS Workflow in Golang Made Simple: Full Process Explained
Leapcell
Leapcell

Posted on

3 1 1 1 1

Complete TLS Workflow in Golang Made Simple: Full Process Explained

Image description

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:

  1. 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).
  2. 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).
  3. 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.
  4. 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.
  5. 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.
  6. Session Keys Creation

    • Using the Master Secret, both parties create:
      • Encryption keys for symmetric encryption.
      • MAC (Message Authentication Code) keys for integrity checks.
  7. 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.
  8. 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.
  9. 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]             |
+----------------------------------------+      +----------------------------------------+
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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))
    }
}
Enter fullscreen mode Exit fullscreen mode

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]))
}
Enter fullscreen mode Exit fullscreen mode

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

Image description

🚀 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.

Image description

📖 Explore Our Documentation

🔹 Follow us on Twitter: @LeapcellHQ

Top comments (0)