| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- package fake_test
-
- import (
- "bytes"
- "encoding/binary"
- "encoding/json"
- "errors"
- "io"
- "os"
- "testing"
- "time"
-
- "github.com/9seconds/mtg/v2/internal/testlib"
- "github.com/9seconds/mtg/v2/mtglib"
- "github.com/9seconds/mtg/v2/mtglib/internal/tls"
- "github.com/9seconds/mtg/v2/mtglib/internal/tls/fake"
- "github.com/stretchr/testify/mock"
- "github.com/stretchr/testify/require"
- "github.com/stretchr/testify/suite"
- )
-
- const (
- TolerateTime = 365 * 30 * 24 * time.Hour
- )
-
- type parseClientHelloConnMock struct {
- testlib.EssentialsConnMock
-
- readBuf *bytes.Buffer
- }
-
- func (m *parseClientHelloConnMock) Read(p []byte) (int, error) {
- return m.readBuf.Read(p)
- }
-
- type ParseClientHelloTestSuite struct {
- suite.Suite
-
- secret mtglib.Secret
- readBuf *bytes.Buffer
- connMock *parseClientHelloConnMock
- }
-
- func (suite *ParseClientHelloTestSuite) SetupSuite() {
- parsed, err := mtglib.ParseSecret("ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d")
- require.NoError(suite.T(), err)
-
- suite.secret = parsed
- }
-
- func (suite *ParseClientHelloTestSuite) SetupTest() {
- suite.readBuf = &bytes.Buffer{}
- suite.connMock = &parseClientHelloConnMock{
- readBuf: suite.readBuf,
- }
-
- suite.connMock.
- On("SetReadDeadline", mock.AnythingOfType("time.Time")).
- Twice().
- Return(nil)
- }
-
- func (suite *ParseClientHelloTestSuite) TearDownTest() {
- suite.connMock.AssertExpectations(suite.T())
- }
-
- type ParseClientHello_TLSHeaderTestSuite struct {
- ParseClientHelloTestSuite
- }
-
- func (suite *ParseClientHello_TLSHeaderTestSuite) TestEmpty() {
- suite.connMock.ExpectedCalls = []*mock.Call{}
- suite.connMock.
- On("SetReadDeadline", mock.AnythingOfType("time.Time")).
- Once().
- Return(errors.New("fail"))
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "fail")
- }
-
- func (suite *ParseClientHello_TLSHeaderTestSuite) TestNothing() {
- suite.connMock.ExpectedCalls = []*mock.Call{}
- suite.connMock.
- On("SetReadDeadline", mock.AnythingOfType("time.Time")).
- Twice().
- Return(nil)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorIs(err, io.EOF)
- }
-
- func (suite *ParseClientHello_TLSHeaderTestSuite) TestUnknownRecord() {
- suite.readBuf.Write([]byte{
- 10,
- 3, 3,
- 0, 0,
- })
- suite.readBuf.WriteByte(10)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "unexpected record type 0xa")
- }
-
- func (suite *ParseClientHello_TLSHeaderTestSuite) TestUnknownProtocolVersion() {
- suite.readBuf.Write([]byte{
- tls.TypeHandshake,
- 3, 3,
- 0, 0,
- })
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "unexpected protocol version")
- }
-
- func (suite *ParseClientHello_TLSHeaderTestSuite) TestCannotReadRestOfRecord() {
- suite.readBuf.Write([]byte{
- tls.TypeHandshake,
- 3, 1,
- 0, 10,
- })
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorIs(err, io.EOF)
- }
-
- type ParseClientHelloHandshakeTestSuite struct {
- ParseClientHelloTestSuite
- }
-
- func (suite *ParseClientHelloHandshakeTestSuite) SetupTest() {
- suite.ParseClientHelloTestSuite.SetupTest()
-
- suite.readBuf.Write([]byte{
- tls.TypeHandshake,
- 3, 1,
- 0,
- })
- }
-
- func (suite *ParseClientHelloHandshakeTestSuite) TestCannotReadHeader() {
- suite.readBuf.Write([]byte{
- 1,
- 10,
- })
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read handshake header")
- }
-
- func (suite *ParseClientHelloHandshakeTestSuite) TestIncorrectHandshakeType() {
- suite.readBuf.Write([]byte{
- 4,
- 10, 0, 0, 0,
- })
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "incorrect handshake type")
- }
-
- func (suite *ParseClientHelloHandshakeTestSuite) TestCannotReadHandshake() {
- suite.readBuf.Write([]byte{
- 4 + 3,
- 10, 0, 0, 0,
- })
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorIs(err, io.EOF)
- }
-
- type ParseClientHelloHandshakeBodyTestSuite struct {
- ParseClientHelloTestSuite
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) SetupTest() {
- suite.ParseClientHelloTestSuite.SetupTest()
-
- suite.readBuf.Write([]byte{
- tls.TypeHandshake,
- 3, 1,
- 0,
- })
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) writeBody(body []byte) {
- suite.readBuf.WriteByte(byte(4 + len(body)))
- suite.readBuf.Write([]byte{
- fake.TypeHandshakeClient,
- 0, 0, byte(len(body)),
- })
- suite.readBuf.Write(body)
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadVersion() {
- suite.writeBody(nil)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read client version")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadRandom() {
- suite.writeBody([]byte{3, 3})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read client random")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadSessionIDLength() {
- body := make([]byte, 2+fake.RandomLen)
-
- suite.writeBody(body)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read session ID length")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadSessionID() {
- body := make([]byte, 2+fake.RandomLen+1)
- body[2+fake.RandomLen] = 32
-
- suite.writeBody(body)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read session id")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCipherSuiteLength() {
- body := make([]byte, 2+fake.RandomLen+1)
-
- suite.writeBody(body)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read cipher suite length")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadFirstCipherSuite() {
- body := make([]byte, 2+fake.RandomLen+1+2)
-
- suite.writeBody(body)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read first cipher suite")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipRemainingCipherSuites() {
- body := make([]byte, 2+fake.RandomLen+1+2+2)
- binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 4)
-
- suite.writeBody(body)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot skip remaining cipher suites")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCompressionMethodsLength() {
- body := make([]byte, 2+fake.RandomLen+1+2+2)
- binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
-
- suite.writeBody(body)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read compression methods length")
- }
-
- func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipCompressionMethods() {
- body := make([]byte, 2+fake.RandomLen+1+2+2+1)
- binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
- body[2+fake.RandomLen+1+2+2] = 1
-
- suite.writeBody(body)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot skip compression methods")
- }
-
- type ParseClientHelloSNITestSuite struct {
- ParseClientHelloTestSuite
- }
-
- func (suite *ParseClientHelloSNITestSuite) SetupTest() {
- suite.ParseClientHelloTestSuite.SetupTest()
-
- suite.readBuf.Write([]byte{
- tls.TypeHandshake,
- 3, 1,
- 0,
- })
- }
-
- func (suite *ParseClientHelloSNITestSuite) writeExtensions(extensions []byte) {
- handshakeBodyLen := 41 + len(extensions)
-
- suite.readBuf.WriteByte(byte(4 + handshakeBodyLen))
- suite.readBuf.Write([]byte{
- fake.TypeHandshakeClient,
- 0, 0, byte(handshakeBodyLen),
- })
-
- // version(2) + random(32) + sessionIDLen(1) + cipherSuiteLen(2) +
- // cipherSuite(2) + compressionLen(1) + compression(1) = 41
- body := make([]byte, 41)
- binary.BigEndian.PutUint16(body[35:], 2)
- body[39] = 1
-
- suite.readBuf.Write(body)
- suite.readBuf.Write(extensions)
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionsLength() {
- suite.writeExtensions(nil)
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read length of TLS extensions")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensions() {
- suite.writeExtensions([]byte{0, 10})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read extensions")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionType() {
- suite.writeExtensions([]byte{0, 1, 0xAB})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read extension type")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionLength() {
- suite.writeExtensions([]byte{0, 2, 0xFF, 0xFF})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "length:")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadExtensionData() {
- suite.writeExtensions([]byte{0, 4, 0xFF, 0xFF, 0, 5})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "data: len")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadSNIRecordLength() {
- suite.writeExtensions([]byte{0, 5, 0, 0, 0, 1, 0xAB})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read the length of the SNI record")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadSNIListType() {
- suite.writeExtensions([]byte{0, 6, 0, 0, 0, 2, 0, 1})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "cannot read SNI list type")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestIncorrectSNIListType() {
- suite.writeExtensions([]byte{0, 7, 0, 0, 0, 3, 0, 1, 5})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "incorrect SNI list type")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadHostnameLength() {
- suite.writeExtensions([]byte{0, 8, 0, 0, 0, 4, 0, 2, 0, 0xAB})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "incorrect length of the hostname")
- }
-
- func (suite *ParseClientHelloSNITestSuite) TestCannotReadHostname() {
- suite.writeExtensions([]byte{0, 9, 0, 0, 0, 5, 0, 3, 0, 0, 5})
-
- _, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
- suite.ErrorContains(err, "incorrect length of SNI hostname")
- }
-
- func TestParseClientHelloTLSHeader(t *testing.T) {
- t.Parallel()
- suite.Run(t, &ParseClientHello_TLSHeaderTestSuite{})
- }
-
- func TestParseClientHelloHandshake(t *testing.T) {
- t.Parallel()
- suite.Run(t, &ParseClientHelloHandshakeTestSuite{})
- }
-
- func TestParseClientHelloHandshakeBody(t *testing.T) {
- t.Parallel()
- suite.Run(t, &ParseClientHelloHandshakeBodyTestSuite{})
- }
-
- func TestParseClientHelloSNI(t *testing.T) {
- t.Parallel()
- suite.Run(t, &ParseClientHelloSNITestSuite{})
- }
-
- // fragmentTLSRecord splits a single TLS record into n TLS records by
- // dividing the payload into roughly equal parts. Each part gets its own
- // TLS record header with the same record type and version.
- func fragmentTLSRecord(t testing.TB, full []byte, n int) []byte {
- t.Helper()
-
- recordType := full[0]
- version := full[1:3]
- payload := full[tls.SizeHeader:]
-
- chunkSize := len(payload) / n
- result := &bytes.Buffer{}
-
- for i := 0; i < n; i++ {
- start := i * chunkSize
- end := start + chunkSize
-
- if i == n-1 {
- end = len(payload)
- }
-
- chunk := payload[start:end]
- result.WriteByte(recordType)
- result.Write(version)
- require.NoError(t, binary.Write(result, binary.BigEndian, uint16(len(chunk))))
- result.Write(chunk)
- }
-
- return result.Bytes()
- }
-
- // splitPayloadAt creates two TLS records from a single record by splitting
- // the payload at the given byte position.
- func splitPayloadAt(t testing.TB, full []byte, pos int) []byte {
- t.Helper()
-
- payload := full[tls.SizeHeader:]
- buf := &bytes.Buffer{}
-
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(t, binary.Write(buf, binary.BigEndian, uint16(pos)))
- buf.Write(payload[:pos])
-
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(t, binary.Write(buf, binary.BigEndian, uint16(len(payload)-pos)))
- buf.Write(payload[pos:])
-
- return buf.Bytes()
- }
-
- type ParseClientHelloFragmentedTestSuite struct {
- suite.Suite
-
- secret mtglib.Secret
- snapshot *clientHelloSnapshot
- }
-
- func (s *ParseClientHelloFragmentedTestSuite) SetupSuite() {
- parsed, err := mtglib.ParseSecret(
- "ee367a189aee18fa31c190054efd4a8e9573746f726167652e676f6f676c65617069732e636f6d",
- )
- require.NoError(s.T(), err)
-
- s.secret = parsed
-
- fileData, err := os.ReadFile("testdata/client-hello-ok-19dfe38384b9884b.json")
- require.NoError(s.T(), err)
-
- s.snapshot = &clientHelloSnapshot{}
- require.NoError(s.T(), json.Unmarshal(fileData, s.snapshot))
- }
-
- func (s *ParseClientHelloFragmentedTestSuite) makeConn(data []byte) *parseClientHelloConnMock {
- readBuf := &bytes.Buffer{}
- readBuf.Write(data)
-
- connMock := &parseClientHelloConnMock{
- readBuf: readBuf,
- }
-
- connMock.
- On("SetReadDeadline", mock.AnythingOfType("time.Time")).
- Twice().
- Return(nil)
-
- return connMock
- }
-
- func (s *ParseClientHelloFragmentedTestSuite) TestReassemblySuccess() {
- full := s.snapshot.GetFull()
-
- tests := []struct {
- name string
- data []byte
- }{
- {"two equal fragments", fragmentTLSRecord(s.T(), full, 2)},
- {"three equal fragments", fragmentTLSRecord(s.T(), full, 3)},
- {"single byte first fragment", splitPayloadAt(s.T(), full, 1)},
- {"three byte first fragment", splitPayloadAt(s.T(), full, 3)},
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- connMock := s.makeConn(tt.data)
- defer connMock.AssertExpectations(s.T())
-
- hello, err := fake.ReadClientHello(
- connMock,
- s.secret.Key[:],
- s.secret.Host,
- TolerateTime,
- )
- s.Require().NoError(err)
-
- s.Equal(s.snapshot.GetRandom(), hello.Random[:])
- s.Equal(s.snapshot.GetSessionID(), hello.SessionID)
- s.Equal(uint16(s.snapshot.CipherSuite), hello.CipherSuite)
- })
- }
- }
-
- func (s *ParseClientHelloFragmentedTestSuite) TestReassemblyErrors() {
- full := s.snapshot.GetFull()
- payload := full[tls.SizeHeader:]
-
- tests := []struct {
- name string
- buildData func() []byte
- errMsg string
- }{
- {
- name: "wrong continuation record type",
- buildData: func() []byte {
- buf := &bytes.Buffer{}
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
- buf.Write(payload[:10])
- // Wrong type: application data instead of handshake
- buf.WriteByte(tls.TypeApplicationData)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(payload)-10)))
- buf.Write(payload[10:])
- return buf.Bytes()
- },
- errMsg: "unexpected record type",
- },
- {
- name: "too many continuation records",
- buildData: func() []byte {
- // Handshake header claiming 256 bytes, but we only send 1 byte per continuation
- handshakePayload := []byte{0x01, 0x00, 0x01, 0x00}
- buf := &bytes.Buffer{}
- buf.WriteByte(tls.TypeHandshake)
- buf.Write([]byte{3, 1})
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(handshakePayload))))
- buf.Write(handshakePayload)
- for range 11 {
- buf.WriteByte(tls.TypeHandshake)
- buf.Write([]byte{3, 1})
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(1)))
- buf.WriteByte(0xAB)
- }
- return buf.Bytes()
- },
- errMsg: "too many fragments",
- },
- {
- name: "zero-length continuation record",
- buildData: func() []byte {
- buf := &bytes.Buffer{}
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
- buf.Write(payload[:10])
- // Valid header but zero-length payload
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(0)))
- return buf.Bytes()
- },
- errMsg: "cannot read record header",
- },
- {
- name: "wrong continuation record version",
- buildData: func() []byte {
- buf := &bytes.Buffer{}
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
- buf.Write(payload[:10])
- // Wrong version: 3.3 instead of 3.1
- buf.WriteByte(tls.TypeHandshake)
- buf.Write([]byte{3, 3})
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(payload)-10)))
- buf.Write(payload[10:])
- return buf.Bytes()
- },
- errMsg: "unexpected protocol version",
- },
- {
- name: "handshake message too large",
- buildData: func() []byte {
- // Handshake header claiming 0x010000 (65536) bytes — exceeds 0xFFFF limit
- handshakePayload := []byte{0x01, 0x01, 0x00, 0x00}
- buf := &bytes.Buffer{}
- buf.WriteByte(tls.TypeHandshake)
- buf.Write([]byte{3, 1})
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(len(handshakePayload))))
- buf.Write(handshakePayload)
- return buf.Bytes()
- },
- errMsg: "cannot read record header",
- },
- {
- name: "truncated continuation record header",
- buildData: func() []byte {
- buf := &bytes.Buffer{}
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
- buf.Write(payload[:10])
- // Connection ends mid-header (only 2 bytes)
- buf.WriteByte(tls.TypeHandshake)
- buf.WriteByte(3)
- return buf.Bytes()
- },
- errMsg: "cannot read record header",
- },
- {
- name: "truncated continuation record payload",
- buildData: func() []byte {
- buf := &bytes.Buffer{}
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(10)))
- buf.Write(payload[:10])
- // Claims 100 bytes but no payload follows
- buf.WriteByte(tls.TypeHandshake)
- buf.Write(full[1:3])
- require.NoError(s.T(), binary.Write(buf, binary.BigEndian, uint16(100)))
- return buf.Bytes()
- },
- errMsg: "EOF",
- },
- }
-
- for _, tt := range tests {
- s.Run(tt.name, func() {
- connMock := s.makeConn(tt.buildData())
- defer connMock.AssertExpectations(s.T())
-
- _, err := fake.ReadClientHello(
- connMock,
- s.secret.Key[:],
- s.secret.Host,
- TolerateTime,
- )
- s.ErrorContains(err, tt.errMsg)
- })
- }
- }
-
- func TestParseClientHelloFragmented(t *testing.T) {
- t.Parallel()
- suite.Run(t, &ParseClientHelloFragmentedTestSuite{})
- }
|