From e8df625026669dab575665786aa27e2a08464250 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:02:20 +0300 Subject: [PATCH 1/8] Updated README.md, added binaries --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index a51be06..4dc3027 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,20 @@ ![mshark_new](https://github.com/user-attachments/assets/ee1b9526-dcae-4ff8-962d-315897e49ed0) # mShark - Mini [Wireshark](https://www.wireshark.org/) written in Go +[![Go Reference](https://pkg.go.dev/badge/github.com/shadowy-pycoder/mshark.svg)](https://pkg.go.dev/github.com/shadowy-pycoder/mshark) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/shadowy-pycoder/mshark) +[![Go Report Card](https://goreportcard.com/badge/github.com/shadowy-pycoder/mshark)](https://goreportcard.com/report/github.com/shadowy-pycoder/mshark) +![GitHub Release](https://img.shields.io/github/v/release/shadowy-pycoder/mshark) +![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/shadowy-pycoder/mshark/total) + ## Installation +Download release from [Releases](https://github.com/shadowy-pycoder/mshark/releases) Page. + +Or install using `go install` (requires Go 1.23+ but may work with older versions): + ```shell CGO_ENABLED=0 go install -ldflags "-s -w" -trimpath github.com/shadowy-pycoder/mshark/cmd/mshark@latest ``` From 3f8e61fd628a697aa632c7d1ced708462c24a307 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:10:06 +0300 Subject: [PATCH 2/8] Added READMEs for mpcap amd mpcapng --- mpcap/README.md | 3 +++ mpcapng/README.md | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 mpcap/README.md create mode 100644 mpcapng/README.md diff --git a/mpcap/README.md b/mpcap/README.md new file mode 100644 index 0000000..d39a986 --- /dev/null +++ b/mpcap/README.md @@ -0,0 +1,3 @@ +# Implementation of PCAP Capture File Format + +See https://www.ietf.org/archive/id/draft-gharris-opsawg-pcap-01.html \ No newline at end of file diff --git a/mpcapng/README.md b/mpcapng/README.md new file mode 100644 index 0000000..2e05ea2 --- /dev/null +++ b/mpcapng/README.md @@ -0,0 +1,3 @@ +# Implementation of PCAP Next Generation (pcapng) Capture File Format + +See https://www.ietf.org/archive/id/draft-tuexen-opsawg-pcapng-03.html \ No newline at end of file From a82c532c4b1eddac166ffecef9eec1d18a516367 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Fri, 13 Jun 2025 21:02:51 +0300 Subject: [PATCH 3/8] first take on tls metadata parsing --- layers/tls.go | 958 ++++++++++++++++++++++++++++++++++++++++++++- layers/tls_test.go | 4 +- 2 files changed, 956 insertions(+), 6 deletions(-) diff --git a/layers/tls.go b/layers/tls.go index 5ad4041..02b1ac5 100644 --- a/layers/tls.go +++ b/layers/tls.go @@ -6,7 +6,9 @@ import ( "strings" ) -const headerSizeTLS = 5 +const ( + headerSizeTLS = 5 +) type Record struct { ContentType uint8 @@ -14,7 +16,106 @@ type Record struct { Version uint16 VersionDesc string Length uint16 - data []byte + Data []byte +} + +type CipherSuite struct { + Value uint16 + Desc string +} + +type ServerName struct { + Type uint16 + Length uint16 + SNListLength uint16 + SNType uint8 + SNNameLength uint16 + SNName []byte +} + +func (sn *ServerName) Parse(data []byte) error { + sn.Type = binary.BigEndian.Uint16(data[0:2]) + sn.Length = binary.BigEndian.Uint16(data[2:4]) + sn.SNListLength = binary.BigEndian.Uint16(data[4:6]) + sn.SNType = data[6] + sn.SNNameLength = binary.BigEndian.Uint16(data[7:9]) + sn.SNName = data[9 : 9+sn.SNNameLength] + return nil +} + +// https://wiki.osdev.org/TLS_Handshake#Client_Hello_Message +type TLSClientHello struct { + Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16)) + Version uint16 + VersionDesc string + Random []byte //32 bytes + SessionIDLength uint8 // if 0 no session follows + SessionID []byte + CipherSuitesLength uint16 + CipherSuites []*CipherSuite + CmprMethodsLength uint8 // usually 0x01 + CmprMethods []byte // usually 0x00 + ExtensionLength uint16 + ServerName ServerName +} + +func (tch *TLSClientHello) Parse(data []byte) error { + // TODO: add ParseHandshake and type dispatcher + // offset 7 bytes + tch.Length = int(uint(data[3]) | uint(data[2])<<8 | uint(data[1])<<16) // 6 - 8 bytes data[1:4] + tch.Version = binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] + tch.VersionDesc = verdesc(tch.Version) + tch.Random = data[6:38] // 11-42 data[6:38] + tch.SessionIDLength = data[38] // 43 data[38] 32 bytes + sid := tch.SessionIDLength + 39 // 70 + tch.SessionID = data[39:sid] // data[39:71] + csl := binary.BigEndian.Uint16(data[sid : sid+2]) // data[71:73] suites count * 2 bytes + tch.CipherSuitesLength = csl + cmproffset := csl + 73 // 107 + css := make([]*CipherSuite, 0, csl/2+1) + for i := range len(data[73:cmproffset]) { + val := binary.BigEndian.Uint16(data[i : i+2]) + valdesc := csuitedesc(val) + css = append(css, &CipherSuite{Value: val, Desc: valdesc}) + } + tch.CipherSuites = css + cml := data[cmproffset] // 107 + tch.CmprMethodsLength = cml + extoffset := cmproffset + 1 + uint16(cml) + tch.CmprMethods = data[cmproffset+1 : extoffset] // data[108:109] + extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2]) // data[109:111] + tch.ExtensionLength = extlen + var i = extoffset + 2 + for i < extoffset+extlen { + typ := binary.BigEndian.Uint16(data[i : i+2]) + length := binary.BigEndian.Uint16(data[i+2 : i+4]) + switch typ { + case 0: // TODO: add more extensions + sn := ServerName{} + err := sn.Parse(data[i : i+length+4]) + if err != nil { + return err + } + tch.ServerName = sn + i += length + 4 + default: + i += length + 4 + } + } + return nil +} + +// https://wiki.osdev.org/TLS_Handshake#Server_Hello_Message +type TLSServerHello struct { + Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16)) + Version uint16 + VersionDesc string + Random []byte //32 bytes + SessionIDLength uint8 // if 0 no session follows + SessionID []byte + CipherSuite *CipherSuite + CmprMethod uint8 + ExtensionLength uint16 } func (r *Record) String() string { @@ -56,7 +157,7 @@ func (t *TLSMessage) Summary() string { } sb.WriteString(fmt.Sprintf("%s (%#04x) ", rec.VersionDesc, rec.Version)) if rec.ContentType == 22 { - hstd := hstypedesc(rec.data[0]) + hstd := hstypedesc(rec.Data[0]) sb.WriteString(fmt.Sprintf("%s ", hstd)) } sb.WriteString(fmt.Sprintf("%s (%d) Len: %d ", @@ -106,7 +207,7 @@ func (t *TLSMessage) Parse(data []byte) error { Version: ver, VersionDesc: verdesc, Length: rlen, - data: data[headerSizeTLS : headerSizeTLS+rlen], + Data: data[headerSizeTLS : headerSizeTLS+rlen], } t.Records = append(t.Records, r) data = data[headerSizeTLS+rlen:] @@ -219,3 +320,852 @@ func hstypedesc(hstype uint8) string { } return hstypedesc } + +func csuitedesc(csuite uint16) string { + var csuitedesc string + switch csuite { + case 0x0000: + csuitedesc = "TLS_NULL_WITH_NULL_NULL" + case 0x0001: + csuitedesc = "TLS_RSA_WITH_NULL_MD5" + case 0x0002: + csuitedesc = "TLS_RSA_WITH_NULL_SHA" + case 0x0003: + csuitedesc = "TLS_RSA_EXPORT_WITH_RC4_40_MD5" + case 0x0004: + csuitedesc = "TLS_RSA_WITH_RC4_128_MD5" + case 0x0005: + csuitedesc = "TLS_RSA_WITH_RC4_128_SHA" + case 0x0006: + csuitedesc = "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5" + case 0x0007: + csuitedesc = "TLS_RSA_WITH_IDEA_CBC_SHA" + case 0x0008: + csuitedesc = "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA" + case 0x0009: + csuitedesc = "TLS_RSA_WITH_DES_CBC_SHA" + case 0x000A: + csuitedesc = "TLS_RSA_WITH_3DES_EDE_CBC_SHA" + case 0x000B: + csuitedesc = "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA" + case 0x000C: + csuitedesc = "TLS_DH_DSS_WITH_DES_CBC_SHA" + case 0x000D: + csuitedesc = "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA" + case 0x000E: + csuitedesc = "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA" + case 0x000F: + csuitedesc = "TLS_DH_RSA_WITH_DES_CBC_SHA" + case 0x0010: + csuitedesc = "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA" + case 0x0011: + csuitedesc = "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" + case 0x0012: + csuitedesc = "TLS_DHE_DSS_WITH_DES_CBC_SHA" + case 0x0013: + csuitedesc = "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA" + case 0x0014: + csuitedesc = "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA" + case 0x0015: + csuitedesc = "TLS_DHE_RSA_WITH_DES_CBC_SHA" + case 0x0016: + csuitedesc = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA" + case 0x0017: + csuitedesc = "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5" + case 0x0018: + csuitedesc = "TLS_DH_anon_WITH_RC4_128_MD5" + case 0x0019: + csuitedesc = "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA" + case 0x001A: + csuitedesc = "TLS_DH_anon_WITH_DES_CBC_SHA" + case 0x001B: + csuitedesc = "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA" + case 0x001E: + csuitedesc = "TLS_KRB5_WITH_DES_CBC_SHA" + case 0x001F: + csuitedesc = "TLS_KRB5_WITH_3DES_EDE_CBC_SHA" + case 0x0020: + csuitedesc = "TLS_KRB5_WITH_RC4_128_SHA" + case 0x0021: + csuitedesc = "TLS_KRB5_WITH_IDEA_CBC_SHA" + case 0x0022: + csuitedesc = "TLS_KRB5_WITH_DES_CBC_MD5" + case 0x0023: + csuitedesc = "TLS_KRB5_WITH_3DES_EDE_CBC_MD5" + case 0x0024: + csuitedesc = "TLS_KRB5_WITH_RC4_128_MD5" + case 0x0025: + csuitedesc = "TLS_KRB5_WITH_IDEA_CBC_MD5" + case 0x0026: + csuitedesc = "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA" + case 0x0027: + csuitedesc = "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA" + case 0x0028: + csuitedesc = "TLS_KRB5_EXPORT_WITH_RC4_40_SHA" + case 0x0029: + csuitedesc = "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5" + case 0x002A: + csuitedesc = "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5" + case 0x002B: + csuitedesc = "TLS_KRB5_EXPORT_WITH_RC4_40_MD5" + case 0x002C: + csuitedesc = "TLS_PSK_WITH_NULL_SHA" + case 0x002D: + csuitedesc = "TLS_DHE_PSK_WITH_NULL_SHA" + case 0x002E: + csuitedesc = "TLS_RSA_PSK_WITH_NULL_SHA" + case 0x002F: + csuitedesc = "TLS_RSA_WITH_AES_128_CBC_SHA" + case 0x0030: + csuitedesc = "TLS_DH_DSS_WITH_AES_128_CBC_SHA" + case 0x0031: + csuitedesc = "TLS_DH_RSA_WITH_AES_128_CBC_SHA" + case 0x0032: + csuitedesc = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA" + case 0x0033: + csuitedesc = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" + case 0x0034: + csuitedesc = "TLS_DH_anon_WITH_AES_128_CBC_SHA" + case 0x0035: + csuitedesc = "TLS_RSA_WITH_AES_256_CBC_SHA" + case 0x0036: + csuitedesc = "TLS_DH_DSS_WITH_AES_256_CBC_SHA" + case 0x0037: + csuitedesc = "TLS_DH_RSA_WITH_AES_256_CBC_SHA" + case 0x0038: + csuitedesc = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA" + case 0x0039: + csuitedesc = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" + case 0x003A: + csuitedesc = "TLS_DH_anon_WITH_AES_256_CBC_SHA" + case 0x003B: + csuitedesc = "TLS_RSA_WITH_NULL_SHA256" + case 0x003C: + csuitedesc = "TLS_RSA_WITH_AES_128_CBC_SHA256" + case 0x003D: + csuitedesc = "TLS_RSA_WITH_AES_256_CBC_SHA256" + case 0x003E: + csuitedesc = "TLS_DH_DSS_WITH_AES_128_CBC_SHA256" + case 0x003F: + csuitedesc = "TLS_DH_RSA_WITH_AES_128_CBC_SHA256" + case 0x0040: + csuitedesc = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256" + case 0x0041: + csuitedesc = "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA" + case 0x0042: + csuitedesc = "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA" + case 0x0043: + csuitedesc = "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA" + case 0x0044: + csuitedesc = "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA" + case 0x0045: + csuitedesc = "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA" + case 0x0046: + csuitedesc = "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA" + case 0x0067: + csuitedesc = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256" + case 0x0068: + csuitedesc = "TLS_DH_DSS_WITH_AES_256_CBC_SHA256" + case 0x0069: + csuitedesc = "TLS_DH_RSA_WITH_AES_256_CBC_SHA256" + case 0x006A: + csuitedesc = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" + case 0x006B: + csuitedesc = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" + case 0x006C: + csuitedesc = "TLS_DH_anon_WITH_AES_128_CBC_SHA256" + case 0x006D: + csuitedesc = "TLS_DH_anon_WITH_AES_256_CBC_SHA256" + case 0x0084: + csuitedesc = "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA" + case 0x0085: + csuitedesc = "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA" + case 0x0086: + csuitedesc = "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA" + case 0x0087: + csuitedesc = "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA" + case 0x0088: + csuitedesc = "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA" + case 0x0089: + csuitedesc = "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA" + case 0x008A: + csuitedesc = "TLS_PSK_WITH_RC4_128_SHA" + case 0x008B: + csuitedesc = "TLS_PSK_WITH_3DES_EDE_CBC_SHA" + case 0x008C: + csuitedesc = "TLS_PSK_WITH_AES_128_CBC_SHA" + case 0x008D: + csuitedesc = "TLS_PSK_WITH_AES_256_CBC_SHA" + case 0x008E: + csuitedesc = "TLS_DHE_PSK_WITH_RC4_128_SHA" + case 0x008F: + csuitedesc = "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA" + case 0x0090: + csuitedesc = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA" + case 0x0091: + csuitedesc = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA" + case 0x0092: + csuitedesc = "TLS_RSA_PSK_WITH_RC4_128_SHA" + case 0x0093: + csuitedesc = "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA" + case 0x0094: + csuitedesc = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA" + case 0x0095: + csuitedesc = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA" + case 0x0096: + csuitedesc = "TLS_RSA_WITH_SEED_CBC_SHA" + case 0x0097: + csuitedesc = "TLS_DH_DSS_WITH_SEED_CBC_SHA" + case 0x0098: + csuitedesc = "TLS_DH_RSA_WITH_SEED_CBC_SHA" + case 0x0099: + csuitedesc = "TLS_DHE_DSS_WITH_SEED_CBC_SHA" + case 0x009A: + csuitedesc = "TLS_DHE_RSA_WITH_SEED_CBC_SHA" + case 0x009B: + csuitedesc = "TLS_DH_anon_WITH_SEED_CBC_SHA" + case 0x009C: + csuitedesc = "TLS_RSA_WITH_AES_128_GCM_SHA256" + case 0x009D: + csuitedesc = "TLS_RSA_WITH_AES_256_GCM_SHA384" + case 0x009E: + csuitedesc = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" + case 0x009F: + csuitedesc = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384" + case 0x00A0: + csuitedesc = "TLS_DH_RSA_WITH_AES_128_GCM_SHA256" + case 0x00A1: + csuitedesc = "TLS_DH_RSA_WITH_AES_256_GCM_SHA384" + case 0x00A2: + csuitedesc = "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256" + case 0x00A3: + csuitedesc = "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384" + case 0x00A4: + csuitedesc = "TLS_DH_DSS_WITH_AES_128_GCM_SHA256" + case 0x00A5: + csuitedesc = "TLS_DH_DSS_WITH_AES_256_GCM_SHA384" + case 0x00A6: + csuitedesc = "TLS_DH_anon_WITH_AES_128_GCM_SHA256" + case 0x00A7: + csuitedesc = "TLS_DH_anon_WITH_AES_256_GCM_SHA384" + case 0x00A8: + csuitedesc = "TLS_PSK_WITH_AES_128_GCM_SHA256" + case 0x00A9: + csuitedesc = "TLS_PSK_WITH_AES_256_GCM_SHA384" + case 0x00AA: + csuitedesc = "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256" + case 0x00AB: + csuitedesc = "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384" + case 0x00AC: + csuitedesc = "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256" + case 0x00AD: + csuitedesc = "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384" + case 0x00AE: + csuitedesc = "TLS_PSK_WITH_AES_128_CBC_SHA256" + case 0x00AF: + csuitedesc = "TLS_PSK_WITH_AES_256_CBC_SHA384" + case 0x00B0: + csuitedesc = "TLS_PSK_WITH_NULL_SHA256" + case 0x00B1: + csuitedesc = "TLS_PSK_WITH_NULL_SHA384" + case 0x00B2: + csuitedesc = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256" + case 0x00B3: + csuitedesc = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384" + case 0x00B4: + csuitedesc = "TLS_DHE_PSK_WITH_NULL_SHA256" + case 0x00B5: + csuitedesc = "TLS_DHE_PSK_WITH_NULL_SHA384" + case 0x00B6: + csuitedesc = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256" + case 0x00B7: + csuitedesc = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384" + case 0x00B8: + csuitedesc = "TLS_RSA_PSK_WITH_NULL_SHA256" + case 0x00B9: + csuitedesc = "TLS_RSA_PSK_WITH_NULL_SHA384" + case 0x00BA: + csuitedesc = "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256" + case 0x00BB: + csuitedesc = "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256" + case 0x00BC: + csuitedesc = "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256" + case 0x00BD: + csuitedesc = "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256" + case 0x00BE: + csuitedesc = "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256" + case 0x00BF: + csuitedesc = "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256" + case 0x00C0: + csuitedesc = "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256" + case 0x00C1: + csuitedesc = "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256" + case 0x00C2: + csuitedesc = "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256" + case 0x00C3: + csuitedesc = "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256" + case 0x00C4: + csuitedesc = "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256" + case 0x00C5: + csuitedesc = "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256" + case 0x00C6: + csuitedesc = "TLS_SM4_GCM_SM3" + case 0x00C7: + csuitedesc = "TLS_SM4_CCM_SM3" + case 0x00FF: + csuitedesc = "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" + case 0x1301: + csuitedesc = "TLS_AES_128_GCM_SHA256" + case 0x1302: + csuitedesc = "TLS_AES_256_GCM_SHA384" + case 0x1303: + csuitedesc = "TLS_CHACHA20_POLY1305_SHA256" + case 0x1304: + csuitedesc = "TLS_AES_128_CCM_SHA256" + case 0x1305: + csuitedesc = "TLS_AES_128_CCM_8_SHA256" + case 0x1306: + csuitedesc = "TLS_AEGIS_256_SHA512" + case 0x1307: + csuitedesc = "TLS_AEGIS_128L_SHA256" + case 0x5600: + csuitedesc = "TLS_FALLBACK_SCSV" + case 0xC001: + csuitedesc = "TLS_ECDH_ECDSA_WITH_NULL_SHA" + case 0xC002: + csuitedesc = "TLS_ECDH_ECDSA_WITH_RC4_128_SHA" + case 0xC003: + csuitedesc = "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA" + case 0xC004: + csuitedesc = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA" + case 0xC005: + csuitedesc = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA" + case 0xC006: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_NULL_SHA" + case 0xC007: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA" + case 0xC008: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA" + case 0xC009: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA" + case 0xC00A: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" + case 0xC00B: + csuitedesc = "TLS_ECDH_RSA_WITH_NULL_SHA" + case 0xC00C: + csuitedesc = "TLS_ECDH_RSA_WITH_RC4_128_SHA" + case 0xC00D: + csuitedesc = "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA" + case 0xC00E: + csuitedesc = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA" + case 0xC00F: + csuitedesc = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA" + case 0xC010: + csuitedesc = "TLS_ECDHE_RSA_WITH_NULL_SHA" + case 0xC011: + csuitedesc = "TLS_ECDHE_RSA_WITH_RC4_128_SHA" + case 0xC012: + csuitedesc = "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA" + case 0xC013: + csuitedesc = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" + case 0xC014: + csuitedesc = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" + case 0xC015: + csuitedesc = "TLS_ECDH_anon_WITH_NULL_SHA" + case 0xC016: + csuitedesc = "TLS_ECDH_anon_WITH_RC4_128_SHA" + case 0xC017: + csuitedesc = "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA" + case 0xC018: + csuitedesc = "TLS_ECDH_anon_WITH_AES_128_CBC_SHA" + case 0xC019: + csuitedesc = "TLS_ECDH_anon_WITH_AES_256_CBC_SHA" + case 0xC01A: + csuitedesc = "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA" + case 0xC01B: + csuitedesc = "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA" + case 0xC01C: + csuitedesc = "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA" + case 0xC01D: + csuitedesc = "TLS_SRP_SHA_WITH_AES_128_CBC_SHA" + case 0xC01E: + csuitedesc = "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA" + case 0xC01F: + csuitedesc = "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA" + case 0xC020: + csuitedesc = "TLS_SRP_SHA_WITH_AES_256_CBC_SHA" + case 0xC021: + csuitedesc = "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA" + case 0xC022: + csuitedesc = "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA" + case 0xC023: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" + case 0xC024: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384" + case 0xC025: + csuitedesc = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256" + case 0xC026: + csuitedesc = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384" + case 0xC027: + csuitedesc = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" + case 0xC028: + csuitedesc = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" + case 0xC029: + csuitedesc = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256" + case 0xC02A: + csuitedesc = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384" + case 0xC02B: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + case 0xC02C: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" + case 0xC02D: + csuitedesc = "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256" + case 0xC02E: + csuitedesc = "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384" + case 0xC02F: + csuitedesc = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + case 0xC030: + csuitedesc = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + case 0xC031: + csuitedesc = "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256" + case 0xC032: + csuitedesc = "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384" + case 0xC033: + csuitedesc = "TLS_ECDHE_PSK_WITH_RC4_128_SHA" + case 0xC034: + csuitedesc = "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA" + case 0xC035: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA" + case 0xC036: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA" + case 0xC037: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256" + case 0xC038: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384" + case 0xC039: + csuitedesc = "TLS_ECDHE_PSK_WITH_NULL_SHA" + case 0xC03A: + csuitedesc = "TLS_ECDHE_PSK_WITH_NULL_SHA256" + case 0xC03B: + csuitedesc = "TLS_ECDHE_PSK_WITH_NULL_SHA384" + case 0xC03C: + csuitedesc = "TLS_RSA_WITH_ARIA_128_CBC_SHA256" + case 0xC03D: + csuitedesc = "TLS_RSA_WITH_ARIA_256_CBC_SHA384" + case 0xC03E: + csuitedesc = "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256" + case 0xC03F: + csuitedesc = "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384" + case 0xC040: + csuitedesc = "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256" + case 0xC041: + csuitedesc = "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384" + case 0xC042: + csuitedesc = "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256" + case 0xC043: + csuitedesc = "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384" + case 0xC044: + csuitedesc = "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256" + case 0xC045: + csuitedesc = "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384" + case 0xC046: + csuitedesc = "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256" + case 0xC047: + csuitedesc = "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384" + case 0xC048: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256" + case 0xC049: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384" + case 0xC04A: + csuitedesc = "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256" + case 0xC04B: + csuitedesc = "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384" + case 0xC04C: + csuitedesc = "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256" + case 0xC04D: + csuitedesc = "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384" + case 0xC04E: + csuitedesc = "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256" + case 0xC04F: + csuitedesc = "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384" + case 0xC050: + csuitedesc = "TLS_RSA_WITH_ARIA_128_GCM_SHA256" + case 0xC051: + csuitedesc = "TLS_RSA_WITH_ARIA_256_GCM_SHA384" + case 0xC052: + csuitedesc = "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256" + case 0xC053: + csuitedesc = "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384" + case 0xC054: + csuitedesc = "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256" + case 0xC055: + csuitedesc = "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384" + case 0xC056: + csuitedesc = "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256" + case 0xC057: + csuitedesc = "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384" + case 0xC058: + csuitedesc = "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256" + case 0xC059: + csuitedesc = "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384" + case 0xC05A: + csuitedesc = "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256" + case 0xC05B: + csuitedesc = "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384" + case 0xC05C: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256" + case 0xC05D: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384" + case 0xC05E: + csuitedesc = "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256" + case 0xC05F: + csuitedesc = "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384" + case 0xC060: + csuitedesc = "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256" + case 0xC061: + csuitedesc = "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384" + case 0xC062: + csuitedesc = "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256" + case 0xC063: + csuitedesc = "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384" + case 0xC064: + csuitedesc = "TLS_PSK_WITH_ARIA_128_CBC_SHA256" + case 0xC065: + csuitedesc = "TLS_PSK_WITH_ARIA_256_CBC_SHA384" + case 0xC066: + csuitedesc = "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256" + case 0xC067: + csuitedesc = "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384" + case 0xC068: + csuitedesc = "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256" + case 0xC069: + csuitedesc = "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384" + case 0xC06A: + csuitedesc = "TLS_PSK_WITH_ARIA_128_GCM_SHA256" + case 0xC06B: + csuitedesc = "TLS_PSK_WITH_ARIA_256_GCM_SHA384" + case 0xC06C: + csuitedesc = "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256" + case 0xC06D: + csuitedesc = "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384" + case 0xC06E: + csuitedesc = "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256" + case 0xC06F: + csuitedesc = "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384" + case 0xC070: + csuitedesc = "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256" + case 0xC071: + csuitedesc = "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384" + case 0xC072: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC073: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC074: + csuitedesc = "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC075: + csuitedesc = "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC076: + csuitedesc = "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC077: + csuitedesc = "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC078: + csuitedesc = "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC079: + csuitedesc = "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC07A: + csuitedesc = "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC07B: + csuitedesc = "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC07C: + csuitedesc = "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC07D: + csuitedesc = "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC07E: + csuitedesc = "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC07F: + csuitedesc = "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC080: + csuitedesc = "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC081: + csuitedesc = "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC082: + csuitedesc = "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC083: + csuitedesc = "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC084: + csuitedesc = "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC085: + csuitedesc = "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC086: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC087: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC088: + csuitedesc = "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC089: + csuitedesc = "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC08A: + csuitedesc = "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC08B: + csuitedesc = "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC08C: + csuitedesc = "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC08D: + csuitedesc = "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC08E: + csuitedesc = "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC08F: + csuitedesc = "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC090: + csuitedesc = "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC091: + csuitedesc = "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC092: + csuitedesc = "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256" + case 0xC093: + csuitedesc = "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384" + case 0xC094: + csuitedesc = "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC095: + csuitedesc = "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC096: + csuitedesc = "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC097: + csuitedesc = "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC098: + csuitedesc = "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC099: + csuitedesc = "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC09A: + csuitedesc = "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256" + case 0xC09B: + csuitedesc = "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384" + case 0xC09C: + csuitedesc = "TLS_RSA_WITH_AES_128_CCM" + case 0xC09D: + csuitedesc = "TLS_RSA_WITH_AES_256_CCM" + case 0xC09E: + csuitedesc = "TLS_DHE_RSA_WITH_AES_128_CCM" + case 0xC09F: + csuitedesc = "TLS_DHE_RSA_WITH_AES_256_CCM" + case 0xC0A0: + csuitedesc = "TLS_RSA_WITH_AES_128_CCM_8" + case 0xC0A1: + csuitedesc = "TLS_RSA_WITH_AES_256_CCM_8" + case 0xC0A2: + csuitedesc = "TLS_DHE_RSA_WITH_AES_128_CCM_8" + case 0xC0A3: + csuitedesc = "TLS_DHE_RSA_WITH_AES_256_CCM_8" + case 0xC0A4: + csuitedesc = "TLS_PSK_WITH_AES_128_CCM" + case 0xC0A5: + csuitedesc = "TLS_PSK_WITH_AES_256_CCM" + case 0xC0A6: + csuitedesc = "TLS_DHE_PSK_WITH_AES_128_CCM" + case 0xC0A7: + csuitedesc = "TLS_DHE_PSK_WITH_AES_256_CCM" + case 0xC0A8: + csuitedesc = "TLS_PSK_WITH_AES_128_CCM_8" + case 0xC0A9: + csuitedesc = "TLS_PSK_WITH_AES_256_CCM_8" + case 0xC0AA: + csuitedesc = "TLS_PSK_DHE_WITH_AES_128_CCM_8" + case 0xC0AB: + csuitedesc = "TLS_PSK_DHE_WITH_AES_256_CCM_8" + case 0xC0AC: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_128_CCM" + case 0xC0AD: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_256_CCM" + case 0xC0AE: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8" + case 0xC0AF: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8" + case 0xC0B0: + csuitedesc = "TLS_ECCPWD_WITH_AES_128_GCM_SHA256" + case 0xC0B1: + csuitedesc = "TLS_ECCPWD_WITH_AES_256_GCM_SHA384" + case 0xC0B2: + csuitedesc = "TLS_ECCPWD_WITH_AES_128_CCM_SHA256" + case 0xC0B3: + csuitedesc = "TLS_ECCPWD_WITH_AES_256_CCM_SHA384" + case 0xC0B4: + csuitedesc = "TLS_SHA256_SHA256" + case 0xC0B5: + csuitedesc = "TLS_SHA384_SHA384" + case 0xC100: + csuitedesc = "TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC" + case 0xC101: + csuitedesc = "TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC" + case 0xC102: + csuitedesc = "TLS_GOSTR341112_256_WITH_28147_CNT_IMIT" + case 0xC103: + csuitedesc = "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L" + case 0xC104: + csuitedesc = "TLS_GOSTR341112_256_WITH_MAGMA_MGM_L" + case 0xC105: + csuitedesc = "TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S" + case 0xC106: + csuitedesc = "TLS_GOSTR341112_256_WITH_MAGMA_MGM_S" + case 0xCCA8: + csuitedesc = "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + case 0xCCA9: + csuitedesc = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" + case 0xCCAA: + csuitedesc = "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + case 0xCCAB: + csuitedesc = "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256" + case 0xCCAC: + csuitedesc = "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256" + case 0xCCAD: + csuitedesc = "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256" + case 0xCCAE: + csuitedesc = "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256" + case 0xD001: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256" + case 0xD002: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384" + case 0xD003: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256" + case 0xD005: + csuitedesc = "TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256" + default: + csuitedesc = "Unknown" + } + return csuitedesc +} +func extdesc(ext uint16) string { + var extdesc string + switch ext { + case 0: + extdesc = "server_name" + case 1: + extdesc = "max_fragment_length" + case 2: + extdesc = "client_certificate_url" + case 3: + extdesc = "trusted_ca_keys" + case 4: + extdesc = "truncated_hmac" + case 5: + extdesc = "status_request" + case 6: + extdesc = "user_mapping" + case 7: + extdesc = "client_authz" + case 8: + extdesc = "server_authz" + case 9: + extdesc = "cert_type" + case 10: + extdesc = "supported_groups" + case 11: + extdesc = "ec_point_formats" + case 12: + extdesc = "srp" + case 13: + extdesc = "signature_algorithms" + case 14: + extdesc = "use_srtp" + case 15: + extdesc = "heartbeat" + case 16: + extdesc = "application_layer_protocol_negotiation" + case 17: + extdesc = "status_request_v2" + case 18: + extdesc = "signed_certificate_timestamp" + case 19: + extdesc = "client_certificate_type" + case 20: + extdesc = "server_certificate_type" + case 21: + extdesc = "padding" + case 22: + extdesc = "encrypt_then_mac" + case 23: + extdesc = "extended_master_secret" + case 24: + extdesc = "token_binding" + case 25: + extdesc = "cached_info" + case 26: + extdesc = "tls_lts" + case 27: + extdesc = "compress_certificate" + case 28: + extdesc = "record_size_limit" + case 29: + extdesc = "pwd_protect" + case 30: + extdesc = "pwd_clear" + case 31: + extdesc = "password_salt" + case 32: + extdesc = "ticket_pinning" + case 33: + extdesc = "tls_cert_with_extern_psk" + case 34: + extdesc = "delegated_credential" + case 35: + extdesc = "session_ticket" + case 36: + extdesc = "TLMSP" + case 37: + extdesc = "TLMSP_proxying" + case 38: + extdesc = "TLMSP_delegate" + case 39: + extdesc = "supported_ekt_ciphers" + case 41: + extdesc = "pre_shared_key" + case 42: + extdesc = "early_data" + case 43: + extdesc = "supported_versions" + case 44: + extdesc = "cookie" + case 45: + extdesc = "psk_key_exchange_modes" + case 47: + extdesc = "certificate_authorities" + case 48: + extdesc = "oid_filters" + case 49: + extdesc = "post_handshake_auth" + case 50: + extdesc = "signature_algorithms_cert" + case 51: + extdesc = "key_share" + case 52: + extdesc = "transparency_info" + case 53: + extdesc = "connection_id (deprecated)" + case 54: + extdesc = "connection_id" + case 55: + extdesc = "external_id_hash" + case 56: + extdesc = "external_session_id" + case 57: + extdesc = "quic_transport_parameters" + case 58: + extdesc = "ticket_request" + case 59: + extdesc = "dnssec_chain" + case 60: + extdesc = "sequence_number_encryption_algorithms" + case 61: + extdesc = "rrc" + case 62: + extdesc = "tls_flags" + case 64768: + extdesc = "ech_outer_extensions" + case 65037: + extdesc = "encrypted_client_hello" + case 65281: + extdesc = "renegotiation_info" + default: + extdesc = "Unknown" + } + return extdesc +} diff --git a/layers/tls_test.go b/layers/tls_test.go index 2d60a5d..75eea79 100644 --- a/layers/tls_test.go +++ b/layers/tls_test.go @@ -27,7 +27,7 @@ func TestParseTLS(t *testing.T) { Version: 0x0303, VersionDesc: "TLS 1.2", Length: 23, - data: []byte{ + Data: []byte{ 0x42, 0xe3, 0xf1, 0x65, 0x80, 0x55, 0x3f, 0x84, 0x2e, 0x54, 0x80, 0xa6, 0xe9, 0x2b, 0x6e, 0xce, 0xdb, 0x0f, 0xb2, 0x53, 0x2e, 0x5f, 0x3e}, @@ -38,7 +38,7 @@ func TestParseTLS(t *testing.T) { Version: 0x0303, VersionDesc: "TLS 1.2", Length: 34, - data: []byte{ + Data: []byte{ 0x44, 0xed, 0x12, 0xf5, 0x5d, 0x28, 0x1e, 0x64, 0xba, 0x28, 0x39, 0x1a, 0x20, 0x5b, 0xb7, 0x14, 0xff, 0x5c, 0x48, 0x43, 0x04, 0x0e, 0x50, 0x13, 0xdf, 0x19, 0xff, 0x26, 0x53, 0xbb, From 4538bcb964f062148e1bb4f2413a3b092f34aa7d Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sat, 14 Jun 2025 08:19:02 +0300 Subject: [PATCH 4/8] fixed some bugs with csuites parsing --- layers/tls.go | 70 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/layers/tls.go b/layers/tls.go index 02b1ac5..bbf1c6b 100644 --- a/layers/tls.go +++ b/layers/tls.go @@ -7,7 +7,9 @@ import ( ) const ( - headerSizeTLS = 5 + headerSizeTLS = 5 + HandshakeTLSVal = 0x16 // 22 + ClientHelloTLSVal = 0x01 ) type Record struct { @@ -19,11 +21,38 @@ type Record struct { Data []byte } +func (r *Record) String() string { + return fmt.Sprintf(` - Content Type: %s (%d) + - Version: %s (%#04x) + - Length: %d`, + r.ContentTypeDesc, + r.ContentType, + r.VersionDesc, + r.Version, + r.Length) +} + +type HSTLSParser interface { + ParseHS(data []byte) error +} + +func HSTLSParserByType(hstype uint8) HSTLSParser { + switch hstype { + case 1: + return &TLSClientHello{} + } + return nil +} + type CipherSuite struct { Value uint16 Desc string } +func (cs *CipherSuite) String() string { + return fmt.Sprintf("%s (%#x)", cs.Desc, cs.Value) +} + type ServerName struct { Type uint16 Length uint16 @@ -56,14 +85,19 @@ type TLSClientHello struct { CmprMethodsLength uint8 // usually 0x01 CmprMethods []byte // usually 0x00 ExtensionLength uint16 - ServerName ServerName + ServerName *ServerName } -func (tch *TLSClientHello) Parse(data []byte) error { - // TODO: add ParseHandshake and type dispatcher +func (tch *TLSClientHello) ParseHS(data []byte) error { // offset 7 bytes + if len(data) < 4 { + return fmt.Errorf("message should be at least 4 bytes, got %d bytes", len(data)) + } tch.Length = int(uint(data[3]) | uint(data[2])<<8 | uint(data[1])<<16) // 6 - 8 bytes data[1:4] - tch.Version = binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] + if len(data)-4 < tch.Length { + return fmt.Errorf("message should be at least %d bytes, got %d bytes", tch.Length, len(data)-4) + } + tch.Version = binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] tch.VersionDesc = verdesc(tch.Version) tch.Random = data[6:38] // 11-42 data[6:38] tch.SessionIDLength = data[38] // 43 data[38] 32 bytes @@ -71,12 +105,15 @@ func (tch *TLSClientHello) Parse(data []byte) error { tch.SessionID = data[39:sid] // data[39:71] csl := binary.BigEndian.Uint16(data[sid : sid+2]) // data[71:73] suites count * 2 bytes tch.CipherSuitesLength = csl - cmproffset := csl + 73 // 107 - css := make([]*CipherSuite, 0, csl/2+1) - for i := range len(data[73:cmproffset]) { - val := binary.BigEndian.Uint16(data[i : i+2]) + offset := uint16(sid + 2) //73 + cmproffset := csl + offset // 107 + css := make([]*CipherSuite, 0, csl/2) + var i uint16 + for i < csl { + val := binary.BigEndian.Uint16(data[i+offset : i+offset+2]) valdesc := csuitedesc(val) css = append(css, &CipherSuite{Value: val, Desc: valdesc}) + i += 2 } tch.CipherSuites = css cml := data[cmproffset] // 107 @@ -85,13 +122,13 @@ func (tch *TLSClientHello) Parse(data []byte) error { tch.CmprMethods = data[cmproffset+1 : extoffset] // data[108:109] extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2]) // data[109:111] tch.ExtensionLength = extlen - var i = extoffset + 2 + i = extoffset + 2 for i < extoffset+extlen { typ := binary.BigEndian.Uint16(data[i : i+2]) length := binary.BigEndian.Uint16(data[i+2 : i+4]) switch typ { case 0: // TODO: add more extensions - sn := ServerName{} + sn := &ServerName{} err := sn.Parse(data[i : i+length+4]) if err != nil { return err @@ -118,17 +155,6 @@ type TLSServerHello struct { ExtensionLength uint16 } -func (r *Record) String() string { - return fmt.Sprintf(` - Content Type: %s (%d) - - Version: %s (%#04x) - - Length: %d`, - r.ContentTypeDesc, - r.ContentType, - r.VersionDesc, - r.Version, - r.Length) -} - // port 443 // https://tls12.xargs.org/#client-hello/annotated // https://tls13.xargs.org/#client-hello/annotated From d6cbb7ad691601d986c50c62e8e09eb2433d4dc9 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 15 Jun 2025 15:08:09 +0300 Subject: [PATCH 5/8] added server hello parsing --- layers/tls.go | 127 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 28 deletions(-) diff --git a/layers/tls.go b/layers/tls.go index bbf1c6b..4e26ca4 100644 --- a/layers/tls.go +++ b/layers/tls.go @@ -2,6 +2,7 @@ package layers import ( "encoding/binary" + "encoding/hex" "fmt" "strings" ) @@ -12,22 +13,29 @@ const ( ClientHelloTLSVal = 0x01 ) +type TLSVersion struct { + Value uint16 + Desc string +} + +func (tv *TLSVersion) String() string { + return fmt.Sprintf("%s (%#04x)", tv.Desc, tv.Value) +} + type Record struct { ContentType uint8 ContentTypeDesc string - Version uint16 - VersionDesc string + Version *TLSVersion Length uint16 Data []byte } func (r *Record) String() string { return fmt.Sprintf(` - Content Type: %s (%d) - - Version: %s (%#04x) + - Version: %s - Length: %d`, r.ContentTypeDesc, r.ContentType, - r.VersionDesc, r.Version, r.Length) } @@ -40,6 +48,8 @@ func HSTLSParserByType(hstype uint8) HSTLSParser { switch hstype { case 1: return &TLSClientHello{} + case 2: + return &TLSServerHello{} } return nil } @@ -53,13 +63,22 @@ func (cs *CipherSuite) String() string { return fmt.Sprintf("%s (%#x)", cs.Desc, cs.Value) } +type Extension struct { + Value uint16 + Desc string +} + +func (e *Extension) String() string { + return fmt.Sprintf("%s (%d)", e.Desc, e.Value) +} + type ServerName struct { Type uint16 Length uint16 SNListLength uint16 SNType uint8 SNNameLength uint16 - SNName []byte + SNName string } func (sn *ServerName) Parse(data []byte) error { @@ -68,24 +87,25 @@ func (sn *ServerName) Parse(data []byte) error { sn.SNListLength = binary.BigEndian.Uint16(data[4:6]) sn.SNType = data[6] sn.SNNameLength = binary.BigEndian.Uint16(data[7:9]) - sn.SNName = data[9 : 9+sn.SNNameLength] + sn.SNName = string(data[9 : 9+sn.SNNameLength]) return nil } // https://wiki.osdev.org/TLS_Handshake#Client_Hello_Message type TLSClientHello struct { Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16)) - Version uint16 - VersionDesc string + Version *TLSVersion Random []byte //32 bytes SessionIDLength uint8 // if 0 no session follows - SessionID []byte + SessionID string CipherSuitesLength uint16 CipherSuites []*CipherSuite CmprMethodsLength uint8 // usually 0x01 CmprMethods []byte // usually 0x00 ExtensionLength uint16 + Extensions []*Extension ServerName *ServerName + ALPN []string } func (tch *TLSClientHello) ParseHS(data []byte) error { @@ -97,12 +117,12 @@ func (tch *TLSClientHello) ParseHS(data []byte) error { if len(data)-4 < tch.Length { return fmt.Errorf("message should be at least %d bytes, got %d bytes", tch.Length, len(data)-4) } - tch.Version = binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] - tch.VersionDesc = verdesc(tch.Version) + ver := binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] + tch.Version = &TLSVersion{Value: ver, Desc: verdesc(ver)} tch.Random = data[6:38] // 11-42 data[6:38] tch.SessionIDLength = data[38] // 43 data[38] 32 bytes sid := tch.SessionIDLength + 39 // 70 - tch.SessionID = data[39:sid] // data[39:71] + tch.SessionID = hex.EncodeToString(data[39:sid]) // data[39:71] csl := binary.BigEndian.Uint16(data[sid : sid+2]) // data[71:73] suites count * 2 bytes tch.CipherSuitesLength = csl offset := uint16(sid + 2) //73 @@ -123,36 +143,88 @@ func (tch *TLSClientHello) ParseHS(data []byte) error { extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2]) // data[109:111] tch.ExtensionLength = extlen i = extoffset + 2 + exts := make([]*Extension, 0, 20) for i < extoffset+extlen { typ := binary.BigEndian.Uint16(data[i : i+2]) length := binary.BigEndian.Uint16(data[i+2 : i+4]) + exts = append(exts, &Extension{Value: typ, Desc: extdesc(typ)}) switch typ { - case 0: // TODO: add more extensions + case 0: // SNI sn := &ServerName{} err := sn.Parse(data[i : i+length+4]) if err != nil { return err } tch.ServerName = sn - i += length + 4 - default: - i += length + 4 + case 16: //ALPN + //skip data[i+4:i+6] alpn extension length + start := i + 6 + alpns := make([]string, 0, 5) + for start < i+length+4 { + alpnStringLength := data[start] + nextProto := string(data[start+1 : start+uint16(alpnStringLength+1)]) + alpns = append(alpns, nextProto) + start += uint16(alpnStringLength + 1) + } + tch.ALPN = alpns } + i += length + 4 } + tch.Extensions = exts return nil } // https://wiki.osdev.org/TLS_Handshake#Server_Hello_Message type TLSServerHello struct { - Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16)) - Version uint16 - VersionDesc string - Random []byte //32 bytes - SessionIDLength uint8 // if 0 no session follows - SessionID []byte - CipherSuite *CipherSuite - CmprMethod uint8 - ExtensionLength uint16 + Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16)) + Version *TLSVersion + Random []byte //32 bytes + SessionIDLength uint8 // if 0 no session follows + SessionID string + CipherSuite *CipherSuite + CmprMethod uint8 + ExtensionLength uint16 + Extensions []*Extension + SupportedVersion *TLSVersion +} + +func (tsh *TLSServerHello) ParseHS(data []byte) error { + // offset 7 bytes + if len(data) < 4 { + return fmt.Errorf("message should be at least 4 bytes, got %d bytes", len(data)) + } + tsh.Length = int(uint(data[3]) | uint(data[2])<<8 | uint(data[1])<<16) // 6 - 8 bytes data[1:4] + if len(data)-4 < tsh.Length { + return fmt.Errorf("message should be at least %d bytes, got %d bytes", tsh.Length, len(data)-4) + } + ver := binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] + tsh.Version = &TLSVersion{Value: ver, Desc: verdesc(ver)} + tsh.Random = data[6:38] // 11-42 data[6:38] + tsh.SessionIDLength = data[38] // 43 data[38] 32 bytes + sid := tsh.SessionIDLength + 39 // 70 + tsh.SessionID = hex.EncodeToString(data[39:sid]) // data[39:71] + val := binary.BigEndian.Uint16(data[sid : sid+2]) + valdesc := csuitedesc(val) + tsh.CipherSuite = &CipherSuite{Value: val, Desc: valdesc} + tsh.CmprMethod = data[sid+2] + extoffset := uint16(sid + 3) + extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2]) + tsh.ExtensionLength = extlen + exts := make([]*Extension, 0, 20) + i := extoffset + 2 + for i < extoffset+extlen { + typ := binary.BigEndian.Uint16(data[i : i+2]) + length := binary.BigEndian.Uint16(data[i+2 : i+4]) + exts = append(exts, &Extension{Value: typ, Desc: extdesc(typ)}) + switch typ { + case 43: // supported versions + ver := binary.BigEndian.Uint16(data[i+4 : i+6]) + tsh.SupportedVersion = &TLSVersion{Value: ver, Desc: verdesc(ver)} + } + i += length + 4 + } + tsh.Extensions = exts + return nil } // port 443 @@ -181,7 +253,7 @@ func (t *TLSMessage) Summary() string { sb.WriteString(fmt.Sprintf("%s (%d) Len: %d ", rec.ContentTypeDesc, rec.ContentType, rec.Length)) continue } - sb.WriteString(fmt.Sprintf("%s (%#04x) ", rec.VersionDesc, rec.Version)) + sb.WriteString(rec.Version.String()) if rec.ContentType == 22 { hstd := hstypedesc(rec.Data[0]) sb.WriteString(fmt.Sprintf("%s ", hstd)) @@ -230,8 +302,7 @@ func (t *TLSMessage) Parse(data []byte) error { r := &Record{ ContentType: ctype, ContentTypeDesc: ctdesc, - Version: ver, - VersionDesc: verdesc, + Version: &TLSVersion{Value: ver, Desc: verdesc}, Length: rlen, Data: data[headerSizeTLS : headerSizeTLS+rlen], } From 95892a2eb0f26e136f5e7c526539e5750a8a10bc Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Mon, 16 Jun 2025 13:51:05 +0300 Subject: [PATCH 6/8] improved hhtp parsing, fixed tls fragmented messages --- layers/http.go | 83 ++++++++++++------- layers/layers.go | 2 +- layers/tls.go | 212 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 248 insertions(+), 49 deletions(-) diff --git a/layers/http.go b/layers/http.go index 082f2a2..30adc3e 100644 --- a/layers/http.go +++ b/layers/http.go @@ -1,57 +1,78 @@ package layers import ( + "bufio" "bytes" "fmt" + "net/http" + "net/http/httputil" +) + +var ( + protohttp10 = []byte("HTTP/1.0") + protohttp11 = []byte("HTTP/1.1") ) // https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages // port 80 type HTTPMessage struct { - summary []byte - data []byte + Request *http.Request + Response *http.Response +} + +func (h *HTTPMessage) IsEmpty() bool { + return h.Request == nil && h.Response == nil } func (h *HTTPMessage) String() string { + m := ellipsis + if h.Request != nil { + m, _ = httputil.DumpRequest(h.Request, false) + m = joinBytes(dash, bytes.TrimRight(bytes.TrimSuffix(bytes.Join(bytes.Split(m, crlf), lfd), crlf), slfd)) + } else if h.Response != nil { + m, _ = httputil.DumpResponse(h.Response, false) + m = joinBytes(dash, bytes.TrimRight(bytes.TrimSuffix(bytes.Join(bytes.Split(m, crlf), lfd), crlf), slfd)) + } return fmt.Sprintf(`%s %s -`, h.Summary(), h.data) -} -func (h *HTTPMessage) Summary() string { - return fmt.Sprintf("HTTP Message: %s", h.summary) +`, h.Summary(), m) } -func (h *HTTPMessage) ellipsify() { - h.summary = contdata - h.data = ellipsis +func (h *HTTPMessage) Summary() string { + m := fmt.Sprintf("HTTP Message: %s", contdata) + if h.Request != nil { + m = fmt.Sprintf("HTTP Request: %s %s%s%s %s Content-Length: %d", + h.Request.Method, h.Request.Host, h.Request.URL.Path, h.Request.URL.RawQuery, h.Request.Proto, h.Request.ContentLength) + } else if h.Response != nil { + m = fmt.Sprintf("HTTP Response: %s %s Content-Length: %d", + h.Response.Proto, h.Response.Status, h.Response.ContentLength) + } + return fmt.Sprintf("%s", m) } func (h *HTTPMessage) Parse(data []byte) error { - if !bytes.Contains(data, proto) { - h.ellipsify() - return nil - } - - var idx int - if idx = bytes.Index(data, dcrlf); idx == -1 { - h.ellipsify() + if !bytes.Contains(data, protohttp10) && !bytes.Contains(data, protohttp11) { + h.Request = nil + h.Response = nil return nil } - - sp := bytes.Split(data[:idx], crlf) - lsp := len(sp) - switch { - case lsp > 2: - h.summary = bytes.Join(sp[:2], bspace) - sp[0] = joinBytes(dash, sp[0]) - h.data = bytes.TrimSuffix(bytes.Join(sp, lfd), crlf) - case lsp > 1: - h.summary = sp[0] - sp[0] = joinBytes(dash, sp[0]) - h.data = bytes.TrimSuffix(bytes.Join(sp, lfd), crlf) - default: - h.ellipsify() + reader := bufio.NewReader(bytes.NewReader(data)) + if bytes.HasPrefix(data, protohttp11) || bytes.HasPrefix(data, protohttp10) { + resp, err := http.ReadResponse(reader, nil) + if err != nil { + return err + } + h.Response = resp + h.Request = nil + } else { + reader := bufio.NewReader(bytes.NewReader(data)) + req, err := http.ReadRequest(reader) + if err != nil { + return err + } + h.Request = req + h.Response = nil } return nil } diff --git a/layers/layers.go b/layers/layers.go index 1cc1c53..790e6d9 100644 --- a/layers/layers.go +++ b/layers/layers.go @@ -28,10 +28,10 @@ var ( bspace = []byte(" ") dash = []byte("- ") lfd = []byte("\n- ") + slfd = "\n- " lf = []byte("\n") crlf = []byte("\r\n") dcrlf = []byte("\r\n\r\n") - proto = []byte("HTTP/1.1") ellipsis = []byte("...") contdata = []byte("Continuation data") ) diff --git a/layers/tls.go b/layers/tls.go index 4e26ca4..1d798ba 100644 --- a/layers/tls.go +++ b/layers/tls.go @@ -11,6 +11,7 @@ const ( headerSizeTLS = 5 HandshakeTLSVal = 0x16 // 22 ClientHelloTLSVal = 0x01 + ServerHelloTLSVal = 0x02 ) type TLSVersion struct { @@ -91,8 +92,28 @@ func (sn *ServerName) Parse(data []byte) error { return nil } +func (sn *ServerName) String() string { + return fmt.Sprintf(`server_name (len=%d) name=%s + - Type: server_name (%d) + - Length: %d + - SNI List length: %d + - SNI Type: %d + - SNI Name Length: %d + - SNI Name: %s`, + sn.Length, + sn.SNName, + sn.Type, + sn.Length, + sn.SNListLength, + sn.SNType, + sn.SNNameLength, + sn.SNName) +} + // https://wiki.osdev.org/TLS_Handshake#Client_Hello_Message type TLSClientHello struct { + Type uint8 + TypeDesc string Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16)) Version *TLSVersion Random []byte //32 bytes @@ -108,21 +129,66 @@ type TLSClientHello struct { ALPN []string } +func (tch *TLSClientHello) String() string { + return fmt.Sprintf(` - Type: %s (%d) + - Length: %d + - Version: %s + - Random: %s + - SessionIDLength: %d + - SessionID: %s + - CipherSuitesLength: %d + - CipherSuites: %v + - CmprMethodsLength: %d + - CmprMethods: %v + - ExtensionLength: %d + - Extensions: %v + - %s + - ALPN: %v +`, + tch.TypeDesc, + tch.Type, + tch.Length, + tch.Version, + hex.EncodeToString(tch.Random), + tch.SessionIDLength, + tch.SessionID, + tch.CipherSuitesLength, + tch.CipherSuites, + tch.CmprMethodsLength, + tch.CmprMethods, + tch.ExtensionLength, + tch.Extensions, + tch.ServerName, + tch.ALPN, + ) +} + func (tch *TLSClientHello) ParseHS(data []byte) error { // offset 7 bytes if len(data) < 4 { return fmt.Errorf("message should be at least 4 bytes, got %d bytes", len(data)) } + tch.Type = data[0] + tch.TypeDesc = hstypedesc(tch.Type) tch.Length = int(uint(data[3]) | uint(data[2])<<8 | uint(data[1])<<16) // 6 - 8 bytes data[1:4] - if len(data)-4 < tch.Length { - return fmt.Errorf("message should be at least %d bytes, got %d bytes", tch.Length, len(data)-4) + if len(data) < 6 { + return nil } ver := binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] tch.Version = &TLSVersion{Value: ver, Desc: verdesc(ver)} - tch.Random = data[6:38] // 11-42 data[6:38] - tch.SessionIDLength = data[38] // 43 data[38] 32 bytes - sid := tch.SessionIDLength + 39 // 70 - tch.SessionID = hex.EncodeToString(data[39:sid]) // data[39:71] + if len(data) < 38 { + return nil + } + tch.Random = data[6:38] // 11-42 data[6:38] + tch.SessionIDLength = data[38] // 43 data[38] 32 bytes + sid := tch.SessionIDLength + 39 // 70 + if len(data) < int(sid) { + return nil + } + tch.SessionID = hex.EncodeToString(data[39:sid]) // data[39:71] + if len(data) < int(sid+2) { + return nil + } csl := binary.BigEndian.Uint16(data[sid : sid+2]) // data[71:73] suites count * 2 bytes tch.CipherSuitesLength = csl offset := uint16(sid + 2) //73 @@ -130,26 +196,47 @@ func (tch *TLSClientHello) ParseHS(data []byte) error { css := make([]*CipherSuite, 0, csl/2) var i uint16 for i < csl { + if len(data) < int(i+offset+2) { + return nil + } val := binary.BigEndian.Uint16(data[i+offset : i+offset+2]) valdesc := csuitedesc(val) css = append(css, &CipherSuite{Value: val, Desc: valdesc}) i += 2 } tch.CipherSuites = css + if len(data) < int(cmproffset) { + return nil + } cml := data[cmproffset] // 107 tch.CmprMethodsLength = cml extoffset := cmproffset + 1 + uint16(cml) - tch.CmprMethods = data[cmproffset+1 : extoffset] // data[108:109] + if len(data) < int(extoffset) { + return nil + } + tch.CmprMethods = data[cmproffset+1 : extoffset] // data[108:109] + if len(data) < int(extoffset+2) { + return nil + } extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2]) // data[109:111] tch.ExtensionLength = extlen i = extoffset + 2 exts := make([]*Extension, 0, 20) for i < extoffset+extlen { + if len(data) < int(i+2) { + return nil + } typ := binary.BigEndian.Uint16(data[i : i+2]) + if len(data) < int(i+4) { + return nil + } length := binary.BigEndian.Uint16(data[i+2 : i+4]) exts = append(exts, &Extension{Value: typ, Desc: extdesc(typ)}) switch typ { case 0: // SNI + if len(data) < int(i+length+4) { + return nil + } sn := &ServerName{} err := sn.Parse(data[i : i+length+4]) if err != nil { @@ -158,10 +245,19 @@ func (tch *TLSClientHello) ParseHS(data []byte) error { tch.ServerName = sn case 16: //ALPN //skip data[i+4:i+6] alpn extension length + if len(data) < int(i+6) { + return nil + } start := i + 6 alpns := make([]string, 0, 5) for start < i+length+4 { + if len(data) < int(start) { + return nil + } alpnStringLength := data[start] + if len(data) < int(start+uint16(alpnStringLength+1)) { + return nil + } nextProto := string(data[start+1 : start+uint16(alpnStringLength+1)]) alpns = append(alpns, nextProto) start += uint16(alpnStringLength + 1) @@ -176,6 +272,8 @@ func (tch *TLSClientHello) ParseHS(data []byte) error { // https://wiki.osdev.org/TLS_Handshake#Server_Hello_Message type TLSServerHello struct { + Type uint8 + TypeDesc string Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16)) Version *TLSVersion Random []byte //32 bytes @@ -188,36 +286,90 @@ type TLSServerHello struct { SupportedVersion *TLSVersion } +func (tsh *TLSServerHello) String() string { + return fmt.Sprintf(` - Type: %s (%d) + - Length: %d + - Version: %s + - Random: %s + - SessionIDLength: %d + - SessionID: %s + - CipherSuite: %s + - CmprMethod: %d + - ExtensionLength: %d + - Extensions: %v + - Supported Version: %s +`, + tsh.TypeDesc, + tsh.Type, + tsh.Length, + tsh.Version, + hex.EncodeToString(tsh.Random), + tsh.SessionIDLength, + tsh.SessionID, + tsh.CipherSuite, + tsh.CmprMethod, + tsh.ExtensionLength, + tsh.Extensions, + tsh.SupportedVersion, + ) +} + func (tsh *TLSServerHello) ParseHS(data []byte) error { // offset 7 bytes if len(data) < 4 { return fmt.Errorf("message should be at least 4 bytes, got %d bytes", len(data)) } + tsh.Type = data[0] + tsh.TypeDesc = hstypedesc(tsh.Type) tsh.Length = int(uint(data[3]) | uint(data[2])<<8 | uint(data[1])<<16) // 6 - 8 bytes data[1:4] if len(data)-4 < tsh.Length { return fmt.Errorf("message should be at least %d bytes, got %d bytes", tsh.Length, len(data)-4) } + if len(data) < 6 { + return nil + } ver := binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6] tsh.Version = &TLSVersion{Value: ver, Desc: verdesc(ver)} - tsh.Random = data[6:38] // 11-42 data[6:38] - tsh.SessionIDLength = data[38] // 43 data[38] 32 bytes - sid := tsh.SessionIDLength + 39 // 70 + if len(data) < 38 { + return nil + } + tsh.Random = data[6:38] // 11-42 data[6:38] + tsh.SessionIDLength = data[38] // 43 data[38] 32 bytes + sid := tsh.SessionIDLength + 39 // 70 + if len(data) < int(sid) { + return nil + } tsh.SessionID = hex.EncodeToString(data[39:sid]) // data[39:71] + if len(data) < int(sid+2) { + return nil + } val := binary.BigEndian.Uint16(data[sid : sid+2]) valdesc := csuitedesc(val) tsh.CipherSuite = &CipherSuite{Value: val, Desc: valdesc} tsh.CmprMethod = data[sid+2] extoffset := uint16(sid + 3) + if len(data) < int(extoffset+2) { + return nil + } extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2]) tsh.ExtensionLength = extlen exts := make([]*Extension, 0, 20) i := extoffset + 2 for i < extoffset+extlen { + if len(data) < int(i+2) { + return nil + } typ := binary.BigEndian.Uint16(data[i : i+2]) + if len(data) < int(i+4) { + return nil + } length := binary.BigEndian.Uint16(data[i+2 : i+4]) exts = append(exts, &Extension{Value: typ, Desc: extdesc(typ)}) switch typ { case 43: // supported versions + if len(data) < int(i+6) { + return nil + } ver := binary.BigEndian.Uint16(data[i+4 : i+6]) tsh.SupportedVersion = &TLSVersion{Value: ver, Desc: verdesc(ver)} } @@ -254,7 +406,8 @@ func (t *TLSMessage) Summary() string { continue } sb.WriteString(rec.Version.String()) - if rec.ContentType == 22 { + sb.WriteString(" ") + if rec.ContentType == HandshakeTLSVal { hstd := hstypedesc(rec.Data[0]) sb.WriteString(fmt.Sprintf("%s ", hstd)) } @@ -274,16 +427,40 @@ func (t *TLSMessage) printRecords() string { var sb strings.Builder for _, rec := range t.Records { + if rec.ContentType == HandshakeTLSVal { + if rec.Data[0] == ClientHelloTLSVal { + tc := TLSClientHello{} + err := tc.ParseHS(rec.Data) + if err == nil { + sb.WriteString(fmt.Sprintf("- %s:\n", rec.ContentTypeDesc)) + sb.WriteString(tc.String()) + } else { + sb.WriteString(fmt.Sprintf("- %s:\n%s\n", rec.ContentTypeDesc, rec)) + } + continue + } + if rec.Data[0] == ServerHelloTLSVal { + ts := TLSServerHello{} + err := ts.ParseHS(rec.Data) + if err == nil { + sb.WriteString(fmt.Sprintf("- %s:\n", rec.ContentTypeDesc)) + sb.WriteString(ts.String()) + } else { + sb.WriteString(fmt.Sprintf("- %s:\n%s\n", rec.ContentTypeDesc, rec)) + } + continue + } + } sb.WriteString(fmt.Sprintf("- %s:\n%s\n", rec.ContentTypeDesc, rec)) } return sb.String() } func (t *TLSMessage) Parse(data []byte) error { + t.Records = make([]*Record, 0, 5) if len(data) < headerSizeTLS { - return fmt.Errorf("minimum header size for TLS is %d bytes, got %d bytes", headerSizeTLS, len(data)) + return nil } - t.Records = make([]*Record, 0, 5) for len(data) > 0 { ctype := data[0] ctdesc := ctdesc(ctype) @@ -296,18 +473,19 @@ func (t *TLSMessage) Parse(data []byte) error { break } rlen := binary.BigEndian.Uint16(data[3:headerSizeTLS]) - if headerSizeTLS+rlen > uint16(len(data)) { - break + rb := uint16(headerSizeTLS + rlen) + if rb > uint16(len(data)) { + rb = uint16(len(data)) } r := &Record{ ContentType: ctype, ContentTypeDesc: ctdesc, Version: &TLSVersion{Value: ver, Desc: verdesc}, Length: rlen, - Data: data[headerSizeTLS : headerSizeTLS+rlen], + Data: data[headerSizeTLS:rb], } t.Records = append(t.Records, r) - data = data[headerSizeTLS+rlen:] + data = data[rb:] } t.Data = data return nil From e63e5cbc5abddc0627c2c0031f2195d4aaac98db Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:26:00 +0300 Subject: [PATCH 7/8] updated Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index d4a583b..23b5c6a 100644 --- a/Makefile +++ b/Makefile @@ -44,4 +44,5 @@ cover: .PHONY: clean clean: + find ./bin ! -name '.gitignore' -type f -exec rm -vrf {} + rm -v *.txt *.pcap* From 767579f7579a00b2adc10916b3c2f3b35685dc38 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Tue, 17 Jun 2025 10:29:10 +0300 Subject: [PATCH 8/8] added json marshalling for tls and http --- layers/http.go | 45 ++++++++++++++++++++++++++++ layers/tls.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/layers/http.go b/layers/http.go index 30adc3e..cb82158 100644 --- a/layers/http.go +++ b/layers/http.go @@ -3,6 +3,7 @@ package layers import ( "bufio" "bytes" + "encoding/json" "fmt" "net/http" "net/http/httputil" @@ -78,3 +79,47 @@ func (h *HTTPMessage) Parse(data []byte) error { } func (h *HTTPMessage) NextLayer() (layer string, payload []byte) { return } + +type HTTPRequestWrapper struct { + Request HTTPRequest `json:"http_request"` +} + +type HTTPRequest struct { + Host string `json:"host,omitempty"` + URI string `json:"uri,omitempty"` + Method string `json:"method,omitempty"` + Proto string `json:"proto,omitempty"` + ContentLength int `json:"content-length,omitempty"` + Header http.Header `json:"header,omitempty"` +} + +type HTTPResponseWrapper struct { + Response HTTPResponse `json:"http_response"` +} + +type HTTPResponse struct { + Proto string `json:"proto,omitempty"` + Status string `json:"status,omitempty"` + ContentLength int `json:"content-length,omitempty"` + Header http.Header `json:"header,omitempty"` +} + +func (h *HTTPMessage) MarshalJSON() ([]byte, error) { + if h.Request != nil { + return json.Marshal(&HTTPRequestWrapper{Request: HTTPRequest{ + Host: h.Request.Host, + URI: h.Request.RequestURI, + Method: h.Request.Method, + Proto: h.Request.Proto, + ContentLength: int(h.Request.ContentLength), + Header: h.Request.Header, + }}) + } else if h.Response != nil { + return json.Marshal(&HTTPResponseWrapper{Response: HTTPResponse{ + Proto: h.Response.Proto, + Status: h.Response.Status, + ContentLength: int(h.Response.ContentLength), + Header: h.Response.Header}}) + } + return nil, fmt.Errorf("both request and response are empty") +} diff --git a/layers/tls.go b/layers/tls.go index 1d798ba..10bb5b1 100644 --- a/layers/tls.go +++ b/layers/tls.go @@ -3,6 +3,7 @@ package layers import ( "encoding/binary" "encoding/hex" + "encoding/json" "fmt" "strings" ) @@ -129,6 +130,47 @@ type TLSClientHello struct { ALPN []string } +type TLSClientHelloRequestWrapper struct { + Request TLSClientHelloRequest `json:"tls_request"` +} + +type TLSClientHelloRequest struct { + SNI string `json:"sni,omitempty"` + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + SessionID string `json:"session_id,omitempty"` + CipherSuites []string `json:"cipher_suites,omitempty"` + Extensions []string `json:"extensions,omitempty"` + ALPN []string `json:"alpn,omitempty"` +} + +func (tch *TLSClientHello) MarshalJSON() ([]byte, error) { + cs := make([]string, 0, len(tch.CipherSuites)) + for _, c := range tch.CipherSuites { + cs = append(cs, c.String()) + } + es := make([]string, 0, len(tch.Extensions)) + for _, e := range tch.Extensions { + es = append(es, e.String()) + } + var ver, sn string + if tch.Version != nil { + ver = tch.Version.String() + } + if tch.ServerName != nil { + sn = tch.ServerName.SNName + } + return json.Marshal(&TLSClientHelloRequestWrapper{Request: TLSClientHelloRequest{ + SNI: sn, + Type: fmt.Sprintf("%s (%d)", tch.TypeDesc, tch.Type), + Version: ver, + SessionID: tch.SessionID, + CipherSuites: cs, + Extensions: es, + ALPN: tch.ALPN, + }}) +} + func (tch *TLSClientHello) String() string { return fmt.Sprintf(` - Type: %s (%d) - Length: %d @@ -286,6 +328,44 @@ type TLSServerHello struct { SupportedVersion *TLSVersion } +type TLSServerHelloResponseWrapper struct { + Response TLSServerHelloResponse `json:"tls_response"` +} + +type TLSServerHelloResponse struct { + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` + SessionID string `json:"session_id,omitempty"` + CipherSuite string `json:"cipher_suite,omitempty"` + Extensions []string `json:"extensions,omitempty"` + SupportedVersion string `json:"supported_version,omitempty"` +} + +func (tsh *TLSServerHello) MarshalJSON() ([]byte, error) { + es := make([]string, 0, len(tsh.Extensions)) + for _, e := range tsh.Extensions { + es = append(es, e.String()) + } + var ver, supver, cs string + if tsh.Version != nil { + ver = tsh.Version.String() + } + if tsh.SupportedVersion != nil { + supver = tsh.SupportedVersion.String() + } + if tsh.CipherSuite != nil { + cs = tsh.CipherSuite.String() + } + return json.Marshal(&TLSServerHelloResponseWrapper{Response: TLSServerHelloResponse{ + Type: fmt.Sprintf("%s (%d)", tsh.TypeDesc, tsh.Type), + Version: ver, + SessionID: tsh.SessionID, + CipherSuite: cs, + Extensions: es, + SupportedVersion: supver, + }}) +} + func (tsh *TLSServerHello) String() string { return fmt.Sprintf(` - Type: %s (%d) - Length: %d