Skip to content

Latest commit

History

47 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

clienthellod: TLS ClientHello/QUIC Initial Packet reflection service

Go Build StatusGo Report CardFOSSA StatusGo Doc

clienthellod, read as "client-hello-D", is a TLS ClientHello/QUIC Initial Packet reflection service. It can be used to parses TLS ClientHello messages and QUIC Initial Packets into human-readable and highly programmable formats such as JSON.

Is is a part of the TLS fingerprintability research project which spans tlsfingerprint.io and quic.tlsfingerprint.io. It parses the ClientHello messages sent by TLS clients and QUIC Client Initial Packets sent by QUIC clients and display the parsed information in a human-readable format with high programmability.

See tlsfingerprint.io and quic.tlsfingerprint.io for more details about the project.

Quick Start

clienthellod comes as a Go library, which can be used to parse both TLS and QUIC protocols.

TLS/QUIC Fingerprinter

tlsFingerprinter:=clienthellod.NewTLSFingerprinter()
quicFingerprinter:=clienthellod.NewQUICFingerprinter()

TLS ClientHello

From a net.Conn

tcpLis, err:=net.Listen("tcp", ":443")
defertcpLis.Close()
conn, err:=tcpLis.Accept()
iferr!=nil {
panic(err)
}
deferconn.Close()
ch, err:=clienthellod.ReadClientHello(conn) // reads ClientHello from the connectioniferr!=nil {
panic(err)
}
err:=ch.ParseClientHello() // parses ClientHello's fieldsiferr!=nil {
panic(err)
}
jsonB, err=json.MarshalIndent(ch, "", " ")
iferr!=nil {
panic(err)
}
fmt.Println(string(jsonB))
fmt.Println("ClientHello ID: "+ch.HexID) // prints ClientHello's original fingerprint ID calculated using observed TLS extension orderfmt.Println("ClientHello NormID: "+ch.NormHexID) // prints ClientHello's normalized fingerprint ID calculated using sorted TLS extension list

From raw []byte

ch, err:=clienthellod.UnmarshalClientHello(raw)
iferr!=nil {
panic(err)
}
// err := ch.ParseClientHello() // no need to call again, UnmarshalClientHello automatically calls ParseClientHello

QUIC Initial Packets (Client-sourced)

Single packet

udpConn, err:=net.ListenUDP("udp", ":443")
deferudpConn.Close()
buf:=make([]byte, 65535)
n, addr, err:=udpConn.ReadFromUDP(buf)
iferr!=nil {
panic(err)
}
ci, err:=clienthellod.UnmarshalQUICClientInitialPacket(buf[:n]) // decodes QUIC Client Initial Packetiferr!=nil {
panic(err) }
jsonB, err=json.MarshalIndent(cip, "", " ")
iferr!=nil {
panic(err)
}
fmt.Println(string(jsonB)) // including fingerprint IDs of: ClientInitialPacket, QUIC Header, QUIC ClientHello, QUIC Transport Parameters' combination

Multiple packets

Implementations including Chrome/Chromium sends oversized Client Hello which does not fit into one single QUIC packet, in which case multiple QUIC Initial Packets are sent.

gci:=GatherClientInitials() // Each GatherClientInitials reassembles one QUIC Client Initial Packets stream. Use a QUIC Fingerprinter for multiple potential senders, which automatically demultiplexes the packets based on the source address.udpConn, err:=net.ListenUDP("udp", ":443")
deferudpConn.Close()
for {
buf:=make([]byte, 65535)
n, addr, err:=udpConn.ReadFromUDP(buf)
iferr!=nil {
panic(err)
}
ifaddr!=knownSenderAddr {
continue
}
ci, err:=clienthellod.UnmarshalQUICClientInitialPacket(buf[:n]) // decodes QUIC Client Initial Packetiferr!=nil {
panic(err) }
err=gci.AddPacket(ci)
iferr!=nil {
panic(err)
}
}

Use with Caddy

We also provide clienthellod as a Caddy Module in modcaddy, which you can use with Caddy to capture ClientHello messages and QUIC Client Initial Packets. See modcaddy for more details.

License

This project is developed and distributed under Apache-2.0 license.

FOSSA Status

About

TLS ClientHello/QUIC Initial Packet reflection service

Topics

Resources

Security policy

Stars

28 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages