-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandshake_message_client_hello.go
122 lines (102 loc) · 2.88 KB
/
handshake_message_client_hello.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package dtls
import (
"encoding/binary"
)
/*
When a client first connects to a server it is required to send
the client hello as its first message. The client can also send a
client hello in response to a hello request or on its own
initiative in order to renegotiate the security parameters in an
existing connection.
*/
type handshakeMessageClientHello struct {
version protocolVersion
random handshakeRandom
cookie []byte
cipherSuites []cipherSuite
compressionMethods []*compressionMethod
extensions []extension
}
const handshakeMessageClientHelloVariableWidthStart = 34
func (h handshakeMessageClientHello) handshakeType() handshakeType {
return handshakeTypeClientHello
}
func (h *handshakeMessageClientHello) Marshal() ([]byte, error) {
if len(h.cookie) > 255 {
return nil, errCookieTooLong
}
out := make([]byte, handshakeMessageClientHelloVariableWidthStart)
out[0] = h.version.major
out[1] = h.version.minor
rand, err := h.random.Marshal()
if err != nil {
return nil, err
}
copy(out[2:], rand)
out = append(out, 0x00) // SessionID
out = append(out, byte(len(h.cookie)))
out = append(out, h.cookie...)
out = append(out, encodeCipherSuites(h.cipherSuites)...)
out = append(out, encodeCompressionMethods(h.compressionMethods)...)
extensions, err := encodeExtensions(h.extensions)
if err != nil {
return nil, err
}
return append(out, extensions...), nil
}
func (h *handshakeMessageClientHello) Unmarshal(data []byte) error {
if len(data) < 2+handshakeRandomLength {
return errBufferTooSmall
}
h.version.major = data[0]
h.version.minor = data[1]
if err := h.random.Unmarshal(data[2 : 2+handshakeRandomLength]); err != nil {
return err
}
// rest of packet has variable width sections
currOffset := handshakeMessageClientHelloVariableWidthStart
currOffset += int(data[currOffset]) + 1 // SessionID
currOffset++
if len(data) <= currOffset {
return errBufferTooSmall
}
n := int(data[currOffset-1])
if len(data) <= currOffset+n {
return errBufferTooSmall
}
h.cookie = append([]byte{}, data[currOffset:currOffset+n]...)
currOffset += len(h.cookie)
// Cipher Suites
if len(data) < currOffset {
return errBufferTooSmall
}
cipherSuites, err := decodeCipherSuites(data[currOffset:])
if err != nil {
return err
}
h.cipherSuites = cipherSuites
if len(data) < currOffset+2 {
return errBufferTooSmall
}
currOffset += int(binary.BigEndian.Uint16(data[currOffset:])) + 2
// Compression Methods
if len(data) < currOffset {
return errBufferTooSmall
}
compressionMethods, err := decodeCompressionMethods(data[currOffset:])
if err != nil {
return err
}
h.compressionMethods = compressionMethods
if len(data) < currOffset {
return errBufferTooSmall
}
currOffset += int(data[currOffset]) + 1
// Extensions
extensions, err := decodeExtensions(data[currOffset:])
if err != nil {
return err
}
h.extensions = extensions
return nil
}