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 }