Skip to content

Commit d6cbb7a

Browse files
added server hello parsing
1 parent 4538bcb commit d6cbb7a

File tree

1 file changed

+99
-28
lines changed

1 file changed

+99
-28
lines changed

layers/tls.go

Lines changed: 99 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package layers
22

33
import (
44
"encoding/binary"
5+
"encoding/hex"
56
"fmt"
67
"strings"
78
)
@@ -12,22 +13,29 @@ const (
1213
ClientHelloTLSVal = 0x01
1314
)
1415

16+
type TLSVersion struct {
17+
Value uint16
18+
Desc string
19+
}
20+
21+
func (tv *TLSVersion) String() string {
22+
return fmt.Sprintf("%s (%#04x)", tv.Desc, tv.Value)
23+
}
24+
1525
type Record struct {
1626
ContentType uint8
1727
ContentTypeDesc string
18-
Version uint16
19-
VersionDesc string
28+
Version *TLSVersion
2029
Length uint16
2130
Data []byte
2231
}
2332

2433
func (r *Record) String() string {
2534
return fmt.Sprintf(` - Content Type: %s (%d)
26-
- Version: %s (%#04x)
35+
- Version: %s
2736
- Length: %d`,
2837
r.ContentTypeDesc,
2938
r.ContentType,
30-
r.VersionDesc,
3139
r.Version,
3240
r.Length)
3341
}
@@ -40,6 +48,8 @@ func HSTLSParserByType(hstype uint8) HSTLSParser {
4048
switch hstype {
4149
case 1:
4250
return &TLSClientHello{}
51+
case 2:
52+
return &TLSServerHello{}
4353
}
4454
return nil
4555
}
@@ -53,13 +63,22 @@ func (cs *CipherSuite) String() string {
5363
return fmt.Sprintf("%s (%#x)", cs.Desc, cs.Value)
5464
}
5565

66+
type Extension struct {
67+
Value uint16
68+
Desc string
69+
}
70+
71+
func (e *Extension) String() string {
72+
return fmt.Sprintf("%s (%d)", e.Desc, e.Value)
73+
}
74+
5675
type ServerName struct {
5776
Type uint16
5877
Length uint16
5978
SNListLength uint16
6079
SNType uint8
6180
SNNameLength uint16
62-
SNName []byte
81+
SNName string
6382
}
6483

6584
func (sn *ServerName) Parse(data []byte) error {
@@ -68,24 +87,25 @@ func (sn *ServerName) Parse(data []byte) error {
6887
sn.SNListLength = binary.BigEndian.Uint16(data[4:6])
6988
sn.SNType = data[6]
7089
sn.SNNameLength = binary.BigEndian.Uint16(data[7:9])
71-
sn.SNName = data[9 : 9+sn.SNNameLength]
90+
sn.SNName = string(data[9 : 9+sn.SNNameLength])
7291
return nil
7392
}
7493

7594
// https://wiki.osdev.org/TLS_Handshake#Client_Hello_Message
7695
type TLSClientHello struct {
7796
Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16))
78-
Version uint16
79-
VersionDesc string
97+
Version *TLSVersion
8098
Random []byte //32 bytes
8199
SessionIDLength uint8 // if 0 no session follows
82-
SessionID []byte
100+
SessionID string
83101
CipherSuitesLength uint16
84102
CipherSuites []*CipherSuite
85103
CmprMethodsLength uint8 // usually 0x01
86104
CmprMethods []byte // usually 0x00
87105
ExtensionLength uint16
106+
Extensions []*Extension
88107
ServerName *ServerName
108+
ALPN []string
89109
}
90110

91111
func (tch *TLSClientHello) ParseHS(data []byte) error {
@@ -97,12 +117,12 @@ func (tch *TLSClientHello) ParseHS(data []byte) error {
97117
if len(data)-4 < tch.Length {
98118
return fmt.Errorf("message should be at least %d bytes, got %d bytes", tch.Length, len(data)-4)
99119
}
100-
tch.Version = binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6]
101-
tch.VersionDesc = verdesc(tch.Version)
120+
ver := binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6]
121+
tch.Version = &TLSVersion{Value: ver, Desc: verdesc(ver)}
102122
tch.Random = data[6:38] // 11-42 data[6:38]
103123
tch.SessionIDLength = data[38] // 43 data[38] 32 bytes
104124
sid := tch.SessionIDLength + 39 // 70
105-
tch.SessionID = data[39:sid] // data[39:71]
125+
tch.SessionID = hex.EncodeToString(data[39:sid]) // data[39:71]
106126
csl := binary.BigEndian.Uint16(data[sid : sid+2]) // data[71:73] suites count * 2 bytes
107127
tch.CipherSuitesLength = csl
108128
offset := uint16(sid + 2) //73
@@ -123,36 +143,88 @@ func (tch *TLSClientHello) ParseHS(data []byte) error {
123143
extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2]) // data[109:111]
124144
tch.ExtensionLength = extlen
125145
i = extoffset + 2
146+
exts := make([]*Extension, 0, 20)
126147
for i < extoffset+extlen {
127148
typ := binary.BigEndian.Uint16(data[i : i+2])
128149
length := binary.BigEndian.Uint16(data[i+2 : i+4])
150+
exts = append(exts, &Extension{Value: typ, Desc: extdesc(typ)})
129151
switch typ {
130-
case 0: // TODO: add more extensions
152+
case 0: // SNI
131153
sn := &ServerName{}
132154
err := sn.Parse(data[i : i+length+4])
133155
if err != nil {
134156
return err
135157
}
136158
tch.ServerName = sn
137-
i += length + 4
138-
default:
139-
i += length + 4
159+
case 16: //ALPN
160+
//skip data[i+4:i+6] alpn extension length
161+
start := i + 6
162+
alpns := make([]string, 0, 5)
163+
for start < i+length+4 {
164+
alpnStringLength := data[start]
165+
nextProto := string(data[start+1 : start+uint16(alpnStringLength+1)])
166+
alpns = append(alpns, nextProto)
167+
start += uint16(alpnStringLength + 1)
168+
}
169+
tch.ALPN = alpns
140170
}
171+
i += length + 4
141172
}
173+
tch.Extensions = exts
142174
return nil
143175
}
144176

145177
// https://wiki.osdev.org/TLS_Handshake#Server_Hello_Message
146178
type TLSServerHello struct {
147-
Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16))
148-
Version uint16
149-
VersionDesc string
150-
Random []byte //32 bytes
151-
SessionIDLength uint8 // if 0 no session follows
152-
SessionID []byte
153-
CipherSuite *CipherSuite
154-
CmprMethod uint8
155-
ExtensionLength uint16
179+
Length int // 3 bytes int(uint(b[2]) | uint(b[1])<<8 | uint(b[0])<<16))
180+
Version *TLSVersion
181+
Random []byte //32 bytes
182+
SessionIDLength uint8 // if 0 no session follows
183+
SessionID string
184+
CipherSuite *CipherSuite
185+
CmprMethod uint8
186+
ExtensionLength uint16
187+
Extensions []*Extension
188+
SupportedVersion *TLSVersion
189+
}
190+
191+
func (tsh *TLSServerHello) ParseHS(data []byte) error {
192+
// offset 7 bytes
193+
if len(data) < 4 {
194+
return fmt.Errorf("message should be at least 4 bytes, got %d bytes", len(data))
195+
}
196+
tsh.Length = int(uint(data[3]) | uint(data[2])<<8 | uint(data[1])<<16) // 6 - 8 bytes data[1:4]
197+
if len(data)-4 < tsh.Length {
198+
return fmt.Errorf("message should be at least %d bytes, got %d bytes", tsh.Length, len(data)-4)
199+
}
200+
ver := binary.BigEndian.Uint16(data[4:6]) // 9 - 10 bytes data[4:6]
201+
tsh.Version = &TLSVersion{Value: ver, Desc: verdesc(ver)}
202+
tsh.Random = data[6:38] // 11-42 data[6:38]
203+
tsh.SessionIDLength = data[38] // 43 data[38] 32 bytes
204+
sid := tsh.SessionIDLength + 39 // 70
205+
tsh.SessionID = hex.EncodeToString(data[39:sid]) // data[39:71]
206+
val := binary.BigEndian.Uint16(data[sid : sid+2])
207+
valdesc := csuitedesc(val)
208+
tsh.CipherSuite = &CipherSuite{Value: val, Desc: valdesc}
209+
tsh.CmprMethod = data[sid+2]
210+
extoffset := uint16(sid + 3)
211+
extlen := binary.BigEndian.Uint16(data[extoffset : extoffset+2])
212+
tsh.ExtensionLength = extlen
213+
exts := make([]*Extension, 0, 20)
214+
i := extoffset + 2
215+
for i < extoffset+extlen {
216+
typ := binary.BigEndian.Uint16(data[i : i+2])
217+
length := binary.BigEndian.Uint16(data[i+2 : i+4])
218+
exts = append(exts, &Extension{Value: typ, Desc: extdesc(typ)})
219+
switch typ {
220+
case 43: // supported versions
221+
ver := binary.BigEndian.Uint16(data[i+4 : i+6])
222+
tsh.SupportedVersion = &TLSVersion{Value: ver, Desc: verdesc(ver)}
223+
}
224+
i += length + 4
225+
}
226+
tsh.Extensions = exts
227+
return nil
156228
}
157229

158230
// port 443
@@ -181,7 +253,7 @@ func (t *TLSMessage) Summary() string {
181253
sb.WriteString(fmt.Sprintf("%s (%d) Len: %d ", rec.ContentTypeDesc, rec.ContentType, rec.Length))
182254
continue
183255
}
184-
sb.WriteString(fmt.Sprintf("%s (%#04x) ", rec.VersionDesc, rec.Version))
256+
sb.WriteString(rec.Version.String())
185257
if rec.ContentType == 22 {
186258
hstd := hstypedesc(rec.Data[0])
187259
sb.WriteString(fmt.Sprintf("%s ", hstd))
@@ -230,8 +302,7 @@ func (t *TLSMessage) Parse(data []byte) error {
230302
r := &Record{
231303
ContentType: ctype,
232304
ContentTypeDesc: ctdesc,
233-
Version: ver,
234-
VersionDesc: verdesc,
305+
Version: &TLSVersion{Value: ver, Desc: verdesc},
235306
Length: rlen,
236307
Data: data[headerSizeTLS : headerSizeTLS+rlen],
237308
}

0 commit comments

Comments
 (0)