From 549437b355eea3c7ece343964f8d68c69aaa4e38 Mon Sep 17 00:00:00 2001 From: Jean-Louis Huynen Date: Mon, 4 Feb 2019 16:26:34 +0100 Subject: [PATCH] refacto --- d4-tlsf.go | 207 +++--------------------------- d4tls/d4tls.go | 220 ++++++++++++++++++++++++++++++++ etls/etls_handshake.go | 12 +- etls/etls_handshake_messages.go | 12 +- 4 files changed, 251 insertions(+), 200 deletions(-) create mode 100644 d4tls/d4tls.go diff --git a/d4-tlsf.go b/d4-tlsf.go index ae2ee85..25a0c62 100644 --- a/d4-tlsf.go +++ b/d4-tlsf.go @@ -2,13 +2,10 @@ package main import ( "bytes" - "crypto/md5" - "crypto/sha256" - "crypto/x509" // TODO consider //"github.com/google/certificate-transparency-go/x509" - "encoding/hex" + "encoding/json" "flag" "fmt" @@ -17,12 +14,10 @@ import ( "log" "os" "os/signal" - "strconv" "strings" "sync" "time" - "github.com/glaslos/tlsh" "github.com/google/gopacket" "github.com/google/gopacket/examples/util" "github.com/google/gopacket/ip4defrag" @@ -30,6 +25,7 @@ import ( "github.com/google/gopacket/pcap" "github.com/google/gopacket/reassembly" + "github.com/D4-project/sensor-d4-tls-fingerprinting/d4tls" "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 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 jobQ chan 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, -} +var jobQ chan d4tls.TLSSession const closeTimeout time.Duration = time.Hour * 24 // Closing inactive: 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 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 func Error(t string, s string, a ...interface{}) { errorsMapMutex.Lock() @@ -155,6 +99,7 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T tcpstate: reassembly.NewTCPSimpleFSM(fsmOptions), ident: fmt.Sprintf("%s:%s", net, transport), optchecker: reassembly.NewTCPOptionCheck(), + tlsSession: d4tls.TLSSession{}, } return stream } @@ -188,7 +133,7 @@ type tcpStream struct { reversed bool urls []string ident string - tlsSession TLSSession + tlsSession d4tls.TLSSession sync.Mutex } @@ -258,32 +203,19 @@ func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.Ass switch tlsrecord.ETLSHandshakeMsgType { // Client Hello 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) - t.tlsSession.record.Timestamp = info.Timestamp - t.tlsSession.gatherJa3() + cip, sip, cp, sp := getIPPorts(t) + t.tlsSession.PopulateClientHello(tlsrecord.ETLSHandshakeClientHello, cip, sip, cp, sp, info.Timestamp) + t.tlsSession.D4Fingerprinting("ja3") // Server Hello case 2: - t.tlsSession.tlsHdskR.ETLSHandshakeServerHello = tlsrecord.ETLSHandshakeServerHello - t.tlsSession.gatherJa3s() + t.tlsSession.PopulateServerHello(tlsrecord.ETLSHandshakeServerHello) + t.tlsSession.D4Fingerprinting("ja3s") // Server Certificate case 11: - for _, asn1Data := range tlsrecord.ETLSHandshakeCertificate.Certificates { - 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.PopulateCertificate(tlsrecord.ETLSHandshakeCertificate) + t.tlsSession.D4Fingerprinting("tlsh") // If we get a cert, we consider the handshake as finished and ready to ship to D4 queueSession(t.tlsSession) default: @@ -306,107 +238,6 @@ func getIPPorts(t *tcpStream) (string, string, string, string) { 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 { Debug("%s: Connection closed\n", t.ident) // do not remove the connection to allow last ACK @@ -465,7 +296,7 @@ func main() { signal.Notify(signalChan, os.Interrupt) // Job chan to hold Completed sessions to write - jobQ = make(chan TLSSession, 100) + jobQ = make(chan d4tls.TLSSession, 100) cancelC := make(chan string) // We start a worker to send the processed TLS connection the outside world @@ -543,7 +374,7 @@ func main() { w.Wait() } -func processCompletedSession(jobQ <-chan TLSSession, w *sync.WaitGroup) { +func processCompletedSession(jobQ <-chan d4tls.TLSSession, w *sync.WaitGroup) { for { tlss, more := <-jobQ if more { @@ -556,7 +387,7 @@ func processCompletedSession(jobQ <-chan TLSSession, w *sync.WaitGroup) { } // Tries to enqueue or false -func queueSession(t TLSSession) bool { +func queueSession(t d4tls.TLSSession) bool { select { case jobQ <- t: 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 *outCerts != "" { 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) if err != nil { panic("Could not write to file.") @@ -586,7 +417,7 @@ func output(t TLSSession) { // If an output folder was specified for json files if *outJSON != "" { 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 { panic("Could not write to file.") } diff --git a/d4tls/d4tls.go b/d4tls/d4tls.go new file mode 100644 index 0000000..cbfe651 --- /dev/null +++ b/d4tls/d4tls.go @@ -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 +} diff --git a/etls/etls_handshake.go b/etls/etls_handshake.go index 8615f77..7037b1f 100644 --- a/etls/etls_handshake.go +++ b/etls/etls_handshake.go @@ -14,9 +14,9 @@ import ( type ETLSHandshakeRecord struct { ETLSRecordHeader ETLSHandshakeMsgType uint8 - ETLSHandshakeServerHello *serverHelloMsg - ETLSHandshakeClientHello *clientHelloMsg - ETLSHandshakeCertificate *certificateMsg + ETLSHandshakeServerHello *ServerHelloMsg + ETLSHandshakeClientHello *ClientHelloMsg + ETLSHandshakeCertificate *CertificateMsg } // 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]) { case typeClientHello: t.ETLSHandshakeMsgType = typeClientHello - t.ETLSHandshakeClientHello = new(clientHelloMsg) + t.ETLSHandshakeClientHello = new(ClientHelloMsg) t.ETLSHandshakeClientHello.unmarshal(data) case typeServerHello: t.ETLSHandshakeMsgType = typeServerHello - t.ETLSHandshakeServerHello = new(serverHelloMsg) + t.ETLSHandshakeServerHello = new(ServerHelloMsg) t.ETLSHandshakeServerHello.unmarshal(data) case typeCertificate: t.ETLSHandshakeMsgType = typeCertificate - t.ETLSHandshakeCertificate = new(certificateMsg) + t.ETLSHandshakeCertificate = new(CertificateMsg) t.ETLSHandshakeCertificate.unmarshal(data) } // Please see the following url if you are interested into implementing the rest: diff --git a/etls/etls_handshake_messages.go b/etls/etls_handshake_messages.go index 60a5072..1e9227a 100644 --- a/etls/etls_handshake_messages.go +++ b/etls/etls_handshake_messages.go @@ -12,7 +12,7 @@ type handshakeMessage interface { unmarshal([]byte) bool } -type clientHelloMsg struct { +type ClientHelloMsg struct { raw []byte extensions map[Extension]uint16 AllExtensions []uint16 @@ -35,7 +35,7 @@ type clientHelloMsg struct { alpnProtocols []string } -func (m *clientHelloMsg) unmarshal(data []byte) bool { +func (m *ClientHelloMsg) unmarshal(data []byte) bool { if len(data) < 42 { return false } @@ -158,7 +158,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return true } -type serverHelloMsg struct { +type ServerHelloMsg struct { raw []byte extensions map[Extension]uint16 AllExtensions []uint16 @@ -177,7 +177,7 @@ type serverHelloMsg struct { alpnProtocol string } -func (m *serverHelloMsg) unmarshal(data []byte) bool { +func (m *ServerHelloMsg) unmarshal(data []byte) bool { if len(data) < 42 { return false } @@ -327,12 +327,12 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return true } -type certificateMsg struct { +type CertificateMsg struct { raw []byte Certificates [][]byte } -func (m *certificateMsg) unmarshal(data []byte) bool { +func (m *CertificateMsg) unmarshal(data []byte) bool { if len(data) < 7 { return false }