Refactoring
Refactored Protocol.Name -> Protocol.Type; added Encapsulation field Refactored TLS parsing; added support for ALPN
This commit is contained in:
@@ -41,5 +41,5 @@ func main() {
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
fmt.Printf("Protocol at address %q is %s version %s (confidence %g%%)\n", address, protocol.Name, protocol.Version, confidence*100)
|
||||
fmt.Printf("Protocol at address %q is %s version %s (confidence %g%%)\n", address, protocol.Type, protocol.Version, confidence*100)
|
||||
}
|
||||
|
@@ -42,11 +42,11 @@ func main() {
|
||||
if p == nil {
|
||||
return errors.New("no protocol detected")
|
||||
}
|
||||
if !accept[p.Name] {
|
||||
return fmt.Errorf("protocol %s is not accepted", p.Name)
|
||||
if !accept[p.Type] {
|
||||
return fmt.Errorf("protocol %s is not accepted", p.Type)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Accepting protocol %s version %s initiated by %s\n",
|
||||
p.Name, p.Version, dir)
|
||||
p.Type, p.Version, dir)
|
||||
return nil
|
||||
})
|
||||
defer func() { _ = c.Close() }()
|
||||
|
@@ -81,7 +81,7 @@ func proxy(client net.Conn, target string) {
|
||||
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)
|
||||
result.Protocol.Type, result.Protocol.Version, result.Direction)
|
||||
}
|
||||
|
||||
// Wait for the multiplexing to finish.
|
||||
|
@@ -31,7 +31,7 @@ func detectHTTPRequest(dir Direction, data []byte, srcPort, dstPort int) (proto
|
||||
)
|
||||
if request, err := http.ReadRequest(r); err == nil {
|
||||
return &Protocol{
|
||||
Name: ProtocolHTTP,
|
||||
Type: TypeHTTP,
|
||||
Version: Version{
|
||||
Major: request.ProtoMajor,
|
||||
Minor: request.ProtoMinor,
|
||||
@@ -66,7 +66,7 @@ func detectHTTPRequest(dir Direction, data []byte, srcPort, dstPort int) (proto
|
||||
_, _ = fmt.Sscanf(string(part[2]), "HTTP/%d.%d ", &version.Major, &version.Minor)
|
||||
|
||||
return &Protocol{
|
||||
Name: ProtocolHTTP,
|
||||
Type: TypeHTTP,
|
||||
Version: version,
|
||||
}, confidence + .75
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func detectHTTPResponse(dir Direction, data []byte, srcPort, dstPort int) (proto
|
||||
)
|
||||
if response, err := http.ReadResponse(r, nil); err == nil {
|
||||
return &Protocol{
|
||||
Name: ProtocolHTTP,
|
||||
Type: TypeHTTP,
|
||||
Version: Version{
|
||||
Major: response.ProtoMajor,
|
||||
Minor: response.ProtoMinor,
|
||||
@@ -110,7 +110,7 @@ func detectHTTPResponse(dir Direction, data []byte, srcPort, dstPort int) (proto
|
||||
_, _ = fmt.Sscanf(string(data), "HTTP/%d.%d ", &version.Major, &version.Minor)
|
||||
|
||||
return &Protocol{
|
||||
Name: ProtocolHTTP,
|
||||
Type: TypeHTTP,
|
||||
Version: version,
|
||||
}, confidence + .75
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ func TestDetectHTTPRequest(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: http10Request,
|
||||
DstPort: 80,
|
||||
WantProto: ProtocolHTTP,
|
||||
WantType: TypeHTTP,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -30,7 +30,7 @@ func TestDetectHTTPRequest(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: getRequest,
|
||||
DstPort: 80,
|
||||
WantProto: ProtocolHTTP,
|
||||
WantType: TypeHTTP,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -81,21 +81,21 @@ func TestDetectHTTPResponse(t *testing.T) {
|
||||
Direction: Server,
|
||||
Data: http10Response,
|
||||
SrcPort: 80,
|
||||
WantProto: ProtocolHTTP,
|
||||
WantType: TypeHTTP,
|
||||
},
|
||||
{
|
||||
Name: "HTTP/1.1 200",
|
||||
Direction: Server,
|
||||
Data: responseOK,
|
||||
SrcPort: 80,
|
||||
WantProto: ProtocolHTTP,
|
||||
WantType: TypeHTTP,
|
||||
},
|
||||
{
|
||||
Name: "HTTP/1.1 404",
|
||||
Direction: Server,
|
||||
Data: responseNotFound,
|
||||
SrcPort: 80,
|
||||
WantProto: ProtocolHTTP,
|
||||
WantType: TypeHTTP,
|
||||
},
|
||||
{
|
||||
Name: "Invalid HTTP/1.1 GET",
|
||||
|
@@ -32,7 +32,7 @@ func detectMQTT(dir Direction, data []byte, srcPort, dstPort int) (proto *Protoc
|
||||
|
||||
// We are reasonabily sure this is MQTT now.
|
||||
proto = &Protocol{
|
||||
Name: ProtocolMQTT,
|
||||
Type: TypeMQTT,
|
||||
}
|
||||
confidence = 0.5
|
||||
|
||||
|
@@ -53,7 +53,7 @@ func TestDetectMQTT(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: validSimplePacket,
|
||||
DstPort: 1883,
|
||||
WantProto: ProtocolMQTT,
|
||||
WantType: TypeMQTT,
|
||||
WantConfidence: .99,
|
||||
},
|
||||
{
|
||||
@@ -61,7 +61,7 @@ func TestDetectMQTT(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: validFullPacket,
|
||||
DstPort: 1883,
|
||||
WantProto: ProtocolMQTT,
|
||||
WantType: TypeMQTT,
|
||||
WantConfidence: .99,
|
||||
},
|
||||
{
|
||||
@@ -69,7 +69,7 @@ func TestDetectMQTT(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: partialPacket,
|
||||
DstPort: 1883,
|
||||
WantProto: ProtocolMQTT,
|
||||
WantType: TypeMQTT,
|
||||
WantConfidence: .5,
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@ func TestDetectMQTT(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: trailingGarbagePacket,
|
||||
DstPort: 1883,
|
||||
WantProto: ProtocolMQTT,
|
||||
WantType: TypeMQTT,
|
||||
WantConfidence: .75,
|
||||
},
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ func detectMySQL(dir Direction, data []byte, srcPort, dstPort int) (proto *Proto
|
||||
_, _ = fmt.Sscanf(string(data[1:serverVersionEndPos]), "%d.%d.%d-%s", &version.Major, &version.Minor, &version.Patch, &version.Extra)
|
||||
|
||||
return &Protocol{
|
||||
Name: ProtocolMySQL,
|
||||
Type: TypeMySQL,
|
||||
Version: version,
|
||||
}, confidence + .75
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@ func TestDetectMySQL(t *testing.T) {
|
||||
Direction: Server,
|
||||
Data: mysql8Banner,
|
||||
SrcPort: 3306,
|
||||
WantProto: ProtocolMySQL,
|
||||
WantType: TypeMySQL,
|
||||
WantConfidence: .85,
|
||||
},
|
||||
{
|
||||
@@ -51,7 +51,7 @@ func TestDetectMySQL(t *testing.T) {
|
||||
Direction: Server,
|
||||
Data: mariaDBBanner,
|
||||
SrcPort: 3306,
|
||||
WantProto: ProtocolMySQL,
|
||||
WantType: TypeMySQL,
|
||||
WantConfidence: .85,
|
||||
},
|
||||
{
|
||||
|
@@ -40,7 +40,7 @@ func detectPostgreSQLClient(dir Direction, data []byte, srcPort, dstPort int) (p
|
||||
minor := int(binary.BigEndian.Uint16(data[6:]))
|
||||
if major == 2 || major == 3 {
|
||||
return &Protocol{
|
||||
Name: ProtocolPostgreSQL,
|
||||
Type: TypePostgreSQL,
|
||||
Version: Version{
|
||||
Major: major,
|
||||
Minor: minor,
|
||||
@@ -70,7 +70,7 @@ func detectPostgreSQLServer(dir Direction, data []byte, srcPort, dstPort int) (p
|
||||
'Z', // ReadyForQuery
|
||||
'E', // ErrorResponse
|
||||
'N': // NoticeResponse
|
||||
return &Protocol{Name: ProtocolPostgreSQL}, confidence + .65
|
||||
return &Protocol{Type: TypePostgreSQL}, confidence + .65
|
||||
|
||||
default:
|
||||
return nil, 0
|
||||
|
@@ -36,7 +36,7 @@ func TestDetectPostgreSQLClient(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: pgClientStartup,
|
||||
DstPort: 5432,
|
||||
WantProto: ProtocolPostgreSQL,
|
||||
WantType: TypePostgreSQL,
|
||||
WantConfidence: .85,
|
||||
},
|
||||
{
|
||||
@@ -77,7 +77,7 @@ func TestDetectPostgreSQLServer(t *testing.T) {
|
||||
Direction: Server,
|
||||
Data: pgServerAuthOK,
|
||||
DstPort: 5432,
|
||||
WantProto: ProtocolPostgreSQL,
|
||||
WantType: TypePostgreSQL,
|
||||
WantConfidence: .65,
|
||||
},
|
||||
{
|
||||
@@ -95,9 +95,9 @@ func TestDetectPostgreSQLServer(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
t.Logf("detected %s version %s confidence %g%%", p.Name, p.Version, c*100)
|
||||
if p.Name != ProtocolPostgreSQL {
|
||||
t.Fatalf("expected postgres protocol, got %s", p.Name)
|
||||
t.Logf("detected %s version %s confidence %g%%", p.Type, p.Version, c*100)
|
||||
if p.Type != TypePostgreSQL {
|
||||
t.Fatalf("expected postgres protocol, got %s", p.Type)
|
||||
return
|
||||
}
|
||||
})
|
||||
@@ -108,9 +108,9 @@ func TestDetectPostgreSQLServer(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
t.Logf("detected %s version %s confidence %g%%", p.Name, p.Version, c*100)
|
||||
if p.Name != ProtocolPostgreSQL {
|
||||
t.Fatalf("expected postgres protocol, got %s", p.Name)
|
||||
t.Logf("detected %s version %s confidence %g%%", p.Type, p.Version, c*100)
|
||||
if p.Type != TypePostgreSQL {
|
||||
t.Fatalf("expected postgres protocol, got %s", p.Type)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
@@ -58,7 +58,7 @@ func detectSSH(dir Direction, data []byte, srcPort, dstPort int) (proto *Protoco
|
||||
}
|
||||
}
|
||||
return &Protocol{
|
||||
Name: ProtocolSSH,
|
||||
Type: TypeSSH,
|
||||
Version: Version{
|
||||
Major: 2,
|
||||
Minor: 0,
|
||||
@@ -78,7 +78,7 @@ func detectSSH(dir Direction, data []byte, srcPort, dstPort int) (proto *Protoco
|
||||
}
|
||||
}
|
||||
return &Protocol{
|
||||
Name: ProtocolSSH,
|
||||
Type: TypeSSH,
|
||||
Version: Version{
|
||||
Major: 1,
|
||||
Minor: 99,
|
||||
|
@@ -36,7 +36,7 @@ func TestDetectSSH(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: openSSHBanner,
|
||||
DstPort: 22,
|
||||
WantProto: ProtocolSSH,
|
||||
WantType: TypeSSH,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -44,7 +44,7 @@ func TestDetectSSH(t *testing.T) {
|
||||
Direction: Server,
|
||||
Data: openSSHBanner,
|
||||
SrcPort: 22,
|
||||
WantProto: ProtocolSSH,
|
||||
WantType: TypeSSH,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -52,7 +52,7 @@ func TestDetectSSH(t *testing.T) {
|
||||
Direction: Server,
|
||||
Data: preBannerSSH,
|
||||
SrcPort: 22,
|
||||
WantProto: ProtocolSSH,
|
||||
WantType: TypeSSH,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -60,7 +60,7 @@ func TestDetectSSH(t *testing.T) {
|
||||
Direction: Server,
|
||||
Data: dropbearBanner,
|
||||
SrcPort: 22,
|
||||
WantProto: ProtocolSSH,
|
||||
WantType: TypeSSH,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
|
@@ -1,6 +1,9 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
|
||||
"git.maze.io/go/dpi"
|
||||
@@ -11,12 +14,18 @@ func init() {
|
||||
}
|
||||
|
||||
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
|
||||
Register(Both, "\x16\x03\x00", detectTLS) // SSL 3.0
|
||||
Register(Both, "\x16\x03\x01", detectTLS) // TLS 1.0
|
||||
Register(Both, "\x16\x03\x02", detectTLS) // TLS 1.1
|
||||
Register(Both, "\x16\x03\x03", detectTLS) // TLS 1.2
|
||||
}
|
||||
|
||||
const (
|
||||
tlsRecordTypeHandshake uint8 = 22
|
||||
tlsTypeClientHello uint8 = 1
|
||||
tlsTypeServerHello uint8 = 2
|
||||
)
|
||||
|
||||
func detectTLS(dir Direction, data []byte, _, _ int) (proto *Protocol, confidence float64) {
|
||||
stream := cryptobyte.String(data)
|
||||
|
||||
@@ -44,27 +53,53 @@ func detectTLS(dir Direction, data []byte, _, _ int) (proto *Protocol, confidenc
|
||||
// Initial confidence
|
||||
confidence = 0.5
|
||||
|
||||
// Detected SSL/TLS version
|
||||
var version dpi.TLSVersion
|
||||
// Detected SSL/TLS tlsVersion
|
||||
var tlsVersion 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
|
||||
confidence += .45
|
||||
}
|
||||
}
|
||||
if tlsVersion == 0 {
|
||||
if record, err := dpi.DecodeTLSRecord(data); err == nil && record.Type == tlsRecordTypeHandshake && len(record.Data) > 1 {
|
||||
tlsVersion = record.Version
|
||||
confidence += .15
|
||||
|
||||
// Attempt to decode the full TLS Server Hello handshake
|
||||
if version == 0 {
|
||||
if hello, err := dpi.DecodeTLSServerHello(data); err == nil {
|
||||
version = hello.Version
|
||||
confidence += .45
|
||||
switch record.Data[0] {
|
||||
case tlsTypeClientHello: // TLS ClientHello
|
||||
if hello, err := dpi.DecodeTLSClientHello(record.Data); err == nil {
|
||||
tlsVersion = hello.Version
|
||||
confidence += .3
|
||||
|
||||
slices.SortStableFunc(hello.ALPNProtocols, func(a, b string) int {
|
||||
return strings.Compare(b, a)
|
||||
})
|
||||
|
||||
for _, id := range hello.ALPNProtocols {
|
||||
if proto = ALPNProtocol[id]; proto != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case tlsTypeServerHello: // TLS ServerHello
|
||||
if hello, err := dpi.DecodeTLSServerHello(record.Data); err == nil {
|
||||
tlsVersion = hello.Version
|
||||
confidence += .3
|
||||
|
||||
slices.SortStableFunc(hello.ALPNProtocols, func(a, b string) int {
|
||||
return strings.Compare(b, a)
|
||||
})
|
||||
|
||||
for _, id := range hello.ALPNProtocols {
|
||||
if proto = ALPNProtocol[id]; proto != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to decode at least the handshake protocol and version.
|
||||
if version == 0 && !Strict {
|
||||
if tlsVersion == 0 && !Strict {
|
||||
var handshakeType uint8
|
||||
if stream.ReadUint8(&handshakeType) && (handshakeType == 1 || handshakeType == 2) {
|
||||
var (
|
||||
@@ -72,33 +107,68 @@ func detectTLS(dir Direction, data []byte, _, _ int) (proto *Protocol, confidenc
|
||||
versionWord uint16
|
||||
)
|
||||
if stream.ReadUint24(&length) && stream.ReadUint16(&versionWord) {
|
||||
version = dpi.TLSVersion(versionWord)
|
||||
tlsVersion = dpi.TLSVersion(versionWord)
|
||||
confidence += .25
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to the version in the TLS record header, this is less accurate
|
||||
if version == 0 && !Strict {
|
||||
version = dpi.TLSVersion(header.Version)
|
||||
if tlsVersion == 0 && !Strict {
|
||||
tlsVersion = dpi.TLSVersion(header.Version)
|
||||
}
|
||||
|
||||
// We're "multi protocol", in that SSL is its own protocol
|
||||
if version == dpi.VersionSSL30 {
|
||||
if tlsVersion == dpi.VersionSSL30 {
|
||||
return &Protocol{
|
||||
Name: ProtocolSSL,
|
||||
Type: TypeSSL,
|
||||
Version: Version{Major: 3, Minor: 0, Patch: -1},
|
||||
}, confidence
|
||||
} else if version >= dpi.VersionTLS10 && version <= dpi.VersionTLS13 {
|
||||
} else if tlsVersion >= dpi.VersionTLS10 && tlsVersion <= dpi.VersionTLS13 {
|
||||
return &Protocol{
|
||||
Name: ProtocolTLS,
|
||||
Version: Version{Major: 1, Minor: int(uint8(version) - 1), Patch: -1},
|
||||
Type: TypeTLS,
|
||||
Version: Version{Major: 1, Minor: int(uint8(tlsVersion) - 1), Patch: -1},
|
||||
}, confidence
|
||||
} else if version >= dpi.VersionTLS13Draft && version <= dpi.VersionTLS13Draft23 {
|
||||
} else if tlsVersion >= dpi.VersionTLS13Draft && tlsVersion <= dpi.VersionTLS13Draft23 {
|
||||
return &Protocol{
|
||||
Name: ProtocolTLS,
|
||||
Type: TypeTLS,
|
||||
Version: Version{Major: 1, Minor: 3, Patch: -1},
|
||||
}, confidence
|
||||
}
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
// ALPNProtocol is a map of TLS Application-Layer Protocol Negotiation (ALPN) Protocol identifier to [Protocol].
|
||||
//
|
||||
// See https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids\
|
||||
var ALPNProtocol = map[string]*Protocol{
|
||||
"acme-tls/1": {Type: TypeACME, Encapsulation: TypeTLS, Version: Version{Major: 1}}, // ACME-TLS/1
|
||||
"co": {Type: TypeCoAP, Encapsulation: TypeTLS}, // CoAP (over DTLS)
|
||||
"coap": {Type: TypeCoAP, Encapsulation: TypeTLS}, // CoAP (over TLS)
|
||||
"c-webrtc": {Type: TypeWebRTC, Encapsulation: TypeTLS}, // Confidential WebRTC Media and Data
|
||||
"dot": {Type: TypeDNS, Encapsulation: TypeTLS}, // DNS-over-TLS
|
||||
"ftp": {Type: TypeFTP, Encapsulation: TypeTLS}, // FTP
|
||||
"http/0.9": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 0, Minor: 9, Patch: -1}}, // HTTP/0.9
|
||||
"http/1.0": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 0, Patch: -1}}, // HTTP/1.0
|
||||
"http/1.1": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 1, Patch: -1}}, // HTTP/1.1
|
||||
"h2": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 2, Minor: -1, Patch: -1}}, // HTTP/2 (over TLS)
|
||||
"h2c": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 2, Minor: -1, Patch: -1}}, // HTTP/2 (over TCP)
|
||||
"h3": {Type: TypeHTTP, Encapsulation: TypeTLS, Version: Version{Major: 3, Minor: -1, Patch: -1}}, // HTTP/3
|
||||
"irc": {Type: TypeIRC, Encapsulation: TypeTLS}, // IRC
|
||||
"imap": {Type: TypeIMAP, Encapsulation: TypeTLS}, // IMAP
|
||||
"managesieve": {Type: TypeManageSieve, Encapsulation: TypeTLS}, // ManageSieve
|
||||
"mqtt": {Type: TypeMQTT, Encapsulation: TypeTLS}, // MQTT
|
||||
"nntp": {Type: TypeNNTP, Encapsulation: TypeTLS}, // NNTP (reading)
|
||||
"nnsp": {Type: TypeNNTP, Encapsulation: TypeTLS}, // NNTP (transit)
|
||||
"postgresql": {Type: TypePostgreSQL, Encapsulation: TypeTLS}, // PostgreSQL
|
||||
"pop3": {Type: TypePOP3, Encapsulation: TypeTLS}, // POP3
|
||||
"radius/1.0": {Type: TypeRADIUS, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 0, Patch: -1}}, // RADIUS/1.0
|
||||
"radius/1.1": {Type: TypeRADIUS, Encapsulation: TypeTLS, Version: Version{Major: 1, Minor: 1, Patch: -1}}, // RADIUS/1.1
|
||||
"smb": {Type: TypeSMB, Encapsulation: TypeTLS, Version: Version{Major: 2, Minor: -1, Patch: -1}}, // SMB2
|
||||
"stun.nat-discovery": {Type: TypeSTUN, Encapsulation: TypeTLS}, // NAT discovery using Session Traversal Utilities for NAT (STUN)
|
||||
"stun.turn": {Type: TypeSTUN, Encapsulation: TypeTLS}, // Traversal Using Relays around NAT (TURN)
|
||||
"sunrpc": {Type: TypeSunRPC, Encapsulation: TypeTLS}, // SunRPC
|
||||
"webrtc": {Type: TypeWebRTC, Encapsulation: TypeTLS}, // WebRTC Media and Data
|
||||
"xmpp-client": {Type: TypeXMPP, Encapsulation: TypeTLS}, // XMPP jabber:client namespace
|
||||
"xmpp-server": {Type: TypeXMPP, Encapsulation: TypeTLS}, // XMPP jabber:server namespace
|
||||
}
|
||||
|
@@ -76,6 +76,45 @@ func TestDetectTLS(t *testing.T) {
|
||||
0x03, 0x02, // Client Version: TLS 1.1 (Major=3, Minor=2)
|
||||
}
|
||||
|
||||
// A valid TLS 1.1 ServerHello
|
||||
tls11ServerHello := []byte{
|
||||
// --- Record Layer (5 bytes) ---
|
||||
0x16, // Content Type: Handshake (22)
|
||||
0x03, 0x02, // Version: TLS 1.1 (for compatibility in a 1.3 hello)
|
||||
0x00, 0x40, // Length of the handshake message below (64 bytes)
|
||||
|
||||
// --- Handshake Protocol: ServerHello (64 bytes) ---
|
||||
0x02, // Handshake Type: ServerHello (2)
|
||||
0x00, 0x00, 0x3c, // Length of the rest of the message (60 bytes)
|
||||
0x03, 0x02, // Server Version: TLS 1.1 (Major=3, Minor=2)
|
||||
|
||||
// Random (32 bytes)
|
||||
0xb7, 0xa8, 0xdf, 0xd5, 0x17, 0xb1, 0x50, 0xb4,
|
||||
0x28, 0xb7, 0xf6, 0xf3, 0xb9, 0x83, 0xcf, 0x9f,
|
||||
0x31, 0x55, 0x79, 0x1f, 0x3b, 0x07, 0x6d, 0x17,
|
||||
0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00,
|
||||
|
||||
// Session ID
|
||||
0x00, // Session ID Length: 0 (new session)
|
||||
|
||||
0xc0, 0x09, // Cipher Suite
|
||||
0x00, // Compression Method
|
||||
|
||||
// --- Extensions (20 bytes) ---
|
||||
0x00, 0x14, // Extensions Length: 20 bytes
|
||||
0xff, 0x01, // Extension Type: renegotiation_info
|
||||
0x00, 0x01, // Extension Length: 1 byte
|
||||
0x00, // Renegotiation Info Length: 0 bytes
|
||||
0x00, 0x10, // Extension Type: alpn
|
||||
0x00, 0x05, // Extension Length: 5 bytes
|
||||
0x00, 0x03, // ALPN Extension Length: 3 bytes
|
||||
0x02, 'h', '2',
|
||||
0x0, 0x0b, // Extension Type: ec_points_format
|
||||
0x0, 0x02, // Extension Length: 2 bytes
|
||||
0x01, // EC Points Format Length: 1 byte
|
||||
0x00, // EC Point Format: uncompressed
|
||||
}
|
||||
|
||||
// A synthesized TLSv1.2 ClientHello
|
||||
tls12ClientHello := []byte{
|
||||
// --- Record Layer (5 bytes) ---
|
||||
@@ -129,35 +168,62 @@ func TestDetectTLS(t *testing.T) {
|
||||
|
||||
// A valid TLS 1.3 Client Hello (captured from a real connection)
|
||||
tls13ClientHello := []byte{
|
||||
// --- Record Layer (5 bytes) ---
|
||||
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,
|
||||
|
||||
// --- Handshake Protocol: ClientHello ---
|
||||
0x01, // Handshake Type: ClientHello (1)
|
||||
0x00, 0x01, 0x36, // Length of the rest of the message
|
||||
0x03, 0x03, // Client Version: TLS 1.2 (Major=3, Minor=3)
|
||||
|
||||
// Random (32 bytes)
|
||||
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,
|
||||
|
||||
// Session ID
|
||||
0x20, // Session ID Length: 32
|
||||
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, //
|
||||
|
||||
// Cipher Suites
|
||||
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,
|
||||
|
||||
// Compression Methods, etc.
|
||||
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,
|
||||
}
|
||||
|
||||
@@ -172,15 +238,23 @@ func TestDetectTLS(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: sslV3ClientHello,
|
||||
DstPort: 443,
|
||||
WantProto: ProtocolSSL,
|
||||
WantType: TypeSSL,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
Name: "TLS 1.1",
|
||||
Name: "TLS 1.1 ClientHello",
|
||||
Direction: Client,
|
||||
Data: tls11ClientHello,
|
||||
DstPort: 443,
|
||||
WantProto: ProtocolTLS,
|
||||
WantType: TypeTLS,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
Name: "TLS 1.1 ServerHello",
|
||||
Direction: Server,
|
||||
Data: tls11ServerHello,
|
||||
SrcPort: 443,
|
||||
WantType: TypeHTTP,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -188,7 +262,7 @@ func TestDetectTLS(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: tls12ClientHello,
|
||||
DstPort: 443,
|
||||
WantProto: ProtocolTLS,
|
||||
WantType: TypeHTTP,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -196,7 +270,7 @@ func TestDetectTLS(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: tls13ClientHello,
|
||||
DstPort: 443,
|
||||
WantProto: ProtocolTLS,
|
||||
WantType: TypeHTTP,
|
||||
WantConfidence: .95,
|
||||
},
|
||||
{
|
||||
@@ -225,7 +299,7 @@ func TestDetectTLS(t *testing.T) {
|
||||
Direction: Client,
|
||||
Data: tls11ClientHelloPartial,
|
||||
DstPort: 443,
|
||||
WantProto: ProtocolTLS,
|
||||
WantType: TypeTLS,
|
||||
WantConfidence: .50,
|
||||
},
|
||||
}, tests...))
|
||||
|
@@ -16,7 +16,7 @@ type testCase struct {
|
||||
Data []byte
|
||||
SrcPort int
|
||||
DstPort int
|
||||
WantProto string
|
||||
WantType string
|
||||
WantConfidence float64
|
||||
WantError error
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func testRunner(t *testing.T, tests []*testCase) {
|
||||
} else if test.WantError != nil {
|
||||
t.Fatalf("Detect(%s, %s, %d, %d) returned protocol %q version %s, expected error %q",
|
||||
test.Direction, testBytesSample(test.Data, 8), test.SrcPort, test.DstPort,
|
||||
proto.Name, proto.Version, test.WantError)
|
||||
proto.Type, proto.Version, test.WantError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -60,16 +60,16 @@ func testRunner(t *testing.T, tests []*testCase) {
|
||||
if proto == nil {
|
||||
t.Fatalf("Detect(%s, %s, %d, %d) returned nil, expected protocol %q",
|
||||
test.Direction, testBytesSample(test.Data, 8), test.SrcPort, test.DstPort,
|
||||
test.WantProto)
|
||||
test.WantType)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("Detect(%s, %s, %d, %d) returned protocol %q version %s with confidence %g%%",
|
||||
t.Logf("Detect(%s, %s, %d, %d) returned protocol %s with confidence %g%%",
|
||||
test.Direction, testBytesSample(test.Data, 4), test.SrcPort, test.DstPort,
|
||||
proto.Name, proto.Version, confidence*100)
|
||||
proto, confidence*100)
|
||||
|
||||
if proto.Name != test.WantProto {
|
||||
t.Errorf("Expected protocol %q", test.WantProto)
|
||||
if proto.Type != test.WantType {
|
||||
t.Errorf("Expected protocol %q, got %q", test.WantType, proto.Type)
|
||||
}
|
||||
if !testAlmostEqual(confidence, test.WantConfidence) {
|
||||
t.Errorf("Expected confidence %g%%", test.WantConfidence*100)
|
||||
|
@@ -7,21 +7,63 @@ import (
|
||||
|
||||
// Protocols supported by this package.
|
||||
const (
|
||||
ProtocolDNS = "dns"
|
||||
ProtocolHTTP = "http"
|
||||
ProtocolMQTT = "mqtt"
|
||||
ProtocolMySQL = "mysql"
|
||||
ProtocolPostgreSQL = "postgresql"
|
||||
ProtocolSSH = "ssh"
|
||||
ProtocolSSL = "ssl"
|
||||
ProtocolTLS = "tls"
|
||||
TypeACME = "ACME"
|
||||
TypeCoAP = "CoAP"
|
||||
TypeDNS = "DNS"
|
||||
TypeFTP = "FTP"
|
||||
TypeHTTP = "HTTP"
|
||||
TypeIRC = "IRC"
|
||||
TypeIMAP = "IMAP"
|
||||
TypeJabber = TypeXMPP
|
||||
TypeManageSieve = "ManageSieve"
|
||||
TypeMosquitto = TypeMQTT
|
||||
TypeMQTT = "MQTT"
|
||||
TypeMySQL = "MySQL"
|
||||
TypeNNTP = "NNTP"
|
||||
TypePOP3 = "POP3"
|
||||
TypePgSQL = TypePostgreSQL
|
||||
TypePostgreSQL = "PostgreSQL"
|
||||
TypeRADIUS = "RADIUS"
|
||||
TypeSamba = TypeSMB
|
||||
TypeSIP = "SIP"
|
||||
TypeSMB = "SMB"
|
||||
TypeSSH = "SSH"
|
||||
TypeSSL = "SSL"
|
||||
TypeSTUN = "STUN"
|
||||
TypeSunRPC = "SunRPC"
|
||||
TypeTLS = "TLS"
|
||||
TypeWebRTC = "WebRTC"
|
||||
TypeXMPP = "XMPP"
|
||||
)
|
||||
|
||||
// Protocol description.
|
||||
type Protocol struct {
|
||||
Name string
|
||||
// Type of protocol, usually one of the constants defined in this package.
|
||||
Type string
|
||||
|
||||
// Encapsulation type, usually one of the constants defined in this package.
|
||||
//
|
||||
// Empty if there is no encapsulation.
|
||||
Encapsulation string
|
||||
|
||||
// Version of the protocol. Unknown versions are marked with [UnknownVersion].
|
||||
Version Version
|
||||
}
|
||||
|
||||
func (proto Protocol) String() string {
|
||||
var s string
|
||||
if proto.Encapsulation != "" {
|
||||
s = proto.Type + " (over " + proto.Encapsulation + ")"
|
||||
} else {
|
||||
s = proto.Type
|
||||
}
|
||||
if proto.Version == UnknownVersion {
|
||||
return s
|
||||
}
|
||||
return s + " version " + proto.Version.String()
|
||||
}
|
||||
|
||||
// Version of a protocol.
|
||||
type Version struct {
|
||||
Major int
|
||||
Minor int
|
||||
@@ -29,15 +71,20 @@ type Version struct {
|
||||
Extra string
|
||||
}
|
||||
|
||||
// UnknownVersion
|
||||
var UnknownVersion Version
|
||||
|
||||
func (v Version) String() string {
|
||||
if v == UnknownVersion {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
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, ".")
|
||||
|
32
tls.go
32
tls.go
@@ -19,7 +19,7 @@ type TLSExtension struct {
|
||||
type TLSRecord struct {
|
||||
Raw []byte
|
||||
Type uint8
|
||||
Version uint16
|
||||
Version TLSVersion
|
||||
Length uint16
|
||||
Data []byte
|
||||
}
|
||||
@@ -30,26 +30,24 @@ func DecodeTLSRecord(data []byte) (*TLSRecord, error) {
|
||||
record = &TLSRecord{Raw: data}
|
||||
)
|
||||
|
||||
var version uint16
|
||||
if !stream.ReadUint8(&record.Type) ||
|
||||
!stream.ReadUint16(&record.Version) ||
|
||||
!stream.ReadUint16(&version) ||
|
||||
!stream.ReadUint16(&record.Length) {
|
||||
return nil, DecodeError{
|
||||
Reason: "invalid TLS record header",
|
||||
Err: io.ErrUnexpectedEOF,
|
||||
}
|
||||
}
|
||||
record.Version = TLSVersion(version)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -166,12 +164,6 @@ func DecodeTLSClientHello(data []byte) (*TLSClientHello, error) {
|
||||
Err: io.ErrUnexpectedEOF,
|
||||
}
|
||||
}
|
||||
if !record.Empty() {
|
||||
return nil, DecodeError{
|
||||
Reason: "extraneous TLS extension data",
|
||||
Err: io.ErrUnexpectedEOF,
|
||||
}
|
||||
}
|
||||
|
||||
for !extensions.Empty() {
|
||||
var (
|
||||
@@ -260,6 +252,7 @@ type TLSServerHello struct {
|
||||
CipherSuite uint16
|
||||
CompressionMethod uint8
|
||||
Extensions []TLSExtension
|
||||
ALPNProtocols []string // RFC 7301, Section 3.1
|
||||
}
|
||||
|
||||
func DecodeTLSServerHello(data []byte) (*TLSServerHello, error) {
|
||||
@@ -347,12 +340,6 @@ func DecodeTLSServerHello(data []byte) (*TLSServerHello, error) {
|
||||
Err: io.ErrUnexpectedEOF,
|
||||
}
|
||||
}
|
||||
if !record.Empty() {
|
||||
return nil, DecodeError{
|
||||
Reason: "extraneous TLS extension data",
|
||||
Err: io.ErrUnexpectedEOF,
|
||||
}
|
||||
}
|
||||
|
||||
for !extensions.Empty() {
|
||||
var (
|
||||
@@ -366,6 +353,11 @@ func DecodeTLSServerHello(data []byte) (*TLSServerHello, error) {
|
||||
}
|
||||
}
|
||||
hello.Extensions = append(hello.Extensions, extension)
|
||||
|
||||
switch extension.Type {
|
||||
case tlsExtensionALPN:
|
||||
_ = readTLSALPN(extensionData, &hello.ALPNProtocols)
|
||||
}
|
||||
}
|
||||
|
||||
return hello, nil
|
||||
|
42
tls_test.go
42
tls_test.go
@@ -72,6 +72,39 @@ func TestDecodeTLSServerHello(t *testing.T) {
|
||||
t.Fatalf("failed to decode test ServerHello: %s", err)
|
||||
}
|
||||
|
||||
tls11ServerHello := []byte{
|
||||
// --- Handshake Protocol: ServerHello (64 bytes) ---
|
||||
0x02, // Handshake Type: ServerHello (2)
|
||||
0x00, 0x00, 0x3c, // Length of the rest of the message (60 bytes)
|
||||
0x03, 0x02, // Server Version: TLS 1.1 (Major=3, Minor=2)
|
||||
|
||||
// Random (32 bytes)
|
||||
0xb7, 0xa8, 0xdf, 0xd5, 0x17, 0xb1, 0x50, 0xb4,
|
||||
0x28, 0xb7, 0xf6, 0xf3, 0xb9, 0x83, 0xcf, 0x9f,
|
||||
0x31, 0x55, 0x79, 0x1f, 0x3b, 0x07, 0x6d, 0x17,
|
||||
0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00,
|
||||
|
||||
// Session ID
|
||||
0x00, // Session ID Length: 0 (new session)
|
||||
|
||||
0xc0, 0x09, // Cipher Suite
|
||||
0x00, // Compression Method
|
||||
|
||||
// --- Extensions (20 bytes) ---
|
||||
0x00, 0x14, // Extensions Length: 20 bytes
|
||||
0xff, 0x01, // Extension Type: renegotiation_info
|
||||
0x00, 0x01, // Extension Length: 1 byte
|
||||
0x00, // Renegotiation Info Length: 0 bytes
|
||||
0x00, 0x10, // Extension Type: alpn
|
||||
0x00, 0x05, // Extension Length: 5 bytes
|
||||
0x00, 0x03, // ALPN Extension Length: 3 bytes
|
||||
0x02, 'h', '2',
|
||||
0x0, 0x0b, // Extension Type: ec_points_format
|
||||
0x0, 0x02, // Extension Length: 2 bytes
|
||||
0x01, // EC Points Format Length: 1 byte
|
||||
0x00, // EC Point Format: uncompressed
|
||||
}
|
||||
|
||||
t.Run("Server Hello", func(t *testing.T) {
|
||||
hello, err := DecodeTLSServerHello(serverHelloBytes)
|
||||
if err != nil {
|
||||
@@ -80,6 +113,15 @@ func TestDecodeTLSServerHello(t *testing.T) {
|
||||
}
|
||||
t.Logf("%#+v", hello)
|
||||
})
|
||||
|
||||
t.Run("TLS 1.1 Server Hello", func(t *testing.T) {
|
||||
hello, err := DecodeTLSServerHello(tls11ServerHello)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
t.Logf("%#+v", hello)
|
||||
})
|
||||
}
|
||||
|
||||
func testDecodeHexString(s string) ([]byte, error) {
|
||||
|
Reference in New Issue
Block a user