Преглед на файлове

Add server side of things

tags/v2.2.0^2^2
9seconds преди 1 месец
родител
ревизия
37f8d18be5

+ 23
- 0
mtglib/internal/tls/fake/bytes_pool.go Целия файл

@@ -0,0 +1,23 @@
1
+package fake
2
+
3
+import (
4
+	"bytes"
5
+	"sync"
6
+)
7
+
8
+var (
9
+	bytesPool = sync.Pool{
10
+		New: func() any {
11
+			return &bytes.Buffer{}
12
+		},
13
+	}
14
+)
15
+
16
+func acquireBuffer() *bytes.Buffer {
17
+	return bytesPool.Get().(*bytes.Buffer)
18
+}
19
+
20
+func releaseBuffer(b *bytes.Buffer) {
21
+	b.Reset()
22
+	bytesPool.Put(b)
23
+}

+ 3
- 3
mtglib/internal/tls/fake/client_side.go Целия файл

@@ -20,9 +20,9 @@ const (
20 20
 	TypeHandshakeClient = 0x01
21 21
 
22 22
 	RandomLen = 32
23
-
24 23
 	// record_type(1) + version(2) + size(2) + handshake_type(1) + uint24_length(3) + client_version(2)
25
-	clientRandomOffset = 1 + 2 + 2 + 1 + 3 + 2
24
+	RandomOffset = 1 + 2 + 2 + 1 + 3 + 2
25
+
26 26
 	sniDNSNamesListType = 0
27 27
 )
28 28
 
@@ -81,7 +81,7 @@ func ReadClientHello(conn net.Conn, secret mtglib.Secret, tolerateTimeSkewness t
81 81
 
82 82
 	digest := hmac.New(sha256.New, secret.Key[:])
83 83
 	// we write a copy of the handshake with client random all nullified.
84
-	digest.Write(handshakeCopyBuf.Next(clientRandomOffset))
84
+	digest.Write(handshakeCopyBuf.Next(RandomOffset))
85 85
 	handshakeCopyBuf.Next(RandomLen)
86 86
 	digest.Write(emptyRandom[:])
87 87
 	digest.Write(handshakeCopyBuf.Bytes())

+ 141
- 0
mtglib/internal/tls/fake/server_side.go Целия файл

@@ -0,0 +1,141 @@
1
+package fake
2
+
3
+import (
4
+	"bytes"
5
+	"crypto/hmac"
6
+	"crypto/rand"
7
+	"crypto/sha256"
8
+	"encoding/binary"
9
+	"io"
10
+
11
+	"github.com/9seconds/mtg/v2/mtglib"
12
+	"github.com/9seconds/mtg/v2/mtglib/internal/tls"
13
+	"golang.org/x/crypto/curve25519"
14
+)
15
+
16
+const (
17
+	TypeHandshakeServer = 0x02
18
+
19
+	ChangeCipherValue = 0x01
20
+
21
+	EllipticCurveLen = 32
22
+)
23
+
24
+var (
25
+	serverHelloSuffix = []byte{
26
+		0x00,       // no compression
27
+		0x00, 0x2e, // 46 bytes of data
28
+		0x00, 0x2b, // Extension - Supported Versions
29
+		0x00, 0x02, // 2 bytes are following
30
+		0x03, 0x04, // TLS 1.3
31
+		0x00, 0x33, // Extension - Key Share
32
+		0x00, 0x24, // 36 bytes
33
+		0x00, 0x1d, // x25519 curve
34
+		0x00, 0x20, // 32 bytes of key
35
+	}
36
+)
37
+
38
+func SendServerHello(w io.Writer, secret mtglib.Secret, clientHello *ClientHello) ([]byte, error) {
39
+	buf := &bytes.Buffer{}
40
+	buf.Grow(tls.MaxRecordSize)
41
+
42
+	generateServerHello(buf, clientHello)
43
+	generateChangeCipherValue(buf)
44
+
45
+	noise := &bytes.Buffer{}
46
+	generateNoise(noise)
47
+
48
+	packet := buf.Bytes()
49
+	digest := hmac.New(sha256.New, secret.Key[:])
50
+
51
+	digest.Write(clientHello.Random[:])
52
+	digest.Write(packet)
53
+	digest.Write(noise.Bytes())
54
+	copy(packet[RandomOffset:], digest.Sum(nil))
55
+
56
+	_, err := w.Write(packet)
57
+
58
+	return noise.Bytes(), err
59
+}
60
+
61
+func generateServerHello(buf *bytes.Buffer, hello *ClientHello) {
62
+	payload := acquireBuffer()
63
+	defer releaseBuffer(payload)
64
+
65
+	generateServerHelloPayload(payload, hello)
66
+
67
+	// 16 - type is 0x16 (handshake record)
68
+	// 03 03 - legacy protocol version of "3,3" (TLS 1.2)
69
+	// 00 7a - 0x7A (122) bytes of handshake message follows
70
+
71
+	// 16 - type is 0x16 (handshake record)
72
+	buf.WriteByte(tls.TypeHandshake)
73
+	// 03 03 - legacy protocol version of "3,3" (TLS 1.2)
74
+	buf.Write(tls.TLSVersion[:])
75
+	// 00 7a - 0x7A (122) bytes of handshake message follows
76
+	binary.Write(buf, binary.BigEndian, uint16(payload.Len())) //nolint: errcheck
77
+
78
+	payload.WriteTo(buf) //nolint: errcheck
79
+}
80
+
81
+func generateServerHelloPayload(buf *bytes.Buffer, hello *ClientHello) {
82
+	data := [4]byte{}
83
+
84
+	payload := acquireBuffer()
85
+	defer releaseBuffer(payload)
86
+
87
+	generateServerHelloHandshakePayload(payload, hello)
88
+
89
+	// 02 - handshake message type 0x02 (server hello)
90
+	// 00 00 76 - 0x76 (118) bytes of server hello data follows
91
+	buf.WriteByte(TypeHandshakeServer)
92
+	// 00 00 76 - 0x76 (118) bytes of server hello data follows
93
+	binary.BigEndian.PutUint32(data[:], uint32(payload.Len()))
94
+	buf.Write(data[1:])
95
+
96
+	payload.WriteTo(buf) //nolint: errcheck
97
+}
98
+
99
+func generateServerHelloHandshakePayload(buf *bytes.Buffer, hello *ClientHello) {
100
+	//  The unusual version number ("3,3" representing TLS 1.2) is due to
101
+	// TLS 1.0 being a minor revision of the SSL 3.0 protocol. Therefore
102
+	// TLS 1.0 is represented by "3,1", TLS 1.1 is "3,2", and so on.
103
+	buf.Write(tls.TLSVersion[:])
104
+
105
+	buf.Write(emptyRandom[:])
106
+
107
+	// 20 - 0x20 (32) bytes of session ID follow
108
+	// e0 e1 ... fe ff - session ID copied from Client Hello
109
+	buf.WriteByte(byte(len(hello.SessionID)))
110
+	buf.Write(hello.SessionID)
111
+
112
+	binary.Write(buf, binary.BigEndian, hello.CipherSuite) //nolint: errcheck
113
+
114
+	buf.Write(serverHelloSuffix)
115
+
116
+	scalar := [EllipticCurveLen]byte{}
117
+
118
+	if _, err := rand.Read(scalar[:]); err != nil {
119
+		panic(err)
120
+	}
121
+
122
+	curve, _ := curve25519.X25519(scalar[:], curve25519.Basepoint)
123
+	buf.Write(curve)
124
+}
125
+
126
+func generateChangeCipherValue(buf *bytes.Buffer) {
127
+	buf.WriteByte(tls.TypeChangeCipherSpec)
128
+	buf.Write(tls.TLSVersion[:])
129
+	binary.Write(buf, binary.BigEndian, uint16(1)) //nolint: errcheck
130
+	buf.WriteByte(ChangeCipherValue)
131
+}
132
+
133
+func generateNoise(buf *bytes.Buffer) {
134
+	data := [1369]byte{}
135
+
136
+	if _, err := rand.Read(data[:]); err != nil {
137
+		panic(err)
138
+	}
139
+
140
+	tls.WriteRecord(buf, data[:]) //nolint: errcheck
141
+}

+ 131
- 0
mtglib/internal/tls/fake/server_side_test.go Целия файл

@@ -0,0 +1,131 @@
1
+package fake_test
2
+
3
+import (
4
+	"bytes"
5
+	"crypto/hmac"
6
+	"crypto/rand"
7
+	"crypto/sha256"
8
+	"testing"
9
+
10
+	"github.com/9seconds/mtg/v2/mtglib"
11
+	"github.com/9seconds/mtg/v2/mtglib/internal/tls"
12
+	"github.com/9seconds/mtg/v2/mtglib/internal/tls/fake"
13
+	"github.com/stretchr/testify/suite"
14
+)
15
+
16
+type SendServerHelloTestSuite struct {
17
+	suite.Suite
18
+
19
+	hello  *fake.ClientHello
20
+	buf    *bytes.Buffer
21
+	secret mtglib.Secret
22
+}
23
+
24
+func (suite *SendServerHelloTestSuite) SetupTest() {
25
+	suite.hello = &fake.ClientHello{
26
+		CipherSuite: 4867,
27
+		SessionID:   make([]byte, 32),
28
+	}
29
+
30
+	_, err := rand.Read(suite.hello.SessionID)
31
+	suite.NoError(err)
32
+
33
+	_, err = rand.Read(suite.hello.Random[:])
34
+	suite.NoError(err)
35
+
36
+	suite.buf = &bytes.Buffer{}
37
+	suite.secret = mtglib.GenerateSecret("google.com")
38
+}
39
+
40
+func (suite *SendServerHelloTestSuite) TestRecordStructure() {
41
+	noise, err := fake.SendServerHello(suite.buf, suite.secret, suite.hello)
42
+	suite.NoError(err)
43
+
44
+	var rec bytes.Buffer
45
+
46
+	recordType, _, err := tls.ReadRecord(suite.buf, &rec)
47
+	suite.NoError(err)
48
+	suite.Equal(byte(tls.TypeHandshake), recordType)
49
+
50
+	rec.Reset()
51
+
52
+	recordType, _, err = tls.ReadRecord(suite.buf, &rec)
53
+	suite.NoError(err)
54
+	suite.Equal(byte(tls.TypeChangeCipherSpec), recordType)
55
+
56
+	suite.Empty(suite.buf.Bytes())
57
+
58
+	noiseBuf := bytes.NewReader(noise)
59
+	rec.Reset()
60
+
61
+	recordType, _, err = tls.ReadRecord(noiseBuf, &rec)
62
+	suite.NoError(err)
63
+	suite.Equal(byte(tls.TypeApplicationData), recordType)
64
+	suite.Zero(noiseBuf.Len())
65
+}
66
+
67
+func (suite *SendServerHelloTestSuite) TestHMAC() {
68
+	noise, err := fake.SendServerHello(suite.buf, suite.secret, suite.hello)
69
+	suite.NoError(err)
70
+
71
+	packet := make([]byte, suite.buf.Len())
72
+	copy(packet, suite.buf.Bytes())
73
+
74
+	random := make([]byte, fake.RandomLen)
75
+	copy(random, packet[fake.RandomOffset:])
76
+	copy(packet[fake.RandomOffset:], make([]byte, fake.RandomLen))
77
+
78
+	mac := hmac.New(sha256.New, suite.secret.Key[:])
79
+	mac.Write(suite.hello.Random[:])
80
+	mac.Write(packet)
81
+	mac.Write(noise)
82
+
83
+	suite.Equal(random, mac.Sum(nil))
84
+}
85
+
86
+func (suite *SendServerHelloTestSuite) TestHandshakePayload() {
87
+	_, err := fake.SendServerHello(suite.buf, suite.secret, suite.hello)
88
+	suite.NoError(err)
89
+
90
+	packet := suite.buf.Bytes()
91
+
92
+	// TLS record header: type(1) + version(2) + length(2)
93
+	suite.Equal(byte(tls.TypeHandshake), packet[0])
94
+	suite.Equal([]byte{3, 3}, packet[1:3])
95
+
96
+	// Handshake header: type(1) + uint24_length(3)
97
+	suite.Equal(byte(fake.TypeHandshakeServer), packet[5])
98
+
99
+	// ServerHello version
100
+	suite.Equal([]byte{3, 3}, packet[9:11])
101
+
102
+	// Session ID
103
+	sessionIDOffset := fake.RandomOffset + fake.RandomLen
104
+	suite.Equal(byte(len(suite.hello.SessionID)), packet[sessionIDOffset])
105
+	suite.Equal(suite.hello.SessionID, packet[sessionIDOffset+1:sessionIDOffset+1+len(suite.hello.SessionID)])
106
+}
107
+
108
+func (suite *SendServerHelloTestSuite) TestChangeCipherSpec() {
109
+	_, err := fake.SendServerHello(suite.buf, suite.secret, suite.hello)
110
+	suite.NoError(err)
111
+
112
+	// Skip first record
113
+	var rec bytes.Buffer
114
+
115
+	_, _, err = tls.ReadRecord(suite.buf, &rec)
116
+	suite.NoError(err)
117
+
118
+	// Read ChangeCipherSpec record
119
+	rec.Reset()
120
+
121
+	recordType, length, err := tls.ReadRecord(suite.buf, &rec)
122
+	suite.NoError(err)
123
+	suite.Equal(byte(tls.TypeChangeCipherSpec), recordType)
124
+	suite.Equal(int64(1), length)
125
+	suite.Equal([]byte{fake.ChangeCipherValue}, rec.Bytes())
126
+}
127
+
128
+func TestSendServerHello(t *testing.T) {
129
+	t.Parallel()
130
+	suite.Run(t, &SendServerHelloTestSuite{})
131
+}

Loading…
Отказ
Запис