Documentation
¶
Overview ¶
Package tlsfingerprint provides TLS client fingerprinting capabilities. It can parse TLS ClientHello messages and generate both JA3 and JA4 fingerprints for identifying and categorizing TLS clients.
The package supports extracting cipher suites, extensions, supported groups, ALPN protocols, signature algorithms, and other handshake parameters from TLS connections. It can compute both JA3 fingerprints (with MD5 hashes) and JA4 fingerprints (with SHA256 hashes) for fingerprinting purposes.
Example ¶
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"math/big"
"net"
"time"
"github.com/psanford/tlsfingerprint"
)
func main() {
cert, err := generateCertificate()
if err != nil {
log.Fatal(err)
}
ln, err := net.Listen("tcp", ":8443")
if err != nil {
log.Fatal(err)
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
log.Fatal(err)
}
go handleConnection(conn, cert)
}
}
func handleConnection(conn net.Conn, cert tls.Certificate) {
defer conn.Close()
fp, wrappedConn, err := tlsfingerprint.FingerprintConn(conn)
if err != nil {
log.Printf("Fingerprint error: %v", err)
return
}
fmt.Printf("JA3 Hash: %s\n", fp.JA3Hash())
fmt.Printf("JA3 String: %s\n", fp.JA3String())
fmt.Printf("JA4: %s\n", fp.JA4String())
fmt.Printf("TLS Version: 0x%04x\n", fp.Version)
fmt.Printf("Cipher Suites: %d\n", len(fp.CipherSuites))
fmt.Printf("Extensions: %d\n", len(fp.Extensions))
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
tlsConn := tls.Server(wrappedConn, tlsConfig)
if err := tlsConn.Handshake(); err != nil {
log.Printf("TLS handshake error: %v", err)
return
}
}
func generateCertificate() (tls.Certificate, error) {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return tls.Certificate{}, err
}
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
if err != nil {
return tls.Certificate{}, err
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Example"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
return tls.Certificate{}, err
}
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return tls.Certificate{}, err
}
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
return tls.X509KeyPair(certPEM, keyPEM)
}
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Fingerprint ¶
type Fingerprint struct {
// Version is the negotiated TLS version, potentially from the supported_versions extension.
Version uint16
// CipherSuites is the list of cipher suites advertised by the client.
CipherSuites []uint16
// Extensions is the list of TLS extensions present in the ClientHello.
Extensions []uint16
// SupportedGroups is the list of elliptic curves and DH groups supported by the client.
SupportedGroups []uint16
// SupportedPoints is the list of EC point formats supported by the client.
SupportedPoints []uint8
// RawVersion is the TLS version from the ClientHello header (will never be > TLS 1.2).
RawVersion uint16
// ALPNProtocols is the list of ALPN protocols advertised by the client.
ALPNProtocols []string
// SignatureAlgorithms is the list of signature algorithms supported by the client.
SignatureAlgorithms []uint16
// HasSNI indicates whether the SNI extension is present.
HasSNI bool
}
Fingerprint represents a TLS client fingerprint extracted from a ClientHello message. It contains the negotiated TLS version, cipher suites, extensions, and other parameters used to uniquely identify TLS clients.
func FingerprintConn ¶
FingerprintConn reads and parses the TLS ClientHello from a connection without consuming it. It returns the extracted Fingerprint, a wrapped connection that replays the buffered data, and any error encountered. The returned connection can be used for the TLS handshake as if nothing was read from it.
func ParseClientHello ¶
func ParseClientHello(data []byte) (*Fingerprint, error)
ParseClientHello parses a TLS ClientHello message and extracts fingerprint information. The data parameter should contain the complete TLS record including the record header. It returns a Fingerprint containing the client's TLS parameters, or an error if parsing fails.
func (*Fingerprint) JA3Hash ¶
func (f *Fingerprint) JA3Hash() string
JA3Hash computes the MD5 hash of the JA3 fingerprint string. This produces a 32-character hexadecimal string that uniquely identifies the client's TLS configuration in a compact form.
func (*Fingerprint) JA3String ¶
func (f *Fingerprint) JA3String() string
JA3String generates the JA3 fingerprint string for this TLS fingerprint. The JA3 string is a comma-separated list of TLS parameters in the format: SSLVersion,Ciphers,Extensions,EllipticCurves,EllipticCurvePointFormats. GREASE values are filtered out per the JA3 specification.
func (*Fingerprint) JA4String ¶
func (f *Fingerprint) JA4String() string
JA4String generates the JA4 fingerprint string for this TLS fingerprint. The JA4 string follows the format: [protocol][version][sni][cipher_count][extension_count][alpn]_[cipher_hash]_[extension_hash] For example: t13d1516h2_8daaf6152771_e5627efa2ab1
func (*Fingerprint) MarshalJSON ¶
func (f *Fingerprint) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler for Fingerprint. It produces a JSON representation with human-readable names for cipher suites, extensions, and supported groups, along with JA3 and JA4 fingerprints.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
lowlevelhttpserver
command
|
|
|
webserver
command
|
|
|
Package fingerprintlistener provides a net.Listener wrapper that automatically extracts TLS fingerprints from incoming connections.
|
Package fingerprintlistener provides a net.Listener wrapper that automatically extracts TLS fingerprints from incoming connections. |
|
Package httpfingerprint provides an HTTP server wrapper that automatically extracts TLS fingerprints from client connections and makes them available through the request context.
|
Package httpfingerprint provides an HTTP server wrapper that automatically extracts TLS fingerprints from client connections and makes them available through the request context. |