Просмотр исходного кода

EmulateChrome refinements
- sync cipherSuites and signatureAndHashes with latest Chrome
- add padding extension
- fix: second GREASE extension value collision and length

Rod Hynes 9 лет назад
Родитель
Сommit
409f35e0c9

+ 1 - 0
psiphon/common/tls/common.go

@@ -86,6 +86,7 @@ const (
 
 	// [Psiphon]
 	// Additional extensions required for EmulateChrome.
+	extensionPadding              uint16 = 21
 	extensionExtendedMasterSecret uint16 = 23
 	extensionChannelID            uint16 = 30032 // not IANA assigned
 )

+ 16 - 13
psiphon/common/tls/handshake_client.go

@@ -191,11 +191,13 @@ NextCipherSuite:
 			TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
 			TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
 			TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+
+			// TODO: remove these soon
+			// See: https://github.com/google/boringssl/commit/2e839244b078205ff677ada3fb83cf9d60ef055b
 			TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_OLD,
 			TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_OLD,
-			TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+
 			TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-			TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
 			TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
 			TLS_RSA_WITH_AES_128_GCM_SHA256,
 			TLS_RSA_WITH_AES_256_GCM_SHA384,
@@ -204,17 +206,18 @@ NextCipherSuite:
 			TLS_RSA_WITH_3DES_EDE_CBC_SHA,
 		}
 
-		if hello.vers >= VersionTLS12 {
-			hello.signatureAndHashes = []signatureAndHash{
-				{hashSHA512, signatureRSA},
-				{hashSHA512, signatureECDSA},
-				{hashSHA256, signatureRSA},
-				{hashSHA256, signatureECDSA},
-				{hashSHA384, signatureRSA},
-				{hashSHA384, signatureECDSA},
-				{hashSHA1, signatureRSA},
-				{hashSHA1, signatureECDSA},
-			}
+		// From: https://github.com/google/boringssl/blob/7d7554b6b3c79e707e25521e61e066ce2b996e4c/ssl/t1_lib.c#L442
+		// TODO: handle RSA-PSS (0x08)
+		hello.signatureAndHashes = []signatureAndHash{
+			{hashSHA256, signatureECDSA},
+			{0x08, 0x04},
+			{hashSHA256, signatureRSA},
+			{hashSHA384, signatureECDSA},
+			{0x08, 0x05},
+			{hashSHA384, signatureRSA},
+			{0x08, 0x06},
+			{hashSHA512, signatureRSA},
+			{hashSHA1, signatureRSA},
 		}
 
 		hello.nextProtoNeg = false

+ 48 - 5
psiphon/common/tls/handshake_messages.go

@@ -131,6 +131,27 @@ func (m *clientHelloMsg) marshal() []byte {
 	if m.emulateChrome {
 		// GREASE extensions
 		numExtensions += 2
+		extensionsLength++
+	}
+
+	// [Psiphon]
+	// Padding extension required for EmulateChrome.
+	// Logic from:
+	//
+	// https://github.com/google/boringssl/blob/7d7554b6b3c79e707e25521e61e066ce2b996e4c/ssl/t1_lib.c#L2803
+	// https://github.com/google/boringssl/blob/master/LICENSE
+
+	unpaddedLength := length + 2 + 4*numExtensions + extensionsLength
+	paddingLength := uint16(0)
+	if unpaddedLength > 0xff && unpaddedLength < 0x200 {
+		paddingLength = 0x200 - uint16(unpaddedLength)
+		if paddingLength >= 4+1 {
+			paddingLength -= 4
+		} else {
+			paddingLength = 1
+		}
+		extensionsLength += int(paddingLength)
+		numExtensions++
 	}
 
 	if numExtensions > 0 {
@@ -337,11 +358,25 @@ func (m *clientHelloMsg) marshal() []byte {
 			z = z[4:]
 		}
 	}
-	marshalGREASE := func() {
-		value := randomGREASEValue()
+	marshalGREASE := func(value uint16, isEmpty bool) {
+		// See: // https://github.com/google/boringssl/blob/46db7af2c998cf8514d606408546d9be9699f03c/ssl/t1_lib.c#L2784
 		z[0] = byte(value >> 8)
 		z[1] = byte(value & 0xff)
-		z = z[4:]
+		if isEmpty {
+			z = z[4:]
+		} else {
+			z[2] = 0
+			z[3] = 1
+			z[4] = 0
+			z = z[5:]
+		}
+	}
+	marshalPadding := func(paddingLength uint16) {
+		z[0] = byte(extensionPadding >> 8)
+		z[1] = byte(extensionPadding & 0xff)
+		z[2] = byte(paddingLength >> 8)
+		z[3] = byte(paddingLength)
+		z = z[4+paddingLength:]
 	}
 
 	z = z[1+len(m.compressionMethods):]
@@ -358,7 +393,8 @@ func (m *clientHelloMsg) marshal() []byte {
 		// of extensions as required for EmulateChrome is handled
 		// in Conn.clientHandshae().
 
-		marshalGREASE()
+		value := randomGREASEValue()
+		marshalGREASE(value, true)
 
 		if m.secureRenegotiationSupported {
 			marshalRenegotiationInfo()
@@ -397,8 +433,15 @@ func (m *clientHelloMsg) marshal() []byte {
 			marshalSupportedCurves()
 		}
 
-		marshalGREASE()
+		previousGREASEValue := value
+		for value == previousGREASEValue {
+			value = randomGREASEValue()
+		}
+		marshalGREASE(value, false)
 
+		if paddingLength > 0 {
+			marshalPadding(paddingLength)
+		}
 	} else {
 		if m.nextProtoNeg {
 			marshalNextProtoNeg()