mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 10:34:01 +03:00
Merge pull request #446 from runixer/fix/grease-cipher-suite
Fix DPI detection: replace GREASE cipher suite in FakeTLS ServerHello
This commit is contained in:
@@ -130,18 +130,25 @@ func parseHandshake(r io.Reader) (*ClientHello, error) {
|
||||
|
||||
cipherSuiteLen := int64(binary.BigEndian.Uint16(header[:]))
|
||||
|
||||
// we do not care about picking up any cipher. we pick the first one,
|
||||
// so it is always should be present.
|
||||
if _, err := io.ReadFull(r, header[:]); err != nil {
|
||||
return nil, fmt.Errorf("cannot read first cipher suite: %w", err)
|
||||
// Pick the first non-GREASE cipher suite from the list.
|
||||
// Real TLS servers never select GREASE values (RFC 8701, pattern 0x?a?a),
|
||||
// so echoing them back is a trivial DPI fingerprint.
|
||||
for remaining := cipherSuiteLen; remaining >= 2; remaining -= 2 {
|
||||
if _, err := io.ReadFull(r, header[:]); err != nil {
|
||||
return nil, fmt.Errorf("cannot read cipher suite: %w", err)
|
||||
}
|
||||
|
||||
cs := binary.BigEndian.Uint16(header[:])
|
||||
if hello.CipherSuite == 0 && cs&0x0f0f != 0x0a0a {
|
||||
hello.CipherSuite = cs
|
||||
}
|
||||
}
|
||||
|
||||
hello.CipherSuite = binary.BigEndian.Uint16(header[:])
|
||||
|
||||
if _, err := io.CopyN(io.Discard, r, cipherSuiteLen-2); err != nil {
|
||||
return nil, fmt.Errorf("cannot skip remaining cipher suites: %w", err)
|
||||
if hello.CipherSuite == 0 {
|
||||
hello.CipherSuite = 0x1301 // fallback: TLS_AES_128_GCM_SHA256
|
||||
}
|
||||
|
||||
|
||||
if _, err := io.ReadFull(r, header[:1]); err != nil {
|
||||
return nil, fmt.Errorf("cannot read compression methods length: %w", err)
|
||||
}
|
||||
|
||||
@@ -234,12 +234,13 @@ func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCipherSuiteLe
|
||||
}
|
||||
|
||||
func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadFirstCipherSuite() {
|
||||
body := make([]byte, 2+fake.RandomLen+1+2)
|
||||
body := make([]byte, 2+fake.RandomLen+1+2+1) // cipherSuiteLen=2 but only 1 byte available
|
||||
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 first cipher suite")
|
||||
suite.ErrorContains(err, "cannot read cipher suite")
|
||||
}
|
||||
|
||||
func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipRemainingCipherSuites() {
|
||||
@@ -249,7 +250,7 @@ func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipRemainingCiph
|
||||
suite.writeBody(body)
|
||||
|
||||
_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
|
||||
suite.ErrorContains(err, "cannot skip remaining cipher suites")
|
||||
suite.ErrorContains(err, "cannot read cipher suite")
|
||||
}
|
||||
|
||||
func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCompressionMethodsLength() {
|
||||
|
||||
@@ -58,7 +58,7 @@ func (suite *SendServerHelloTestSuite) TestRecordStructure() {
|
||||
recordType, length, err := tls.ReadRecord(suite.buf, &rec)
|
||||
suite.NoError(err)
|
||||
suite.Equal(byte(tls.TypeApplicationData), recordType)
|
||||
suite.Greater(length, int64(2500))
|
||||
suite.GreaterOrEqual(length, int64(2500))
|
||||
|
||||
suite.Empty(suite.buf.Bytes())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"time": 1617181365,
|
||||
"random": "w4TaDfYg/aUKdx1oi68vxMKvHJczRNvtRRppLETzeNE=",
|
||||
"sessionId": "St2BZ2uHMFn3B2trD1jfdtpjoJOOg6JBeLhFcyCMCq4=",
|
||||
"host": "storage.googleapis.com",
|
||||
"cipherSuite": 4867,
|
||||
"full": "FgMBAgIBAAH+AwPDhNoN9iD9pQp3HWiLry/Ewq8clzNE2+1FGmksRPN40SBK3YFna4cwWfcHa2sPWN922mOgk46DokF4uEVzIIwKrgA2WloTAxMBEwLALMArwCTAI8AKwAnMqcAwwC/AKMAnwBTAE8yoAJ0AnAA9ADwANQAvwAjAEgAKAQABf/8BAAEAAAAAGwAZAAAWc3RvcmFnZS5nb29nbGVhcGlzLmNvbQAXAAAADQAYABYEAwgEBAEFAwIDCAUIBQUBCAYGAQIBAAUABQEAAAAAM3QAAAASAAAAEAAwAC4CaDIFaDItMTYFaDItMTUFaDItMTQIc3BkeS8zLjEGc3BkeS8zCGh0dHAvMS4xAAsAAgEAADMAJgAkAB0AIAf+6C8fSRJSAC7CyUvdR9kDclNR9KLCsCFHpVZ3bC8iAC0AAgEBACsACQgDBAMDAwIDAQAKAAoACAAdABcAGAAZABUAoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
}
|
||||
Reference in New Issue
Block a user