refacto
							parent
							
								
									d6d9f8a111
								
							
						
					
					
						commit
						549437b355
					
				
							
								
								
									
										207
									
								
								d4-tlsf.go
								
								
								
								
							
							
						
						
									
										207
									
								
								d4-tlsf.go
								
								
								
								
							| 
						 | 
					@ -2,13 +2,10 @@ package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"crypto/md5"
 | 
					 | 
				
			||||||
	"crypto/sha256"
 | 
					 | 
				
			||||||
	"crypto/x509"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO consider
 | 
						// TODO consider
 | 
				
			||||||
	//"github.com/google/certificate-transparency-go/x509"
 | 
						//"github.com/google/certificate-transparency-go/x509"
 | 
				
			||||||
	"encoding/hex"
 | 
					
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"flag"
 | 
						"flag"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
| 
						 | 
					@ -17,12 +14,10 @@ import (
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/signal"
 | 
						"os/signal"
 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/glaslos/tlsh"
 | 
					 | 
				
			||||||
	"github.com/google/gopacket"
 | 
						"github.com/google/gopacket"
 | 
				
			||||||
	"github.com/google/gopacket/examples/util"
 | 
						"github.com/google/gopacket/examples/util"
 | 
				
			||||||
	"github.com/google/gopacket/ip4defrag"
 | 
						"github.com/google/gopacket/ip4defrag"
 | 
				
			||||||
| 
						 | 
					@ -30,6 +25,7 @@ import (
 | 
				
			||||||
	"github.com/google/gopacket/pcap"
 | 
						"github.com/google/gopacket/pcap"
 | 
				
			||||||
	"github.com/google/gopacket/reassembly"
 | 
						"github.com/google/gopacket/reassembly"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/D4-project/sensor-d4-tls-fingerprinting/d4tls"
 | 
				
			||||||
	"github.com/D4-project/sensor-d4-tls-fingerprinting/etls"
 | 
						"github.com/D4-project/sensor-d4-tls-fingerprinting/etls"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,38 +48,7 @@ var fname = flag.String("r", "", "Filename to read from, overrides -i")
 | 
				
			||||||
// writing
 | 
					// writing
 | 
				
			||||||
var outCerts = flag.String("w", "", "Folder to write certificates into")
 | 
					var outCerts = flag.String("w", "", "Folder to write certificates into")
 | 
				
			||||||
var outJSON = flag.String("j", "", "Folder to write certificates into, stdin if not set")
 | 
					var outJSON = flag.String("j", "", "Folder to write certificates into, stdin if not set")
 | 
				
			||||||
var jobQ chan TLSSession
 | 
					var jobQ chan d4tls.TLSSession
 | 
				
			||||||
 | 
					 | 
				
			||||||
type CertMapElm struct {
 | 
					 | 
				
			||||||
	CertHash string
 | 
					 | 
				
			||||||
	*x509.Certificate
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type SessionRecord struct {
 | 
					 | 
				
			||||||
	ServerIP     string
 | 
					 | 
				
			||||||
	ServerPort   string
 | 
					 | 
				
			||||||
	ClientIP     string
 | 
					 | 
				
			||||||
	ClientPort   string
 | 
					 | 
				
			||||||
	TLSH         string
 | 
					 | 
				
			||||||
	Timestamp    time.Time
 | 
					 | 
				
			||||||
	JA3          string
 | 
					 | 
				
			||||||
	JA3Digest    string
 | 
					 | 
				
			||||||
	JA3S         string
 | 
					 | 
				
			||||||
	JA3SDigest   string
 | 
					 | 
				
			||||||
	Certificates []CertMapElm
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type TLSSession struct {
 | 
					 | 
				
			||||||
	record   SessionRecord
 | 
					 | 
				
			||||||
	tlsHdskR etls.ETLSHandshakeRecord
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var grease = map[uint16]bool{
 | 
					 | 
				
			||||||
	0x0a0a: true, 0x1a1a: true, 0x2a2a: true, 0x3a3a: true,
 | 
					 | 
				
			||||||
	0x4a4a: true, 0x5a5a: true, 0x6a6a: true, 0x7a7a: true,
 | 
					 | 
				
			||||||
	0x8a8a: true, 0x9a9a: true, 0xaaaa: true, 0xbaba: true,
 | 
					 | 
				
			||||||
	0xcaca: true, 0xdada: true, 0xeaea: true, 0xfafa: true,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const closeTimeout time.Duration = time.Hour * 24 // Closing inactive: TODO: from CLI
 | 
					const closeTimeout time.Duration = time.Hour * 24 // Closing inactive: TODO: from CLI
 | 
				
			||||||
const timeout time.Duration = time.Minute * 5     // Pending bytes: TODO: from CLI
 | 
					const timeout time.Duration = time.Minute * 5     // Pending bytes: TODO: from CLI
 | 
				
			||||||
| 
						 | 
					@ -93,27 +58,6 @@ var errorsMap map[string]uint
 | 
				
			||||||
var errorsMapMutex sync.Mutex
 | 
					var errorsMapMutex sync.Mutex
 | 
				
			||||||
var errors uint
 | 
					var errors uint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (t *TLSSession) String() string {
 | 
					 | 
				
			||||||
	var buf bytes.Buffer
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("---------------SESSION START-------------------\n"))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("Time: %d\n", t.record.Timestamp))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("Client: %v:%v\n", t.record.ClientIP, t.record.ClientPort))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("Server: %v:%v\n", t.record.ServerIP, t.record.ServerPort))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("TLSH: %q\n", t.record.TLSH))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("ja3: %q\n", t.record.JA3))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("ja3 Digest: %q\n", t.record.JA3Digest))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("ja3s: %q\n", t.record.JA3S))
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("ja3s Digest: %q\n", t.record.JA3SDigest))
 | 
					 | 
				
			||||||
	for _, certMe := range t.record.Certificates {
 | 
					 | 
				
			||||||
		buf.WriteString(fmt.Sprintf("Certificate Issuer: %q\n", certMe.Certificate.Issuer))
 | 
					 | 
				
			||||||
		buf.WriteString(fmt.Sprintf("Certificate Subject: %q\n", certMe.Certificate.Subject))
 | 
					 | 
				
			||||||
		buf.WriteString(fmt.Sprintf("Certificate is CA: %t\n", certMe.Certificate.IsCA))
 | 
					 | 
				
			||||||
		buf.WriteString(fmt.Sprintf("Certificate SHA256: %t\n", certMe.CertHash))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	buf.WriteString(fmt.Sprintf("---------------SESSION  END--------------------\n"))
 | 
					 | 
				
			||||||
	return buf.String()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Too bad for perf that a... is evaluated
 | 
					// Too bad for perf that a... is evaluated
 | 
				
			||||||
func Error(t string, s string, a ...interface{}) {
 | 
					func Error(t string, s string, a ...interface{}) {
 | 
				
			||||||
	errorsMapMutex.Lock()
 | 
						errorsMapMutex.Lock()
 | 
				
			||||||
| 
						 | 
					@ -155,6 +99,7 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T
 | 
				
			||||||
		tcpstate:   reassembly.NewTCPSimpleFSM(fsmOptions),
 | 
							tcpstate:   reassembly.NewTCPSimpleFSM(fsmOptions),
 | 
				
			||||||
		ident:      fmt.Sprintf("%s:%s", net, transport),
 | 
							ident:      fmt.Sprintf("%s:%s", net, transport),
 | 
				
			||||||
		optchecker: reassembly.NewTCPOptionCheck(),
 | 
							optchecker: reassembly.NewTCPOptionCheck(),
 | 
				
			||||||
 | 
							tlsSession: d4tls.TLSSession{},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return stream
 | 
						return stream
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -188,7 +133,7 @@ type tcpStream struct {
 | 
				
			||||||
	reversed       bool
 | 
						reversed       bool
 | 
				
			||||||
	urls           []string
 | 
						urls           []string
 | 
				
			||||||
	ident          string
 | 
						ident          string
 | 
				
			||||||
	tlsSession     TLSSession
 | 
						tlsSession     d4tls.TLSSession
 | 
				
			||||||
	sync.Mutex
 | 
						sync.Mutex
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -258,32 +203,19 @@ func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass
 | 
				
			||||||
						switch tlsrecord.ETLSHandshakeMsgType {
 | 
											switch tlsrecord.ETLSHandshakeMsgType {
 | 
				
			||||||
						// Client Hello
 | 
											// Client Hello
 | 
				
			||||||
						case 1:
 | 
											case 1:
 | 
				
			||||||
							t.tlsSession.tlsHdskR.ETLSHandshakeClientHello = tlsrecord.ETLSHandshakeClientHello
 | 
					 | 
				
			||||||
							t.tlsSession.record.ClientIP, t.tlsSession.record.ServerIP, t.tlsSession.record.ClientPort, t.tlsSession.record.ServerPort = getIPPorts(t)
 | 
					 | 
				
			||||||
							// Set up first seen
 | 
					 | 
				
			||||||
							info := sg.CaptureInfo(0)
 | 
												info := sg.CaptureInfo(0)
 | 
				
			||||||
							t.tlsSession.record.Timestamp = info.Timestamp
 | 
												cip, sip, cp, sp := getIPPorts(t)
 | 
				
			||||||
							t.tlsSession.gatherJa3()
 | 
												t.tlsSession.PopulateClientHello(tlsrecord.ETLSHandshakeClientHello, cip, sip, cp, sp, info.Timestamp)
 | 
				
			||||||
 | 
												t.tlsSession.D4Fingerprinting("ja3")
 | 
				
			||||||
						// Server Hello
 | 
											// Server Hello
 | 
				
			||||||
						case 2:
 | 
											case 2:
 | 
				
			||||||
							t.tlsSession.tlsHdskR.ETLSHandshakeServerHello = tlsrecord.ETLSHandshakeServerHello
 | 
												t.tlsSession.PopulateServerHello(tlsrecord.ETLSHandshakeServerHello)
 | 
				
			||||||
							t.tlsSession.gatherJa3s()
 | 
												t.tlsSession.D4Fingerprinting("ja3s")
 | 
				
			||||||
						// Server Certificate
 | 
											// Server Certificate
 | 
				
			||||||
						case 11:
 | 
											case 11:
 | 
				
			||||||
							for _, asn1Data := range tlsrecord.ETLSHandshakeCertificate.Certificates {
 | 
												t.tlsSession.PopulateCertificate(tlsrecord.ETLSHandshakeCertificate)
 | 
				
			||||||
								cert, err := x509.ParseCertificate(asn1Data)
 | 
					 | 
				
			||||||
								if err != nil {
 | 
					 | 
				
			||||||
									Error("tls", "Failed to parse certificate from server: %x", err)
 | 
					 | 
				
			||||||
								} else {
 | 
					 | 
				
			||||||
									h := sha256.New()
 | 
					 | 
				
			||||||
									h.Write(cert.Raw)
 | 
					 | 
				
			||||||
									t.tlsSession.record.Certificates = append(t.tlsSession.record.Certificates, CertMapElm{Certificate: cert, CertHash: fmt.Sprintf("%x", h.Sum(nil))})
 | 
					 | 
				
			||||||
								}
 | 
					 | 
				
			||||||
							}
 | 
					 | 
				
			||||||
							// We compute ja3jl
 | 
					 | 
				
			||||||
							out, _ := tlsh.HashBytes(t.tlsSession.record.ja3jl())
 | 
					 | 
				
			||||||
							t.tlsSession.record.TLSH = out.String()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												t.tlsSession.D4Fingerprinting("tlsh")
 | 
				
			||||||
							// If we get a cert, we consider the handshake as finished and ready to ship to D4
 | 
												// If we get a cert, we consider the handshake as finished and ready to ship to D4
 | 
				
			||||||
							queueSession(t.tlsSession)
 | 
												queueSession(t.tlsSession)
 | 
				
			||||||
						default:
 | 
											default:
 | 
				
			||||||
| 
						 | 
					@ -306,107 +238,6 @@ func getIPPorts(t *tcpStream) (string, string, string, string) {
 | 
				
			||||||
	return ipc, ips, cp, ps
 | 
						return ipc, ips, cp, ps
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (sr *SessionRecord) ja3jl() []byte {
 | 
					 | 
				
			||||||
	buf := sr.JA3 + sr.JA3S
 | 
					 | 
				
			||||||
	for _, cert := range sr.Certificates {
 | 
					 | 
				
			||||||
		buf += fmt.Sprintf("%q", cert.Issuer) + fmt.Sprintf("%q", cert.Subject)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	buf = strings.Replace(buf, "-", "", -1)
 | 
					 | 
				
			||||||
	buf = strings.Replace(buf, ",", "", -1)
 | 
					 | 
				
			||||||
	buf = strings.Replace(buf, "\"", "", -1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return []byte(buf)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ts *TLSSession) gatherJa3s() bool {
 | 
					 | 
				
			||||||
	var buf []byte
 | 
					 | 
				
			||||||
	buf = strconv.AppendInt(buf, int64(ts.tlsHdskR.ETLSHandshakeServerHello.Vers), 10)
 | 
					 | 
				
			||||||
	// byte (44) is ","
 | 
					 | 
				
			||||||
	buf = append(buf, byte(44))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If there are Cipher Suites
 | 
					 | 
				
			||||||
	buf = strconv.AppendInt(buf, int64(ts.tlsHdskR.ETLSHandshakeServerHello.CipherSuite), 10)
 | 
					 | 
				
			||||||
	buf = append(buf, byte(44))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If there are extensions
 | 
					 | 
				
			||||||
	if len(ts.tlsHdskR.ETLSHandshakeServerHello.AllExtensions) > 0 {
 | 
					 | 
				
			||||||
		for i, e := range ts.tlsHdskR.ETLSHandshakeServerHello.AllExtensions {
 | 
					 | 
				
			||||||
			// TODO check this grease thingy
 | 
					 | 
				
			||||||
			if grease[uint16(e)] == false {
 | 
					 | 
				
			||||||
				buf = strconv.AppendInt(buf, int64(e), 10)
 | 
					 | 
				
			||||||
				if (i + 1) < len(ts.tlsHdskR.ETLSHandshakeServerHello.AllExtensions) {
 | 
					 | 
				
			||||||
					// byte(45) is "-"
 | 
					 | 
				
			||||||
					buf = append(buf, byte(45))
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ts.record.JA3S = string(buf)
 | 
					 | 
				
			||||||
	tmp := md5.Sum(buf)
 | 
					 | 
				
			||||||
	ts.record.JA3SDigest = hex.EncodeToString(tmp[:])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ts *TLSSession) gatherJa3() bool {
 | 
					 | 
				
			||||||
	var buf []byte
 | 
					 | 
				
			||||||
	buf = strconv.AppendInt(buf, int64(ts.tlsHdskR.ETLSHandshakeClientHello.Vers), 10)
 | 
					 | 
				
			||||||
	// byte (44) is ","
 | 
					 | 
				
			||||||
	buf = append(buf, byte(44))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If there are Cipher Suites
 | 
					 | 
				
			||||||
	if len(ts.tlsHdskR.ETLSHandshakeClientHello.CipherSuites) > 0 {
 | 
					 | 
				
			||||||
		for i, cs := range ts.tlsHdskR.ETLSHandshakeClientHello.CipherSuites {
 | 
					 | 
				
			||||||
			buf = strconv.AppendInt(buf, int64(cs), 10)
 | 
					 | 
				
			||||||
			// byte(45) is "-"
 | 
					 | 
				
			||||||
			if (i + 1) < len(ts.tlsHdskR.ETLSHandshakeClientHello.CipherSuites) {
 | 
					 | 
				
			||||||
				buf = append(buf, byte(45))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	buf = append(buf, byte(44))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If there are extensions
 | 
					 | 
				
			||||||
	if len(ts.tlsHdskR.ETLSHandshakeClientHello.AllExtensions) > 0 {
 | 
					 | 
				
			||||||
		for i, e := range ts.tlsHdskR.ETLSHandshakeClientHello.AllExtensions {
 | 
					 | 
				
			||||||
			// TODO check this grease thingy
 | 
					 | 
				
			||||||
			if grease[uint16(e)] == false {
 | 
					 | 
				
			||||||
				buf = strconv.AppendInt(buf, int64(e), 10)
 | 
					 | 
				
			||||||
				if (i + 1) < len(ts.tlsHdskR.ETLSHandshakeClientHello.AllExtensions) {
 | 
					 | 
				
			||||||
					buf = append(buf, byte(45))
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	buf = append(buf, byte(44))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If there are Supported Curves
 | 
					 | 
				
			||||||
	if len(ts.tlsHdskR.ETLSHandshakeClientHello.SupportedCurves) > 0 {
 | 
					 | 
				
			||||||
		for i, cs := range ts.tlsHdskR.ETLSHandshakeClientHello.SupportedCurves {
 | 
					 | 
				
			||||||
			buf = strconv.AppendInt(buf, int64(cs), 10)
 | 
					 | 
				
			||||||
			if (i + 1) < len(ts.tlsHdskR.ETLSHandshakeClientHello.SupportedCurves) {
 | 
					 | 
				
			||||||
				buf = append(buf, byte(45))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	buf = append(buf, byte(44))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If there are Supported Points
 | 
					 | 
				
			||||||
	if len(ts.tlsHdskR.ETLSHandshakeClientHello.SupportedPoints) > 0 {
 | 
					 | 
				
			||||||
		for i, cs := range ts.tlsHdskR.ETLSHandshakeClientHello.SupportedPoints {
 | 
					 | 
				
			||||||
			buf = strconv.AppendInt(buf, int64(cs), 10)
 | 
					 | 
				
			||||||
			if (i + 1) < len(ts.tlsHdskR.ETLSHandshakeClientHello.SupportedPoints) {
 | 
					 | 
				
			||||||
				buf = append(buf, byte(45))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ts.record.JA3 = string(buf)
 | 
					 | 
				
			||||||
	tmp := md5.Sum(buf)
 | 
					 | 
				
			||||||
	ts.record.JA3Digest = hex.EncodeToString(tmp[:])
 | 
					 | 
				
			||||||
	return true
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (t *tcpStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool {
 | 
					func (t *tcpStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool {
 | 
				
			||||||
	Debug("%s: Connection closed\n", t.ident)
 | 
						Debug("%s: Connection closed\n", t.ident)
 | 
				
			||||||
	// do not remove the connection to allow last ACK
 | 
						// do not remove the connection to allow last ACK
 | 
				
			||||||
| 
						 | 
					@ -465,7 +296,7 @@ func main() {
 | 
				
			||||||
	signal.Notify(signalChan, os.Interrupt)
 | 
						signal.Notify(signalChan, os.Interrupt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Job chan to hold Completed sessions to write
 | 
						// Job chan to hold Completed sessions to write
 | 
				
			||||||
	jobQ = make(chan TLSSession, 100)
 | 
						jobQ = make(chan d4tls.TLSSession, 100)
 | 
				
			||||||
	cancelC := make(chan string)
 | 
						cancelC := make(chan string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// We start a worker to send the processed TLS connection the outside world
 | 
						// We start a worker to send the processed TLS connection the outside world
 | 
				
			||||||
| 
						 | 
					@ -543,7 +374,7 @@ func main() {
 | 
				
			||||||
	w.Wait()
 | 
						w.Wait()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func processCompletedSession(jobQ <-chan TLSSession, w *sync.WaitGroup) {
 | 
					func processCompletedSession(jobQ <-chan d4tls.TLSSession, w *sync.WaitGroup) {
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		tlss, more := <-jobQ
 | 
							tlss, more := <-jobQ
 | 
				
			||||||
		if more {
 | 
							if more {
 | 
				
			||||||
| 
						 | 
					@ -556,7 +387,7 @@ func processCompletedSession(jobQ <-chan TLSSession, w *sync.WaitGroup) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Tries to enqueue or false
 | 
					// Tries to enqueue or false
 | 
				
			||||||
func queueSession(t TLSSession) bool {
 | 
					func queueSession(t d4tls.TLSSession) bool {
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
	case jobQ <- t:
 | 
						case jobQ <- t:
 | 
				
			||||||
		return true
 | 
							return true
 | 
				
			||||||
| 
						 | 
					@ -565,14 +396,14 @@ func queueSession(t TLSSession) bool {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func output(t TLSSession) {
 | 
					func output(t d4tls.TLSSession) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jsonRecord, _ := json.MarshalIndent(t.record, "", "    ")
 | 
						jsonRecord, _ := json.MarshalIndent(t.Record, "", "    ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If an output folder was specified for certificates
 | 
						// If an output folder was specified for certificates
 | 
				
			||||||
	if *outCerts != "" {
 | 
						if *outCerts != "" {
 | 
				
			||||||
		if _, err := os.Stat(fmt.Sprintf("./%s", *outCerts)); !os.IsNotExist(err) {
 | 
							if _, err := os.Stat(fmt.Sprintf("./%s", *outCerts)); !os.IsNotExist(err) {
 | 
				
			||||||
			for _, certMe := range t.record.Certificates {
 | 
								for _, certMe := range t.Record.Certificates {
 | 
				
			||||||
				err := ioutil.WriteFile(fmt.Sprintf("./%s/%s.crt", *outCerts, certMe.CertHash), certMe.Certificate.Raw, 0644)
 | 
									err := ioutil.WriteFile(fmt.Sprintf("./%s/%s.crt", *outCerts, certMe.CertHash), certMe.Certificate.Raw, 0644)
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					panic("Could not write to file.")
 | 
										panic("Could not write to file.")
 | 
				
			||||||
| 
						 | 
					@ -586,7 +417,7 @@ func output(t TLSSession) {
 | 
				
			||||||
	// If an output folder was specified for json files
 | 
						// If an output folder was specified for json files
 | 
				
			||||||
	if *outJSON != "" {
 | 
						if *outJSON != "" {
 | 
				
			||||||
		if _, err := os.Stat(fmt.Sprintf("./%s", *outJSON)); !os.IsNotExist(err) {
 | 
							if _, err := os.Stat(fmt.Sprintf("./%s", *outJSON)); !os.IsNotExist(err) {
 | 
				
			||||||
			err := ioutil.WriteFile(fmt.Sprintf("./%s/%s.json", *outJSON, t.record.Timestamp.Format(time.RFC3339)), jsonRecord, 0644)
 | 
								err := ioutil.WriteFile(fmt.Sprintf("./%s/%s.json", *outJSON, t.Record.Timestamp.Format(time.RFC3339)), jsonRecord, 0644)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				panic("Could not write to file.")
 | 
									panic("Could not write to file.")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,220 @@
 | 
				
			||||||
 | 
					package d4tls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"crypto/sha256"
 | 
				
			||||||
 | 
						"crypto/x509"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/D4-project/sensor-d4-tls-fingerprinting/etls"
 | 
				
			||||||
 | 
						"github.com/glaslos/tlsh"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var grease = map[uint16]bool{
 | 
				
			||||||
 | 
						0x0a0a: true, 0x1a1a: true, 0x2a2a: true, 0x3a3a: true,
 | 
				
			||||||
 | 
						0x4a4a: true, 0x5a5a: true, 0x6a6a: true, 0x7a7a: true,
 | 
				
			||||||
 | 
						0x8a8a: true, 0x9a9a: true, 0xaaaa: true, 0xbaba: true,
 | 
				
			||||||
 | 
						0xcaca: true, 0xdada: true, 0xeaea: true, 0xfafa: true,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type certMapElm struct {
 | 
				
			||||||
 | 
						CertHash string
 | 
				
			||||||
 | 
						*x509.Certificate
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type sessionRecord struct {
 | 
				
			||||||
 | 
						ServerIP     string
 | 
				
			||||||
 | 
						ServerPort   string
 | 
				
			||||||
 | 
						ClientIP     string
 | 
				
			||||||
 | 
						ClientPort   string
 | 
				
			||||||
 | 
						TLSH         string
 | 
				
			||||||
 | 
						Timestamp    time.Time
 | 
				
			||||||
 | 
						JA3          string
 | 
				
			||||||
 | 
						JA3Digest    string
 | 
				
			||||||
 | 
						JA3S         string
 | 
				
			||||||
 | 
						JA3SDigest   string
 | 
				
			||||||
 | 
						Certificates []certMapElm
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TLSSession contains a handshakeRecord that had to be filled during the handshake,
 | 
				
			||||||
 | 
					// and a Record that will be at last exported to Json
 | 
				
			||||||
 | 
					type TLSSession struct {
 | 
				
			||||||
 | 
						Record          sessionRecord
 | 
				
			||||||
 | 
						handShakeRecord etls.ETLSHandshakeRecord
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// String returns a string that describes a TLSSession
 | 
				
			||||||
 | 
					func (t *TLSSession) String() string {
 | 
				
			||||||
 | 
						var buf bytes.Buffer
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("---------------SESSION START-------------------\n"))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("Time: %v\n", t.Record.Timestamp))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("Client: %v:%v\n", t.Record.ClientIP, t.Record.ClientPort))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("Server: %v:%v\n", t.Record.ServerIP, t.Record.ServerPort))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("TLSH: %q\n", t.Record.TLSH))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("ja3: %q\n", t.Record.JA3))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("ja3 Digest: %q\n", t.Record.JA3Digest))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("ja3s: %q\n", t.Record.JA3S))
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("ja3s Digest: %q\n", t.Record.JA3SDigest))
 | 
				
			||||||
 | 
						for _, certMe := range t.Record.Certificates {
 | 
				
			||||||
 | 
							buf.WriteString(fmt.Sprintf("Certificate Issuer: %q\n", certMe.Certificate.Issuer))
 | 
				
			||||||
 | 
							buf.WriteString(fmt.Sprintf("Certificate Subject: %q\n", certMe.Certificate.Subject))
 | 
				
			||||||
 | 
							buf.WriteString(fmt.Sprintf("Certificate is CA: %t\n", certMe.Certificate.IsCA))
 | 
				
			||||||
 | 
							buf.WriteString(fmt.Sprintf("Certificate SHA256: %q\n", certMe.CertHash))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf.WriteString(fmt.Sprintf("---------------SESSION  END--------------------\n"))
 | 
				
			||||||
 | 
						return buf.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PopulateClientHello takes a pointer to an etls ClientHelloMsg and writes it to the the TLSSession struct
 | 
				
			||||||
 | 
					func (t *TLSSession) PopulateClientHello(h *etls.ClientHelloMsg, cip string, sip string, cp string, sp string, ti time.Time) {
 | 
				
			||||||
 | 
						t.Record.ClientIP = cip
 | 
				
			||||||
 | 
						t.Record.ServerIP = sip
 | 
				
			||||||
 | 
						t.Record.ClientPort = cp
 | 
				
			||||||
 | 
						t.Record.ServerPort = sp
 | 
				
			||||||
 | 
						t.Record.Timestamp = ti
 | 
				
			||||||
 | 
						t.handShakeRecord.ETLSHandshakeClientHello = h
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PopulateServerHello takes a pointer to an etls ServerHelloMsg and writes it to the TLSSession struct
 | 
				
			||||||
 | 
					func (t *TLSSession) PopulateServerHello(h *etls.ServerHelloMsg) {
 | 
				
			||||||
 | 
						t.handShakeRecord.ETLSHandshakeServerHello = h
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PopulateCertificate takes a pointer to an etls ServerHelloMsg and writes it to the TLSSession struct
 | 
				
			||||||
 | 
					func (t *TLSSession) PopulateCertificate(c *etls.CertificateMsg) {
 | 
				
			||||||
 | 
						t.handShakeRecord.ETLSHandshakeCertificate = c
 | 
				
			||||||
 | 
						for _, asn1Data := range t.handShakeRecord.ETLSHandshakeCertificate.Certificates {
 | 
				
			||||||
 | 
							cert, err := x509.ParseCertificate(asn1Data)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								//return err
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								h := sha256.New()
 | 
				
			||||||
 | 
								h.Write(cert.Raw)
 | 
				
			||||||
 | 
								t.Record.Certificates = append(t.Record.Certificates, certMapElm{Certificate: cert, CertHash: fmt.Sprintf("%x", h.Sum(nil))})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// D4Fingerprinting computes fingerprints doh
 | 
				
			||||||
 | 
					func (t *TLSSession) D4Fingerprinting(fd string) bool {
 | 
				
			||||||
 | 
						switch fd {
 | 
				
			||||||
 | 
						case "ja3":
 | 
				
			||||||
 | 
							t.ja3()
 | 
				
			||||||
 | 
						case "ja3s":
 | 
				
			||||||
 | 
							t.ja3s()
 | 
				
			||||||
 | 
						case "tlsh":
 | 
				
			||||||
 | 
							t.d4fg()
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *TLSSession) d4fg() string {
 | 
				
			||||||
 | 
						buf := t.Record.JA3 + t.Record.JA3S
 | 
				
			||||||
 | 
						for _, cert := range t.Record.Certificates {
 | 
				
			||||||
 | 
							buf += fmt.Sprintf("%q", cert.Issuer) + fmt.Sprintf("%q", cert.Subject)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf = strings.Replace(buf, "-", "", -1)
 | 
				
			||||||
 | 
						buf = strings.Replace(buf, ",", "", -1)
 | 
				
			||||||
 | 
						buf = strings.Replace(buf, "\"", "", -1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out, _ := tlsh.HashBytes([]byte(buf))
 | 
				
			||||||
 | 
						t.Record.TLSH = out.String()
 | 
				
			||||||
 | 
						return buf
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *TLSSession) ja3s() bool {
 | 
				
			||||||
 | 
						var buf []byte
 | 
				
			||||||
 | 
						buf = strconv.AppendInt(buf, int64(t.handShakeRecord.ETLSHandshakeServerHello.Vers), 10)
 | 
				
			||||||
 | 
						// byte (44) is ","
 | 
				
			||||||
 | 
						buf = append(buf, byte(44))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there are Cipher Suites
 | 
				
			||||||
 | 
						buf = strconv.AppendInt(buf, int64(t.handShakeRecord.ETLSHandshakeServerHello.CipherSuite), 10)
 | 
				
			||||||
 | 
						buf = append(buf, byte(44))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there are extensions
 | 
				
			||||||
 | 
						if len(t.handShakeRecord.ETLSHandshakeServerHello.AllExtensions) > 0 {
 | 
				
			||||||
 | 
							for i, e := range t.handShakeRecord.ETLSHandshakeServerHello.AllExtensions {
 | 
				
			||||||
 | 
								// TODO check this grease thingy
 | 
				
			||||||
 | 
								if grease[uint16(e)] == false {
 | 
				
			||||||
 | 
									buf = strconv.AppendInt(buf, int64(e), 10)
 | 
				
			||||||
 | 
									if (i + 1) < len(t.handShakeRecord.ETLSHandshakeServerHello.AllExtensions) {
 | 
				
			||||||
 | 
										// byte(45) is "-"
 | 
				
			||||||
 | 
										buf = append(buf, byte(45))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Record.JA3S = string(buf)
 | 
				
			||||||
 | 
						tmp := md5.Sum(buf)
 | 
				
			||||||
 | 
						t.Record.JA3SDigest = hex.EncodeToString(tmp[:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (t *TLSSession) ja3() bool {
 | 
				
			||||||
 | 
						var buf []byte
 | 
				
			||||||
 | 
						buf = strconv.AppendInt(buf, int64(t.handShakeRecord.ETLSHandshakeClientHello.Vers), 10)
 | 
				
			||||||
 | 
						// byte (44) is ","
 | 
				
			||||||
 | 
						buf = append(buf, byte(44))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there are Cipher Suites
 | 
				
			||||||
 | 
						if len(t.handShakeRecord.ETLSHandshakeClientHello.CipherSuites) > 0 {
 | 
				
			||||||
 | 
							for i, cs := range t.handShakeRecord.ETLSHandshakeClientHello.CipherSuites {
 | 
				
			||||||
 | 
								buf = strconv.AppendInt(buf, int64(cs), 10)
 | 
				
			||||||
 | 
								// byte(45) is "-"
 | 
				
			||||||
 | 
								if (i + 1) < len(t.handShakeRecord.ETLSHandshakeClientHello.CipherSuites) {
 | 
				
			||||||
 | 
									buf = append(buf, byte(45))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf = append(buf, byte(44))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there are extensions
 | 
				
			||||||
 | 
						if len(t.handShakeRecord.ETLSHandshakeClientHello.AllExtensions) > 0 {
 | 
				
			||||||
 | 
							for i, e := range t.handShakeRecord.ETLSHandshakeClientHello.AllExtensions {
 | 
				
			||||||
 | 
								// TODO check this grease thingy
 | 
				
			||||||
 | 
								if grease[uint16(e)] == false {
 | 
				
			||||||
 | 
									buf = strconv.AppendInt(buf, int64(e), 10)
 | 
				
			||||||
 | 
									if (i + 1) < len(t.handShakeRecord.ETLSHandshakeClientHello.AllExtensions) {
 | 
				
			||||||
 | 
										buf = append(buf, byte(45))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf = append(buf, byte(44))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there are Supported Curves
 | 
				
			||||||
 | 
						if len(t.handShakeRecord.ETLSHandshakeClientHello.SupportedCurves) > 0 {
 | 
				
			||||||
 | 
							for i, cs := range t.handShakeRecord.ETLSHandshakeClientHello.SupportedCurves {
 | 
				
			||||||
 | 
								buf = strconv.AppendInt(buf, int64(cs), 10)
 | 
				
			||||||
 | 
								if (i + 1) < len(t.handShakeRecord.ETLSHandshakeClientHello.SupportedCurves) {
 | 
				
			||||||
 | 
									buf = append(buf, byte(45))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf = append(buf, byte(44))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there are Supported Points
 | 
				
			||||||
 | 
						if len(t.handShakeRecord.ETLSHandshakeClientHello.SupportedPoints) > 0 {
 | 
				
			||||||
 | 
							for i, cs := range t.handShakeRecord.ETLSHandshakeClientHello.SupportedPoints {
 | 
				
			||||||
 | 
								buf = strconv.AppendInt(buf, int64(cs), 10)
 | 
				
			||||||
 | 
								if (i + 1) < len(t.handShakeRecord.ETLSHandshakeClientHello.SupportedPoints) {
 | 
				
			||||||
 | 
									buf = append(buf, byte(45))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Record.JA3 = string(buf)
 | 
				
			||||||
 | 
						tmp := md5.Sum(buf)
 | 
				
			||||||
 | 
						t.Record.JA3Digest = hex.EncodeToString(tmp[:])
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -14,9 +14,9 @@ import (
 | 
				
			||||||
type ETLSHandshakeRecord struct {
 | 
					type ETLSHandshakeRecord struct {
 | 
				
			||||||
	ETLSRecordHeader
 | 
						ETLSRecordHeader
 | 
				
			||||||
	ETLSHandshakeMsgType     uint8
 | 
						ETLSHandshakeMsgType     uint8
 | 
				
			||||||
	ETLSHandshakeServerHello *serverHelloMsg
 | 
						ETLSHandshakeServerHello *ServerHelloMsg
 | 
				
			||||||
	ETLSHandshakeClientHello *clientHelloMsg
 | 
						ETLSHandshakeClientHello *ClientHelloMsg
 | 
				
			||||||
	ETLSHandshakeCertificate *certificateMsg
 | 
						ETLSHandshakeCertificate *CertificateMsg
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DecodeFromBytes decodes the slice into the ETLS struct.
 | 
					// DecodeFromBytes decodes the slice into the ETLS struct.
 | 
				
			||||||
| 
						 | 
					@ -30,15 +30,15 @@ func (t *ETLSHandshakeRecord) decodeFromBytes(h ETLSRecordHeader, data []byte, d
 | 
				
			||||||
	switch uint8(data[0]) {
 | 
						switch uint8(data[0]) {
 | 
				
			||||||
	case typeClientHello:
 | 
						case typeClientHello:
 | 
				
			||||||
		t.ETLSHandshakeMsgType = typeClientHello
 | 
							t.ETLSHandshakeMsgType = typeClientHello
 | 
				
			||||||
		t.ETLSHandshakeClientHello = new(clientHelloMsg)
 | 
							t.ETLSHandshakeClientHello = new(ClientHelloMsg)
 | 
				
			||||||
		t.ETLSHandshakeClientHello.unmarshal(data)
 | 
							t.ETLSHandshakeClientHello.unmarshal(data)
 | 
				
			||||||
	case typeServerHello:
 | 
						case typeServerHello:
 | 
				
			||||||
		t.ETLSHandshakeMsgType = typeServerHello
 | 
							t.ETLSHandshakeMsgType = typeServerHello
 | 
				
			||||||
		t.ETLSHandshakeServerHello = new(serverHelloMsg)
 | 
							t.ETLSHandshakeServerHello = new(ServerHelloMsg)
 | 
				
			||||||
		t.ETLSHandshakeServerHello.unmarshal(data)
 | 
							t.ETLSHandshakeServerHello.unmarshal(data)
 | 
				
			||||||
	case typeCertificate:
 | 
						case typeCertificate:
 | 
				
			||||||
		t.ETLSHandshakeMsgType = typeCertificate
 | 
							t.ETLSHandshakeMsgType = typeCertificate
 | 
				
			||||||
		t.ETLSHandshakeCertificate = new(certificateMsg)
 | 
							t.ETLSHandshakeCertificate = new(CertificateMsg)
 | 
				
			||||||
		t.ETLSHandshakeCertificate.unmarshal(data)
 | 
							t.ETLSHandshakeCertificate.unmarshal(data)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Please see the following url if you are interested into implementing the rest:
 | 
						// Please see the following url if you are interested into implementing the rest:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@ type handshakeMessage interface {
 | 
				
			||||||
	unmarshal([]byte) bool
 | 
						unmarshal([]byte) bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type clientHelloMsg struct {
 | 
					type ClientHelloMsg struct {
 | 
				
			||||||
	raw                          []byte
 | 
						raw                          []byte
 | 
				
			||||||
	extensions                   map[Extension]uint16
 | 
						extensions                   map[Extension]uint16
 | 
				
			||||||
	AllExtensions                []uint16
 | 
						AllExtensions                []uint16
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,7 @@ type clientHelloMsg struct {
 | 
				
			||||||
	alpnProtocols                []string
 | 
						alpnProtocols                []string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *clientHelloMsg) unmarshal(data []byte) bool {
 | 
					func (m *ClientHelloMsg) unmarshal(data []byte) bool {
 | 
				
			||||||
	if len(data) < 42 {
 | 
						if len(data) < 42 {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -158,7 +158,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type serverHelloMsg struct {
 | 
					type ServerHelloMsg struct {
 | 
				
			||||||
	raw                          []byte
 | 
						raw                          []byte
 | 
				
			||||||
	extensions                   map[Extension]uint16
 | 
						extensions                   map[Extension]uint16
 | 
				
			||||||
	AllExtensions                []uint16
 | 
						AllExtensions                []uint16
 | 
				
			||||||
| 
						 | 
					@ -177,7 +177,7 @@ type serverHelloMsg struct {
 | 
				
			||||||
	alpnProtocol                 string
 | 
						alpnProtocol                 string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *serverHelloMsg) unmarshal(data []byte) bool {
 | 
					func (m *ServerHelloMsg) unmarshal(data []byte) bool {
 | 
				
			||||||
	if len(data) < 42 {
 | 
						if len(data) < 42 {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -327,12 +327,12 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type certificateMsg struct {
 | 
					type CertificateMsg struct {
 | 
				
			||||||
	raw          []byte
 | 
						raw          []byte
 | 
				
			||||||
	Certificates [][]byte
 | 
						Certificates [][]byte
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *certificateMsg) unmarshal(data []byte) bool {
 | 
					func (m *CertificateMsg) unmarshal(data []byte) bool {
 | 
				
			||||||
	if len(data) < 7 {
 | 
						if len(data) < 7 {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue