hellosplitter

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2021 License: Apache-2.0 Imports: 8 Imported by: 1

README

hellosplitter

A package for splitting TLS ClientHello messages across multiple TCP packets.

Documentation

Overview

Package hellosplitter is used to split TLS ClientHello messages across multiple TCP packets. To achieve this, use hellosplitter's Conn as a transport in a TLS client connection.

Example
package main

import (
	"crypto/tls"
	"fmt"
	"net"
	"os"
)

func main() {
	s, err := startTLSHandshakeServer()
	if err != nil {
		panic(err)
	}
	tcpConn, err := net.Dial("tcp", s.Addr())
	if err != nil {
		panic(err)
	}
	tcpConn = Wrap(tcpConn, func(b []byte) [][]byte {
		splits := make([][]byte, 2)
		splits[0], splits[1] = b[:len(b)/2], b[len(b)/2:]
		return splits
	})
	tlsConn := tls.Client(tcpConn, &tls.Config{InsecureSkipVerify: true})
	defer tlsConn.Close()
	if err := tlsConn.Handshake(); err != nil {
		panic(err)
	}
}

// Conducts a handshake with any incoming TLS client connections.
type tlsHandshakeServer struct {
	l net.Listener
}

func startTLSHandshakeServer() (*tlsHandshakeServer, error) {
	l, err := tls.Listen("tcp", "", &tls.Config{Certificates: []tls.Certificate{cert}})
	if err != nil {
		return nil, fmt.Errorf("failed to start TLS listener: %w", err)
	}
	go func() {
		for {
			conn, err := l.Accept()
			if err != nil {
				fmt.Fprintln(os.Stderr, "server: accept error:", err)
				return
			}
			if err := conn.(*tls.Conn).Handshake(); err != nil {
				fmt.Fprintln(os.Stderr, "server: handshake error:", err)
			}
			conn.Close()
		}
	}()
	return &tlsHandshakeServer{l}, nil
}

func (ths tlsHandshakeServer) Addr() string {
	return ths.l.Addr().String()
}

func (ths tlsHandshakeServer) Close() error {
	return ths.l.Close()
}

var (
	certPem = []byte(`-----BEGIN CERTIFICATE-----
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
6MF9+Yw1Yy0t
-----END CERTIFICATE-----`)
	keyPem = []byte(`-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
-----END EC PRIVATE KEY-----`)

	cert tls.Certificate
)

func init() {
	var err error
	cert, err = tls.X509KeyPair(certPem, keyPem)
	if err != nil {
		panic(err)
	}
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BufferedWriteError

type BufferedWriteError struct {
	BufferedData []byte

	// Written is the number of bytes from BufferedData which were successfully written to the
	// underlying transport.
	Written int
	// contains filtered or unexported fields
}

A BufferedWriteError occurs when a Conn attempts to write buffered data and fails.

func (BufferedWriteError) Error

func (err BufferedWriteError) Error() string

func (BufferedWriteError) Unwrap

func (err BufferedWriteError) Unwrap() error

Unwrap supports Go 1.13-style error unwrapping.

type Conn

type Conn struct {
	net.Conn
	// contains filtered or unexported fields
}

Conn is intended for use as a transport in a TLS client connection. When Conn is used in this manner, the ClientHello will be split across multiple TCP packets. The ClientHello should be the first record written to this connection.

func Wrap

func Wrap(conn net.Conn, f SplitFunc) *Conn

Wrap the input connection with a hello-splitting connection. The ClientHello should be the first record written to the returned connection.

If conn is a *net.TCPConn, then TCP_NODELAY will be configured on the connection. This is a requirement for splitting the ClientHello. To override this behavior for transmissions after the ClientHello, use Conn.SetNoDelay.

If conn is not a *net.TCPConn, it must mimic TCP_NODELAY (sending packets as soon as they are ready). If the host OS does not support TCP_NODELAY, hello-splitting may not function as desired.

func (*Conn) SetNoDelay

func (c *Conn) SetNoDelay(noDelay bool) error

SetNoDelay behaves like net.TCPConn.SetNoDelay except that the choice only applies after the ClientHello. Until the ClientHello is set, TCP_NODELAY will always be used.

This is a no-op if the underlying transport is not a *net.TCPConn.

func (*Conn) Write

func (c *Conn) Write(b []byte) (n int, err error)

type HelloParsingError

type HelloParsingError struct {
	BufferedData []byte
	// contains filtered or unexported fields
}

A HelloParsingError occurs when a Conn fails to parse buffered data as a ClientHello.

func (HelloParsingError) Error

func (err HelloParsingError) Error() string

func (HelloParsingError) Unwrap

func (err HelloParsingError) Unwrap() error

Unwrap supports Go 1.13-style error unwrapping.

type SplitFunc

type SplitFunc func([]byte) [][]byte

A SplitFunc defines how a ClientHello is split.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL