Commit 7fc0940f authored by Matthew Holt's avatar Matthew Holt

mitm: Fix false positive for Firefox 55 nightly

parent 7323b145
...@@ -326,24 +326,34 @@ func (info rawHelloInfo) looksLikeFirefox() bool { ...@@ -326,24 +326,34 @@ func (info rawHelloInfo) looksLikeFirefox() bool {
// EC point formats, and handshake compression methods." // EC point formats, and handshake compression methods."
// We check for the presence and order of the extensions. // We check for the presence and order of the extensions.
// Note: Sometimes padding (21) is present, sometimes not. // Note: Sometimes 0x15 (21, padding) is present, sometimes not.
// Note: Firefox 51+ does not advertise 0x3374 (13172, NPN). // Note: Firefox 51+ does not advertise 0x3374 (13172, NPN).
// Note: Firefox doesn't advertise 0x0 (0, SNI) when connecting to IP addresses. // Note: Firefox doesn't advertise 0x0 (0, SNI) when connecting to IP addresses.
requiredExtensionsOrder := []uint16{23, 65281, 10, 11, 35, 16, 5, 65283, 13} // Note: Firefox 55+ doesn't appear to advertise 0xFF03 (65283, short headers). It used to be between 5 and 13.
requiredExtensionsOrder := []uint16{23, 65281, 10, 11, 35, 16, 5, 13}
if !assertPresenceAndOrdering(requiredExtensionsOrder, info.extensions, true) { if !assertPresenceAndOrdering(requiredExtensionsOrder, info.extensions, true) {
return false return false
} }
// We check for both presence of curves and their ordering. // We check for both presence of curves and their ordering.
expectedCurves := []tls.CurveID{29, 23, 24, 25} requiredCurves := []tls.CurveID{29, 23, 24, 25}
if len(info.curves) != len(expectedCurves) { if len(info.curves) < len(requiredCurves) {
return false return false
} }
for i := range expectedCurves { for i := range requiredCurves {
if info.curves[i] != expectedCurves[i] { if info.curves[i] != requiredCurves[i] {
return false return false
} }
} }
if len(info.curves) > len(requiredCurves) {
// newer Firefox (55 Nightly?) may have additional curves at end of list
allowedCurves := []tls.CurveID{256, 257}
for i := range allowedCurves {
if info.curves[len(requiredCurves)+i] != allowedCurves[i] {
return false
}
}
}
if hasGreaseCiphers(info.cipherSuites) { if hasGreaseCiphers(info.cipherSuites) {
return false return false
...@@ -353,6 +363,9 @@ func (info rawHelloInfo) looksLikeFirefox() bool { ...@@ -353,6 +363,9 @@ func (info rawHelloInfo) looksLikeFirefox() bool {
// according to the paper, cipher suites may be not be added // according to the paper, cipher suites may be not be added
// or reordered by the user, but they may be disabled. // or reordered by the user, but they may be disabled.
expectedCipherSuiteOrder := []uint16{ expectedCipherSuiteOrder := []uint16{
TLS_AES_128_GCM_SHA256, // 0x1301
TLS_CHACHA20_POLY1305_SHA256, // 0x1303
TLS_AES_256_GCM_SHA384, // 0x1302
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // 0xc02b tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // 0xc02b
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // 0xc02f tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // 0xc02f
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, // 0xcca9 tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, // 0xcca9
...@@ -401,14 +414,14 @@ func (info rawHelloInfo) looksLikeChrome() bool { ...@@ -401,14 +414,14 @@ func (info rawHelloInfo) looksLikeChrome() bool {
// 0xc00a, 0xc014, 0xc009, 0x9c, 0x9d, 0x2f, 0x35, 0xa // 0xc00a, 0xc014, 0xc009, 0x9c, 0x9d, 0x2f, 0x35, 0xa
chromeCipherExclusions := map[uint16]struct{}{ chromeCipherExclusions := map[uint16]struct{}{
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: {}, // 0xc024 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: {}, // 0xc024
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: {}, // 0xc023 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: {}, // 0xc023
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: {}, // 0xc028 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: {}, // 0xc028
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: {}, // 0xc027 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: {}, // 0xc027
TLS_RSA_WITH_AES_256_CBC_SHA256: {}, // 0x3d TLS_RSA_WITH_AES_256_CBC_SHA256: {}, // 0x3d
tls.TLS_RSA_WITH_AES_128_CBC_SHA256: {}, // 0x3c tls.TLS_RSA_WITH_AES_128_CBC_SHA256: {}, // 0x3c
TLS_DHE_RSA_WITH_AES_128_CBC_SHA: {}, // 0x33 TLS_DHE_RSA_WITH_AES_128_CBC_SHA: {}, // 0x33
TLS_DHE_RSA_WITH_AES_256_CBC_SHA: {}, // 0x39 TLS_DHE_RSA_WITH_AES_256_CBC_SHA: {}, // 0x39
} }
for _, ext := range info.cipherSuites { for _, ext := range info.cipherSuites {
if _, ok := chromeCipherExclusions[ext]; ok { if _, ok := chromeCipherExclusions[ext]; ok {
...@@ -511,7 +524,7 @@ func (info rawHelloInfo) looksLikeSafari() bool { ...@@ -511,7 +524,7 @@ func (info rawHelloInfo) looksLikeSafari() bool {
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, // 0xc02c tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, // 0xc02c
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // 0xc02b tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // 0xc02b
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, // 0xc024 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, // 0xc024
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // 0xc023 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // 0xc023
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, // 0xc00a tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, // 0xc00a
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, // 0xc009 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, // 0xc009
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, // 0xc030 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, // 0xc030
...@@ -523,7 +536,7 @@ func (info rawHelloInfo) looksLikeSafari() bool { ...@@ -523,7 +536,7 @@ func (info rawHelloInfo) looksLikeSafari() bool {
tls.TLS_RSA_WITH_AES_256_GCM_SHA384, // 0x9d tls.TLS_RSA_WITH_AES_256_GCM_SHA384, // 0x9d
tls.TLS_RSA_WITH_AES_128_GCM_SHA256, // 0x9c tls.TLS_RSA_WITH_AES_128_GCM_SHA256, // 0x9c
TLS_RSA_WITH_AES_256_CBC_SHA256, // 0x3d TLS_RSA_WITH_AES_256_CBC_SHA256, // 0x3d
TLS_RSA_WITH_AES_128_CBC_SHA256, // 0x3c tls.TLS_RSA_WITH_AES_128_CBC_SHA256, // 0x3c
tls.TLS_RSA_WITH_AES_256_CBC_SHA, // 0x35 tls.TLS_RSA_WITH_AES_256_CBC_SHA, // 0x35
tls.TLS_RSA_WITH_AES_128_CBC_SHA, // 0x2f tls.TLS_RSA_WITH_AES_128_CBC_SHA, // 0x2f
} }
...@@ -610,11 +623,17 @@ const ( ...@@ -610,11 +623,17 @@ const (
// cipher suites missing from the crypto/tls package, // cipher suites missing from the crypto/tls package,
// in no particular order here // in no particular order here
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xc024 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xc024
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xc023
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xc028 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xc028
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x3c
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3d TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3d
TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x33 TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x33
TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x39 TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x39
TLS_RSA_WITH_RC4_128_MD5 = 0x4 TLS_RSA_WITH_RC4_128_MD5 = 0x4
// new PSK ciphers introduced by TLS 1.3, not (yet) in crypto/tls
// https://tlswg.github.io/tls13-spec/#rfc.appendix.A.4)
TLS_AES_128_GCM_SHA256 = 0x1301
TLS_AES_256_GCM_SHA384 = 0x1302
TLS_CHACHA20_POLY1305_SHA256 = 0x1303
TLS_AES_128_CCM_SHA256 = 0x1304
TLS_AES_128_CCM_8_SHA256 = 0x1305
) )
...@@ -139,6 +139,12 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) { ...@@ -139,6 +139,12 @@ func TestHeuristicFunctionsAndHandler(t *testing.T) {
helloHex: `010000bd030375f9022fc3a6562467f3540d68013b2d0b961979de6129e944efe0b35531323500001ec02bc02fcca9cca8c02cc030c00ac009c013c01400330039002f0035000a010000760000000e000c0000096c6f63616c686f737400170000ff01000100000a000a0008001d001700180019000b00020100002300000010000e000c02683208687474702f312e31000500050100000000ff030000000d0020001e040305030603020308040805080604010501060102010402050206020202`, helloHex: `010000bd030375f9022fc3a6562467f3540d68013b2d0b961979de6129e944efe0b35531323500001ec02bc02fcca9cca8c02cc030c00ac009c013c01400330039002f0035000a010000760000000e000c0000096c6f63616c686f737400170000ff01000100000a000a0008001d001700180019000b00020100002300000010000e000c02683208687474702f312e31000500050100000000ff030000000d0020001e040305030603020308040805080604010501060102010402050206020202`,
interception: false, interception: false,
}, },
{
// this was a Nightly release at the time
userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0",
helloHex: `010001fc030331e380b7d12018e1202ef3327607203df5c5732b4fa5ab5abaf0b60034c2fb662070c836b9b89123e37f4f1074d152df438fa8ee8a0f89b036fd952f4fcc0b994f001c130113031302c02bc02fcca9cca8c02cc030c013c014002f0035000a0100019700000014001200000f63616464797365727665722e636f6d00170000ff01000100000a000e000c001d00170018001901000101000b0002010000230078c97e7716a041e2ea824571bef26a3dff2bf50a883cd15d904ab2d17deb514f6e0a079ee7c212c000178387ffafc2e530b6df6662f570aae134330f13c458a0eaad5a96a9696f572110918740b15db1143d19aaaa706942030b433a7e6150f62b443c0564e5b8f7ee9577bf3bf7faec8c67425b648ab54d880010000e000c02683208687474702f312e310005000501000000000028006b0069001d0020aee6e596155ee6f79f943e81ceabe0979d27fbbb8b9189ccb2ebc75226351f32001700410421875a44e510decac11ef1d7cfddd4dfe105d5cd3a2d42fba03ebde23e51e8ce65bda1b48be82d4848d1db2bfce68e94092e925a9ce0dbf5df35479558108489002b0009087f12030303020301000d0018001604030503060308040805080604010501060102030201002d000201010015002500000000000000000000000000000000000000000000000000000000000000000000000000`,
interception: false,
},
}, },
"Edge": { "Edge": {
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment