commit 2081d684ed83d4f9de66d195340ce2abe38b7398 Author: maze Date: Wed Oct 8 20:53:56 2025 +0200 Initial import diff --git a/cmd/protodial/main.go b/cmd/protodial/main.go new file mode 100644 index 0000000..5e9d3bf --- /dev/null +++ b/cmd/protodial/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "sync" + + "git.maze.io/go/dpi/protocol" +) + +func main() { + acceptFlag := flag.String("accept", "", "comma separated list of accepted protocols") + flag.Parse() + + if flag.NArg() != 2 { + fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) + os.Exit(1) + } + + accept := make(map[string]bool) + acceptFlags := strings.Split(*acceptFlag, ",") + if len(acceptFlags) == 0 { + fmt.Fprintln(os.Stderr, "No -accept was provided, refusing all protocols!") + } else { + for _, proto := range acceptFlags { + accept[proto] = true + } + } + + c, err := net.Dial("tcp", net.JoinHostPort(flag.Arg(0), flag.Arg(1))) + if err != nil { + log.Fatalln(err) + } + + c = protocol.Limit(c, func(dir protocol.Direction, p *protocol.Protocol) error { + if p == nil { + return errors.New("No protocol detected") + } + if !accept[p.Name] { + return fmt.Errorf("Protocol %s is not accepted", p.Name) + } + fmt.Fprintf(os.Stderr, "Accepting protocol %s version %s initiated by %s\n", + p.Name, p.Version, dir) + return nil + }) + defer c.Close() + + var wait sync.WaitGroup + wait.Go(func() { multiplex(c, os.Stdin) }) + wait.Go(func() { multiplex(os.Stdout, c) }) + wait.Wait() +} + +func multiplex(w io.Writer, r io.Reader) { + if _, err := io.Copy(w, r); err != nil && !errors.Is(err, io.EOF) { + log.Fatalln("Copy terminated:", err) + } +} diff --git a/cmd/protoproxy/main.go b/cmd/protoproxy/main.go new file mode 100644 index 0000000..acdb40b --- /dev/null +++ b/cmd/protoproxy/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "context" + "flag" + "io" + "log" + "net" + "sync" + "time" + + "git.maze.io/go/dpi/protocol" +) + +func main() { + listenFlag := flag.String("listen", "localhost:4080", "proxy listen address") + targetFlag := flag.String("target", "localhost:22", "proxy target address") + flag.Parse() + + l, err := net.Listen("tcp", *listenFlag) + if err != nil { + log.Fatalf("listen error: %v", err) + } + + log.Printf("listening on %s", l.Addr()) + for { + c, err := l.Accept() + if err != nil { + log.Fatalln("accept error:", err) + } + go proxy(c, *targetFlag) + } +} + +func proxy(client net.Conn, target string) { + log.Printf("new connection from %s", client.RemoteAddr()) + + // Hangup client if we return + defer func() { + log.Printf("closing connection to %s: %v", client.RemoteAddr(), client.Close()) + }() + + log.Printf("dialing %s", target) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + var dialer net.Dialer + + server, err := dialer.DialContext(ctx, "tcp", target) + if err != nil { + cancel() + log.Printf("error connecting to %s: %v", target, err) + return + } + cancel() + + // Hangup server if we return + defer func() { + log.Printf("closing connection to %s: %v", server.RemoteAddr(), server.Close()) + }() + + // Setup interceptor and wrap the client and server connections. + interceptor := protocol.NewInterceptor() + client = interceptor.Client(client) + server = interceptor.Server(server) + + // Request a return channel and start the detection before doing anything + // else with the client and server connections. + intercepted := interceptor.Detect(10 * time.Second) + + log.Printf("client %s connected to %s; proxying", client.RemoteAddr(), server.RemoteAddr()) + + // Create a wait group and copy between client and server bidirectionally, + // either side needs to generate data for the detection to work. + var group sync.WaitGroup + group.Go(func() { io.Copy(client, server) }) + group.Go(func() { io.Copy(server, client) }) + + // Wait until the interceptor produces data. + result := <-intercepted + if result.Error != nil { + log.Printf("protocol detection failed: %v", result.Error) + } else { + log.Printf("detected protocol %s version %s initiated by %s", + result.Protocol.Name, result.Protocol.Version, result.Direction) + } + + // Wait for the multiplexing to finish. + group.Wait() +} diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..deea6ca --- /dev/null +++ b/doc.go @@ -0,0 +1,2 @@ +// Package dpi contains helpers for performing deep packet inspection. +package dpi diff --git a/error.go b/error.go new file mode 100644 index 0000000..de80f6b --- /dev/null +++ b/error.go @@ -0,0 +1,26 @@ +package dpi + +import ( + "errors" + "fmt" +) + +var ( + ErrInvalid = errors.New("invalid") +) + +type DecodeError struct { + Reason string + Err error +} + +func (err DecodeError) Error() string { + if err.Reason != "" { + return fmt.Sprintf("dpi: %s: %v", err.Reason, err.Err.Error()) + } + return err.Error() +} + +func (err DecodeError) Unwrap() error { + return err.Err +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ce95ba7 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.maze.io/go/dpi + +go 1.25 + +require golang.org/x/crypto v0.42.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..48e0464 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= diff --git a/protocol/detect.go b/protocol/detect.go new file mode 100644 index 0000000..bc1f641 --- /dev/null +++ b/protocol/detect.go @@ -0,0 +1,113 @@ +package protocol + +import ( + "errors" + "fmt" + "sync" + "sync/atomic" +) + +// Strict mode requires a full, compliant packet to be captured. This is only +// implemented by some detectors. +var Strict bool + +// Common errors. +var ( + ErrTimeout = errors.New("timeout") + ErrUnknown = errors.New("unknown protocol") +) + +// Direction indicates the communcation direction. +type Direction int + +// Directions supported by this package. +const ( + Unknown Direction = iota + Client + Server + Both +) + +func (dir Direction) Contains(other Direction) bool { + switch dir { + case Client: + return other == Client || other == Both + case Server: + return other == Server || other == Both + case Both: + return other == Client || other == Server + default: + return false + } +} + +var directionName = map[Direction]string{ + Client: "client", + Server: "server", + Both: "both", +} + +func (dir Direction) String() string { + if s, ok := directionName[dir]; ok { + return s + } + return fmt.Sprintf("invalid (%d)", int(dir)) +} + +type format struct { + dir Direction + magic string + detect DetectFunc +} + +// Formats is the list of registered formats. +var ( + formatsMu sync.Mutex + atomicFormats atomic.Value +) + +type DetectFunc func(Direction, []byte) *Protocol + +func Register(dir Direction, magic string, detect DetectFunc) { + formatsMu.Lock() + formats, _ := atomicFormats.Load().([]format) + atomicFormats.Store(append(formats, format{dir, magic, detect})) + formatsMu.Unlock() +} + +func matchMagic(magic string, data []byte) bool { + // Empty magic means the detector will always run. + if len(magic) == 0 { + return true + } + + // The buffer should contain at least the same number of bytes + // as our magic. + if len(data) < len(magic) { + return false + } + + // Match bytes in magic with bytes in data. + for i, b := range []byte(magic) { + if b != '?' && data[i] != b { + return false + } + } + return true +} + +// Detect a protocol based on the provided data. +func Detect(dir Direction, data []byte) (*Protocol, error) { + formats, _ := atomicFormats.Load().([]format) + for _, f := range formats { + if f.dir.Contains(dir) { + // Check the buffer to see if we have sufficient bytes + if matchMagic(f.magic, data) { + if p := f.detect(dir, data); p != nil { + return p, nil + } + } + } + } + return nil, ErrUnknown +} diff --git a/protocol/detect_http.go b/protocol/detect_http.go new file mode 100644 index 0000000..f487924 --- /dev/null +++ b/protocol/detect_http.go @@ -0,0 +1,94 @@ +package protocol + +import ( + "bufio" + "bytes" + "fmt" + "net/http" +) + +func init() { + Register(Client, "", detectHTTPRequest) + Register(Server, "HTTP/?.", detectHTTPResponse) +} + +func detectHTTPRequest(dir Direction, data []byte) *Protocol { + // A minimal request "GET / HTTP/1.0\r\n" is > 8 bytes. + if len(data) < 8 { + return nil + } + + if Strict { + var ( + b = append(data, '\r', '\n') + r = bufio.NewReader(bytes.NewReader(b)) + ) + if request, err := http.ReadRequest(r); err == nil { + return &Protocol{ + Name: ProtocolHTTP, + Version: Version{ + Major: request.ProtoMajor, + Minor: request.ProtoMinor, + Patch: -1, + }, + } + } + r.Reset(bytes.NewReader(b)) + if response, err := http.ReadResponse(r, nil); err == nil { + return &Protocol{ + Name: ProtocolHTTP, + Version: Version{ + Major: response.ProtoMajor, + Minor: response.ProtoMinor, + Patch: -1, + }, + } + } + return nil + } + + crlfIndex := bytes.IndexFunc(data, func(r rune) bool { + return r == '\r' || r == '\n' + }) + if crlfIndex == -1 { + return nil + } + + // A request has three, space-separated parts. + part := bytes.Split(data[:crlfIndex], []byte(" ")) + if len(part) != 3 { + return nil + } + + // The last part starts with "HTTP/". + if !bytes.HasPrefix(part[2], []byte("HTTP/1")) { + return nil + } + + var version = Version{Patch: -1} + fmt.Sscanf(string(part[2]), "HTTP/%d.%d ", &version.Major, &version.Minor) + + return &Protocol{ + Name: ProtocolHTTP, + Version: version, + } +} + +func detectHTTPResponse(dir Direction, data []byte) *Protocol { + if !dir.Contains(Server) { + return nil + } + + // A minimal response "HTTP/1.0 200 OK\r\n" is > 8 bytes. + if len(data) < 8 { + return nil + } + + var version = Version{Patch: -1} + fmt.Sscanf(string(data), "HTTP/%d.%d ", &version.Major, &version.Minor) + + return &Protocol{ + Name: ProtocolHTTP, + Version: version, + } +} diff --git a/protocol/detect_http_test.go b/protocol/detect_http_test.go new file mode 100644 index 0000000..4374871 --- /dev/null +++ b/protocol/detect_http_test.go @@ -0,0 +1,154 @@ +package protocol + +import ( + "errors" + "testing" +) + +func TestDetectHTTPRequest(t *testing.T) { + atomicFormats.Store([]format{{Client, "", detectHTTPRequest}}) + + // A valid HTTP/1.0 GET request + http10Request := []byte("GET /old-page.html HTTP/1.0\r\nUser-Agent: NCSA_Mosaic/1.0\r\n\r\n") + + // A valid HTTP/1.1 GET request + getRequest := []byte("GET /resource/item?id=123 HTTP/1.1\r\nHost: example.com\r\n\r\n") + + // An invalid HTTP request + sshBanner := []byte("SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.4\r\n") + + defer func() { Strict = false }() + for _, strict := range []bool{false, true} { + Strict = strict + + name := "loose" + if strict { + name = "strict" + } + + t.Run(name, func(t *testing.T) { + t.Run("HTTP/1.0 GET", func(t *testing.T) { + p, err := Detect(Client, http10Request) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolHTTP { + t.Fatalf("expected http protocol, got %s", p.Name) + return + } + }) + + t.Run("HTTP/1.1 GET", func(t *testing.T) { + p, err := Detect(Client, getRequest) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolHTTP { + t.Fatalf("expected http protocol, got %s", p.Name) + return + } + }) + + t.Run("Invalid SSH", func(t *testing.T) { + _, err := Detect(Server, sshBanner) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) + }) + } +} + +func TestDetectHTTPResponse(t *testing.T) { + atomicFormats.Store([]format{{Server, "HTTP/?.? ", detectHTTPResponse}}) + + // A valid HTTP/1.0 403 Forbidden response + http10Response := []byte("HTTP/1.0 403 Forbidden\r\nServer: CERN/3.0\r\n\r\n") + + // A valid HTTP/1.1 200 OK response + responseOK := []byte("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n...") + + // A valid HTTP/1.1 404 Not Found response + responseNotFound := []byte("HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n") + + // An invalid HTTP GET request + getRequest := []byte("GET /resource/item?id=123 HTTP/1.1\r\nHost: example.com\r\n\r\n") + + // An invalid banner (SSH) + sshBanner := []byte("SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.4\r\n") + + defer func() { Strict = false }() + for _, strict := range []bool{false, true} { + Strict = strict + + name := "loose" + if strict { + name = "strict" + } + + t.Run(name, func(t *testing.T) { + t.Run("HTTP/1.0 403", func(t *testing.T) { + p, err := Detect(Server, http10Response) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolHTTP { + t.Fatalf("expected http protocol, got %s", p.Name) + return + } + }) + + t.Run("HTTP/1.1 200", func(t *testing.T) { + p, err := Detect(Server, responseOK) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolHTTP { + t.Fatalf("expected http protocol, got %s", p.Name) + return + } + }) + + t.Run("HTTP/1.1 404", func(t *testing.T) { + p, err := Detect(Server, responseNotFound) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolHTTP { + t.Fatalf("expected http protocol, got %s", p.Name) + return + } + }) + + t.Run("Invalid HTTP/1.1 GET", func(t *testing.T) { + _, err := Detect(Server, getRequest) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) + + t.Run("Invalid SSH", func(t *testing.T) { + _, err := Detect(Server, sshBanner) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) + }) + } +} diff --git a/protocol/detect_mysql.go b/protocol/detect_mysql.go new file mode 100644 index 0000000..03cb3cd --- /dev/null +++ b/protocol/detect_mysql.go @@ -0,0 +1,51 @@ +package protocol + +import ( + "bytes" + "fmt" +) + +func init() { + Register(Server, "\x0a", detectMySQL) +} + +func detectMySQL(dir Direction, data []byte) *Protocol { + if len(data) < 7 { + return nil + } + + // The first byte of the handshake packet is the protocol version. + // For MySQL, this is 10 (0x0A). + if data[0] != 0x0A { + return nil + } + + // After the protocol version, there is a null-terminated server version string. + // We search for the null byte starting from the second byte (index 1). + nullIndex := bytes.IndexByte(data[1:], 0x00) + + // If no null byte is found, it's not a valid banner. + if nullIndex == -1 { + return nil + } + + // The position of the null byte is relative to the start of the whole slice. + // It's 1 (for the protocol byte) + nullIndex. + serverVersionEndPos := 1 + nullIndex + + // After the null-terminated version string, there must be at least 4 bytes + // for the connection ID, plus more data for capabilities, auth, etc. + // We'll check for the 4-byte connection ID as a minimum requirement. + const connectionIDLength = 4 + if len(data) < serverVersionEndPos+1+connectionIDLength { + return nil + } + + var version Version + fmt.Sscanf(string(data[1:serverVersionEndPos]), "%d.%d.%d-%s", &version.Major, &version.Minor, &version.Patch, &version.Extra) + + return &Protocol{ + Name: ProtocolMySQL, + Version: version, + } +} diff --git a/protocol/detect_mysql_test.go b/protocol/detect_mysql_test.go new file mode 100644 index 0000000..3e019b2 --- /dev/null +++ b/protocol/detect_mysql_test.go @@ -0,0 +1,82 @@ +package protocol + +import ( + "errors" + "testing" +) + +func TestDetectMySQL(t *testing.T) { + atomicFormats.Store([]format{{Server, "\x0a", detectMySQL}}) + + // 1. A valid MySQL 8.0 banner + mysql8Banner := []byte{ + 0x0a, 0x38, 0x2e, 0x30, 0x2e, 0x33, 0x32, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x04, 0x5a, 0x56, 0x5f, 0x3e, 0x6e, 0x76, 0x27, 0x00, 0xff, 0xff, 0xff, + 0x02, 0x00, 0xff, 0xc7, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x63, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x73, + 0x68, 0x61, 0x32, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00, + } + + // 2. A valid MariaDB banner (protocol-compatible) + mariaDBBanner := []byte{ + 0x0a, 0x35, 0x2e, 0x35, 0x2e, 0x35, 0x2d, 0x31, 0x30, 0x2e, 0x36, 0x2e, + 0x35, 0x2d, 0x4d, 0x61, 0x72, 0x69, 0x61, 0x44, 0x42, 0x2d, 0x6c, 0x6f, + 0x67, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x4e, 0x5c, 0x32, 0x7b, 0x45, 0x3b, + 0x40, 0x60, 0x00, 0xff, 0xf7, 0x08, 0x02, 0x00, 0xff, 0x81, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x79, 0x73, + 0x71, 0x6c, 0x5f, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, + 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x00, + } + + // 3. An invalid banner (e.g., an HTTP request) + httpBanner := []byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") + + // 4. A short, invalid slice + shortSlice := []byte{0x0a, 0x31, 0x32, 0x33} + + // 5. A slice that starts correctly but is malformed (no null terminator) + malformedSlice := []byte{0x0a, 0x38, 0x2e, 0x30, 0x2e, 0x30, 0x01, 0x02, 0x03, 0x04, 0x05} + + t.Run("MySQL 8", func(t *testing.T) { + p, _ := Detect(Server, mysql8Banner) + if p == nil { + t.Fatal("expected MySQL protocol, got nil") + } + t.Logf("detected %s version %s", p.Name, p.Version) + }) + + t.Run("MariaDB", func(t *testing.T) { + p, _ := Detect(Server, mariaDBBanner) + if p == nil { + t.Fatal("expected MySQL protocol, got nil") + } + t.Logf("detected %s version %s", p.Name, p.Version) + }) + + t.Run("Invalid HTTP", func(t *testing.T) { + _, err := Detect(Server, httpBanner) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) + + t.Run("Too short", func(t *testing.T) { + _, err := Detect(Server, shortSlice) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) + + t.Run("Malformed", func(t *testing.T) { + _, err := Detect(Server, malformedSlice) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) +} diff --git a/protocol/detect_postgres.go b/protocol/detect_postgres.go new file mode 100644 index 0000000..4235534 --- /dev/null +++ b/protocol/detect_postgres.go @@ -0,0 +1,70 @@ +package protocol + +import ( + "encoding/binary" + "log" +) + +func init() { + registerPostgreSQL() +} + +func registerPostgreSQL() { + Register(Server, "R\x00???", detectPostgreSQLServer) // Authentication request + Register(Server, "K\x00???", detectPostgreSQLServer) // BackendKeyData + Register(Server, "S\x00???", detectPostgreSQLServer) // ParameterStatus + Register(Server, "Z\x00???", detectPostgreSQLServer) // ReadyForQuery + Register(Server, "E\x00???", detectPostgreSQLServer) // ErrorResponse + Register(Server, "N\x00???", detectPostgreSQLServer) // NoticeResponse + Register(Client, "????\x00\x02\x00\x00", detectPostgreSQLClient) // Startup packet, protocol 2.0 + Register(Client, "????\x00\x03\x00\x00", detectPostgreSQLClient) // Startup packet, protocol 3.0 +} + +func detectPostgreSQLClient(dir Direction, data []byte) *Protocol { + // A client startup message needs at least 8 bytes (length + protocol version). + if len(data) < 8 { + return nil + } + + length := int(binary.BigEndian.Uint32(data[0:])) + if len(data) != length { + log.Printf("not postgres %q: %d != %d", data, len(data), length) + return nil + } + + major := int(binary.BigEndian.Uint16(data[4:])) + minor := int(binary.BigEndian.Uint16(data[6:])) + if major == 2 || major == 3 { + return &Protocol{ + Name: ProtocolPostgreSQL, + Version: Version{ + Major: major, + Minor: minor, + Patch: -1, + }, + } + } + return nil +} + +func detectPostgreSQLServer(dir Direction, data []byte) *Protocol { + // A server message needs at least 5 bytes (type + length). + if len(data) < 5 { + return nil + } + + // All server messages (and subsequent client messages) are tagged with a single-byte type. + firstByte := data[0] + switch firstByte { + case 'R', // Authentication request + 'K', // BackendKeyData + 'S', // ParameterStatus + 'Z', // ReadyForQuery + 'E', // ErrorResponse + 'N': // NoticeResponse + return &Protocol{Name: ProtocolPostgreSQL} + + default: + return nil + } +} diff --git a/protocol/detect_postgres_test.go b/protocol/detect_postgres_test.go new file mode 100644 index 0000000..c35f338 --- /dev/null +++ b/protocol/detect_postgres_test.go @@ -0,0 +1,94 @@ +package protocol + +import ( + "errors" + "testing" +) + +func TestDetectPostgreSQLClient(t *testing.T) { + atomicFormats.Store([]format{}) + registerPostgreSQL() + + // 1. A valid PostgreSQL client startup message + // Format: len (4b), proto (4b), params (n-bytes) + // Here, user=mazeio, database=test + // The message is: "user\0mazeio\0database\0test\0\0" + // Total length: 4 (len) + 4 (proto) + 27 (params) = 35 (0x23) + pgClientStartup := []byte{ + 0x00, 0x00, 0x00, 0x23, // Length: 35 + 0x00, 0x03, 0x00, 0x00, // Protocol Version 3.0 + 'u', 's', 'e', 'r', 0x00, 'm', 'a', 'z', 'e', 'i', 'o', 0x00, + 'd', 'a', 't', 'a', 'b', 'a', 's', 'e', 0x00, 't', 'e', 's', 't', 0x00, 0x00, + } + + t.Run("Protocol 3.0", func(t *testing.T) { + p, err := Detect(Client, pgClientStartup) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolPostgreSQL { + t.Fatalf("expected postgres protocol, got %s", p.Name) + return + } + }) +} + +func TestDetectPostgreSQLServer(t *testing.T) { + atomicFormats.Store([]format{}) + registerPostgreSQL() + + // A valid PostgreSQL server AuthenticationOk response + // Format: type (1b), len (4b), content (4b) + pgServerAuthOK := []byte{ + 'R', // Type: Authentication + 0x00, 0x00, 0x00, 0x08, // Length: 8 + 0x00, 0x00, 0x00, 0x00, // Auth OK (0) + } + + // A valid PostgreSQL server ErrorResponse + pgServerError := []byte{ + 'E', // Type: ErrorResponse + 0x00, 0x00, 0x00, 0x31, // Length + 'S', 'E', 'R', 'R', 'O', 'R', 0x00, // ... and so on + } + + // Invalid data (HTTP GET request) + httpBanner := []byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") + + t.Run("AuthenticationOk", func(t *testing.T) { + p, err := Detect(Server, pgServerAuthOK) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolPostgreSQL { + t.Fatalf("expected postgres protocol, got %s", p.Name) + return + } + }) + + t.Run("ErrorResponse", func(t *testing.T) { + p, err := Detect(Server, pgServerError) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolPostgreSQL { + t.Fatalf("expected postgres protocol, got %s", p.Name) + return + } + }) + + t.Run("Invalid HTTP", func(t *testing.T) { + _, err := Detect(Server, httpBanner) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) +} diff --git a/protocol/detect_ssh.go b/protocol/detect_ssh.go new file mode 100644 index 0000000..8953900 --- /dev/null +++ b/protocol/detect_ssh.go @@ -0,0 +1,51 @@ +package protocol + +import ( + "bytes" +) + +// The required prefix for the SSH protocol identification line. +const ( + ssh199Prefix = "SSH-1.99-" + ssh20Prefix = "SSH-2.0-" +) + +func init() { + Register(Both, "", detectSSH) +} + +func detectSSH(dir Direction, data []byte) *Protocol { + // The data must be at least as long as the prefix itself. + if len(data) < len(ssh20Prefix) { + return nil + } + + // The protocol allows for pre-banner text, so we have to check all lines. + for _, line := range bytes.Split(data, []byte{'\n'}) { + line = bytes.TrimSuffix(line, []byte{'\r'}) + if bytes.HasPrefix(line, []byte(ssh20Prefix)) { + return &Protocol{ + Name: ProtocolSSH, + Version: Version{ + Major: 2, + Minor: 0, + Patch: -1, + Extra: string(line[len(ssh20Prefix):]), + }, + } + } + if bytes.HasPrefix(line, []byte(ssh199Prefix)) { + return &Protocol{ + Name: ProtocolSSH, + Version: Version{ + Major: 1, + Minor: 99, + Patch: -1, + Extra: string(line[len(ssh20Prefix):]), + }, + } + } + } + + return nil +} diff --git a/protocol/detect_ssh_test.go b/protocol/detect_ssh_test.go new file mode 100644 index 0000000..82fd982 --- /dev/null +++ b/protocol/detect_ssh_test.go @@ -0,0 +1,103 @@ +package protocol + +import ( + "errors" + "testing" +) + +func TestDetectSSH(t *testing.T) { + atomicFormats.Store([]format{{Both, "", detectSSH}}) + + // 1. A standard OpenSSH banner + openSSHBanner := []byte("SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.4\r\n") + + // 2. An SSH banner with a pre-banner legal notice + preBannerSSH := []byte( + "*******************************************************************\r\n" + + "* W A R N I N G *\r\n" + + "* This system is for the use of authorized users only. *\r\n" + + "*******************************************************************\r\n" + + "SSH-2.0-OpenSSH_7.6p1\r\n", + ) + + // 3. A different SSH implementation (Dropbear) + dropbearBanner := []byte("SSH-2.0-dropbear_2020.81\r\n") + + // 4. An invalid banner (e.g., the MySQL banner from the previous example) + mysqlBanner := []byte{ + 0x0a, 0x38, 0x2e, 0x30, 0x2e, 0x33, 0x32, 0x00, 0x0d, 0x00, 0x00, 0x00, + } + + // 5. A simple HTTP request + httpBanner := []byte("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") + + t.Run("OpenSSH client", func(t *testing.T) { + p, err := Detect(Server, openSSHBanner) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolSSH { + t.Fatalf("expected ssh protocol, got %s", p.Name) + return + } + }) + + t.Run("OpenSSH server", func(t *testing.T) { + p, err := Detect(Server, openSSHBanner) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolSSH { + t.Fatalf("expected ssh protocol, got %s", p.Name) + return + } + }) + + t.Run("OpenSSH server with banner", func(t *testing.T) { + p, err := Detect(Server, preBannerSSH) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolSSH { + t.Fatalf("expected ssh protocol, got %s", p.Name) + return + } + }) + + t.Run("Dropbear server", func(t *testing.T) { + p, err := Detect(Server, dropbearBanner) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolSSH { + t.Fatalf("expected ssh protocol, got %s", p.Name) + return + } + }) + + t.Run("Invalid MySQL banner", func(t *testing.T) { + _, err := Detect(Server, mysqlBanner) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) + + t.Run("Invalid HTTP banner", func(t *testing.T) { + _, err := Detect(Server, httpBanner) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) +} diff --git a/protocol/detect_tls.go b/protocol/detect_tls.go new file mode 100644 index 0000000..5838dfe --- /dev/null +++ b/protocol/detect_tls.go @@ -0,0 +1,98 @@ +package protocol + +import ( + "golang.org/x/crypto/cryptobyte" + + "git.maze.io/go/dpi" +) + +func init() { + registerTLS() +} + +func registerTLS() { + Register(Both, "\x16\x03\x00", detectTLS) // SSLv3 + Register(Both, "\x16\x03\x01", detectTLS) // TLSv1.0 + Register(Both, "\x16\x03\x02", detectTLS) // TLSv1.1 + Register(Both, "\x16\x03\x03", detectTLS) // TLSv1.2 +} + +func detectTLS(dir Direction, data []byte) *Protocol { + stream := cryptobyte.String(data) + + // A TLS packet always has a content type (1 byte), version (2 bytes) and length (2 bytes). + if len(stream) < 5 { + return nil + } + + // Check for TLS Handshake (type 22) + var header struct { + Type uint8 + Version uint16 + Length uint32 + } + if !stream.ReadUint8(&header.Type) || header.Type != 0x16 { + return nil + } + if !stream.ReadUint16(&header.Version) { + return nil + } + if !stream.ReadUint24(&header.Length) { + return nil + } + + // Detected SSL/TLS version + var version dpi.TLSVersion + + // Attempt to decode the full TLS Client Hello handshake + if version == 0 { + if hello, err := dpi.DecodeTLSClientHelloHandshake(data); err == nil { + version = hello.Version + } + } + + // Attempt to decode the full TLS Server Hello handshake + if version == 0 { + if hello, err := dpi.DecodeTLSServerHello(data); err == nil { + version = hello.Version + } + } + + // Attempt to decode at least the handshake protocol and version. + if version == 0 && !Strict { + var handshakeType uint8 + if stream.ReadUint8(&handshakeType) && (handshakeType == 1 || handshakeType == 2) { + var ( + length uint32 + versionWord uint16 + ) + if stream.ReadUint24(&length) && stream.ReadUint16(&versionWord) { + version = dpi.TLSVersion(versionWord) + } + } + } + + // Fall back to the version in the TLS record header, this is less accurate + if version == 0 && !Strict { + version = dpi.TLSVersion(header.Version) + } + + // We're "multi protocol", in that SSL is its own protocol + if version == dpi.VersionSSL30 { + return &Protocol{ + Name: ProtocolSSL, + Version: Version{Major: 3, Minor: 0, Patch: -1}, + } + } else if version >= dpi.VersionTLS10 && version <= dpi.VersionTLS13 { + return &Protocol{ + Name: ProtocolTLS, + Version: Version{Major: 1, Minor: int(uint8(version) - 1), Patch: -1}, + } + } else if version >= dpi.VersionTLS13Draft && version <= dpi.VersionTLS13Draft23 { + return &Protocol{ + Name: ProtocolTLS, + Version: Version{Major: 1, Minor: 3, Patch: -1}, + } + } + return nil +} diff --git a/protocol/detect_tls_test.go b/protocol/detect_tls_test.go new file mode 100644 index 0000000..452d4e8 --- /dev/null +++ b/protocol/detect_tls_test.go @@ -0,0 +1,280 @@ +package protocol + +import ( + "encoding/hex" + "errors" + "strings" + "testing" +) + +func TestDetectTLS(t *testing.T) { + atomicFormats.Store([]format{}) + registerTLS() + + // A SSLv3 Client Hello + sslV3ClientHello := testMustDecodeHexString(` + 16 03 00 00 51 01 00 00 4d 03 + 00 50 42 b2 29 1f cf 52 a0 94 87 05 e7 0b 63 08 + 12 a2 6c 59 f7 f5 72 2b 57 14 a7 07 95 cb ce e5 + e4 00 00 26 00 04 00 05 00 2f 00 33 00 32 00 0a + fe ff 00 16 00 13 00 66 00 09 fe fe 00 15 00 12 + 00 03 00 08 00 06 00 14 00 11 01 00`) + + // A synthesized TLS 1.1 ClientHello + tls11ClientHello := []byte{ + // --- Record Layer (5 bytes) --- + 0x16, // Content Type: Handshake (22) + 0x03, 0x02, // Version: TLS 1.1 (Major=3, Minor=2) + 0x00, 0x45, // Length of the handshake message below (69 bytes) + + // --- Handshake Protocol: ClientHello (69 bytes) --- + 0x01, // Handshake Type: ClientHello (1) + 0x00, 0x00, 0x41, // Length of the rest of the message (65 bytes) + 0x03, 0x02, // Client Version: TLS 1.1 (Major=3, Minor=2) + + // Random (32 bytes): + // In TLS 1.1+, the entire 32 bytes are fully random. + // The timestamp structure from SSLv3 is removed. + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, + + // Session ID + 0x00, // Session ID Length: 0 (new session) + + // Cipher Suites + 0x00, 0x04, // Cipher Suites Length: 4 bytes (2 suites) + 0x00, 0x2F, // Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA + 0x00, 0x35, // Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA + + // Compression Methods + 0x01, // Compression Methods Length: 1 byte + 0x00, // Compression Method: NULL (0) + + // --- Extensions (20 bytes) --- + 0x00, 0x14, // Extensions Length: 20 bytes + // Extension: Server Name Indication (SNI) + 0x00, 0x00, // Extension Type: server_name (0) + 0x00, 0x10, // Extension Length: 16 bytes + 0x00, 0x0E, // Server Name List Length: 14 bytes + 0x00, // Server Name Type: host_name (0) + 0x00, 0x0B, // Server Name Length: 11 bytes + // Server Name: "example.com" + 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', + } + + // A synthesized partial TLS 1.1 ClientHello + tls11ClientHelloPartial := []byte{ + // --- Record Layer (5 bytes) --- + 0x16, // Content Type: Handshake (22) + 0x03, 0x02, // Version: TLS 1.1 (Major=3, Minor=2) + 0x00, 0x45, // Length of the handshake message below (69 bytes) + + // --- Handshake Protocol: ClientHello (69 bytes) --- + 0x01, // Handshake Type: ClientHello (1) + 0x00, 0x00, 0x41, // Length of the rest of the message (65 bytes) + 0x03, 0x02, // Client Version: TLS 1.1 (Major=3, Minor=2) + } + + // A synthesized TLSv1.2 ClientHello + tls12ClientHello := []byte{ + // --- Record Layer (5 bytes) --- + 0x16, // Content Type: Handshake (22) + 0x03, 0x03, // Version: TLS 1.2 (Major=3, Minor=3) + 0x00, 0x61, // Length of handshake message below (97 bytes) + + // --- Handshake Protocol: ClientHello (97 bytes) --- + 0x01, // Handshake Type: ClientHello (1) + 0x00, 0x00, 0x5D, // Length of the rest of the message (93 bytes) + 0x03, 0x03, // Client Version: TLS 1.2 (Major=3, Minor=3) + + // Random (32 bytes) + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, + + // Session ID + 0x00, // Session ID Length: 0 (new session) + + // Cipher Suites (using modern GCM suites) + 0x00, 0x04, // Cipher Suites Length: 4 bytes (2 suites) + 0xC0, 0x2F, // Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + 0xC0, 0x30, // Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + + // Compression Methods + 0x01, // Compression Methods Length: 1 byte + 0x00, // Compression Method: NULL (0) + + // --- Extensions (48 bytes) --- + 0x00, 0x30, // Extensions Length: 48 bytes + // Extension: Server Name Indication (SNI) (20 bytes) + 0x00, 0x00, 0x00, 0x10, 0x00, 0x0E, 0x00, 0x00, 0x0B, + 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', + // Extension: Signature Algorithms (10 bytes) - CRITICAL for TLS 1.2 + 0x00, 0x0D, // Extension Type: signature_algorithms (13) + 0x00, 0x06, // Extension Length: 6 bytes + 0x00, 0x04, // Hash/Signature Algorithm List Length: 4 bytes + 0x04, 0x01, // Algorithm: rsa_pkcs1_sha256 + 0x05, 0x01, // Algorithm: rsa_pkcs1_sha384 + // Extension: Application-Layer Protocol Negotiation (ALPN) (18 bytes) + 0x00, 0x10, // Extension Type: application_layer_protocol_negotiation (16) + 0x00, 0x0E, // Extension Length: 14 bytes + 0x00, 0x0C, // ALPN Extension Length: 12 bytes + // ALPN Protocol: "h2" (HTTP/2) + 0x02, 'h', '2', + // ALPN Protocol: "http/1.1" + 0x08, 'h', 't', 't', 'p', '/', '1', '.', '1', + } + + // A valid TLS 1.3 Client Hello (captured from a real connection) + tls13ClientHello := []byte{ + 0x16, // Content Type: Handshake (22) + 0x03, 0x01, // Version: TLS 1.0 (for compatibility in a 1.3 hello) + 0x01, 0x3a, // Length + 0x01, 0x00, 0x01, 0x36, 0x03, 0x03, 0xb1, + 0x40, 0xd3, 0xf1, 0x7d, 0xa3, 0xb8, 0x33, 0xac, 0xad, 0x21, 0x79, 0x9c, + 0xbe, 0x39, 0x96, 0x08, 0x49, 0x3b, 0x53, 0x75, 0xa0, 0x1b, 0xee, 0x6e, + 0x6a, 0xbe, 0x6c, 0x41, 0xdf, 0x6c, 0xf4, 0x20, 0xa4, 0xaa, 0x0c, 0xca, + 0xd4, 0x37, 0x76, 0x5f, 0x49, 0xc6, 0x06, 0x9b, 0xac, 0x90, 0x89, 0x76, + 0x1c, 0xc7, 0xc4, 0x12, 0xb4, 0x4a, 0xe0, 0x27, 0x72, 0x89, 0x97, 0x85, + 0x76, 0xf8, 0xc8, 0x83, 0x00, 0x62, 0x13, 0x03, 0x13, 0x02, 0x13, 0x01, + 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x30, 0xc0, 0x2c, 0xc0, 0x28, + 0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x0a, 0x00, 0x9f, 0x00, 0x6b, 0x00, 0x39, + 0xff, 0x85, 0x00, 0xc4, 0x00, 0x88, 0x00, 0x81, 0x00, 0x9d, 0x00, 0x3d, + 0x00, 0x35, 0x00, 0xc0, 0x00, 0x84, 0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, + 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x09, 0x00, 0x9e, 0x00, 0x67, 0x00, 0x33, + 0x00, 0xbe, 0x00, 0x45, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0xba, + 0x00, 0x41, 0xc0, 0x11, 0xc0, 0x07, 0x00, 0x05, 0x00, 0x04, 0xc0, 0x12, + 0xc0, 0x08, 0x00, 0x16, 0x00, 0x0a, 0x00, 0xff, 0x01, 0x00, 0x00, 0x8b, + 0x00, 0x2b, 0x00, 0x09, 0x08, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, + 0x01, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x2c, + 0x4b, 0xaa, 0xb4, 0xb3, 0xc8, 0x93, 0xcd, 0x5c, 0x24, 0xb9, 0x9b, 0xd4, + 0x59, 0x04, 0xfe, 0x69, 0xaf, 0x68, 0xb9, 0xa6, 0x36, 0xbb, 0xab, 0x87, + 0xfa, 0x15, 0x59, 0xea, 0xdd, 0x38, 0x68, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, + 0x74, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00, + 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x0d, 0x00, + 0x18, 0x00, 0x16, 0x08, 0x06, 0x06, 0x01, 0x06, 0x03, 0x08, 0x05, 0x05, + 0x01, 0x05, 0x03, 0x08, 0x04, 0x04, 0x01, 0x04, 0x03, 0x02, 0x01, 0x02, + 0x03, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, + 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, + } + + // Invalid data (Postgres client startup) + pgClientStartup := []byte{ + 0x00, 0x00, 0x00, 0x25, 0x00, 0x03, 0x00, 0x00, + } + + defer func() { Strict = false }() + for _, strict := range []bool{false, true} { + Strict = strict + + name := "loose" + if strict { + name = "strict" + } + + t.Run(name, func(t *testing.T) { + + t.Run("SSLv3 Client Hello", func(t *testing.T) { + p, err := Detect(Client, sslV3ClientHello) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolSSL { + t.Fatalf("expected ssl protocol, got %s", p.Name) + return + } + }) + + t.Run("TLS 1.1 Client Hello", func(t *testing.T) { + p, err := Detect(Client, tls11ClientHello) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolTLS { + t.Fatalf("expected tls protocol, got %s", p.Name) + return + } + }) + + t.Run("TLS 1.1 partial Client Hello", func(t *testing.T) { + p, err := Detect(Client, tls11ClientHelloPartial) + if strict { + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + } else { + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolTLS { + t.Fatalf("expected tls protocol, got %s", p.Name) + return + } + } + }) + + t.Run("TLS 1.2 Client Hello", func(t *testing.T) { + p, err := Detect(Client, tls12ClientHello) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolTLS { + t.Fatalf("expected tls protocol, got %s", p.Name) + return + } + }) + + t.Run("TLS 1.3 Client Hello", func(t *testing.T) { + p, err := Detect(Client, tls13ClientHello) + if err != nil { + t.Fatal(err) + return + } + t.Logf("detected %s version %s", p.Name, p.Version) + if p.Name != ProtocolTLS { + t.Fatalf("expected tls protocol, got %s", p.Name) + return + } + }) + + t.Run("Invalid PostgreSQL", func(t *testing.T) { + _, err := Detect(Server, pgClientStartup) + if !errors.Is(err, ErrUnknown) { + t.Fatalf("expected unknown format, got error %T: %q", err, err) + } else { + t.Logf("error %q, as expected", err) + } + }) + }) + } +} + +func testDecodeHexString(s string) ([]byte, error) { + s = strings.TrimSpace(s) + s = strings.ReplaceAll(s, " ", "") + s = strings.ReplaceAll(s, "\n", "") + s = strings.ReplaceAll(s, "\t", "") + return hex.DecodeString(s) +} + +func testMustDecodeHexString(s string) []byte { + b, err := testDecodeHexString(s) + if err != nil { + panic(err) + } + return b +} diff --git a/protocol/intercept.go b/protocol/intercept.go new file mode 100644 index 0000000..50e155e --- /dev/null +++ b/protocol/intercept.go @@ -0,0 +1,128 @@ +package protocol + +import ( + "net" + "sync/atomic" + "time" +) + +// Intercepted is the result returned by [Interceptor.Detect]. +type Intercepted struct { + Direction Direction + Protocol *Protocol + Error error +} + +// Interceptor intercepts reads from client or server. +type Interceptor struct { + clientBytes chan []byte + clientReader *readInterceptor + serverBytes chan []byte + serverReader *readInterceptor +} + +// NewInterceptor creates a new (transparent) protocol interceptor. +func NewInterceptor() *Interceptor { + return &Interceptor{ + clientBytes: make(chan []byte, 1), + serverBytes: make(chan []byte, 1), + } +} + +type readInterceptor struct { + net.Conn + bytes chan []byte + once atomic.Bool +} + +func newReadInterceptor(c net.Conn, bytes chan []byte) *readInterceptor { + return &readInterceptor{ + Conn: c, + bytes: bytes, + } +} + +// Cancel any future Read interceptions and closes the channel. +func (r *readInterceptor) Cancel() { + if r == nil { + return + } + r.once.Store(true) + close(r.bytes) +} + +func (r *readInterceptor) Read(p []byte) (n int, err error) { + if r.once.CompareAndSwap(false, true) { + if n, err = r.Conn.Read(p); n > 0 { + // We create a copy, since the Read caller may modify p + // immediately after reading. + data := make([]byte, n) + copy(data, p[:n]) + // Buffer the bytes in the channel. + r.bytes <- data + } + return + } + return r.Conn.Read(p) +} + +// Client binds the client connection to the interceptor. +func (i *Interceptor) Client(c net.Conn) net.Conn { + if ri, ok := c.(*readInterceptor); ok { + return ri + } + i.clientReader = newReadInterceptor(c, i.clientBytes) + return i.clientReader +} + +// Server binds the server connection to the interceptor. +func (i *Interceptor) Server(c net.Conn) net.Conn { + if ri, ok := c.(*readInterceptor); ok { + return ri + } + i.serverReader = newReadInterceptor(c, i.serverBytes) + return i.serverReader +} + +// Detect runs protocol detection on the previously bound Client and Server connection. +// +// It waits until either the client or the server performs a read operation, +// which is then used for running protocol detection. If the read operation +// takes longer than timeout, an error is returned. +// +// The returned channel always yields one result and is then closed. +func (i *Interceptor) Detect(timeout time.Duration) <-chan *Intercepted { + var interceptc = make(chan *Intercepted, 1) + + go func() { + // Make sure all channels are closed once we finish processing. + defer close(interceptc) + defer i.clientReader.Cancel() + defer i.serverReader.Cancel() + + select { + case <-time.After(timeout): // timeout + interceptc <- &Intercepted{ + Error: ErrTimeout, + } + + case data := <-i.clientBytes: // client sent banner + p, err := Detect(Client, data) + interceptc <- &Intercepted{ + Direction: Client, + Protocol: p, + Error: err, + } + + case data := <-i.serverBytes: // server sent banner + p, err := Detect(Server, data) + interceptc <- &Intercepted{ + Direction: Server, + Protocol: p, + Error: err, + } + } + }() + + return interceptc +} diff --git a/protocol/limit.go b/protocol/limit.go new file mode 100644 index 0000000..2ec10e9 --- /dev/null +++ b/protocol/limit.go @@ -0,0 +1,76 @@ +package protocol + +import ( + "net" + "sync" + "sync/atomic" +) + +// AcceptFunc receives a direction and a detected protocol. +type AcceptFunc func(Direction, *Protocol) error + +// Limit the connection protocol, by running a detection after either side sends +// a banner within timeout. +// +// If no protocol could be detected, the accept function is called with a nil +// argument to check if we should proceed. +// +// If the accept function returns false, the connection will be closed. +func Limit(conn net.Conn, accept AcceptFunc) net.Conn { + if accept == nil { + // Nothing to do here. + return conn + } + + return &connLimiter{ + Conn: conn, + accept: accept, + } +} + +type connLimiter struct { + net.Conn + accept AcceptFunc + acceptOnce sync.Once + acceptError atomic.Value +} + +func (l *connLimiter) init(readData, writeData []byte) { + l.acceptOnce.Do(func() { + var ( + dir Direction + data []byte + ) + if readData != nil { + // init called by initial read + dir, data = Server, readData + } else { + // init called by initial write + dir, data = Client, writeData + } + protocol, _ := Detect(dir, data) + if err := l.accept(dir, protocol); err != nil { + l.acceptError.Store(err) + } + }) +} + +func (l *connLimiter) Read(p []byte) (n int, err error) { + var ok bool + if err, ok = l.acceptError.Load().(error); ok && err != nil { + return + } + if n, err = l.Conn.Read(p); n > 0 { + l.init(p[:n], nil) + } + return +} + +func (l *connLimiter) Write(p []byte) (n int, err error) { + l.init(nil, p) + var ok bool + if err, ok = l.acceptError.Load().(error); ok && err != nil { + return + } + return l.Conn.Write(p) +} diff --git a/protocol/protocol.go b/protocol/protocol.go new file mode 100644 index 0000000..7c7d8db --- /dev/null +++ b/protocol/protocol.go @@ -0,0 +1,47 @@ +package protocol + +import ( + "strconv" + "strings" +) + +// Protocols supported by this package. +const ( + ProtocolDNS = "dns" + ProtocolHTTP = "http" + ProtocolMySQL = "mysql" + ProtocolPostgreSQL = "postgresql" + ProtocolSSH = "ssh" + ProtocolSSL = "ssl" + ProtocolTLS = "tls" +) + +type Protocol struct { + Name string + Version Version +} + +type Version struct { + Major int + Minor int + Patch int + Extra string +} + +func (v Version) String() string { + p := make([]string, 0, 3) + if v.Major >= 0 { + p = append(p, strconv.Itoa(v.Major)) + if v.Minor >= 0 { + p = append(p, strconv.Itoa(v.Minor)) + if v.Patch >= 0 { + p = append(p, strconv.Itoa(v.Patch)) + } + } + } + s := strings.Join(p, ".") + if v.Extra != "" { + return s + "-" + v.Extra + } + return s +} diff --git a/testdata/tls13-clienthello.bin b/testdata/tls13-clienthello.bin new file mode 100644 index 0000000..4b1526b Binary files /dev/null and b/testdata/tls13-clienthello.bin differ diff --git a/tls.go b/tls.go new file mode 100644 index 0000000..f02e774 --- /dev/null +++ b/tls.go @@ -0,0 +1,455 @@ +package dpi + +import ( + "encoding/binary" + "fmt" + "io" + "time" + + "golang.org/x/crypto/cryptobyte" +) + +// TLSExtension is a TLS extension. +type TLSExtension struct { + Type uint16 + Data []byte +} + +// TLSRecord is a TLS record. +type TLSRecord struct { + Raw []byte + Type uint8 + Version uint16 + Length uint16 + Data []byte +} + +func DecodeTLSRecord(data []byte) (*TLSRecord, error) { + var ( + stream = cryptobyte.String(data) + record = &TLSRecord{Raw: data} + ) + + if !stream.ReadUint8(&record.Type) || + !stream.ReadUint16(&record.Version) || + !stream.ReadUint16(&record.Length) { + return nil, DecodeError{ + Reason: "invalid TLS record header", + Err: io.ErrUnexpectedEOF, + } + } + if !stream.ReadBytes(&record.Data, int(record.Length)) { + return nil, DecodeError{ + Reason: "invalid TLS record data", + Err: io.ErrUnexpectedEOF, + } + } + if !stream.Empty() { + return nil, DecodeError{ + Reason: "extraneous data after TLS record", + Err: ErrInvalid, + } + } + return record, nil +} + +// TLSClientHello is a TLS ClientHello packet as part of the TLS handshake. +type TLSClientHello struct { + Raw []byte + Version TLSVersion + Random []byte + SessionID []byte + CipherSuites []uint16 + CompressionMethods []uint8 + Extensions []TLSExtension + ServerName string + SupportedCurves []uint16 // aka "Supported Groups" + SupportedSignatureAlgorithms []TLSSignatureScheme // RFC 5246, Section 7.4.1.4.1 + ALPNProtocols []string // RFC 7301, Section 3.1 + SupportedVersions []TLSVersion // RFC 8446, Section 4.2.1z +} + +func DecodeTLSClientHello(data []byte) (*TLSClientHello, error) { + var ( + stream = cryptobyte.String(data) + hello = &TLSClientHello{Raw: data} + ) + + // Read header (4 bytes) + var handshakeType uint8 + if !stream.ReadUint8(&handshakeType) || handshakeType != tlsTypeClientHello { + return nil, DecodeError{ + Reason: fmt.Sprintf("expected a TLS ClientHello (0x%02X), got 0x%02X", tlsTypeClientHello, handshakeType), + Err: ErrInvalid, + } + } + var record cryptobyte.String + if !stream.ReadUint24LengthPrefixed(&record) { + return nil, DecodeError{ + Reason: "incomplete TLS record", + Err: io.ErrUnexpectedEOF, + } + } + if !stream.Empty() { + return nil, DecodeError{ + Reason: "invalid TLS record length", + Err: ErrInvalid, + } + } + + // Parser client version. + var version uint16 + if !record.ReadUint16(&version) { + return nil, DecodeError{ + Reason: "incomplete TLS version", + Err: io.ErrUnexpectedEOF, + } + } + hello.Version = TLSVersion(version) + + // Parse random (32 bytes) + if !record.ReadBytes(&hello.Random, 32) { + return nil, DecodeError{ + Reason: "incomplete TLS random bytes", + Err: io.ErrUnexpectedEOF, + } + } + + // Parse session ID + var sessionID cryptobyte.String + if !record.ReadUint8LengthPrefixed(&sessionID) { + return nil, DecodeError{ + Reason: "incomplete TLS session ID", + Err: io.ErrUnexpectedEOF, + } + } + hello.SessionID = sessionID + + // Parse cipher suites + var cipherSuites cryptobyte.String + if !record.ReadUint16LengthPrefixed(&cipherSuites) { + return nil, DecodeError{ + Reason: "incomplete TLS cipher suites bytes", + Err: io.ErrUnexpectedEOF, + } + } + for !cipherSuites.Empty() { + var cipherSuite uint16 + if !cipherSuites.ReadUint16(&cipherSuite) { + return nil, DecodeError{ + Reason: "incomplete TLS cipher suite", + Err: io.ErrUnexpectedEOF, + } + } + hello.CipherSuites = append(hello.CipherSuites, cipherSuite) + } + + // Parse compression methods + var compressionMethods cryptobyte.String + if !record.ReadUint8LengthPrefixed(&compressionMethods) { + return nil, DecodeError{ + Reason: "incomplete TLS compression methods bytes", + Err: io.ErrUnexpectedEOF, + } + } + hello.CompressionMethods = compressionMethods + + // Parse extensions (optional) + if record.Empty() { + return hello, nil + } + + var extensions cryptobyte.String + if !record.ReadUint16LengthPrefixed(&extensions) { + return nil, DecodeError{ + Reason: "incomplete TLS extensions", + Err: io.ErrUnexpectedEOF, + } + } + if !record.Empty() { + return nil, DecodeError{ + Reason: "extraneous TLS extension data", + Err: io.ErrUnexpectedEOF, + } + } + + for !extensions.Empty() { + var ( + extension TLSExtension + extensionData = cryptobyte.String(extension.Data) + ) + if !extensions.ReadUint16(&extension.Type) || !extensions.ReadUint16LengthPrefixed(&extensionData) { + return nil, DecodeError{ + Reason: "incomplete TLS extension record data", + Err: io.ErrUnexpectedEOF, + } + } + hello.Extensions = append(hello.Extensions, extension) + + switch extension.Type { + case tlsExtensionServerName: + // RFC 6066, Section 3 + if !readTLSServerName(extensionData, &hello.ServerName) { + return nil, DecodeError{ + Reason: "invalid TLS server name extension data", + Err: io.ErrUnexpectedEOF, + } + } + + case tlsExtensionSupportedGroups: + // RFC 4492, Section 5.1.1 + // RFC 8446, Section 4.2.7 + if !readTLSSupportedGroups(extensionData, &hello.SupportedCurves) { + return nil, DecodeError{ + Reason: "invalid TLS supported groups extension data", + Err: io.ErrUnexpectedEOF, + } + } + + case tlsExtensionSignatureAlgorithms: + // RFC 5246, Section 7.4.1 + if !readTLSSignatureAlgorithms(extensionData, &hello.SupportedSignatureAlgorithms) { + return nil, DecodeError{ + Reason: "invalid TLS supported signature algorithms extension data", + Err: io.ErrUnexpectedEOF, + } + } + + case tlsExtensionALPN: + if !readTLSALPN(extensionData, &hello.ALPNProtocols) { + return nil, DecodeError{ + Reason: "invalid TLS ALPN extension data", + Err: io.ErrUnexpectedEOF, + } + } + + case tlsExtensionSupportedVersions: + if !readTLSSupportedVersions(extensionData, &hello.SupportedVersions) { + return nil, DecodeError{ + Reason: "invalid TLS supported versions extension data", + Err: io.ErrUnexpectedEOF, + } + } + } + } + + return hello, nil +} + +func DecodeTLSClientHelloHandshake(data []byte) (*TLSClientHello, error) { + record, err := DecodeTLSRecord(data) + if err != nil { + return nil, err + } + if record.Type != tlsRecordTypeHandshake { + return nil, DecodeError{ + Reason: fmt.Sprintf("expected TLS handshake record type (0x%02X), got 0x%02X", tlsRecordTypeHandshake, record.Type), + Err: ErrInvalid, + } + } + return DecodeTLSClientHello(record.Data) +} + +// TLSServerHello is a TLS ServerHello packet as part of the TLS handshake. +type TLSServerHello struct { + Raw []byte + Version TLSVersion + RandomTimestamp time.Time + Random []byte + SessionID []byte + CipherSuite uint16 + CompressionMethod uint8 + Extensions []TLSExtension +} + +func DecodeTLSServerHello(data []byte) (*TLSServerHello, error) { + var ( + stream = cryptobyte.String(data) + hello = &TLSServerHello{Raw: data} + ) + + // Read header (4 bytes) + var handshakeType uint8 + if !stream.ReadUint8(&handshakeType) || handshakeType != tlsTypeServerHello { + return nil, DecodeError{ + Reason: fmt.Sprintf("expected a TLS ServerHello (0x%02X), got 0x%02X", tlsTypeServerHello, handshakeType), + Err: ErrInvalid, + } + } + var record cryptobyte.String + if !stream.ReadUint24LengthPrefixed(&record) { + return nil, DecodeError{ + Reason: "incomplete TLS record", + Err: io.ErrUnexpectedEOF, + } + } + if !stream.Empty() { + return nil, DecodeError{ + Reason: "invalid TLS record length", + Err: ErrInvalid, + } + } + + // Parser server version. + var version uint16 + if !record.ReadUint16(&version) { + return nil, DecodeError{ + Reason: "incomplete TLS version", + Err: io.ErrUnexpectedEOF, + } + } + hello.Version = TLSVersion(version) + + // Parse random (32 bytes) + if !record.ReadBytes(&hello.Random, 32) { + return nil, DecodeError{ + Reason: "incomplete TLS random bytes", + Err: io.ErrUnexpectedEOF, + } + } + hello.RandomTimestamp = time.Unix(int64(binary.BigEndian.Uint32(hello.Random)), 0) + + // Parse session ID + var sessionID cryptobyte.String + if !record.ReadUint8LengthPrefixed(&sessionID) { + return nil, DecodeError{ + Reason: "incomplete TLS session ID", + Err: io.ErrUnexpectedEOF, + } + } + hello.SessionID = sessionID + + // Parse cipher suite + if !record.ReadUint16(&hello.CipherSuite) { + return nil, DecodeError{ + Reason: "incomplete TLS cipher suite", + Err: io.ErrUnexpectedEOF, + } + } + + // Parse compression method + if !record.ReadUint8(&hello.CompressionMethod) { + return nil, DecodeError{ + Reason: "incomplete TLS compression method", + Err: io.ErrUnexpectedEOF, + } + } + + // Parse extensions (optional) + if record.Empty() { + return hello, nil + } + + var extensions cryptobyte.String + if !record.ReadUint16LengthPrefixed(&extensions) { + return nil, DecodeError{ + Reason: "incomplete TLS extensions", + Err: io.ErrUnexpectedEOF, + } + } + if !record.Empty() { + return nil, DecodeError{ + Reason: "extraneous TLS extension data", + Err: io.ErrUnexpectedEOF, + } + } + + for !extensions.Empty() { + var ( + extension TLSExtension + extensionData = cryptobyte.String(extension.Data) + ) + if !extensions.ReadUint16(&extension.Type) || !extensions.ReadUint16LengthPrefixed(&extensionData) { + return nil, DecodeError{ + Reason: "incomplete TLS extension record data", + Err: io.ErrUnexpectedEOF, + } + } + hello.Extensions = append(hello.Extensions, extension) + } + + return hello, nil +} + +func readTLSServerName(data cryptobyte.String, serverName *string) bool { + var list cryptobyte.String + if !data.ReadUint16LengthPrefixed(&list) || list.Empty() { + return false + } + for !list.Empty() { + var ( + nameType uint8 + name cryptobyte.String + ) + if !list.ReadUint8(&nameType) || !list.ReadUint16LengthPrefixed(&name) || name.Empty() { + return false + } + if nameType != 0 { + continue + } + if *serverName == "" { + *serverName = string(name) + } + } + return true +} + +func readTLSSupportedGroups(data cryptobyte.String, supported *[]uint16) bool { + var groups cryptobyte.String + if !data.ReadUint16LengthPrefixed(&groups) || groups.Empty() { + return false + } + for !groups.Empty() { + var group uint16 + if !groups.ReadUint16(&group) { + return false + } + *supported = append(*supported, group) + } + return true +} + +func readTLSSignatureAlgorithms(data cryptobyte.String, supported *[]TLSSignatureScheme) bool { + var algorithms cryptobyte.String + if !data.ReadUint16LengthPrefixed(&algorithms) || algorithms.Empty() { + return false + } + for !algorithms.Empty() { + var algorithm uint16 + if !algorithms.ReadUint16(&algorithm) { + return false + } + *supported = append(*supported, TLSSignatureScheme(algorithm)) + } + return true +} + +func readTLSALPN(data cryptobyte.String, alpnProtocols *[]string) bool { + var list cryptobyte.String + if !data.ReadUint16LengthPrefixed(&list) || list.Empty() { + return false + } + for !list.Empty() { + var proto cryptobyte.String + if !list.ReadUint8LengthPrefixed(&proto) || proto.Empty() { + return false + } + *alpnProtocols = append(*alpnProtocols, string(proto)) + } + return true +} + +func readTLSSupportedVersions(data cryptobyte.String, versions *[]TLSVersion) bool { + var list cryptobyte.String + if !data.ReadUint8LengthPrefixed(&list) || list.Empty() { + return false + } + for !list.Empty() { + var version uint16 + if !list.ReadUint16(&version) { + return false + } + *versions = append(*versions, TLSVersion(version)) + } + return true +} diff --git a/tls_const.go b/tls_const.go new file mode 100644 index 0000000..4c5ca38 --- /dev/null +++ b/tls_const.go @@ -0,0 +1,525 @@ +package dpi + +import ( + "crypto/tls" + "fmt" + "strconv" +) + +//go:generate stringer -linecomment -type=TLSCipherSuite,TLSSignatureScheme -output=tls_const_string.go + +// TLS Version +type TLSVersion uint16 + +func (version TLSVersion) String() string { + return TLSVersionName(version) +} + +// TLS versions. +const ( + VersionSSL30 TLSVersion = 0x0300 // SSLv3 + VersionTLS10 TLSVersion = tls.VersionTLS10 // TLS 1.0 + VersionTLS11 TLSVersion = tls.VersionTLS11 // TLS 1.1 + VersionTLS12 TLSVersion = tls.VersionTLS12 // TLS 1.2 + VersionTLS13 TLSVersion = tls.VersionTLS13 // TLS 1.3 + VersionTLS13Draft TLSVersion = 0x7F00 // TLS 1.3 (draft) + VersionTLS13Draft18 TLSVersion = 0x7F12 // TLS 1.3 (draft 18) + VersionTLS13Draft19 TLSVersion = 0x7F13 // TLS 1.3 (draft 19) + VersionTLS13Draft20 TLSVersion = 0x7F14 // TLS 1.3 (draft 20) + VersionTLS13Draft21 TLSVersion = 0x7F15 // TLS 1.3 (draft 21) + VersionTLS13Draft22 TLSVersion = 0x7F16 // TLS 1.3 (draft 22) + VersionTLS13Draft23 TLSVersion = 0x7F17 // TLS 1.3 (draft 23) +) + +var tlsVersionName = map[TLSVersion]string{ + VersionSSL30: "SSLv3", + VersionTLS10: "TLS 1.0", + VersionTLS11: "TLS 1.1", + VersionTLS12: "TLS 1.2", + VersionTLS13: "TLS 1.3", + VersionTLS13Draft: "TLS 1.3 (draft)", + VersionTLS13Draft18: "TLS 1.3 (draft 18)", + VersionTLS13Draft19: "TLS 1.3 (draft 19)", + VersionTLS13Draft20: "TLS 1.3 (draft 20)", + VersionTLS13Draft21: "TLS 1.3 (draft 21)", + VersionTLS13Draft22: "TLS 1.3 (draft 22)", + VersionTLS13Draft23: "TLS 1.3 (draft 23)", +} + +func TLSVersionName(version TLSVersion) string { + if s, ok := tlsVersionName[version]; ok { + return s + } + return "TLSVersion(0x" + strconv.FormatUint(uint64(version), 16) + ")" +} + +const ( + tlsRecordTypeChangeCipherSpec uint8 = 20 + tlsRecordTypeAlert uint8 = 21 + tlsRecordTypeHandshake uint8 = 22 + tlsRecordTypeApplicationData uint8 = 23 +) + +// TLS handshake message types. +const ( + tlsTypeHelloRequest uint8 = 0 + tlsTypeClientHello uint8 = 1 + tlsTypeServerHello uint8 = 2 + tlsTypeNewSessionTicket uint8 = 4 + tlsTypeEndOfEarlyData uint8 = 5 + tlsTypeEncryptedExtensions uint8 = 8 + tlsTypeCertificate uint8 = 11 + tlsTypeServerKeyExchange uint8 = 12 + tlsTypeCertificateRequest uint8 = 13 + tlsTypeServerHelloDone uint8 = 14 + tlsTypeCertificateVerify uint8 = 15 + tlsTypeClientKeyExchange uint8 = 16 + tlsTypeFinished uint8 = 20 + tlsTypeCertificateStatus uint8 = 22 + tlsTypeKeyUpdate uint8 = 24 + tlsTypeMessageHash uint8 = 254 +) + +// TLS extensions. +const ( + tlsExtensionServerName uint16 = 0 + tlsExtensionStatusRequest uint16 = 5 + tlsExtensionSupportedGroups uint16 = 10 + tlsExtensionSupportedPoints uint16 = 11 + tlsExtensionSignatureAlgorithms uint16 = 13 + tlsExtensionALPN uint16 = 16 + tlsExtensionStatusRequestV2 uint16 = 17 + tlsExtensionSCT uint16 = 18 + tlsExtensionExtendedMasterSecret uint16 = 23 + tlsExtensionDelegatedCredentials uint16 = 34 + tlsExtensionSessionTicket uint16 = 35 + tlsExtensionPreSharedKey uint16 = 41 + tlsExtensionEarlyData uint16 = 42 + tlsExtensionSupportedVersions uint16 = 43 + tlsExtensionCookie uint16 = 44 + tlsExtensionPSKModes uint16 = 45 + tlsExtensionCertificateAuthorities uint16 = 47 + tlsExtensionSignatureAlgorithmsCert uint16 = 50 + tlsExtensionKeyShare uint16 = 51 + tlsExtensionQUICTransportParameters uint16 = 57 + tlsExtensionRenegotiationInfo uint16 = 0xff01 + tlsExtensionECHOuterExtensions uint16 = 0xfd00 + tlsExtensionEncryptedClientHello uint16 = 0xfe0d +) + +// TLS cipher suite. +type TLSCipherSuite uint16 + +// TLS cipher suites. +// +// See https://www.iana.org/assignments/tls-parameters/tls-parameters.xml +const ( + TLS_NULL_WITH_NULL_NULL TLSCipherSuite = 0x0000 + TLS_RSA_WITH_NULL_MD5 TLSCipherSuite = 0x0001 // RFC5246 + TLS_RSA_WITH_NULL_SHA TLSCipherSuite = 0x0002 // RFC5246 + TLS_RSA_EXPORT_WITH_RC4_40_MD5 TLSCipherSuite = 0x0003 // RFC4346 RFC6347 + TLS_RSA_WITH_RC4_128_MD5 TLSCipherSuite = 0x0004 // RFC5246 RFC6347 + TLS_RSA_WITH_RC4_128_SHA TLSCipherSuite = 0x0005 // RFC5246 RFC6347 + TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 TLSCipherSuite = 0x0006 // RFC4346 + TLS_RSA_WITH_IDEA_CBC_SHA TLSCipherSuite = 0x0007 // RFC8996 + TLS_RSA_EXPORT_WITH_DES40_CBC_SHA TLSCipherSuite = 0x0008 // RFC4346 + TLS_RSA_WITH_DES_CBC_SHA TLSCipherSuite = 0x0009 // RFC8996 + TLS_RSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x000A // RFC5246 + TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA TLSCipherSuite = 0x000B // RFC4346 + TLS_DH_DSS_WITH_DES_CBC_SHA TLSCipherSuite = 0x000C // RFC8996 + TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x000D // RFC5246 + TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA TLSCipherSuite = 0x000E // RFC4346 + TLS_DH_RSA_WITH_DES_CBC_SHA TLSCipherSuite = 0x000F // RFC8996 + TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x0010 // RFC5246 + TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA TLSCipherSuite = 0x0011 // RFC4346 + TLS_DHE_DSS_WITH_DES_CBC_SHA TLSCipherSuite = 0x0012 // RFC8996 + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x0013 // RFC5246 + TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA TLSCipherSuite = 0x0014 // RFC4346 + TLS_DHE_RSA_WITH_DES_CBC_SHA TLSCipherSuite = 0x0015 // RFC8996 + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x0016 // RFC5246 + TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 TLSCipherSuite = 0x0017 // RFC4346 RFC6347 + TLS_DH_anon_WITH_RC4_128_MD5 TLSCipherSuite = 0x0018 // RFC5246 RFC6347 + TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA TLSCipherSuite = 0x0019 // RFC4346 + TLS_DH_anon_WITH_DES_CBC_SHA TLSCipherSuite = 0x001A // RFC8996 + TLS_DH_anon_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x001B // RFC5246 + TLS_KRB5_WITH_DES_CBC_SHA TLSCipherSuite = 0x001E // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x001F // RFC2712 + TLS_KRB5_WITH_RC4_128_SHA TLSCipherSuite = 0x0020 // RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_WITH_IDEA_CBC_SHA TLSCipherSuite = 0x0021 // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_WITH_DES_CBC_MD5 TLSCipherSuite = 0x0022 // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_WITH_3DES_EDE_CBC_MD5 TLSCipherSuite = 0x0023 // RFC2712 + TLS_KRB5_WITH_RC4_128_MD5 TLSCipherSuite = 0x0024 // RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_WITH_IDEA_CBC_MD5 TLSCipherSuite = 0x0025 // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA TLSCipherSuite = 0x0026 // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA TLSCipherSuite = 0x0027 // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_EXPORT_WITH_RC4_40_SHA TLSCipherSuite = 0x0028 // RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 TLSCipherSuite = 0x0029 // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 TLSCipherSuite = 0x002A // RFC2712 RFC-ietf-tls-rfc8447bis-14 + TLS_KRB5_EXPORT_WITH_RC4_40_MD5 TLSCipherSuite = 0x002B // RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_PSK_WITH_NULL_SHA TLSCipherSuite = 0x002C // RFC4785 RFC-ietf-tls-rfc8447bis-14 + TLS_DHE_PSK_WITH_NULL_SHA TLSCipherSuite = 0x002D // RFC4785 + TLS_RSA_PSK_WITH_NULL_SHA TLSCipherSuite = 0x002E // RFC4785 + TLS_RSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x002F // RFC5246 + TLS_DH_DSS_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x0030 // RFC5246 + TLS_DH_RSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x0031 // RFC5246 + TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x0032 // RFC5246 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x0033 // RFC5246 + TLS_DH_anon_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x0034 // RFC5246 + TLS_RSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x0035 // RFC5246 + TLS_DH_DSS_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x0036 // RFC5246 + TLS_DH_RSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x0037 // RFC5246 + TLS_DHE_DSS_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x0038 // RFC5246 + TLS_DHE_RSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x0039 // RFC5246 + TLS_DH_anon_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x003A // RFC5246 + TLS_RSA_WITH_NULL_SHA256 TLSCipherSuite = 0x003B // RFC5246 + TLS_RSA_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x003C // RFC5246 + TLS_RSA_WITH_AES_256_CBC_SHA256 TLSCipherSuite = 0x003D // RFC5246 + TLS_DH_DSS_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x003E // RFC5246 + TLS_DH_RSA_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x003F // RFC5246 + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x0040 // RFC5246 + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA TLSCipherSuite = 0x0041 // RFC5932 + TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA TLSCipherSuite = 0x0042 // RFC5932 + TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA TLSCipherSuite = 0x0043 // RFC5932 + TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA TLSCipherSuite = 0x0044 // RFC5932 + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA TLSCipherSuite = 0x0045 // RFC5932 + TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA TLSCipherSuite = 0x0046 // RFC5932 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x0067 // RFC5246 + TLS_DH_DSS_WITH_AES_256_CBC_SHA256 TLSCipherSuite = 0x0068 // RFC5246 + TLS_DH_RSA_WITH_AES_256_CBC_SHA256 TLSCipherSuite = 0x0069 // RFC5246 + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 TLSCipherSuite = 0x006A // RFC5246 + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 TLSCipherSuite = 0x006B // RFC5246 + TLS_DH_anon_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x006C // RFC5246 + TLS_DH_anon_WITH_AES_256_CBC_SHA256 TLSCipherSuite = 0x006D // RFC5246 + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA TLSCipherSuite = 0x0084 // RFC5932 + TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA TLSCipherSuite = 0x0085 // RFC5932 + TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA TLSCipherSuite = 0x0086 // RFC5932 + TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA TLSCipherSuite = 0x0087 // RFC5932 + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA TLSCipherSuite = 0x0088 // RFC5932 + TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA TLSCipherSuite = 0x0089 // RFC5932 + TLS_PSK_WITH_RC4_128_SHA TLSCipherSuite = 0x008A // RFC4279 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_PSK_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x008B // RFC4279 + TLS_PSK_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x008C // RFC4279 + TLS_PSK_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x008D // RFC4279 + TLS_DHE_PSK_WITH_RC4_128_SHA TLSCipherSuite = 0x008E // RFC4279 RFC6347 + TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x008F // RFC4279 + TLS_DHE_PSK_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x0090 // RFC4279 + TLS_DHE_PSK_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x0091 // RFC4279 + TLS_RSA_PSK_WITH_RC4_128_SHA TLSCipherSuite = 0x0092 // RFC4279 RFC6347 + TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0x0093 // RFC4279 + TLS_RSA_PSK_WITH_AES_128_CBC_SHA TLSCipherSuite = 0x0094 // RFC4279 + TLS_RSA_PSK_WITH_AES_256_CBC_SHA TLSCipherSuite = 0x0095 // RFC4279 + TLS_RSA_WITH_SEED_CBC_SHA TLSCipherSuite = 0x0096 // RFC4162 + TLS_DH_DSS_WITH_SEED_CBC_SHA TLSCipherSuite = 0x0097 // RFC4162 + TLS_DH_RSA_WITH_SEED_CBC_SHA TLSCipherSuite = 0x0098 // RFC4162 + TLS_DHE_DSS_WITH_SEED_CBC_SHA TLSCipherSuite = 0x0099 // RFC4162 + TLS_DHE_RSA_WITH_SEED_CBC_SHA TLSCipherSuite = 0x009A // RFC4162 + TLS_DH_anon_WITH_SEED_CBC_SHA TLSCipherSuite = 0x009B // RFC4162 + TLS_RSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x009C // RFC5288 + TLS_RSA_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x009D // RFC5288 + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x009E // RFC5288 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x009F // RFC5288 + TLS_DH_RSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x00A0 // RFC5288 + TLS_DH_RSA_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x00A1 // RFC5288 + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x00A2 // RFC5288 + TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x00A3 // RFC5288 + TLS_DH_DSS_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x00A4 // RFC5288 + TLS_DH_DSS_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x00A5 // RFC5288 + TLS_DH_anon_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x00A6 // RFC5288 + TLS_DH_anon_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x00A7 // RFC5288 + TLS_PSK_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x00A8 // RFC5487 + TLS_PSK_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x00A9 // RFC5487 + TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x00AA // RFC5487 + TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x00AB // RFC5487 + TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0x00AC // RFC5487 + TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0x00AD // RFC5487 + TLS_PSK_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x00AE // RFC5487 + TLS_PSK_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0x00AF // RFC5487 + TLS_PSK_WITH_NULL_SHA256 TLSCipherSuite = 0x00B0 // RFC5487 RFC-ietf-tls-rfc8447bis-14 + TLS_PSK_WITH_NULL_SHA384 TLSCipherSuite = 0x00B1 // RFC5487 RFC-ietf-tls-rfc8447bis-14 + TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x00B2 // RFC5487 + TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0x00B3 // RFC5487 + TLS_DHE_PSK_WITH_NULL_SHA256 TLSCipherSuite = 0x00B4 // RFC5487 + TLS_DHE_PSK_WITH_NULL_SHA384 TLSCipherSuite = 0x00B5 // RFC5487 + TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0x00B6 // RFC5487 + TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0x00B7 // RFC5487 + TLS_RSA_PSK_WITH_NULL_SHA256 TLSCipherSuite = 0x00B8 // RFC5487 + TLS_RSA_PSK_WITH_NULL_SHA384 TLSCipherSuite = 0x00B9 // RFC5487 + TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0x00BA // RFC5932 + TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0x00BB // RFC5932 + TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0x00BC // RFC5932 + TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0x00BD // RFC5932 + TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0x00BE // RFC5932 + TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0x00BF // RFC5932 + TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 TLSCipherSuite = 0x00C0 // RFC5932 + TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 TLSCipherSuite = 0x00C1 // RFC5932 + TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 TLSCipherSuite = 0x00C2 // RFC5932 + TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 TLSCipherSuite = 0x00C3 // RFC5932 + TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 TLSCipherSuite = 0x00C4 // RFC5932 + TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 TLSCipherSuite = 0x00C5 // RFC5932 + TLS_SM4_GCM_SM3 TLSCipherSuite = 0x00C6 // RFC8998 + TLS_SM4_CCM_SM3 TLSCipherSuite = 0x00C7 // RFC8998 + TLS_EMPTY_RENEGOTIATION_INFO_SCSV TLSCipherSuite = 0x00FF + TLS_AES_128_GCM_SHA256 TLSCipherSuite = 0x1301 // RFC-ietf-tls-rfc8446bis-13 + TLS_AES_256_GCM_SHA384 TLSCipherSuite = 0x1302 // RFC-ietf-tls-rfc8446bis-13 + TLS_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0x1303 // RFC-ietf-tls-rfc8446bis-13 + TLS_AES_128_CCM_SHA256 TLSCipherSuite = 0x1304 // RFC-ietf-tls-rfc8446bis-13 + TLS_AES_128_CCM_8_SHA256 TLSCipherSuite = 0x1305 // RFC-ietf-tls-rfc8446bis-13 IESG Action 2018-08-16 + TLS_AEGIS_256_SHA512 TLSCipherSuite = 0x1306 // draft-irtf-cfrg-aegis-aead-08] + TLS_AEGIS_128L_SHA256 TLSCipherSuite = 0x1307 + TLS_FALLBACK_SCSV TLSCipherSuite = 0x5600 + TLS_ECDH_ECDSA_WITH_NULL_SHA TLSCipherSuite = 0xC001 // RFC8422 + TLS_ECDH_ECDSA_WITH_RC4_128_SHA TLSCipherSuite = 0xC002 // RFC8422 RFC6347 + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC003 // RFC8422 + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC004 // RFC8422 + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC005 // RFC8422 + TLS_ECDHE_ECDSA_WITH_NULL_SHA TLSCipherSuite = 0xC006 // RFC8422 RFC-ietf-tls-rfc8447bis-14 + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLSCipherSuite = 0xC007 // RFC8422 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC008 // RFC8422 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC009 // RFC8422 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC00A // RFC8422 + TLS_ECDH_RSA_WITH_NULL_SHA TLSCipherSuite = 0xC00B // RFC8422 + TLS_ECDH_RSA_WITH_RC4_128_SHA TLSCipherSuite = 0xC00C // RFC8422 RFC6347 + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC00D // RFC8422 + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC00E // RFC8422 + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC00F // RFC8422 + TLS_ECDHE_RSA_WITH_NULL_SHA TLSCipherSuite = 0xC010 // RFC8422 RFC-ietf-tls-rfc8447bis-14 + TLS_ECDHE_RSA_WITH_RC4_128_SHA TLSCipherSuite = 0xC011 // RFC8422 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC012 // RFC8422 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC013 // RFC8422 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC014 // RFC8422 + TLS_ECDH_anon_WITH_NULL_SHA TLSCipherSuite = 0xC015 // RFC8422 + TLS_ECDH_anon_WITH_RC4_128_SHA TLSCipherSuite = 0xC016 // RFC8422 RFC6347 + TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC017 // RFC8422 + TLS_ECDH_anon_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC018 // RFC8422 + TLS_ECDH_anon_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC019 // RFC8422 + TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC01A // RFC5054 + TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC01B // RFC5054 + TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC01C // RFC5054 + TLS_SRP_SHA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC01D // RFC5054 + TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC01E // RFC5054 + TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC01F // RFC5054 + TLS_SRP_SHA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC020 // RFC5054 + TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC021 // RFC5054 + TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC022 // RFC5054 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0xC023 // RFC5289 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0xC024 // RFC5289 + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0xC025 // RFC5289 + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0xC026 // RFC5289 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0xC027 // RFC5289 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0xC028 // RFC5289 + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0xC029 // RFC5289 + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0xC02A // RFC5289 + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0xC02B // RFC5289 + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0xC02C // RFC5289 + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0xC02D // RFC5289 + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0xC02E // RFC5289 + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0xC02F // RFC5289 + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0xC030 // RFC5289 + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0xC031 // RFC5289 + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0xC032 // RFC5289 + TLS_ECDHE_PSK_WITH_RC4_128_SHA TLSCipherSuite = 0xC033 // RFC5489 RFC6347 RFC-ietf-tls-rfc8447bis-14 + TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA TLSCipherSuite = 0xC034 // RFC5489 + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA TLSCipherSuite = 0xC035 // RFC5489 + TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA TLSCipherSuite = 0xC036 // RFC5489 + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 TLSCipherSuite = 0xC037 // RFC5489 + TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 TLSCipherSuite = 0xC038 // RFC5489 + TLS_ECDHE_PSK_WITH_NULL_SHA TLSCipherSuite = 0xC039 // RFC5489 RFC-ietf-tls-rfc8447bis-14 + TLS_ECDHE_PSK_WITH_NULL_SHA256 TLSCipherSuite = 0xC03A // RFC5489 RFC-ietf-tls-rfc8447bis-14 + TLS_ECDHE_PSK_WITH_NULL_SHA384 TLSCipherSuite = 0xC03B // RFC5489 RFC-ietf-tls-rfc8447bis-14 + TLS_RSA_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC03C // RFC6209 + TLS_RSA_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC03D // RFC6209 + TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC03E // RFC6209 + TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC03F // RFC6209 + TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC040 // RFC6209 + TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC041 // RFC6209 + TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC042 // RFC6209 + TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC043 // RFC6209 + TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC044 // RFC6209 + TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC045 // RFC6209 + TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC046 // RFC6209 + TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC047 // RFC6209 + TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC048 // RFC6209 + TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC049 // RFC6209 + TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC04A // RFC6209 + TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC04B // RFC6209 + TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC04C // RFC6209 + TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC04D // RFC6209 + TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC04E // RFC6209 + TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC04F // RFC6209 + TLS_RSA_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC050 // RFC6209 + TLS_RSA_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC051 // RFC6209 + TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC052 // RFC6209 + TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC053 // RFC6209 + TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC054 // RFC6209 + TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC055 // RFC6209 + TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC056 // RFC6209 + TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC057 // RFC6209 + TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC058 // RFC6209 + TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC059 // RFC6209 + TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC05A // RFC6209 + TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC05B // RFC6209 + TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC05C // RFC6209 + TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC05D // RFC6209 + TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC05E // RFC6209 + TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC05F // RFC6209 + TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC060 // RFC6209 + TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC061 // RFC6209 + TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC062 // RFC6209 + TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC063 // RFC6209 + TLS_PSK_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC064 // RFC6209 + TLS_PSK_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC065 // RFC6209 + TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC066 // RFC6209 + TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC067 // RFC6209 + TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC068 // RFC6209 + TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC069 // RFC6209 + TLS_PSK_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC06A // RFC6209 + TLS_PSK_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC06B // RFC6209 + TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC06C // RFC6209 + TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC06D // RFC6209 + TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 TLSCipherSuite = 0xC06E // RFC6209 + TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 TLSCipherSuite = 0xC06F // RFC6209 + TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 TLSCipherSuite = 0xC070 // RFC6209 + TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 TLSCipherSuite = 0xC071 // RFC6209 + TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC072 // RFC6367 + TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC073 // RFC6367 + TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC074 // RFC6367 + TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC075 // RFC6367 + TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC076 // RFC6367 + TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC077 // RFC6367 + TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC078 // RFC6367 + TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC079 // RFC6367 + TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC07A // RFC6367 + TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC07B // RFC6367 + TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC07C // RFC6367 + TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC07D // RFC6367 + TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC07E // RFC6367 + TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC07F // RFC6367 + TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC080 // RFC6367 + TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC081 // RFC6367 + TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC082 // RFC6367 + TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC083 // RFC6367 + TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC084 // RFC6367 + TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC085 // RFC6367 + TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC086 // RFC6367 + TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC087 // RFC6367 + TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC088 // RFC6367 + TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC089 // RFC6367 + TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC08A // RFC6367 + TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC08B // RFC6367 + TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC08C // RFC6367 + TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC08D // RFC6367 + TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC08E // RFC6367 + TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC08F // RFC6367 + TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC090 // RFC6367 + TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC091 // RFC6367 + TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 TLSCipherSuite = 0xC092 // RFC6367 + TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 TLSCipherSuite = 0xC093 // RFC6367 + TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC094 // RFC6367 + TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC095 // RFC6367 + TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC096 // RFC6367 + TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC097 // RFC6367 + TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC098 // RFC6367 + TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC099 // RFC6367 + TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 TLSCipherSuite = 0xC09A // RFC6367 + TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 TLSCipherSuite = 0xC09B // RFC6367 + TLS_RSA_WITH_AES_128_CCM TLSCipherSuite = 0xC09C // RFC6655 + TLS_RSA_WITH_AES_256_CCM TLSCipherSuite = 0xC09D // RFC6655 + TLS_DHE_RSA_WITH_AES_128_CCM TLSCipherSuite = 0xC09E // RFC6655 + TLS_DHE_RSA_WITH_AES_256_CCM TLSCipherSuite = 0xC09F // RFC6655 + TLS_RSA_WITH_AES_128_CCM_8 TLSCipherSuite = 0xC0A0 // RFC6655 + TLS_RSA_WITH_AES_256_CCM_8 TLSCipherSuite = 0xC0A1 // RFC6655 + TLS_DHE_RSA_WITH_AES_128_CCM_8 TLSCipherSuite = 0xC0A2 // RFC6655 + TLS_DHE_RSA_WITH_AES_256_CCM_8 TLSCipherSuite = 0xC0A3 // RFC6655 + TLS_PSK_WITH_AES_128_CCM TLSCipherSuite = 0xC0A4 // RFC6655 + TLS_PSK_WITH_AES_256_CCM TLSCipherSuite = 0xC0A5 // RFC6655 + TLS_DHE_PSK_WITH_AES_128_CCM TLSCipherSuite = 0xC0A6 // RFC6655 + TLS_DHE_PSK_WITH_AES_256_CCM TLSCipherSuite = 0xC0A7 // RFC6655 + TLS_PSK_WITH_AES_128_CCM_8 TLSCipherSuite = 0xC0A8 // RFC6655 + TLS_PSK_WITH_AES_256_CCM_8 TLSCipherSuite = 0xC0A9 // RFC6655 + TLS_PSK_DHE_WITH_AES_128_CCM_8 TLSCipherSuite = 0xC0AA // RFC6655 + TLS_PSK_DHE_WITH_AES_256_CCM_8 TLSCipherSuite = 0xC0AB // RFC6655 + TLS_ECDHE_ECDSA_WITH_AES_128_CCM TLSCipherSuite = 0xC0AC // RFC7251 + TLS_ECDHE_ECDSA_WITH_AES_256_CCM TLSCipherSuite = 0xC0AD // RFC7251 + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 TLSCipherSuite = 0xC0AE // RFC7251 + TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 TLSCipherSuite = 0xC0AF // RFC7251 + TLS_ECCPWD_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0xC0B0 // RFC8492 + TLS_ECCPWD_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0xC0B1 // RFC8492 + TLS_ECCPWD_WITH_AES_128_CCM_SHA256 TLSCipherSuite = 0xC0B2 // RFC8492 + TLS_ECCPWD_WITH_AES_256_CCM_SHA384 TLSCipherSuite = 0xC0B3 // RFC8492 + TLS_SHA256_SHA256 TLSCipherSuite = 0xC0B4 // RFC9150 RFC-ietf-tls-rfc8447bis-14 + TLS_SHA384_SHA384 TLSCipherSuite = 0xC0B5 // RFC9150 RFC-ietf-tls-rfc8447bis-14 + TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC TLSCipherSuite = 0xC100 // RFC9189 + TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC TLSCipherSuite = 0xC101 // RFC9189 + TLS_GOSTR341112_256_WITH_28147_CNT_IMIT TLSCipherSuite = 0xC102 // RFC9189 + TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L TLSCipherSuite = 0xC103 // RFC9367 + TLS_GOSTR341112_256_WITH_MAGMA_MGM_L TLSCipherSuite = 0xC104 // RFC9367 + TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S TLSCipherSuite = 0xC105 // RFC9367 + TLS_GOSTR341112_256_WITH_MAGMA_MGM_S TLSCipherSuite = 0xC106 // RFC9367 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0xCCA8 // RFC7905 + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0xCCA9 // RFC7905 + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0xCCAA // RFC7905 + TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0xCCAB // RFC7905 + TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0xCCAC // RFC7905 + TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0xCCAD // RFC7905 + TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 TLSCipherSuite = 0xCCAE // RFC7905 + TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 TLSCipherSuite = 0xD001 // RFC8442 + TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 TLSCipherSuite = 0xD002 // RFC8442 + TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 TLSCipherSuite = 0xD003 // RFC8442 + TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 TLSCipherSuite = 0xD005 +) + +func TLSCipherSuiteName(suite TLSCipherSuite) string { + return suite.String() +} + +// TLS compression methods +// +// See https://www.iana.org/assignments/comp-meth-ids/comp-meth-ids.xhtml +const ( + TLS_COMPRESS_NULL uint8 = 0 + TLS_COMPRESS_DEFLATE uint8 = 1 + TLS_COMPRESS_LSZ uint8 = 64 +) + +var tlsCompressionMethodNames = map[uint8]string{ + TLS_COMPRESS_NULL: "NULL", + TLS_COMPRESS_DEFLATE: "DEFLATE", + TLS_COMPRESS_LSZ: "LSZ", +} + +func TLSCompressionMethodName(method uint8) string { + if s, ok := tlsCompressionMethodNames[method]; ok { + return s + } + return fmt.Sprintf("0x%02X", method) +} + +// TLS signature scheme. +type TLSSignatureScheme uint16 + +// TLS signature schemes. +// +// See RFC 8446, Section 4.2.3 +const ( + // RSASSA-PKCS1-v1_5 algorithms. + PKCS1WithSHA256 TLSSignatureScheme = 0x0401 + PKCS1WithSHA384 TLSSignatureScheme = 0x0501 + PKCS1WithSHA512 TLSSignatureScheme = 0x0601 + + // RSASSA-PSS algorithms with public key OID rsaEncryption. + PSSWithSHA256 TLSSignatureScheme = 0x0804 + PSSWithSHA384 TLSSignatureScheme = 0x0805 + PSSWithSHA512 TLSSignatureScheme = 0x0806 + + // ECDSA algorithms. Only constrained to a specific curve in TLS 1.3. + ECDSAWithP256AndSHA256 TLSSignatureScheme = 0x0403 + ECDSAWithP384AndSHA384 TLSSignatureScheme = 0x0503 + ECDSAWithP521AndSHA512 TLSSignatureScheme = 0x0603 + + // EdDSA algorithms. + Ed25519 TLSSignatureScheme = 0x0807 + + // Legacy signature and hash algorithms for TLS 1.2. + PKCS1WithSHA1 TLSSignatureScheme = 0x0201 + ECDSAWithSHA1 TLSSignatureScheme = 0x0203 +) diff --git a/tls_const_string.go b/tls_const_string.go new file mode 100644 index 0000000..f096d77 --- /dev/null +++ b/tls_const_string.go @@ -0,0 +1,786 @@ +// Code generated by "stringer -linecomment -type=TLSCipherSuite,TLSSignatureScheme -output=tls_const_string.go"; DO NOT EDIT. + +package dpi + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[TLS_NULL_WITH_NULL_NULL-0] + _ = x[TLS_RSA_WITH_NULL_MD5-1] + _ = x[TLS_RSA_WITH_NULL_SHA-2] + _ = x[TLS_RSA_EXPORT_WITH_RC4_40_MD5-3] + _ = x[TLS_RSA_WITH_RC4_128_MD5-4] + _ = x[TLS_RSA_WITH_RC4_128_SHA-5] + _ = x[TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5-6] + _ = x[TLS_RSA_WITH_IDEA_CBC_SHA-7] + _ = x[TLS_RSA_EXPORT_WITH_DES40_CBC_SHA-8] + _ = x[TLS_RSA_WITH_DES_CBC_SHA-9] + _ = x[TLS_RSA_WITH_3DES_EDE_CBC_SHA-10] + _ = x[TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA-11] + _ = x[TLS_DH_DSS_WITH_DES_CBC_SHA-12] + _ = x[TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA-13] + _ = x[TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA-14] + _ = x[TLS_DH_RSA_WITH_DES_CBC_SHA-15] + _ = x[TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA-16] + _ = x[TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA-17] + _ = x[TLS_DHE_DSS_WITH_DES_CBC_SHA-18] + _ = x[TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA-19] + _ = x[TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA-20] + _ = x[TLS_DHE_RSA_WITH_DES_CBC_SHA-21] + _ = x[TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA-22] + _ = x[TLS_DH_anon_EXPORT_WITH_RC4_40_MD5-23] + _ = x[TLS_DH_anon_WITH_RC4_128_MD5-24] + _ = x[TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA-25] + _ = x[TLS_DH_anon_WITH_DES_CBC_SHA-26] + _ = x[TLS_DH_anon_WITH_3DES_EDE_CBC_SHA-27] + _ = x[TLS_KRB5_WITH_DES_CBC_SHA-30] + _ = x[TLS_KRB5_WITH_3DES_EDE_CBC_SHA-31] + _ = x[TLS_KRB5_WITH_RC4_128_SHA-32] + _ = x[TLS_KRB5_WITH_IDEA_CBC_SHA-33] + _ = x[TLS_KRB5_WITH_DES_CBC_MD5-34] + _ = x[TLS_KRB5_WITH_3DES_EDE_CBC_MD5-35] + _ = x[TLS_KRB5_WITH_RC4_128_MD5-36] + _ = x[TLS_KRB5_WITH_IDEA_CBC_MD5-37] + _ = x[TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA-38] + _ = x[TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA-39] + _ = x[TLS_KRB5_EXPORT_WITH_RC4_40_SHA-40] + _ = x[TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5-41] + _ = x[TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5-42] + _ = x[TLS_KRB5_EXPORT_WITH_RC4_40_MD5-43] + _ = x[TLS_PSK_WITH_NULL_SHA-44] + _ = x[TLS_DHE_PSK_WITH_NULL_SHA-45] + _ = x[TLS_RSA_PSK_WITH_NULL_SHA-46] + _ = x[TLS_RSA_WITH_AES_128_CBC_SHA-47] + _ = x[TLS_DH_DSS_WITH_AES_128_CBC_SHA-48] + _ = x[TLS_DH_RSA_WITH_AES_128_CBC_SHA-49] + _ = x[TLS_DHE_DSS_WITH_AES_128_CBC_SHA-50] + _ = x[TLS_DHE_RSA_WITH_AES_128_CBC_SHA-51] + _ = x[TLS_DH_anon_WITH_AES_128_CBC_SHA-52] + _ = x[TLS_RSA_WITH_AES_256_CBC_SHA-53] + _ = x[TLS_DH_DSS_WITH_AES_256_CBC_SHA-54] + _ = x[TLS_DH_RSA_WITH_AES_256_CBC_SHA-55] + _ = x[TLS_DHE_DSS_WITH_AES_256_CBC_SHA-56] + _ = x[TLS_DHE_RSA_WITH_AES_256_CBC_SHA-57] + _ = x[TLS_DH_anon_WITH_AES_256_CBC_SHA-58] + _ = x[TLS_RSA_WITH_NULL_SHA256-59] + _ = x[TLS_RSA_WITH_AES_128_CBC_SHA256-60] + _ = x[TLS_RSA_WITH_AES_256_CBC_SHA256-61] + _ = x[TLS_DH_DSS_WITH_AES_128_CBC_SHA256-62] + _ = x[TLS_DH_RSA_WITH_AES_128_CBC_SHA256-63] + _ = x[TLS_DHE_DSS_WITH_AES_128_CBC_SHA256-64] + _ = x[TLS_RSA_WITH_CAMELLIA_128_CBC_SHA-65] + _ = x[TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA-66] + _ = x[TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA-67] + _ = x[TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA-68] + _ = x[TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA-69] + _ = x[TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA-70] + _ = x[TLS_DHE_RSA_WITH_AES_128_CBC_SHA256-103] + _ = x[TLS_DH_DSS_WITH_AES_256_CBC_SHA256-104] + _ = x[TLS_DH_RSA_WITH_AES_256_CBC_SHA256-105] + _ = x[TLS_DHE_DSS_WITH_AES_256_CBC_SHA256-106] + _ = x[TLS_DHE_RSA_WITH_AES_256_CBC_SHA256-107] + _ = x[TLS_DH_anon_WITH_AES_128_CBC_SHA256-108] + _ = x[TLS_DH_anon_WITH_AES_256_CBC_SHA256-109] + _ = x[TLS_RSA_WITH_CAMELLIA_256_CBC_SHA-132] + _ = x[TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA-133] + _ = x[TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA-134] + _ = x[TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA-135] + _ = x[TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA-136] + _ = x[TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA-137] + _ = x[TLS_PSK_WITH_RC4_128_SHA-138] + _ = x[TLS_PSK_WITH_3DES_EDE_CBC_SHA-139] + _ = x[TLS_PSK_WITH_AES_128_CBC_SHA-140] + _ = x[TLS_PSK_WITH_AES_256_CBC_SHA-141] + _ = x[TLS_DHE_PSK_WITH_RC4_128_SHA-142] + _ = x[TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA-143] + _ = x[TLS_DHE_PSK_WITH_AES_128_CBC_SHA-144] + _ = x[TLS_DHE_PSK_WITH_AES_256_CBC_SHA-145] + _ = x[TLS_RSA_PSK_WITH_RC4_128_SHA-146] + _ = x[TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA-147] + _ = x[TLS_RSA_PSK_WITH_AES_128_CBC_SHA-148] + _ = x[TLS_RSA_PSK_WITH_AES_256_CBC_SHA-149] + _ = x[TLS_RSA_WITH_SEED_CBC_SHA-150] + _ = x[TLS_DH_DSS_WITH_SEED_CBC_SHA-151] + _ = x[TLS_DH_RSA_WITH_SEED_CBC_SHA-152] + _ = x[TLS_DHE_DSS_WITH_SEED_CBC_SHA-153] + _ = x[TLS_DHE_RSA_WITH_SEED_CBC_SHA-154] + _ = x[TLS_DH_anon_WITH_SEED_CBC_SHA-155] + _ = x[TLS_RSA_WITH_AES_128_GCM_SHA256-156] + _ = x[TLS_RSA_WITH_AES_256_GCM_SHA384-157] + _ = x[TLS_DHE_RSA_WITH_AES_128_GCM_SHA256-158] + _ = x[TLS_DHE_RSA_WITH_AES_256_GCM_SHA384-159] + _ = x[TLS_DH_RSA_WITH_AES_128_GCM_SHA256-160] + _ = x[TLS_DH_RSA_WITH_AES_256_GCM_SHA384-161] + _ = x[TLS_DHE_DSS_WITH_AES_128_GCM_SHA256-162] + _ = x[TLS_DHE_DSS_WITH_AES_256_GCM_SHA384-163] + _ = x[TLS_DH_DSS_WITH_AES_128_GCM_SHA256-164] + _ = x[TLS_DH_DSS_WITH_AES_256_GCM_SHA384-165] + _ = x[TLS_DH_anon_WITH_AES_128_GCM_SHA256-166] + _ = x[TLS_DH_anon_WITH_AES_256_GCM_SHA384-167] + _ = x[TLS_PSK_WITH_AES_128_GCM_SHA256-168] + _ = x[TLS_PSK_WITH_AES_256_GCM_SHA384-169] + _ = x[TLS_DHE_PSK_WITH_AES_128_GCM_SHA256-170] + _ = x[TLS_DHE_PSK_WITH_AES_256_GCM_SHA384-171] + _ = x[TLS_RSA_PSK_WITH_AES_128_GCM_SHA256-172] + _ = x[TLS_RSA_PSK_WITH_AES_256_GCM_SHA384-173] + _ = x[TLS_PSK_WITH_AES_128_CBC_SHA256-174] + _ = x[TLS_PSK_WITH_AES_256_CBC_SHA384-175] + _ = x[TLS_PSK_WITH_NULL_SHA256-176] + _ = x[TLS_PSK_WITH_NULL_SHA384-177] + _ = x[TLS_DHE_PSK_WITH_AES_128_CBC_SHA256-178] + _ = x[TLS_DHE_PSK_WITH_AES_256_CBC_SHA384-179] + _ = x[TLS_DHE_PSK_WITH_NULL_SHA256-180] + _ = x[TLS_DHE_PSK_WITH_NULL_SHA384-181] + _ = x[TLS_RSA_PSK_WITH_AES_128_CBC_SHA256-182] + _ = x[TLS_RSA_PSK_WITH_AES_256_CBC_SHA384-183] + _ = x[TLS_RSA_PSK_WITH_NULL_SHA256-184] + _ = x[TLS_RSA_PSK_WITH_NULL_SHA384-185] + _ = x[TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256-186] + _ = x[TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256-187] + _ = x[TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256-188] + _ = x[TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256-189] + _ = x[TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256-190] + _ = x[TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256-191] + _ = x[TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256-192] + _ = x[TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256-193] + _ = x[TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256-194] + _ = x[TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256-195] + _ = x[TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256-196] + _ = x[TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256-197] + _ = x[TLS_SM4_GCM_SM3-198] + _ = x[TLS_SM4_CCM_SM3-199] + _ = x[TLS_EMPTY_RENEGOTIATION_INFO_SCSV-255] + _ = x[TLS_AES_128_GCM_SHA256-4865] + _ = x[TLS_AES_256_GCM_SHA384-4866] + _ = x[TLS_CHACHA20_POLY1305_SHA256-4867] + _ = x[TLS_AES_128_CCM_SHA256-4868] + _ = x[TLS_AES_128_CCM_8_SHA256-4869] + _ = x[TLS_AEGIS_256_SHA512-4870] + _ = x[TLS_AEGIS_128L_SHA256-4871] + _ = x[TLS_FALLBACK_SCSV-22016] + _ = x[TLS_ECDH_ECDSA_WITH_NULL_SHA-49153] + _ = x[TLS_ECDH_ECDSA_WITH_RC4_128_SHA-49154] + _ = x[TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA-49155] + _ = x[TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA-49156] + _ = x[TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA-49157] + _ = x[TLS_ECDHE_ECDSA_WITH_NULL_SHA-49158] + _ = x[TLS_ECDHE_ECDSA_WITH_RC4_128_SHA-49159] + _ = x[TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA-49160] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA-49161] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA-49162] + _ = x[TLS_ECDH_RSA_WITH_NULL_SHA-49163] + _ = x[TLS_ECDH_RSA_WITH_RC4_128_SHA-49164] + _ = x[TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA-49165] + _ = x[TLS_ECDH_RSA_WITH_AES_128_CBC_SHA-49166] + _ = x[TLS_ECDH_RSA_WITH_AES_256_CBC_SHA-49167] + _ = x[TLS_ECDHE_RSA_WITH_NULL_SHA-49168] + _ = x[TLS_ECDHE_RSA_WITH_RC4_128_SHA-49169] + _ = x[TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA-49170] + _ = x[TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA-49171] + _ = x[TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA-49172] + _ = x[TLS_ECDH_anon_WITH_NULL_SHA-49173] + _ = x[TLS_ECDH_anon_WITH_RC4_128_SHA-49174] + _ = x[TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA-49175] + _ = x[TLS_ECDH_anon_WITH_AES_128_CBC_SHA-49176] + _ = x[TLS_ECDH_anon_WITH_AES_256_CBC_SHA-49177] + _ = x[TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA-49178] + _ = x[TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA-49179] + _ = x[TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA-49180] + _ = x[TLS_SRP_SHA_WITH_AES_128_CBC_SHA-49181] + _ = x[TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA-49182] + _ = x[TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA-49183] + _ = x[TLS_SRP_SHA_WITH_AES_256_CBC_SHA-49184] + _ = x[TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA-49185] + _ = x[TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA-49186] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256-49187] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384-49188] + _ = x[TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256-49189] + _ = x[TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384-49190] + _ = x[TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256-49191] + _ = x[TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384-49192] + _ = x[TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256-49193] + _ = x[TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384-49194] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256-49195] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384-49196] + _ = x[TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256-49197] + _ = x[TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384-49198] + _ = x[TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256-49199] + _ = x[TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384-49200] + _ = x[TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256-49201] + _ = x[TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384-49202] + _ = x[TLS_ECDHE_PSK_WITH_RC4_128_SHA-49203] + _ = x[TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA-49204] + _ = x[TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA-49205] + _ = x[TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA-49206] + _ = x[TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256-49207] + _ = x[TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384-49208] + _ = x[TLS_ECDHE_PSK_WITH_NULL_SHA-49209] + _ = x[TLS_ECDHE_PSK_WITH_NULL_SHA256-49210] + _ = x[TLS_ECDHE_PSK_WITH_NULL_SHA384-49211] + _ = x[TLS_RSA_WITH_ARIA_128_CBC_SHA256-49212] + _ = x[TLS_RSA_WITH_ARIA_256_CBC_SHA384-49213] + _ = x[TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256-49214] + _ = x[TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384-49215] + _ = x[TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256-49216] + _ = x[TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384-49217] + _ = x[TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256-49218] + _ = x[TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384-49219] + _ = x[TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256-49220] + _ = x[TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384-49221] + _ = x[TLS_DH_anon_WITH_ARIA_128_CBC_SHA256-49222] + _ = x[TLS_DH_anon_WITH_ARIA_256_CBC_SHA384-49223] + _ = x[TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256-49224] + _ = x[TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384-49225] + _ = x[TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256-49226] + _ = x[TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384-49227] + _ = x[TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256-49228] + _ = x[TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384-49229] + _ = x[TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256-49230] + _ = x[TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384-49231] + _ = x[TLS_RSA_WITH_ARIA_128_GCM_SHA256-49232] + _ = x[TLS_RSA_WITH_ARIA_256_GCM_SHA384-49233] + _ = x[TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256-49234] + _ = x[TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384-49235] + _ = x[TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256-49236] + _ = x[TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384-49237] + _ = x[TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256-49238] + _ = x[TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384-49239] + _ = x[TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256-49240] + _ = x[TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384-49241] + _ = x[TLS_DH_anon_WITH_ARIA_128_GCM_SHA256-49242] + _ = x[TLS_DH_anon_WITH_ARIA_256_GCM_SHA384-49243] + _ = x[TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256-49244] + _ = x[TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384-49245] + _ = x[TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256-49246] + _ = x[TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384-49247] + _ = x[TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256-49248] + _ = x[TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384-49249] + _ = x[TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256-49250] + _ = x[TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384-49251] + _ = x[TLS_PSK_WITH_ARIA_128_CBC_SHA256-49252] + _ = x[TLS_PSK_WITH_ARIA_256_CBC_SHA384-49253] + _ = x[TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256-49254] + _ = x[TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384-49255] + _ = x[TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256-49256] + _ = x[TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384-49257] + _ = x[TLS_PSK_WITH_ARIA_128_GCM_SHA256-49258] + _ = x[TLS_PSK_WITH_ARIA_256_GCM_SHA384-49259] + _ = x[TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256-49260] + _ = x[TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384-49261] + _ = x[TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256-49262] + _ = x[TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384-49263] + _ = x[TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256-49264] + _ = x[TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384-49265] + _ = x[TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256-49266] + _ = x[TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384-49267] + _ = x[TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256-49268] + _ = x[TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384-49269] + _ = x[TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256-49270] + _ = x[TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384-49271] + _ = x[TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256-49272] + _ = x[TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384-49273] + _ = x[TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256-49274] + _ = x[TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384-49275] + _ = x[TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256-49276] + _ = x[TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384-49277] + _ = x[TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256-49278] + _ = x[TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384-49279] + _ = x[TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256-49280] + _ = x[TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384-49281] + _ = x[TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256-49282] + _ = x[TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384-49283] + _ = x[TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256-49284] + _ = x[TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384-49285] + _ = x[TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256-49286] + _ = x[TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384-49287] + _ = x[TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256-49288] + _ = x[TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384-49289] + _ = x[TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256-49290] + _ = x[TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384-49291] + _ = x[TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256-49292] + _ = x[TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384-49293] + _ = x[TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256-49294] + _ = x[TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384-49295] + _ = x[TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256-49296] + _ = x[TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384-49297] + _ = x[TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256-49298] + _ = x[TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384-49299] + _ = x[TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256-49300] + _ = x[TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384-49301] + _ = x[TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256-49302] + _ = x[TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384-49303] + _ = x[TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256-49304] + _ = x[TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384-49305] + _ = x[TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256-49306] + _ = x[TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384-49307] + _ = x[TLS_RSA_WITH_AES_128_CCM-49308] + _ = x[TLS_RSA_WITH_AES_256_CCM-49309] + _ = x[TLS_DHE_RSA_WITH_AES_128_CCM-49310] + _ = x[TLS_DHE_RSA_WITH_AES_256_CCM-49311] + _ = x[TLS_RSA_WITH_AES_128_CCM_8-49312] + _ = x[TLS_RSA_WITH_AES_256_CCM_8-49313] + _ = x[TLS_DHE_RSA_WITH_AES_128_CCM_8-49314] + _ = x[TLS_DHE_RSA_WITH_AES_256_CCM_8-49315] + _ = x[TLS_PSK_WITH_AES_128_CCM-49316] + _ = x[TLS_PSK_WITH_AES_256_CCM-49317] + _ = x[TLS_DHE_PSK_WITH_AES_128_CCM-49318] + _ = x[TLS_DHE_PSK_WITH_AES_256_CCM-49319] + _ = x[TLS_PSK_WITH_AES_128_CCM_8-49320] + _ = x[TLS_PSK_WITH_AES_256_CCM_8-49321] + _ = x[TLS_PSK_DHE_WITH_AES_128_CCM_8-49322] + _ = x[TLS_PSK_DHE_WITH_AES_256_CCM_8-49323] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_128_CCM-49324] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_256_CCM-49325] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8-49326] + _ = x[TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8-49327] + _ = x[TLS_ECCPWD_WITH_AES_128_GCM_SHA256-49328] + _ = x[TLS_ECCPWD_WITH_AES_256_GCM_SHA384-49329] + _ = x[TLS_ECCPWD_WITH_AES_128_CCM_SHA256-49330] + _ = x[TLS_ECCPWD_WITH_AES_256_CCM_SHA384-49331] + _ = x[TLS_SHA256_SHA256-49332] + _ = x[TLS_SHA384_SHA384-49333] + _ = x[TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC-49408] + _ = x[TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC-49409] + _ = x[TLS_GOSTR341112_256_WITH_28147_CNT_IMIT-49410] + _ = x[TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L-49411] + _ = x[TLS_GOSTR341112_256_WITH_MAGMA_MGM_L-49412] + _ = x[TLS_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S-49413] + _ = x[TLS_GOSTR341112_256_WITH_MAGMA_MGM_S-49414] + _ = x[TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256-52392] + _ = x[TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256-52393] + _ = x[TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256-52394] + _ = x[TLS_PSK_WITH_CHACHA20_POLY1305_SHA256-52395] + _ = x[TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256-52396] + _ = x[TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256-52397] + _ = x[TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256-52398] + _ = x[TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256-53249] + _ = x[TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384-53250] + _ = x[TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256-53251] + _ = x[TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256-53253] +} + +const _TLSCipherSuite_name = "TLS_NULL_WITH_NULL_NULLRFC5246RFC5246RFC4346 RFC6347RFC5246 RFC6347RFC5246 RFC6347RFC4346RFC8996RFC4346RFC8996RFC5246RFC4346RFC8996RFC5246RFC4346RFC8996RFC5246RFC4346RFC8996RFC5246RFC4346RFC8996RFC5246RFC4346 RFC6347RFC5246 RFC6347RFC4346RFC8996RFC5246RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC-ietf-tls-rfc8447bis-14RFC2712 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC4785 RFC-ietf-tls-rfc8447bis-14RFC4785RFC4785RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5246RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC4279 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC4279RFC4279RFC4279RFC4279 RFC6347RFC4279RFC4279RFC4279RFC4279 RFC6347RFC4279RFC4279RFC4279RFC4162RFC4162RFC4162RFC4162RFC4162RFC4162RFC5288RFC5288RFC5288RFC5288RFC5288RFC5288RFC5288RFC5288RFC5288RFC5288RFC5288RFC5288RFC5487RFC5487RFC5487RFC5487RFC5487RFC5487RFC5487RFC5487RFC5487 RFC-ietf-tls-rfc8447bis-14RFC5487 RFC-ietf-tls-rfc8447bis-14RFC5487RFC5487RFC5487RFC5487RFC5487RFC5487RFC5487RFC5487RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC5932RFC8998RFC8998TLS_EMPTY_RENEGOTIATION_INFO_SCSVRFC-ietf-tls-rfc8446bis-13RFC-ietf-tls-rfc8446bis-13RFC-ietf-tls-rfc8446bis-13RFC-ietf-tls-rfc8446bis-13RFC-ietf-tls-rfc8446bis-13 IESG Action 2018-08-16draft-irtf-cfrg-aegis-aead-08]TLS_AEGIS_128L_SHA256TLS_FALLBACK_SCSVRFC8422RFC8422 RFC6347RFC8422RFC8422RFC8422RFC8422 RFC-ietf-tls-rfc8447bis-14RFC8422 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC8422RFC8422RFC8422RFC8422RFC8422 RFC6347RFC8422RFC8422RFC8422RFC8422 RFC-ietf-tls-rfc8447bis-14RFC8422 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC8422RFC8422RFC8422RFC8422RFC8422 RFC6347RFC8422RFC8422RFC8422RFC5054RFC5054RFC5054RFC5054RFC5054RFC5054RFC5054RFC5054RFC5054RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5289RFC5489 RFC6347 RFC-ietf-tls-rfc8447bis-14RFC5489RFC5489RFC5489RFC5489RFC5489RFC5489 RFC-ietf-tls-rfc8447bis-14RFC5489 RFC-ietf-tls-rfc8447bis-14RFC5489 RFC-ietf-tls-rfc8447bis-14RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6209RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6367RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC6655RFC7251RFC7251RFC7251RFC7251RFC8492RFC8492RFC8492RFC8492RFC9150 RFC-ietf-tls-rfc8447bis-14RFC9150 RFC-ietf-tls-rfc8447bis-14RFC9189RFC9189RFC9189RFC9367RFC9367RFC9367RFC9367RFC7905RFC7905RFC7905RFC7905RFC7905RFC7905RFC7905RFC8442RFC8442RFC8442TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256" + +var _TLSCipherSuite_map = map[TLSCipherSuite]string{ + 0: _TLSCipherSuite_name[0:23], + 1: _TLSCipherSuite_name[23:30], + 2: _TLSCipherSuite_name[30:37], + 3: _TLSCipherSuite_name[37:52], + 4: _TLSCipherSuite_name[52:67], + 5: _TLSCipherSuite_name[67:82], + 6: _TLSCipherSuite_name[82:89], + 7: _TLSCipherSuite_name[89:96], + 8: _TLSCipherSuite_name[96:103], + 9: _TLSCipherSuite_name[103:110], + 10: _TLSCipherSuite_name[110:117], + 11: _TLSCipherSuite_name[117:124], + 12: _TLSCipherSuite_name[124:131], + 13: _TLSCipherSuite_name[131:138], + 14: _TLSCipherSuite_name[138:145], + 15: _TLSCipherSuite_name[145:152], + 16: _TLSCipherSuite_name[152:159], + 17: _TLSCipherSuite_name[159:166], + 18: _TLSCipherSuite_name[166:173], + 19: _TLSCipherSuite_name[173:180], + 20: _TLSCipherSuite_name[180:187], + 21: _TLSCipherSuite_name[187:194], + 22: _TLSCipherSuite_name[194:201], + 23: _TLSCipherSuite_name[201:216], + 24: _TLSCipherSuite_name[216:231], + 25: _TLSCipherSuite_name[231:238], + 26: _TLSCipherSuite_name[238:245], + 27: _TLSCipherSuite_name[245:252], + 30: _TLSCipherSuite_name[252:286], + 31: _TLSCipherSuite_name[286:293], + 32: _TLSCipherSuite_name[293:335], + 33: _TLSCipherSuite_name[335:369], + 34: _TLSCipherSuite_name[369:403], + 35: _TLSCipherSuite_name[403:410], + 36: _TLSCipherSuite_name[410:452], + 37: _TLSCipherSuite_name[452:486], + 38: _TLSCipherSuite_name[486:520], + 39: _TLSCipherSuite_name[520:554], + 40: _TLSCipherSuite_name[554:596], + 41: _TLSCipherSuite_name[596:630], + 42: _TLSCipherSuite_name[630:664], + 43: _TLSCipherSuite_name[664:706], + 44: _TLSCipherSuite_name[706:740], + 45: _TLSCipherSuite_name[740:747], + 46: _TLSCipherSuite_name[747:754], + 47: _TLSCipherSuite_name[754:761], + 48: _TLSCipherSuite_name[761:768], + 49: _TLSCipherSuite_name[768:775], + 50: _TLSCipherSuite_name[775:782], + 51: _TLSCipherSuite_name[782:789], + 52: _TLSCipherSuite_name[789:796], + 53: _TLSCipherSuite_name[796:803], + 54: _TLSCipherSuite_name[803:810], + 55: _TLSCipherSuite_name[810:817], + 56: _TLSCipherSuite_name[817:824], + 57: _TLSCipherSuite_name[824:831], + 58: _TLSCipherSuite_name[831:838], + 59: _TLSCipherSuite_name[838:845], + 60: _TLSCipherSuite_name[845:852], + 61: _TLSCipherSuite_name[852:859], + 62: _TLSCipherSuite_name[859:866], + 63: _TLSCipherSuite_name[866:873], + 64: _TLSCipherSuite_name[873:880], + 65: _TLSCipherSuite_name[880:887], + 66: _TLSCipherSuite_name[887:894], + 67: _TLSCipherSuite_name[894:901], + 68: _TLSCipherSuite_name[901:908], + 69: _TLSCipherSuite_name[908:915], + 70: _TLSCipherSuite_name[915:922], + 103: _TLSCipherSuite_name[922:929], + 104: _TLSCipherSuite_name[929:936], + 105: _TLSCipherSuite_name[936:943], + 106: _TLSCipherSuite_name[943:950], + 107: _TLSCipherSuite_name[950:957], + 108: _TLSCipherSuite_name[957:964], + 109: _TLSCipherSuite_name[964:971], + 132: _TLSCipherSuite_name[971:978], + 133: _TLSCipherSuite_name[978:985], + 134: _TLSCipherSuite_name[985:992], + 135: _TLSCipherSuite_name[992:999], + 136: _TLSCipherSuite_name[999:1006], + 137: _TLSCipherSuite_name[1006:1013], + 138: _TLSCipherSuite_name[1013:1055], + 139: _TLSCipherSuite_name[1055:1062], + 140: _TLSCipherSuite_name[1062:1069], + 141: _TLSCipherSuite_name[1069:1076], + 142: _TLSCipherSuite_name[1076:1091], + 143: _TLSCipherSuite_name[1091:1098], + 144: _TLSCipherSuite_name[1098:1105], + 145: _TLSCipherSuite_name[1105:1112], + 146: _TLSCipherSuite_name[1112:1127], + 147: _TLSCipherSuite_name[1127:1134], + 148: _TLSCipherSuite_name[1134:1141], + 149: _TLSCipherSuite_name[1141:1148], + 150: _TLSCipherSuite_name[1148:1155], + 151: _TLSCipherSuite_name[1155:1162], + 152: _TLSCipherSuite_name[1162:1169], + 153: _TLSCipherSuite_name[1169:1176], + 154: _TLSCipherSuite_name[1176:1183], + 155: _TLSCipherSuite_name[1183:1190], + 156: _TLSCipherSuite_name[1190:1197], + 157: _TLSCipherSuite_name[1197:1204], + 158: _TLSCipherSuite_name[1204:1211], + 159: _TLSCipherSuite_name[1211:1218], + 160: _TLSCipherSuite_name[1218:1225], + 161: _TLSCipherSuite_name[1225:1232], + 162: _TLSCipherSuite_name[1232:1239], + 163: _TLSCipherSuite_name[1239:1246], + 164: _TLSCipherSuite_name[1246:1253], + 165: _TLSCipherSuite_name[1253:1260], + 166: _TLSCipherSuite_name[1260:1267], + 167: _TLSCipherSuite_name[1267:1274], + 168: _TLSCipherSuite_name[1274:1281], + 169: _TLSCipherSuite_name[1281:1288], + 170: _TLSCipherSuite_name[1288:1295], + 171: _TLSCipherSuite_name[1295:1302], + 172: _TLSCipherSuite_name[1302:1309], + 173: _TLSCipherSuite_name[1309:1316], + 174: _TLSCipherSuite_name[1316:1323], + 175: _TLSCipherSuite_name[1323:1330], + 176: _TLSCipherSuite_name[1330:1364], + 177: _TLSCipherSuite_name[1364:1398], + 178: _TLSCipherSuite_name[1398:1405], + 179: _TLSCipherSuite_name[1405:1412], + 180: _TLSCipherSuite_name[1412:1419], + 181: _TLSCipherSuite_name[1419:1426], + 182: _TLSCipherSuite_name[1426:1433], + 183: _TLSCipherSuite_name[1433:1440], + 184: _TLSCipherSuite_name[1440:1447], + 185: _TLSCipherSuite_name[1447:1454], + 186: _TLSCipherSuite_name[1454:1461], + 187: _TLSCipherSuite_name[1461:1468], + 188: _TLSCipherSuite_name[1468:1475], + 189: _TLSCipherSuite_name[1475:1482], + 190: _TLSCipherSuite_name[1482:1489], + 191: _TLSCipherSuite_name[1489:1496], + 192: _TLSCipherSuite_name[1496:1503], + 193: _TLSCipherSuite_name[1503:1510], + 194: _TLSCipherSuite_name[1510:1517], + 195: _TLSCipherSuite_name[1517:1524], + 196: _TLSCipherSuite_name[1524:1531], + 197: _TLSCipherSuite_name[1531:1538], + 198: _TLSCipherSuite_name[1538:1545], + 199: _TLSCipherSuite_name[1545:1552], + 255: _TLSCipherSuite_name[1552:1585], + 4865: _TLSCipherSuite_name[1585:1611], + 4866: _TLSCipherSuite_name[1611:1637], + 4867: _TLSCipherSuite_name[1637:1663], + 4868: _TLSCipherSuite_name[1663:1689], + 4869: _TLSCipherSuite_name[1689:1738], + 4870: _TLSCipherSuite_name[1738:1768], + 4871: _TLSCipherSuite_name[1768:1789], + 22016: _TLSCipherSuite_name[1789:1806], + 49153: _TLSCipherSuite_name[1806:1813], + 49154: _TLSCipherSuite_name[1813:1828], + 49155: _TLSCipherSuite_name[1828:1835], + 49156: _TLSCipherSuite_name[1835:1842], + 49157: _TLSCipherSuite_name[1842:1849], + 49158: _TLSCipherSuite_name[1849:1883], + 49159: _TLSCipherSuite_name[1883:1925], + 49160: _TLSCipherSuite_name[1925:1932], + 49161: _TLSCipherSuite_name[1932:1939], + 49162: _TLSCipherSuite_name[1939:1946], + 49163: _TLSCipherSuite_name[1946:1953], + 49164: _TLSCipherSuite_name[1953:1968], + 49165: _TLSCipherSuite_name[1968:1975], + 49166: _TLSCipherSuite_name[1975:1982], + 49167: _TLSCipherSuite_name[1982:1989], + 49168: _TLSCipherSuite_name[1989:2023], + 49169: _TLSCipherSuite_name[2023:2065], + 49170: _TLSCipherSuite_name[2065:2072], + 49171: _TLSCipherSuite_name[2072:2079], + 49172: _TLSCipherSuite_name[2079:2086], + 49173: _TLSCipherSuite_name[2086:2093], + 49174: _TLSCipherSuite_name[2093:2108], + 49175: _TLSCipherSuite_name[2108:2115], + 49176: _TLSCipherSuite_name[2115:2122], + 49177: _TLSCipherSuite_name[2122:2129], + 49178: _TLSCipherSuite_name[2129:2136], + 49179: _TLSCipherSuite_name[2136:2143], + 49180: _TLSCipherSuite_name[2143:2150], + 49181: _TLSCipherSuite_name[2150:2157], + 49182: _TLSCipherSuite_name[2157:2164], + 49183: _TLSCipherSuite_name[2164:2171], + 49184: _TLSCipherSuite_name[2171:2178], + 49185: _TLSCipherSuite_name[2178:2185], + 49186: _TLSCipherSuite_name[2185:2192], + 49187: _TLSCipherSuite_name[2192:2199], + 49188: _TLSCipherSuite_name[2199:2206], + 49189: _TLSCipherSuite_name[2206:2213], + 49190: _TLSCipherSuite_name[2213:2220], + 49191: _TLSCipherSuite_name[2220:2227], + 49192: _TLSCipherSuite_name[2227:2234], + 49193: _TLSCipherSuite_name[2234:2241], + 49194: _TLSCipherSuite_name[2241:2248], + 49195: _TLSCipherSuite_name[2248:2255], + 49196: _TLSCipherSuite_name[2255:2262], + 49197: _TLSCipherSuite_name[2262:2269], + 49198: _TLSCipherSuite_name[2269:2276], + 49199: _TLSCipherSuite_name[2276:2283], + 49200: _TLSCipherSuite_name[2283:2290], + 49201: _TLSCipherSuite_name[2290:2297], + 49202: _TLSCipherSuite_name[2297:2304], + 49203: _TLSCipherSuite_name[2304:2346], + 49204: _TLSCipherSuite_name[2346:2353], + 49205: _TLSCipherSuite_name[2353:2360], + 49206: _TLSCipherSuite_name[2360:2367], + 49207: _TLSCipherSuite_name[2367:2374], + 49208: _TLSCipherSuite_name[2374:2381], + 49209: _TLSCipherSuite_name[2381:2415], + 49210: _TLSCipherSuite_name[2415:2449], + 49211: _TLSCipherSuite_name[2449:2483], + 49212: _TLSCipherSuite_name[2483:2490], + 49213: _TLSCipherSuite_name[2490:2497], + 49214: _TLSCipherSuite_name[2497:2504], + 49215: _TLSCipherSuite_name[2504:2511], + 49216: _TLSCipherSuite_name[2511:2518], + 49217: _TLSCipherSuite_name[2518:2525], + 49218: _TLSCipherSuite_name[2525:2532], + 49219: _TLSCipherSuite_name[2532:2539], + 49220: _TLSCipherSuite_name[2539:2546], + 49221: _TLSCipherSuite_name[2546:2553], + 49222: _TLSCipherSuite_name[2553:2560], + 49223: _TLSCipherSuite_name[2560:2567], + 49224: _TLSCipherSuite_name[2567:2574], + 49225: _TLSCipherSuite_name[2574:2581], + 49226: _TLSCipherSuite_name[2581:2588], + 49227: _TLSCipherSuite_name[2588:2595], + 49228: _TLSCipherSuite_name[2595:2602], + 49229: _TLSCipherSuite_name[2602:2609], + 49230: _TLSCipherSuite_name[2609:2616], + 49231: _TLSCipherSuite_name[2616:2623], + 49232: _TLSCipherSuite_name[2623:2630], + 49233: _TLSCipherSuite_name[2630:2637], + 49234: _TLSCipherSuite_name[2637:2644], + 49235: _TLSCipherSuite_name[2644:2651], + 49236: _TLSCipherSuite_name[2651:2658], + 49237: _TLSCipherSuite_name[2658:2665], + 49238: _TLSCipherSuite_name[2665:2672], + 49239: _TLSCipherSuite_name[2672:2679], + 49240: _TLSCipherSuite_name[2679:2686], + 49241: _TLSCipherSuite_name[2686:2693], + 49242: _TLSCipherSuite_name[2693:2700], + 49243: _TLSCipherSuite_name[2700:2707], + 49244: _TLSCipherSuite_name[2707:2714], + 49245: _TLSCipherSuite_name[2714:2721], + 49246: _TLSCipherSuite_name[2721:2728], + 49247: _TLSCipherSuite_name[2728:2735], + 49248: _TLSCipherSuite_name[2735:2742], + 49249: _TLSCipherSuite_name[2742:2749], + 49250: _TLSCipherSuite_name[2749:2756], + 49251: _TLSCipherSuite_name[2756:2763], + 49252: _TLSCipherSuite_name[2763:2770], + 49253: _TLSCipherSuite_name[2770:2777], + 49254: _TLSCipherSuite_name[2777:2784], + 49255: _TLSCipherSuite_name[2784:2791], + 49256: _TLSCipherSuite_name[2791:2798], + 49257: _TLSCipherSuite_name[2798:2805], + 49258: _TLSCipherSuite_name[2805:2812], + 49259: _TLSCipherSuite_name[2812:2819], + 49260: _TLSCipherSuite_name[2819:2826], + 49261: _TLSCipherSuite_name[2826:2833], + 49262: _TLSCipherSuite_name[2833:2840], + 49263: _TLSCipherSuite_name[2840:2847], + 49264: _TLSCipherSuite_name[2847:2854], + 49265: _TLSCipherSuite_name[2854:2861], + 49266: _TLSCipherSuite_name[2861:2868], + 49267: _TLSCipherSuite_name[2868:2875], + 49268: _TLSCipherSuite_name[2875:2882], + 49269: _TLSCipherSuite_name[2882:2889], + 49270: _TLSCipherSuite_name[2889:2896], + 49271: _TLSCipherSuite_name[2896:2903], + 49272: _TLSCipherSuite_name[2903:2910], + 49273: _TLSCipherSuite_name[2910:2917], + 49274: _TLSCipherSuite_name[2917:2924], + 49275: _TLSCipherSuite_name[2924:2931], + 49276: _TLSCipherSuite_name[2931:2938], + 49277: _TLSCipherSuite_name[2938:2945], + 49278: _TLSCipherSuite_name[2945:2952], + 49279: _TLSCipherSuite_name[2952:2959], + 49280: _TLSCipherSuite_name[2959:2966], + 49281: _TLSCipherSuite_name[2966:2973], + 49282: _TLSCipherSuite_name[2973:2980], + 49283: _TLSCipherSuite_name[2980:2987], + 49284: _TLSCipherSuite_name[2987:2994], + 49285: _TLSCipherSuite_name[2994:3001], + 49286: _TLSCipherSuite_name[3001:3008], + 49287: _TLSCipherSuite_name[3008:3015], + 49288: _TLSCipherSuite_name[3015:3022], + 49289: _TLSCipherSuite_name[3022:3029], + 49290: _TLSCipherSuite_name[3029:3036], + 49291: _TLSCipherSuite_name[3036:3043], + 49292: _TLSCipherSuite_name[3043:3050], + 49293: _TLSCipherSuite_name[3050:3057], + 49294: _TLSCipherSuite_name[3057:3064], + 49295: _TLSCipherSuite_name[3064:3071], + 49296: _TLSCipherSuite_name[3071:3078], + 49297: _TLSCipherSuite_name[3078:3085], + 49298: _TLSCipherSuite_name[3085:3092], + 49299: _TLSCipherSuite_name[3092:3099], + 49300: _TLSCipherSuite_name[3099:3106], + 49301: _TLSCipherSuite_name[3106:3113], + 49302: _TLSCipherSuite_name[3113:3120], + 49303: _TLSCipherSuite_name[3120:3127], + 49304: _TLSCipherSuite_name[3127:3134], + 49305: _TLSCipherSuite_name[3134:3141], + 49306: _TLSCipherSuite_name[3141:3148], + 49307: _TLSCipherSuite_name[3148:3155], + 49308: _TLSCipherSuite_name[3155:3162], + 49309: _TLSCipherSuite_name[3162:3169], + 49310: _TLSCipherSuite_name[3169:3176], + 49311: _TLSCipherSuite_name[3176:3183], + 49312: _TLSCipherSuite_name[3183:3190], + 49313: _TLSCipherSuite_name[3190:3197], + 49314: _TLSCipherSuite_name[3197:3204], + 49315: _TLSCipherSuite_name[3204:3211], + 49316: _TLSCipherSuite_name[3211:3218], + 49317: _TLSCipherSuite_name[3218:3225], + 49318: _TLSCipherSuite_name[3225:3232], + 49319: _TLSCipherSuite_name[3232:3239], + 49320: _TLSCipherSuite_name[3239:3246], + 49321: _TLSCipherSuite_name[3246:3253], + 49322: _TLSCipherSuite_name[3253:3260], + 49323: _TLSCipherSuite_name[3260:3267], + 49324: _TLSCipherSuite_name[3267:3274], + 49325: _TLSCipherSuite_name[3274:3281], + 49326: _TLSCipherSuite_name[3281:3288], + 49327: _TLSCipherSuite_name[3288:3295], + 49328: _TLSCipherSuite_name[3295:3302], + 49329: _TLSCipherSuite_name[3302:3309], + 49330: _TLSCipherSuite_name[3309:3316], + 49331: _TLSCipherSuite_name[3316:3323], + 49332: _TLSCipherSuite_name[3323:3357], + 49333: _TLSCipherSuite_name[3357:3391], + 49408: _TLSCipherSuite_name[3391:3398], + 49409: _TLSCipherSuite_name[3398:3405], + 49410: _TLSCipherSuite_name[3405:3412], + 49411: _TLSCipherSuite_name[3412:3419], + 49412: _TLSCipherSuite_name[3419:3426], + 49413: _TLSCipherSuite_name[3426:3433], + 49414: _TLSCipherSuite_name[3433:3440], + 52392: _TLSCipherSuite_name[3440:3447], + 52393: _TLSCipherSuite_name[3447:3454], + 52394: _TLSCipherSuite_name[3454:3461], + 52395: _TLSCipherSuite_name[3461:3468], + 52396: _TLSCipherSuite_name[3468:3475], + 52397: _TLSCipherSuite_name[3475:3482], + 52398: _TLSCipherSuite_name[3482:3489], + 53249: _TLSCipherSuite_name[3489:3496], + 53250: _TLSCipherSuite_name[3496:3503], + 53251: _TLSCipherSuite_name[3503:3510], + 53253: _TLSCipherSuite_name[3510:3547], +} + +func (i TLSCipherSuite) String() string { + if str, ok := _TLSCipherSuite_map[i]; ok { + return str + } + return "TLSCipherSuite(" + strconv.FormatInt(int64(i), 10) + ")" +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[PKCS1WithSHA256-1025] + _ = x[PKCS1WithSHA384-1281] + _ = x[PKCS1WithSHA512-1537] + _ = x[PSSWithSHA256-2052] + _ = x[PSSWithSHA384-2053] + _ = x[PSSWithSHA512-2054] + _ = x[ECDSAWithP256AndSHA256-1027] + _ = x[ECDSAWithP384AndSHA384-1283] + _ = x[ECDSAWithP521AndSHA512-1539] + _ = x[Ed25519-2055] + _ = x[PKCS1WithSHA1-513] + _ = x[ECDSAWithSHA1-515] +} + +const ( + _TLSSignatureScheme_name_0 = "PKCS1WithSHA1" + _TLSSignatureScheme_name_1 = "ECDSAWithSHA1" + _TLSSignatureScheme_name_2 = "PKCS1WithSHA256" + _TLSSignatureScheme_name_3 = "ECDSAWithP256AndSHA256" + _TLSSignatureScheme_name_4 = "PKCS1WithSHA384" + _TLSSignatureScheme_name_5 = "ECDSAWithP384AndSHA384" + _TLSSignatureScheme_name_6 = "PKCS1WithSHA512" + _TLSSignatureScheme_name_7 = "ECDSAWithP521AndSHA512" + _TLSSignatureScheme_name_8 = "PSSWithSHA256PSSWithSHA384PSSWithSHA512Ed25519" +) + +var ( + _TLSSignatureScheme_index_8 = [...]uint8{0, 13, 26, 39, 46} +) + +func (i TLSSignatureScheme) String() string { + switch { + case i == 513: + return _TLSSignatureScheme_name_0 + case i == 515: + return _TLSSignatureScheme_name_1 + case i == 1025: + return _TLSSignatureScheme_name_2 + case i == 1027: + return _TLSSignatureScheme_name_3 + case i == 1281: + return _TLSSignatureScheme_name_4 + case i == 1283: + return _TLSSignatureScheme_name_5 + case i == 1537: + return _TLSSignatureScheme_name_6 + case i == 1539: + return _TLSSignatureScheme_name_7 + case 2052 <= i && i <= 2055: + i -= 2052 + return _TLSSignatureScheme_name_8[_TLSSignatureScheme_index_8[i]:_TLSSignatureScheme_index_8[i+1]] + default: + return "TLSSignatureScheme(" + strconv.FormatInt(int64(i), 10) + ")" + } +} diff --git a/tls_test.go b/tls_test.go new file mode 100644 index 0000000..6224101 --- /dev/null +++ b/tls_test.go @@ -0,0 +1,91 @@ +package dpi + +import ( + "encoding/hex" + "strings" + "testing" +) + +func TestDecodeTLSClientHello(t *testing.T) { + // Taken from a random PCAP on the internet + clientHelloBytes, err := testDecodeHexString(` + 1603 0100 c801 0000 c403 03ec 12dd + 1764 a439 fd7e 8c85 46b8 4d1e a06e b3d7 + a051 f03c b817 470d 4c54 c5df 7200 001c + eaea c02b c02f c02c c030 cca9 cca8 c013 + c014 009c 009d 002f 0035 000a 0100 007f + dada 0000 ff01 0001 0000 0000 1600 1400 + 0011 7777 772e 7769 6b69 7065 6469 612e + 6f72 6700 1700 0000 2300 0000 0d00 1400 + 1204 0308 0404 0105 0308 0505 0108 0606 + 0102 0100 0500 0501 0000 0000 0012 0000 + 0010 000e 000c 0268 3208 6874 7470 2f31 + 2e31 7550 0000 000b 0002 0100 000a 000a + 0008 1a1a 001d 0017 0018 1a1a 0001 00 + `) + if err != nil { + t.Fatalf("failed to decode test ClientHello: %s", err) + } + + // Taken from RFC8443 TLS 1.3 traces example: + rfc8443ClientHelloBytes, err := testDecodeHexString(` + 16 03 01 00 c4 01 00 00 c0 03 03 cb + 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 + ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 + 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 + 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 + 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d + e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d + 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e + 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 + 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 + `) + if err != nil { + t.Fatalf("failed to decode test ClientHello: %s", err) + } + + t.Run("Client Hello", func(t *testing.T) { + hello, err := DecodeTLSClientHelloHandshake(clientHelloBytes) + if err != nil { + t.Fatal(err) + return + } + hello.Raw = nil + t.Logf("%#v", hello) + }) + + t.Run("TLS 1.3 Client Hello", func(t *testing.T) { + hello, err := DecodeTLSClientHelloHandshake(rfc8443ClientHelloBytes) + if err != nil { + t.Fatal(err) + return + } + hello.Raw = nil + t.Logf("%#v", hello) + }) + +} + +func TestDecodeTLSServerHello(t *testing.T) { + serverHelloBytes, err := hex.DecodeString("02000030030300000000000000000000000000000000000000000000000000000000000000000000000000080005000000050000") + if err != nil { + t.Fatalf("failed to decode test ServerHello: %s", err) + } + + t.Run("Server Hello", func(t *testing.T) { + hello, err := DecodeTLSServerHello(serverHelloBytes) + if err != nil { + t.Fatal(err) + return + } + t.Logf("%#+v", hello) + }) +} + +func testDecodeHexString(s string) ([]byte, error) { + s = strings.TrimSpace(s) + s = strings.ReplaceAll(s, " ", "") + s = strings.ReplaceAll(s, "\n", "") + s = strings.ReplaceAll(s, "\t", "") + return hex.DecodeString(s) +}