Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

client_side_test.go 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. package fake_test
  2. import (
  3. "bytes"
  4. cryptotls "crypto/tls"
  5. "encoding/binary"
  6. "encoding/json"
  7. "io"
  8. "os"
  9. "testing"
  10. "time"
  11. "github.com/9seconds/mtg/v2/internal/testlib"
  12. "github.com/9seconds/mtg/v2/mtglib"
  13. "github.com/9seconds/mtg/v2/mtglib/internal/tls"
  14. "github.com/9seconds/mtg/v2/mtglib/internal/tls/fake"
  15. "github.com/stretchr/testify/require"
  16. "github.com/stretchr/testify/suite"
  17. )
  18. const (
  19. TolerateTime = 365 * 30 * 24 * time.Hour
  20. )
  21. type parseClientHelloConnMock struct {
  22. testlib.EssentialsConnMock
  23. readBuf *bytes.Buffer
  24. }
  25. func (m *parseClientHelloConnMock) Read(p []byte) (int, error) {
  26. return m.readBuf.Read(p)
  27. }
  28. type ParseClientHelloTestSuite struct {
  29. suite.Suite
  30. secret mtglib.Secret
  31. readBuf *bytes.Buffer
  32. connMock *parseClientHelloConnMock
  33. }
  34. func (suite *ParseClientHelloTestSuite) SetupSuite() {
  35. parsed, err := mtglib.ParseSecret("ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d")
  36. require.NoError(suite.T(), err)
  37. suite.secret = parsed
  38. }
  39. func (suite *ParseClientHelloTestSuite) SetupTest() {
  40. suite.readBuf = &bytes.Buffer{}
  41. suite.connMock = &parseClientHelloConnMock{
  42. readBuf: suite.readBuf,
  43. }
  44. }
  45. func (suite *ParseClientHelloTestSuite) TearDownTest() {
  46. suite.connMock.AssertExpectations(suite.T())
  47. }
  48. type ParseClientHello_TLSHeaderTestSuite struct {
  49. ParseClientHelloTestSuite
  50. }
  51. func (suite *ParseClientHello_TLSHeaderTestSuite) TestEmpty() {
  52. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  53. suite.ErrorContains(err, "cannot read client hello")
  54. }
  55. func (suite *ParseClientHello_TLSHeaderTestSuite) TestNothing() {
  56. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  57. suite.ErrorIs(err, io.EOF)
  58. }
  59. func (suite *ParseClientHello_TLSHeaderTestSuite) TestUnknownRecord() {
  60. suite.readBuf.Write([]byte{
  61. 10,
  62. 3, 3,
  63. 0, 0,
  64. })
  65. suite.readBuf.WriteByte(10)
  66. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  67. suite.ErrorContains(err, "unexpected record type 0xa")
  68. }
  69. func (suite *ParseClientHello_TLSHeaderTestSuite) TestUnknownProtocolVersion() {
  70. suite.readBuf.Write([]byte{
  71. tls.TypeHandshake,
  72. 3, 3,
  73. 0, 0,
  74. })
  75. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  76. suite.ErrorContains(err, "unexpected protocol version")
  77. }
  78. func (suite *ParseClientHello_TLSHeaderTestSuite) TestCannotReadRestOfRecord() {
  79. suite.readBuf.Write([]byte{
  80. tls.TypeHandshake,
  81. 3, 1,
  82. 0, 10,
  83. })
  84. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  85. suite.ErrorIs(err, io.EOF)
  86. }
  87. type ParseClientHelloHandshakeTestSuite struct {
  88. ParseClientHelloTestSuite
  89. }
  90. func (suite *ParseClientHelloHandshakeTestSuite) SetupTest() {
  91. suite.ParseClientHelloTestSuite.SetupTest()
  92. suite.readBuf.Write([]byte{
  93. tls.TypeHandshake,
  94. 3, 1,
  95. 0,
  96. })
  97. }
  98. func (suite *ParseClientHelloHandshakeTestSuite) TestCannotReadHeader() {
  99. suite.readBuf.Write([]byte{
  100. 1,
  101. 10,
  102. })
  103. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  104. suite.ErrorContains(err, "cannot read handshake header")
  105. }
  106. func (suite *ParseClientHelloHandshakeTestSuite) TestIncorrectHandshakeType() {
  107. suite.readBuf.Write([]byte{
  108. 4,
  109. 10, 0, 0, 0,
  110. })
  111. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  112. suite.ErrorContains(err, "incorrect handshake type")
  113. }
  114. func (suite *ParseClientHelloHandshakeTestSuite) TestCannotReadHandshake() {
  115. suite.readBuf.Write([]byte{
  116. 4 + 3,
  117. 10, 0, 0, 0,
  118. })
  119. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  120. suite.ErrorIs(err, io.EOF)
  121. }
  122. type ParseClientHelloHandshakeBodyTestSuite struct {
  123. ParseClientHelloTestSuite
  124. }
  125. func (suite *ParseClientHelloHandshakeBodyTestSuite) SetupTest() {
  126. suite.ParseClientHelloTestSuite.SetupTest()
  127. suite.readBuf.Write([]byte{
  128. tls.TypeHandshake,
  129. 3, 1,
  130. 0,
  131. })
  132. }
  133. func (suite *ParseClientHelloHandshakeBodyTestSuite) writeBody(body []byte) {
  134. suite.readBuf.WriteByte(byte(4 + len(body)))
  135. suite.readBuf.Write([]byte{
  136. fake.TypeHandshakeClient,
  137. 0, 0, byte(len(body)),
  138. })
  139. suite.readBuf.Write(body)
  140. }
  141. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadVersion() {
  142. suite.writeBody(nil)
  143. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  144. suite.ErrorContains(err, "cannot read client version")
  145. }
  146. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadRandom() {
  147. suite.writeBody([]byte{3, 3})
  148. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  149. suite.ErrorContains(err, "cannot read client random")
  150. }
  151. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadSessionIDLength() {
  152. body := make([]byte, 2+fake.RandomLen)
  153. suite.writeBody(body)
  154. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  155. suite.ErrorContains(err, "cannot read session ID length")
  156. }
  157. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadSessionID() {
  158. body := make([]byte, 2+fake.RandomLen+1)
  159. body[2+fake.RandomLen] = 32
  160. suite.writeBody(body)
  161. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  162. suite.ErrorContains(err, "cannot read session id")
  163. }
  164. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCipherSuiteLength() {
  165. body := make([]byte, 2+fake.RandomLen+1)
  166. suite.writeBody(body)
  167. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  168. suite.ErrorContains(err, "cannot read cipher suite length")
  169. }
  170. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadFirstCipherSuite() {
  171. body := make([]byte, 2+fake.RandomLen+1+2+1) // cipherSuiteLen=2 but only 1 byte available
  172. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
  173. suite.writeBody(body)
  174. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  175. suite.ErrorContains(err, "cannot read cipher suite")
  176. }
  177. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipRemainingCipherSuites() {
  178. body := make([]byte, 2+fake.RandomLen+1+2+2)
  179. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 4)
  180. suite.writeBody(body)
  181. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  182. suite.ErrorContains(err, "cannot read cipher suite")
  183. }
  184. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotFindCipher() {
  185. // All cipher suites are GREASE values — must return ErrCannotFindCipher.
  186. body := make([]byte, 2+fake.RandomLen+1+2+4+1)
  187. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 4)
  188. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2:], 0x0a0a)
  189. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2+2:], 0x1a1a)
  190. body[2+fake.RandomLen+1+2+4] = 1
  191. suite.writeBody(body)
  192. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  193. suite.ErrorIs(err, fake.ErrCannotFindCipher)
  194. }
  195. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCompressionMethodsLength() {
  196. body := make([]byte, 2+fake.RandomLen+1+2+2)
  197. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
  198. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2:], cryptotls.TLS_AES_128_GCM_SHA256)
  199. suite.writeBody(body)
  200. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  201. suite.ErrorContains(err, "cannot read compression methods length")
  202. }
  203. func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipCompressionMethods() {
  204. body := make([]byte, 2+fake.RandomLen+1+2+2+1)
  205. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
  206. binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2:], cryptotls.TLS_AES_128_GCM_SHA256)
  207. body[2+fake.RandomLen+1+2+2] = 1
  208. suite.writeBody(body)
  209. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  210. suite.ErrorContains(err, "cannot skip compression methods")
  211. }
  212. type ParseClientHelloSNITestSuite struct {
  213. ParseClientHelloTestSuite
  214. }
  215. func (suite *ParseClientHelloSNITestSuite) SetupTest() {
  216. suite.ParseClientHelloTestSuite.SetupTest()
  217. suite.readBuf.Write([]byte{
  218. tls.TypeHandshake,
  219. 3, 1,
  220. 0,
  221. })
  222. }
  223. func (suite *ParseClientHelloSNITestSuite) writeExtensions(extensions []byte) {
  224. handshakeBodyLen := 41 + len(extensions)
  225. suite.readBuf.WriteByte(byte(4 + handshakeBodyLen))
  226. suite.readBuf.Write([]byte{
  227. fake.TypeHandshakeClient,
  228. 0, 0, byte(handshakeBodyLen),
  229. })
  230. // version(2) + random(32) + sessionIDLen(1) + cipherSuiteLen(2) +
  231. // cipherSuite(2) + compressionLen(1) + compression(1) = 41
  232. body := make([]byte, 41)
  233. binary.BigEndian.PutUint16(body[35:], 2)
  234. binary.BigEndian.PutUint16(body[37:], cryptotls.TLS_AES_128_GCM_SHA256)
  235. body[39] = 1
  236. suite.readBuf.Write(body)
  237. suite.readBuf.Write(extensions)
  238. }
  239. func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionsLength() {
  240. suite.writeExtensions(nil)
  241. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  242. suite.ErrorContains(err, "cannot read length of TLS extensions")
  243. }
  244. func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensions() {
  245. suite.writeExtensions([]byte{0, 10})
  246. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  247. suite.ErrorContains(err, "cannot read extensions")
  248. }
  249. func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionType() {
  250. suite.writeExtensions([]byte{0, 1, 0xAB})
  251. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  252. suite.ErrorContains(err, "cannot read extension type")
  253. }
  254. func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionLength() {
  255. suite.writeExtensions([]byte{0, 2, 0xFF, 0xFF})
  256. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  257. suite.ErrorContains(err, "length:")
  258. }
  259. func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionData() {
  260. suite.writeExtensions([]byte{0, 4, 0xFF, 0xFF, 0, 5})
  261. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  262. suite.ErrorContains(err, "data: len")
  263. }
  264. func (suite *ParseClientHelloSNITestSuite) TestCannotReadSNIRecordLength() {
  265. suite.writeExtensions([]byte{0, 5, 0, 0, 0, 1, 0xAB})
  266. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  267. suite.ErrorContains(err, "cannot read the length of the SNI record")
  268. }
  269. func (suite *ParseClientHelloSNITestSuite) TestCannotReadSNIListType() {
  270. suite.writeExtensions([]byte{0, 6, 0, 0, 0, 2, 0, 1})
  271. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  272. suite.ErrorContains(err, "cannot read SNI list type")
  273. }
  274. func (suite *ParseClientHelloSNITestSuite) TestIncorrectSNIListType() {
  275. suite.writeExtensions([]byte{0, 7, 0, 0, 0, 3, 0, 1, 5})
  276. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  277. suite.ErrorContains(err, "incorrect SNI list type")
  278. }
  279. func (suite *ParseClientHelloSNITestSuite) TestCannotReadHostnameLength() {
  280. suite.writeExtensions([]byte{0, 8, 0, 0, 0, 4, 0, 2, 0, 0xAB})
  281. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  282. suite.ErrorContains(err, "incorrect length of the hostname")
  283. }
  284. func (suite *ParseClientHelloSNITestSuite) TestCannotReadHostname() {
  285. suite.writeExtensions([]byte{0, 9, 0, 0, 0, 5, 0, 3, 0, 0, 5})
  286. _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
  287. suite.ErrorContains(err, "incorrect length of SNI hostname")
  288. }
  289. func TestParseClientHelloTLSHeader(t *testing.T) {
  290. t.Parallel()
  291. suite.Run(t, &ParseClientHello_TLSHeaderTestSuite{})
  292. }
  293. func TestParseClientHelloHandshake(t *testing.T) {
  294. t.Parallel()
  295. suite.Run(t, &ParseClientHelloHandshakeTestSuite{})
  296. }
  297. func TestParseClientHelloHandshakeBody(t *testing.T) {
  298. t.Parallel()
  299. suite.Run(t, &ParseClientHelloHandshakeBodyTestSuite{})
  300. }
  301. func TestParseClientHelloSNI(t *testing.T) {
  302. t.Parallel()
  303. suite.Run(t, &ParseClientHelloSNITestSuite{})
  304. }
  305. // fragmentTLSRecord splits a single TLS record into n TLS records by
  306. // dividing the payload into roughly equal parts. Each part gets its own
  307. // TLS record header with the same record type and version.
  308. func fragmentTLSRecord(t testing.TB, full []byte, n int) []byte {
  309. t.Helper()
  310. recordType := full[0]
  311. version := full[1:3]
  312. payload := full[tls.SizeHeader:]
  313. chunkSize := len(payload) / n
  314. result := &bytes.Buffer{}
  315. for i := 0; i < n; i++ {
  316. start := i * chunkSize
  317. end := start + chunkSize
  318. if i == n-1 {
  319. end = len(payload)
  320. }
  321. chunk := payload[start:end]
  322. result.WriteByte(recordType)
  323. result.Write(version)
  324. require.NoError(t, binary.Write(result, binary.BigEndian, uint16(len(chunk))))
  325. result.Write(chunk)
  326. }
  327. return result.Bytes()
  328. }
  329. // splitPayloadAt creates two TLS records from a single record by splitting
  330. // the payload at the given byte position.
  331. func splitPayloadAt(t testing.TB, full []byte, pos int) []byte {
  332. t.Helper()
  333. payload := full[tls.SizeHeader:]
  334. buf := &bytes.Buffer{}
  335. buf.WriteByte(tls.TypeHandshake)
  336. buf.Write(full[1:3])
  337. require.NoError(t, binary.Write(buf, binary.BigEndian, uint16(pos)))
  338. buf.Write(payload[:pos])
  339. buf.WriteByte(tls.TypeHandshake)
  340. buf.Write(full[1:3])
  341. require.NoError(t, binary.Write(buf, binary.BigEndian, uint16(len(payload)-pos)))
  342. buf.Write(payload[pos:])
  343. return buf.Bytes()
  344. }
  345. type ParseClientHelloFragmentedTestSuite struct {
  346. suite.Suite
  347. secret mtglib.Secret
  348. snapshot *clientHelloSnapshot
  349. }
  350. func (s *ParseClientHelloFragmentedTestSuite) SetupSuite() {
  351. parsed, err := mtglib.ParseSecret(
  352. "ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d",
  353. )
  354. require.NoError(s.T(), err)
  355. s.secret = parsed
  356. fileData, err := os.ReadFile("testdata/client-hello-ok-19dfe38384b9884b.json")
  357. require.NoError(s.T(), err)
  358. s.snapshot = &clientHelloSnapshot{}
  359. require.NoError(s.T(), json.Unmarshal(fileData, s.snapshot))
  360. }
  361. func (s *ParseClientHelloFragmentedTestSuite) makeConn(data []byte) *parseClientHelloConnMock {
  362. readBuf := &bytes.Buffer{}
  363. readBuf.Write(data)
  364. connMock := &parseClientHelloConnMock{
  365. readBuf: readBuf,
  366. }
  367. return connMock
  368. }
  369. func (s *ParseClientHelloFragmentedTestSuite) TestReassemblySuccess() {
  370. full := s.snapshot.GetFull()
  371. tests := []struct {
  372. name string
  373. data []byte
  374. }{
  375. {"two equal fragments", fragmentTLSRecord(s.T(), full, 2)},
  376. {"three equal fragments", fragmentTLSRecord(s.T(), full, 3)},
  377. {"single byte first fragment", splitPayloadAt(s.T(), full, 1)},
  378. {"three byte first fragment", splitPayloadAt(s.T(), full, 3)},
  379. }
  380. for _, tt := range tests {
  381. s.Run(tt.name, func() {
  382. connMock := s.makeConn(tt.data)
  383. defer connMock.AssertExpectations(s.T())
  384. hello, err := fake.ReadClientHello(
  385. connMock,
  386. s.secret.Key[:],
  387. s.secret.Host,
  388. TolerateTime,
  389. )
  390. s.Require().NoError(err)
  391. s.Equal(s.snapshot.GetRandom(), hello.Random[:])
  392. s.Equal(s.snapshot.GetSessionID(), hello.SessionID)
  393. s.Equal(uint16(s.snapshot.CipherSuite), hello.CipherSuite)
  394. })
  395. }
  396. }
  397. func (s *ParseClientHelloFragmentedTestSuite) TestReassemblyErrors() {
  398. full := s.snapshot.GetFull()
  399. payload := full[tls.SizeHeader:]
  400. tests := []struct {
  401. name string
  402. buildData func() []byte
  403. errMsg string
  404. }{
  405. {
  406. name: "wrong continuation record type",
  407. buildData: func() []byte {
  408. buf := &bytes.Buffer{}
  409. buf.WriteByte(tls.TypeHandshake)
  410. buf.Write(full[1:3])
  411. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
  412. buf.Write(payload[:10])
  413. // Wrong type: application data instead of handshake
  414. buf.WriteByte(tls.TypeApplicationData)
  415. buf.Write(full[1:3])
  416. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(payload)-10)))
  417. buf.Write(payload[10:])
  418. return buf.Bytes()
  419. },
  420. errMsg: "unexpected record type",
  421. },
  422. {
  423. name: "too many continuation records",
  424. buildData: func() []byte {
  425. // Handshake header claiming 256 bytes, but we only send 1 byte per continuation
  426. handshakePayload := []byte{0x01, 0x00, 0x01, 0x00}
  427. buf := &bytes.Buffer{}
  428. buf.WriteByte(tls.TypeHandshake)
  429. buf.Write([]byte{3, 1})
  430. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(handshakePayload))))
  431. buf.Write(handshakePayload)
  432. for range 11 {
  433. buf.WriteByte(tls.TypeHandshake)
  434. buf.Write([]byte{3, 1})
  435. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(1)))
  436. buf.WriteByte(0xAB)
  437. }
  438. return buf.Bytes()
  439. },
  440. errMsg: "too many fragments",
  441. },
  442. {
  443. name: "zero-length continuation record",
  444. buildData: func() []byte {
  445. buf := &bytes.Buffer{}
  446. buf.WriteByte(tls.TypeHandshake)
  447. buf.Write(full[1:3])
  448. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
  449. buf.Write(payload[:10])
  450. // Valid header but zero-length payload
  451. buf.WriteByte(tls.TypeHandshake)
  452. buf.Write(full[1:3])
  453. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(0)))
  454. return buf.Bytes()
  455. },
  456. errMsg: "cannot read record header",
  457. },
  458. {
  459. name: "wrong continuation record version",
  460. buildData: func() []byte {
  461. buf := &bytes.Buffer{}
  462. buf.WriteByte(tls.TypeHandshake)
  463. buf.Write(full[1:3])
  464. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
  465. buf.Write(payload[:10])
  466. // Wrong version: 3.3 instead of 3.1
  467. buf.WriteByte(tls.TypeHandshake)
  468. buf.Write([]byte{3, 3})
  469. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(payload)-10)))
  470. buf.Write(payload[10:])
  471. return buf.Bytes()
  472. },
  473. errMsg: "unexpected protocol version",
  474. },
  475. {
  476. name: "handshake message too large",
  477. buildData: func() []byte {
  478. // Handshake header claiming 0x010000 (65536) bytes — exceeds 0xFFFF limit
  479. handshakePayload := []byte{0x01, 0x01, 0x00, 0x00}
  480. buf := &bytes.Buffer{}
  481. buf.WriteByte(tls.TypeHandshake)
  482. buf.Write([]byte{3, 1})
  483. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(handshakePayload))))
  484. buf.Write(handshakePayload)
  485. return buf.Bytes()
  486. },
  487. errMsg: "cannot read record header",
  488. },
  489. {
  490. name: "truncated continuation record header",
  491. buildData: func() []byte {
  492. buf := &bytes.Buffer{}
  493. buf.WriteByte(tls.TypeHandshake)
  494. buf.Write(full[1:3])
  495. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
  496. buf.Write(payload[:10])
  497. // Connection ends mid-header (only 2 bytes)
  498. buf.WriteByte(tls.TypeHandshake)
  499. buf.WriteByte(3)
  500. return buf.Bytes()
  501. },
  502. errMsg: "cannot read record header",
  503. },
  504. {
  505. name: "truncated continuation record payload",
  506. buildData: func() []byte {
  507. buf := &bytes.Buffer{}
  508. buf.WriteByte(tls.TypeHandshake)
  509. buf.Write(full[1:3])
  510. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
  511. buf.Write(payload[:10])
  512. // Claims 100 bytes but no payload follows
  513. buf.WriteByte(tls.TypeHandshake)
  514. buf.Write(full[1:3])
  515. require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(100)))
  516. return buf.Bytes()
  517. },
  518. errMsg: "EOF",
  519. },
  520. }
  521. for _, tt := range tests {
  522. s.Run(tt.name, func() {
  523. connMock := s.makeConn(tt.buildData())
  524. defer connMock.AssertExpectations(s.T())
  525. _, err := fake.ReadClientHello(
  526. connMock,
  527. s.secret.Key[:],
  528. s.secret.Host,
  529. TolerateTime,
  530. )
  531. s.ErrorContains(err, tt.errMsg)
  532. })
  533. }
  534. }
  535. func TestParseClientHelloFragmented(t *testing.T) {
  536. t.Parallel()
  537. suite.Run(t, &ParseClientHelloFragmentedTestSuite{})
  538. }