Implement FingerprintClientHello to generate ClientHelloSpec from ClientHello raw bytes (#67)

This commit is contained in:
maxb 2020-12-09 21:37:06 -08:00 committed by GitHub
parent f7e7360167
commit 2179f28668
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1652 additions and 159 deletions

View file

@ -102,6 +102,26 @@ you can set UConn.HandshakeStateBuilt = true, and marshal clientHello into UConn
In this case you will be responsible for modifying other parts of Config and ClientHelloMsg to reflect your setup
and not confuse "crypto/tls", which will be processing response from server.
### Fingerprinting Captured Client Hello
You can use a captured client hello to generate new ones that mimic/have the same properties as the original.
The generated client hellos _should_ look like they were generated from the same client software as the original fingerprinted bytes.
In order to do this:
1) Create a `ClientHelloSpec` from the raw bytes of the original client hello
2) Use `HelloCustom` as an argument for `UClient()` to get empty config
3) Use `ApplyPreset` with the generated `ClientHelloSpec` to set the appropriate connection properties
```
uConn := UClient(&net.TCPConn{}, nil, HelloCustom)
fingerprinter := &Fingerprinter{}
generatedSpec, err := fingerprinter.FingerprintClientHello(rawCapturedClientHelloBytes)
if err != nil {
panic("fingerprinting failed: %v", err)
}
if err := uConn.ApplyPreset(generatedSpec); err != nil {
panic("applying generated spec failed: %v", err)
}
```
The `rawCapturedClientHelloBytes` should be the full tls record, including the record type/version/length header.
## Roller
A simple wrapper, that allows to easily use multiple latest(auto-updated) fingerprints.

View file

@ -0,0 +1,91 @@
>>> Flow 1 (client to server)
00000000 16 03 01 00 dd 01 00 00 d9 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 1c 0a 0a |................|
00000050 c0 2b c0 2f c0 2c c0 30 cc a9 cc a8 c0 13 c0 14 |.+./.,.0........|
00000060 00 9c 00 9d 00 2f 00 35 00 0a 01 00 00 74 0a 0a |...../.5.....t..|
00000070 00 00 ff 01 00 01 00 00 00 00 0b 00 09 00 00 06 |................|
00000080 66 6f 6f 62 61 72 00 17 00 00 00 23 00 00 00 0d |foobar.....#....|
00000090 00 14 00 12 04 03 08 04 04 01 05 03 08 05 05 01 |................|
000000a0 08 06 06 01 02 01 00 05 00 05 01 00 00 00 00 00 |................|
000000b0 12 00 00 00 10 00 0e 00 0c 02 68 32 08 68 74 74 |..........h2.htt|
000000c0 70 2f 31 2e 31 75 50 00 00 00 0b 00 02 01 00 00 |p/1.1uP.........|
000000d0 0a 00 0a 00 08 0a 0a 00 1d 00 17 00 18 1a 1a 00 |................|
000000e0 01 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 5d 02 00 00 59 03 03 e3 95 26 49 88 |....]...Y....&I.|
00000010 52 b1 c0 bf a0 61 e1 d2 52 f3 cd 1f bb c9 92 66 |R....a..R......f|
00000020 1a 84 ae 97 61 fd 74 68 cc 02 37 20 55 af 37 bb |....a.th..7 U.7.|
00000030 58 09 95 db 22 49 cd b2 c7 ca 5c a5 be b5 b0 b1 |X..."I....\.....|
00000040 cb af ba 27 97 41 d9 30 02 22 da 5d c0 2f 00 00 |...'.A.0.".]./..|
00000050 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 17 |................|
00000060 00 00 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 |......Y...U..R..|
00000070 4f 30 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 |O0..K0..........|
00000080 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 |....?.[..0...*.H|
00000090 86 f7 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 |........0.1.0...|
000000a0 55 04 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 |U....Go1.0...U..|
000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 |..Go Root0...160|
000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
000000d0 30 31 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 |01000000Z0.1.0..|
000000e0 03 55 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 |.U....Go1.0...U.|
000000f0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
00000100 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
00000110 81 00 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab |...F}...'.H..(!.|
00000120 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d |~...]..RE.z6G...|
00000130 92 42 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd |.B[.....y.@.Om..|
00000140 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a |+.....g....."8.J|
00000150 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 |.ts+.4......t{.X|
00000160 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c |.la<..A..++$#w[.|
00000170 3b bd 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 |;.u]. T..c...$..|
00000180 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 |..P....C...ub...|
00000190 52 d7 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |R.........0..0..|
000001a0 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
000001b0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
000001c0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
000001d0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
000001e0 0e 04 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d |.........CC>I..m|
000001f0 b6 80 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 |....`0...U.#..0.|
00000200 80 10 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab |..H.IM.~.1......|
00000210 6e 7b 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |n{0...U....0...e|
00000220 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
00000230 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
00000240 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed |.0.@+[P.a...SX..|
00000250 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 |.(.X..8....1Z..f|
00000260 3d 43 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a |=C.-...... d8.$:|
00000270 00 bc cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 |....}.@ ._...a..|
00000280 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed |v......\.....l..|
00000290 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 |s..Cw.......@.a.|
000002a0 4c 72 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 |Lr+...F..M...>..|
000002b0 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 |.B...=.`.\!.;...|
000002c0 16 03 03 00 ac 0c 00 00 a8 03 00 1d 20 c0 48 97 |............ .H.|
000002d0 bf 0d 8d 9e f9 bb 77 f4 0f 86 cc 81 ad 94 74 0e |......w.......t.|
000002e0 9d ef b2 27 52 f2 cf 60 1c 84 4b c3 59 08 04 00 |...'R..`..K.Y...|
000002f0 80 02 45 0b 36 e5 4b 48 d8 c3 7e 4f c3 43 6b b4 |..E.6.KH..~O.Ck.|
00000300 bd 6a a2 04 ee c4 59 32 a3 d2 5d 72 8d d8 49 b9 |.j....Y2..]r..I.|
00000310 de 31 04 bf dc f3 1a d8 31 d4 eb b4 98 e4 2c d3 |.1......1.....,.|
00000320 50 42 f6 cc 41 2f 75 aa 63 19 99 49 38 ec 0b ed |PB..A/u.c..I8...|
00000330 59 6a 82 58 ea 9c 58 d8 6b 88 60 35 b7 06 21 10 |Yj.X..X.k.`5..!.|
00000340 54 c8 d4 6b af fc 6e 2b 90 15 b1 87 ed aa 96 bb |T..k..n+........|
00000350 ad 8d dc e1 7b 48 bf da d2 70 eb cf 73 4a e6 60 |....{H...p..sJ.`|
00000360 ac ef 39 57 a6 ff 5d 34 bb 7b e1 e0 e5 11 67 62 |..9W..]4.{....gb|
00000370 6c 16 03 03 00 04 0e 00 00 00 |l.........|
>>> Flow 3 (client to server)
00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 eb f8 36 |....(..........6|
00000040 16 8e 9a 9f 52 62 a6 85 c3 05 4b 76 16 35 63 fe |....Rb....Kv.5c.|
00000050 0c c3 4a 1e f0 0e 24 b5 6e db 0d bc 65 |..J...$.n...e|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 28 5f 6d 17 67 11 |..........(_m.g.|
00000010 3a 9b 08 87 88 c2 6d ee 8a 1a 0f e9 30 fe 9a 30 |:.....m.....0..0|
00000020 63 ad 2e a1 a6 8f b8 4e fa c9 65 64 87 96 b4 66 |c......N..ed...f|
00000030 39 03 7b |9.{|
>>> Flow 5 (client to server)
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 68 fb 78 |.............h.x|
00000010 2f 1b 5b 21 fc e3 f5 39 69 29 63 35 54 71 06 4a |/.[!...9i)c5Tq.J|
00000020 fc f1 f9 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
00000030 10 fb 34 b1 37 06 12 4b c2 17 dd ef 2f 52 2e 22 |..4.7..K..../R."|
00000040 60 4f |`O|

View file

@ -0,0 +1,107 @@
>>> Flow 1 (client to server)
00000000 16 03 01 02 00 01 00 01 fc 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 22 0a 0a |............."..|
00000050 13 01 13 02 13 03 c0 2b c0 2f c0 2c c0 30 cc a9 |.......+./.,.0..|
00000060 cc a8 c0 13 c0 14 00 9c 00 9d 00 2f 00 35 00 0a |.........../.5..|
00000070 01 00 01 91 0a 0a 00 00 ff 01 00 01 00 00 00 00 |................|
00000080 0b 00 09 00 00 06 66 6f 6f 62 61 72 00 17 00 00 |......foobar....|
00000090 00 23 00 00 00 0d 00 14 00 12 04 03 08 04 04 01 |.#..............|
000000a0 05 03 08 05 05 01 08 06 06 01 02 01 00 05 00 05 |................|
000000b0 01 00 00 00 00 00 12 00 00 00 10 00 0e 00 0c 02 |................|
000000c0 68 32 08 68 74 74 70 2f 31 2e 31 75 50 00 00 00 |h2.http/1.1uP...|
000000d0 0b 00 02 01 00 00 33 00 2b 00 29 0a 0a 00 01 00 |......3.+.).....|
000000e0 00 1d 00 20 2f e5 7d a3 47 cd 62 43 15 28 da ac |... /.}.G.bC.(..|
000000f0 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f |_.).0.........._|
00000100 58 cb 3b 74 00 2d 00 02 01 01 00 2b 00 0b 0a 0a |X.;t.-.....+....|
00000110 0a 03 04 03 03 03 02 03 01 00 0a 00 0a 00 08 0a |................|
00000120 0a 00 1d 00 17 00 18 00 1b 00 03 02 00 02 1a 1a |................|
00000130 00 01 00 00 15 00 ce 00 00 00 00 00 00 00 00 00 |................|
00000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000200 00 00 00 00 00 |.....|
>>> Flow 2 (server to client)
00000000 16 03 03 00 7a 02 00 00 76 03 03 c5 4a de 6c e8 |....z...v...J.l.|
00000010 25 6d db 77 3b ef e6 22 28 0a 19 ec 58 2d ae a1 |%m.w;.."(...X-..|
00000020 57 f6 1b 08 52 c8 5d 79 4b b1 a4 20 00 00 00 00 |W...R.]yK.. ....|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 01 00 00 |................|
00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 df |..+.....3.$... .|
00000060 ec d9 e6 68 f6 90 5d 47 35 4b 5c 4d 2f 91 fe 68 |...h..]G5K\M/..h|
00000070 43 d8 0f f5 1e de 21 03 8e 4f d4 b1 f7 8f 58 14 |C.....!..O....X.|
00000080 03 03 00 01 01 17 03 03 00 17 10 ec 0b 62 a4 0e |.............b..|
00000090 bb 5d ea 09 4a 83 92 13 c8 a7 5e d6 8e 1b 11 91 |.]..J.....^.....|
000000a0 6b 17 03 03 02 6d ff 05 19 3f ec 22 b2 6d 0c ea |k....m...?.".m..|
000000b0 4d 4f 32 26 11 c6 b3 fd 29 04 e5 dc 50 ec ff 1f |MO2&....)...P...|
000000c0 fb af 2e c9 a0 6c 4a 58 17 b1 04 e8 3c bc 62 cd |.....lJX....<.b.|
000000d0 08 c1 42 d1 be 56 5d 70 25 f2 f1 37 be df 9f a7 |..B..V]p%..7....|
000000e0 1b f8 2b f9 3f 1c cc ed 66 d4 06 19 0e f9 ef bc |..+.?...f.......|
000000f0 aa ac c3 89 7e 22 30 5f 8e b7 ca 54 93 ae 29 b3 |....~"0_...T..).|
00000100 5d 9d 9e c2 9c 03 3f 0e 25 1f 9a 73 13 74 18 03 |].....?.%..s.t..|
00000110 94 7d 23 54 5b bd 9c 82 d1 ae cd 42 95 9b 37 a7 |.}#T[......B..7.|
00000120 7f 1c 75 5c 3a 21 5d aa 34 bb 9a d1 26 75 09 a7 |..u\:!].4...&u..|
00000130 4f 63 24 c2 50 90 28 a9 b3 92 61 ac 9f 68 f6 50 |Oc$.P.(...a..h.P|
00000140 eb 16 3f 1a 96 3f 36 2f e8 16 d2 2c 66 ee 80 b7 |..?..?6/...,f...|
00000150 0c 58 bf 0d f4 38 09 cb ad fa aa 22 a0 e7 66 bb |.X...8....."..f.|
00000160 27 7f 57 5c 82 24 f6 b5 af 4f a7 90 ba 60 62 3c |'.W\.$...O...`b<|
00000170 4d 74 b4 33 aa ab 23 07 11 84 3e bd 98 aa d5 42 |Mt.3..#...>....B|
00000180 a8 43 79 58 31 e7 e2 e6 52 bd 30 60 27 f9 da 17 |.CyX1...R.0`'...|
00000190 16 0b 7c 15 14 30 0e ae 11 16 e1 71 c9 cc f8 2f |..|..0.....q.../|
000001a0 91 31 34 09 95 6a 10 4b 04 73 27 77 73 4f 2e 7a |.14..j.K.s'wsO.z|
000001b0 27 b4 79 5e 3a 50 42 60 f8 e0 48 98 a3 b0 5c 6d |'.y^:PB`..H...\m|
000001c0 36 bd 2d 42 3c 82 0b 7e 81 55 a1 74 75 83 80 22 |6.-B<..~.U.tu.."|
000001d0 28 e0 41 4e 7d f5 7f f2 2a 5b b0 7d 39 ab 45 80 |(.AN}...*[.}9.E.|
000001e0 17 4c 41 b5 ec e5 4f 45 e0 ee 6c c0 64 0a 9a c3 |.LA...OE..l.d...|
000001f0 b4 46 df d6 bf 2b 23 96 44 e5 fc 29 9c d3 f0 7f |.F...+#.D..)....|
00000200 dd f9 63 86 07 90 be 0a d4 19 2c 1d 52 db aa 3d |..c.......,.R..=|
00000210 92 0d 07 94 71 f9 78 e6 41 84 4f 94 30 1c b5 ae |....q.x.A.O.0...|
00000220 3f de 5e 95 13 23 4b 43 42 87 68 05 48 41 d6 52 |?.^..#KCB.h.HA.R|
00000230 bc af 11 22 25 4a a3 2a 1c 7e 49 a2 ed 0f c5 27 |..."%J.*.~I....'|
00000240 3c 39 48 5b af a9 49 81 f2 b2 73 e3 dc de d5 fd |<9H[..I...s.....|
00000250 1c 32 a3 c8 7d bb 8c 5e 4c 25 24 a6 ae 86 d0 25 |.2..}..^L%$....%|
00000260 83 cb 38 16 62 27 f3 d8 57 cf eb 2f 27 24 55 c5 |..8.b'..W../'$U.|
00000270 7b 65 7a 25 b4 40 97 18 79 e1 fb 3b b6 12 2e 10 |{ez%.@..y..;....|
00000280 ac 89 21 9d f7 5a 3e 00 65 f8 6f 31 4b 02 2d 9f |..!..Z>.e.o1K.-.|
00000290 07 00 1e 2d 85 27 c1 17 4a 26 78 4a 0e eb ca b6 |...-.'..J&xJ....|
000002a0 32 57 48 7f 87 5a b2 ce 24 03 75 b9 d3 94 48 f9 |2WH..Z..$.u...H.|
000002b0 f4 b1 e8 89 ab 7e c9 75 c6 0d 18 cd c8 3a 05 9f |.....~.u.....:..|
000002c0 8a d9 42 39 30 69 0a d7 56 9d 3b 51 af 13 6a 59 |..B90i..V.;Q..jY|
000002d0 ea 72 e2 75 8a aa 3f 25 49 93 e5 a2 da f6 31 67 |.r.u..?%I.....1g|
000002e0 6a 68 af b4 6e 14 8e 75 91 b5 3d 24 52 11 da 0b |jh..n..u..=$R...|
000002f0 d0 66 db 8b 61 13 c7 93 0d bd bc b9 78 85 fd 12 |.f..a.......x...|
00000300 b5 56 84 3d 7b 75 9f 50 bf d6 a4 eb 8d 24 4c 11 |.V.={u.P.....$L.|
00000310 1c 16 4d 17 03 03 00 99 a8 de 68 0a 8c 77 18 87 |..M.......h..w..|
00000320 24 be eb 40 1d a0 f6 92 f2 ac 90 15 b7 6c 0b cc |$..@.........l..|
00000330 6c 85 54 42 d5 89 91 57 bc dd b6 7f ee a2 e0 6f |l.TB...W.......o|
00000340 17 92 23 cc 73 1e 16 f3 49 8c 82 ef 15 4f 8a be |..#.s...I....O..|
00000350 bd 07 8f 72 5c b1 fc b3 8c e9 a3 e1 ec 9d 7a a2 |...r\.........z.|
00000360 8f 68 1a 91 ab e8 d7 3a 67 b5 bc 8a 72 1f 2d 51 |.h.....:g...r.-Q|
00000370 ba 1a 2b 75 24 3f 0c 8a 79 a9 ac ba 71 da 0c 60 |..+u$?..y...q..`|
00000380 55 3b 60 2c 51 18 f8 ab c2 45 33 74 76 2e 2c eb |U;`,Q....E3tv.,.|
00000390 d0 d5 36 10 5a ee 88 2a 96 15 19 f3 aa ba b9 71 |..6.Z..*.......q|
000003a0 e6 40 42 a0 92 3a 76 22 de a6 f9 49 22 35 c2 56 |.@B..:v"...I"5.V|
000003b0 b2 17 03 03 00 35 5d 29 4e e1 67 87 54 08 21 98 |.....5])N.g.T.!.|
000003c0 a1 dd 93 e9 22 d2 4f 65 5e 41 99 1d 7e 72 c0 20 |....".Oe^A..~r. |
000003d0 2b f9 67 7a 79 68 3a 00 b1 99 39 fe 33 27 5e 4b |+.gzyh:...9.3'^K|
000003e0 67 aa fd 0e 3c b6 1f fd cb 91 e1 |g...<......|
>>> Flow 3 (client to server)
00000000 14 03 03 00 01 01 17 03 03 00 35 2c 4a 03 fc 16 |..........5,J...|
00000010 01 d8 10 25 27 1e 2d 0e b8 62 9c b4 f3 bd 50 a2 |...%'.-..b....P.|
00000020 d1 e7 9e 5f cb 2c d5 ce 5a 56 c5 50 ab 12 4b 69 |..._.,..ZV.P..Ki|
00000030 4c e3 eb 20 ca 91 e0 07 9c b4 6c 5b 79 d3 c5 a4 |L.. ......l[y...|
00000040 17 03 03 00 17 12 d5 76 2d 12 23 20 e5 a4 35 45 |.......v-.# ..5E|
00000050 7d 5a e1 bc a3 da 08 11 5e a5 3b 78 17 03 03 00 |}Z......^.;x....|
00000060 13 d7 07 1e 17 ef df 5d da 27 29 52 5a 9a ed a5 |.......].')RZ...|
00000070 07 1b 81 f1 |....|

View file

@ -0,0 +1,107 @@
>>> Flow 1 (client to server)
00000000 16 03 01 02 00 01 00 01 fc 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 24 13 01 |.............$..|
00000050 13 03 13 02 c0 2b c0 2f cc a9 cc a8 c0 2c c0 30 |.....+./.....,.0|
00000060 c0 0a c0 09 c0 13 c0 14 00 9c 00 9d 00 2f 00 35 |............./.5|
00000070 00 0a 01 00 01 8f 00 00 00 05 00 03 00 00 00 00 |................|
00000080 17 00 00 ff 01 00 01 00 00 0a 00 0e 00 0c 00 1d |................|
00000090 00 17 00 18 00 19 01 00 01 01 00 0b 00 02 01 00 |................|
000000a0 00 10 00 0e 00 0c 02 68 32 08 68 74 74 70 2f 31 |.......h2.http/1|
000000b0 2e 31 00 05 00 05 01 00 00 00 00 00 33 00 6b 00 |.1..........3.k.|
000000c0 69 00 1d 00 20 2f e5 7d a3 47 cd 62 43 15 28 da |i... /.}.G.bC.(.|
000000d0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
000000e0 5f 58 cb 3b 74 00 17 00 41 04 1e 18 37 ef 0d 19 |_X.;t...A...7...|
000000f0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
00000100 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
00000110 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
00000120 b5 68 1a 41 03 56 6b dc 5a 89 00 2b 00 05 04 03 |.h.A.Vk.Z..+....|
00000130 04 03 03 00 0d 00 18 00 16 04 03 05 03 06 03 08 |................|
00000140 04 08 05 08 06 04 01 05 01 06 01 02 03 02 01 00 |................|
00000150 1c 00 02 40 01 00 15 00 ac 00 00 00 00 00 00 00 |...@............|
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000200 00 00 00 00 00 |.....|
>>> Flow 2 (server to client)
00000000 16 03 03 00 7a 02 00 00 76 03 03 0c f4 d3 9a 51 |....z...v......Q|
00000010 ee f9 a7 5d ca 63 bc d1 41 e4 18 b3 11 4e b7 27 |...].c..A....N.'|
00000020 b2 81 9d ff 98 da 3c 9a 5c 0b 07 20 00 00 00 00 |......<.\.. ....|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 01 00 00 |................|
00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 3d |..+.....3.$... =|
00000060 58 17 cf 6c 8d 8a 8f f3 79 a9 c4 c9 3f 5e 15 f8 |X..l....y...?^..|
00000070 49 6a e0 61 be 0d 62 fd 20 6a ad 9d 66 71 57 14 |Ij.a..b. j..fqW.|
00000080 03 03 00 01 01 17 03 03 00 17 26 47 66 c9 a5 1d |..........&Gf...|
00000090 0c 10 9f 98 a7 47 33 8b ef aa 90 41 13 1c 34 b3 |.....G3....A..4.|
000000a0 ed 17 03 03 02 6d 8e 5f cb 3d 6f 38 a4 96 a4 7f |.....m._.=o8....|
000000b0 64 f4 7b 90 a8 83 f7 a9 42 ff 86 dd 18 5e aa 5f |d.{.....B....^._|
000000c0 01 0d 73 8f 4c 9e d2 f9 e2 c1 83 ec c5 cf 7a 6a |..s.L.........zj|
000000d0 20 2e 1f 81 55 0b cb e4 2e f9 5a cf 2d 13 5b 8c | ...U.....Z.-.[.|
000000e0 4b 15 3f ac 5c 35 87 60 a7 53 33 93 d9 8c b6 19 |K.?.\5.`.S3.....|
000000f0 cf 4f cb 18 0d 53 e1 11 3d f7 c0 f0 65 1c 1f 7a |.O...S..=...e..z|
00000100 92 fd 9f bb 93 08 b5 68 29 3a 5c b0 24 7a e9 37 |.......h):\.$z.7|
00000110 a8 e0 e8 a1 fd c2 34 d4 2f ae 48 dc 4d 78 95 dd |......4./.H.Mx..|
00000120 ae fe 88 02 74 bc d9 03 13 11 49 d1 ba b1 fb 49 |....t.....I....I|
00000130 92 8e ae ef 43 3e 19 85 70 46 28 20 b4 4b 6b 4e |....C>..pF( .KkN|
00000140 b1 8f a8 4b ce 48 4c 6f f0 12 5c 10 de 9e 37 d7 |...K.HLo..\...7.|
00000150 82 f3 f7 5e aa 3f 25 0b 74 e7 fa 7a 26 7b 88 c1 |...^.?%.t..z&{..|
00000160 a9 df cb 70 98 91 4a 4a ec f3 62 ef 13 42 71 5a |...p..JJ..b..BqZ|
00000170 ca ca 59 c6 4b c0 8b 0b 82 51 14 11 8c 7a c0 d6 |..Y.K....Q...z..|
00000180 42 5a 1d 7c ff d7 5e de 6e 99 f8 ee 55 aa 8f 27 |BZ.|..^.n...U..'|
00000190 b1 c0 65 a8 52 74 42 35 0d e5 3e 0e 0e 0c c4 a3 |..e.RtB5..>.....|
000001a0 32 63 1d 72 57 55 f1 a5 d5 f9 95 99 31 1c 09 d6 |2c.rWU......1...|
000001b0 48 58 cf 6e f7 8d a9 a7 c6 74 91 77 6c 28 13 65 |HX.n.....t.wl(.e|
000001c0 b8 53 f8 4b e1 1b 32 39 31 36 41 d2 35 4c 7b 82 |.S.K..2916A.5L{.|
000001d0 75 bc a6 66 b3 d2 df 51 c8 da 65 7e 94 93 0d e8 |u..f...Q..e~....|
000001e0 33 4c f8 c6 16 50 12 c7 06 0c 9e f9 57 36 3c e3 |3L...P......W6<.|
000001f0 94 ba 50 c7 ab 27 33 cb 7b 82 ce fc 39 1a c8 7f |..P..'3.{...9...|
00000200 59 85 d7 3c 37 ff fc b8 03 2b da 62 80 d3 c0 c6 |Y..<7....+.b....|
00000210 96 d0 fc 50 08 7e 02 25 c7 ca b6 6a 27 cc b8 d2 |...P.~.%...j'...|
00000220 58 15 18 58 01 67 10 c8 a0 0b b1 39 34 ce fe 64 |X..X.g.....94..d|
00000230 25 22 68 39 82 a7 21 ab e2 41 c6 35 dd 40 5c e7 |%"h9..!..A.5.@\.|
00000240 88 e5 b0 9e 8d 20 2a 9a f2 f7 6e d0 6e fe 06 9f |..... *...n.n...|
00000250 9f b4 56 e8 e4 1d cd 55 5c 68 6e 8d 40 77 e6 d5 |..V....U\hn.@w..|
00000260 98 73 8f d2 53 34 1c 15 aa ad 27 51 ef 31 b2 0f |.s..S4....'Q.1..|
00000270 94 d5 69 1f 70 ec e3 ac 0c cc a3 a1 d7 61 ee 1e |..i.p........a..|
00000280 15 83 bd 41 9f 4c 2b d3 cc d8 06 d8 d8 a4 d3 64 |...A.L+........d|
00000290 95 49 e4 03 73 54 f6 f7 24 3d c3 a6 f3 6a 19 dc |.I..sT..$=...j..|
000002a0 a3 00 00 7e 56 f2 f9 26 5f 09 ca c5 b0 eb 58 d8 |...~V..&_.....X.|
000002b0 22 93 c9 ce 5d f7 63 72 7d 72 56 77 38 08 f9 86 |"...].cr}rVw8...|
000002c0 8e 8f ad 8c 02 64 36 fe b8 09 d7 0e 58 73 aa 99 |.....d6.....Xs..|
000002d0 d1 d1 60 4c 65 5f 80 ed 13 0d a0 19 b4 b5 d3 8a |..`Le_..........|
000002e0 ba dc 84 94 af 7a 77 61 b0 bb 01 38 d2 6d 82 6d |.....zwa...8.m.m|
000002f0 22 08 17 17 16 0c 48 25 c3 b9 35 ff 78 7b ab af |".....H%..5.x{..|
00000300 63 9a d9 83 d1 65 2a 3e 7f b0 90 dd 67 c1 be 0a |c....e*>....g...|
00000310 14 e5 17 17 03 03 00 99 ff 0b c2 4f 7d 1f 7a 8e |...........O}.z.|
00000320 15 a1 53 35 e1 bd c7 20 ad 87 e9 22 99 0b 46 76 |..S5... ..."..Fv|
00000330 1f 9d 87 6c 64 ef 5f 34 66 fa c5 6a af bd c5 34 |...ld._4f..j...4|
00000340 c8 32 f4 c4 06 3e 85 b4 41 e9 1a e8 98 c1 69 20 |.2...>..A.....i |
00000350 3e ec 84 ae 63 27 98 e5 81 07 89 8b d5 74 6f b1 |>...c'.......to.|
00000360 80 b9 fb e0 f8 d8 ef 3e 00 d8 57 97 41 87 26 02 |.......>..W.A.&.|
00000370 a9 58 83 5a 5f ad 3c 1f ed 24 50 fe a3 3b 70 be |.X.Z_.<..$P..;p.|
00000380 bd 03 19 d6 6a 46 72 7a 68 36 bb 40 e5 88 bc 1e |....jFrzh6.@....|
00000390 cc 02 3d 09 0b 59 be 40 71 44 0c 34 17 40 bf 46 |..=..Y.@qD.4.@.F|
000003a0 c6 6c 01 05 bd a1 83 e7 ad 12 1c 9d 78 c5 08 a2 |.l..........x...|
000003b0 26 17 03 03 00 35 0b c5 51 ec 7b c5 96 9d 93 b6 |&....5..Q.{.....|
000003c0 1e 71 3f 2d 34 32 50 c1 77 08 ce e9 83 59 47 da |.q?-42P.w....YG.|
000003d0 b5 8c 5e cf 58 89 da 98 c4 b8 73 c0 1c f6 30 bd |..^.X.....s...0.|
000003e0 c2 b1 34 7a 1a 54 ad ef c2 2b 2b |..4z.T...++|
>>> Flow 3 (client to server)
00000000 14 03 03 00 01 01 17 03 03 00 35 5e 98 29 74 04 |..........5^.)t.|
00000010 bb f5 5e 17 dc 36 8f cb 3c e0 45 1a d2 54 ae f6 |..^..6..<.E..T..|
00000020 3a 36 59 c0 fa dc 2d e7 73 66 ca af d5 c7 e6 0d |:6Y...-.sf......|
00000030 e1 23 17 a3 88 85 16 83 16 ec 78 d3 78 bc 39 ba |.#........x.x.9.|
00000040 17 03 03 00 17 91 53 7f ab 3a 4a a0 d2 e5 0a 7e |......S..:J....~|
00000050 e9 52 2a fa de f8 f8 20 76 ad 9f 48 17 03 03 00 |.R*.... v..H....|
00000060 13 0d 74 fc f8 27 c1 fd 06 b1 3a 5c 2d 37 63 dd |..t..'....:\-7c.|
00000070 5c 59 28 9a |\Y(.|

View file

@ -162,6 +162,20 @@ var (
// https://tools.ietf.org/html/draft-ietf-tls-grease-01
const GREASE_PLACEHOLDER = 0x0a0a
func isGREASEUint16(v uint16) bool {
// First byte is same as second byte
// and lowest nibble is 0xa
return ((v >> 8) == v&0xff) && v&0xf == 0xa
}
func unGREASEUint16(v uint16) uint16 {
if isGREASEUint16(v) {
return GREASE_PLACEHOLDER
} else {
return v
}
}
// utlsMacSHA384 returns a SHA-384 based MAC. These are only supported in TLS 1.2
// so the given version is ignored.
func utlsMacSHA384(version uint16, key []byte) macFunction {

33
u_common_test.go Normal file
View file

@ -0,0 +1,33 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
import (
"testing"
)
func TestUTLSIsGrease(t *testing.T) {
var testMap = []struct {
version uint16
isGREASE bool
}{
{0x0a0a, true},
{0x1a1a, true},
{0x2a1a, false},
{0x2a2a, true},
{0x1234, false},
{0x1a2a, false},
{0xdeed, false},
{0xb1b1, false},
{0x0b0b, false},
}
for _, testCase := range testMap {
if isGREASEUint16(testCase.version) != testCase.isGREASE {
t.Errorf("misidentified GREASE: testing %x, isGREASE: %v", testCase.version, isGREASEUint16(testCase.version))
}
}
}

View file

@ -17,6 +17,28 @@ import (
"time"
)
// helloStrategy is a sum type interface which allows us to pass either a ClientHelloID or a ClientHelloSpec and then act accordingly
type helloStrategy interface {
helloName() string
}
type helloID struct {
id ClientHelloID
}
func (hid *helloID) helloName() string {
return hid.id.Str()
}
type helloSpec struct {
name string
spec *ClientHelloSpec
}
func (hs *helloSpec) helloName() string {
return hs.name
}
func TestUTLSMarshalNoOp(t *testing.T) {
str := "We rely on clientHelloMsg.marshal() not doing anything if clientHelloMsg.raw is set"
uconn := UClient(&net.TCPConn{}, &Config{ServerName: "foobar"}, HelloGolang)
@ -32,146 +54,146 @@ func TestUTLSMarshalNoOp(t *testing.T) {
}
func TestUTLSHandshakeClientParrotGolang(t *testing.T) {
helloID := HelloGolang
hello := &helloID{HelloGolang}
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, hello)
}
func TestUTLSHandshakeClientParrotChrome_70(t *testing.T) {
helloID := HelloChrome_70
hello := &helloID{HelloChrome_70}
testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t, helloID)
testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, helloID)
testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t, hello)
testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t, hello)
testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, hello)
}
func TestUTLSHandshakeClientParrotChrome_58(t *testing.T) {
helloID := HelloChrome_58
hello := &helloID{HelloChrome_58}
// TODO: EC tests below are disabled because latest version of reference OpenSSL doesn't support p256 nor p384
// nor X25519 and I can't find configuration flag to enable it. Therefore I can't record replays.
//testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, hello)
}
func TestUTLSHandshakeClientParrotFirefox_63(t *testing.T) {
helloID := HelloFirefox_63
hello := &helloID{HelloFirefox_63}
testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t, helloID)
testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t, helloID)
testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t, hello)
testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t, hello)
testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, helloID) TODO: enable when OpenSSL supports it
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello) TODO: enable when OpenSSL supports it
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
}
func TestUTLSHandshakeClientParrotFirefox_55(t *testing.T) {
helloID := HelloFirefox_55
hello := &helloID{HelloFirefox_55}
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, helloID) TODO: enable when OpenSSL supports it
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, helloID)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello) TODO: enable when OpenSSL supports it
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
}
func TestUTLSHandshakeClientParrotChrome_58_setclienthello(t *testing.T) {
helloID := HelloChrome_58
hello := &helloID{HelloChrome_58}
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-setclienthello-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
name: "UTLS-setclienthello-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
// tests consistency of fingerprint after HelloRetryRequest
// chrome 70 is used, due to only specifying X25519 in keyshare, but being able to generate P-256 curve too
// openssl server, configured to use P-256, will send HelloRetryRequest
func TestUTLSHelloRetryRequest(t *testing.T) {
helloID := HelloChrome_70
hello := &helloID{HelloChrome_70}
config := testConfig.Clone()
config.CurvePreferences = []CurveID{X25519, CurveP256}
test := &clientTest{
name: "UTLS-HelloRetryRequest-" + helloID.Str(),
args: []string{"-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "P-256"},
config: config,
name: "UTLS-HelloRetryRequest-" + hello.helloName(),
args: []string{"-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "P-256"},
config: config,
}
runUTLSClientTestTLS13(t, test, helloID)
runUTLSClientTestTLS13(t, test, hello)
}
func TestUTLSRemoveSNIExtension(t *testing.T) {
helloID := HelloChrome_70
hello := &helloID{HelloChrome_70}
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str() + "-OmitSNI",
name: "UTLS-" + opensslCipherName + "-" + hello.helloName() + "-OmitSNI",
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", helloID, true)
runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", hello, true)
}
/*
@ -194,192 +216,192 @@ func getUTLSTestConfig() *Config {
return testUTLSConfig
}
func testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES256-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES128-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES256-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES256-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "TLS_AES_128_GCM_SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
}
runUTLSClientTestTLS13(t, test, helloID)
runUTLSClientTestTLS13(t, test, hello)
}
func testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "TLS_AES_256_GCM_SHA384"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
}
runUTLSClientTestTLS13(t, test, helloID)
runUTLSClientTestTLS13(t, test, hello)
}
func testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "TLS_CHACHA20_POLY1305_SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
}
runUTLSClientTestTLS13(t, test, helloID)
runUTLSClientTestTLS13(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}
opensslCipherName := "ECDHE-RSA-CHACHA20-POLY1305"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t *testing.T, helloID ClientHelloID) {
func testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}
opensslCipherName := "ECDHE-ECDSA-CHACHA20-POLY1305"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
args: []string{"-cipher", opensslCipherName},
config: config,
cert: testECDSACertificate,
key: testECDSAPrivateKey,
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
cert: testECDSACertificate,
key: testECDSAPrivateKey,
}
runUTLSClientTestTLS12(t, test, helloID)
runUTLSClientTestTLS12(t, test, hello)
}
func runUTLSClientTestForVersion(t *testing.T, template *clientTest, prefix, option string, helloID ClientHelloID, omitSNI bool) {
func runUTLSClientTestForVersion(t *testing.T, template *clientTest, prefix, option string, hello helloStrategy, omitSNI bool) {
test := *template
test.name = prefix + test.name
if len(test.args) == 0 {
@ -387,18 +409,18 @@ func runUTLSClientTestForVersion(t *testing.T, template *clientTest, prefix, opt
}
test.args = append([]string(nil), test.args...)
test.args = append(test.args, option)
test.runUTLS(t, *update, helloID, omitSNI)
test.runUTLS(t, *update, hello, omitSNI)
}
func runUTLSClientTestTLS12(t *testing.T, template *clientTest, helloID ClientHelloID) {
runUTLSClientTestForVersion(t, template, "TLSv12-", "-tls1_2", helloID, false)
func runUTLSClientTestTLS12(t *testing.T, template *clientTest, hello helloStrategy) {
runUTLSClientTestForVersion(t, template, "TLSv12-", "-tls1_2", hello, false)
}
func runUTLSClientTestTLS13(t *testing.T, template *clientTest, helloID ClientHelloID) {
runUTLSClientTestForVersion(t, template, "TLSv13-", "-tls1_3", helloID, false)
func runUTLSClientTestTLS13(t *testing.T, template *clientTest, hello helloStrategy) {
runUTLSClientTestForVersion(t, template, "TLSv13-", "-tls1_3", hello, false)
}
func (test *clientTest) runUTLS(t *testing.T, write bool, helloID ClientHelloID, omitSNIExtension bool) {
func (test *clientTest) runUTLS(t *testing.T, write bool, hello helloStrategy, omitSNIExtension bool) {
checkOpenSSLVersion(t)
var clientConn, serverConn net.Conn
@ -423,7 +445,20 @@ func (test *clientTest) runUTLS(t *testing.T, write bool, helloID ClientHelloID,
t.Error("Explicit config is mandatory")
return
}
client := UClient(clientConn, config, helloID)
var client *UConn
switch h := hello.(type) {
case *helloID:
client = UClient(clientConn, config, h.id)
case *helloSpec:
client = UClient(clientConn, config, HelloCustom)
if err := client.ApplyPreset(h.spec); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
return
}
default:
panic("unknown helloStrategy")
}
if omitSNIExtension {
if err := client.RemoveSNIExtension(); err != nil {

360
u_fingerprinter.go Normal file
View file

@ -0,0 +1,360 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
import (
"errors"
"fmt"
"strings"
"golang.org/x/crypto/cryptobyte"
)
// Fingerprinter is a struct largely for holding options for the FingerprintClientHello func
type Fingerprinter struct {
// KeepPSK will ensure that the PreSharedKey extension is passed along into the resulting ClientHelloSpec as-is
KeepPSK bool
// AllowBluntMimicry will ensure that unknown extensions are
// passed along into the resulting ClientHelloSpec as-is
// It will not ensure that the PSK is passed along, if you require that, use KeepPSK
// WARNING: there could be numerous subtle issues with ClientHelloSpecs
// that are generated with this flag which could compromise security and/or mimicry
AllowBluntMimicry bool
// AlwaysAddPadding will always add a UtlsPaddingExtension with BoringPaddingStyle
// at the end of the extensions list if it isn't found in the fingerprinted hello.
// This could be useful in scenarios where the hello you are fingerprinting does not
// have any padding, but you suspect that other changes you make to the final hello
// (including things like different SNI lengths) would cause padding to be necessary
AlwaysAddPadding bool
}
// FingerprintClientHello returns a ClientHelloSpec which is based on the
// ClientHello that is passed in as the data argument
//
// If the ClientHello passed in has extensions that are not recognized or cannot be handled
// it will return a non-nil error and a nil *ClientHelloSpec value
//
// The data should be the full tls record, including the record type/version/length header
// as well as the handshake type/length/version header
// https://tools.ietf.org/html/rfc5246#section-6.2
// https://tools.ietf.org/html/rfc5246#section-7.4
func (f *Fingerprinter) FingerprintClientHello(data []byte) (*ClientHelloSpec, error) {
clientHelloSpec := &ClientHelloSpec{}
s := cryptobyte.String(data)
var contentType uint8
var recordVersion uint16
if !s.ReadUint8(&contentType) || // record type
!s.ReadUint16(&recordVersion) || !s.Skip(2) { // record version and length
return nil, errors.New("unable to read record type, version, and length")
}
if recordType(contentType) != recordTypeHandshake {
return nil, errors.New("record is not a handshake")
}
var handshakeVersion uint16
var handshakeType uint8
if !s.ReadUint8(&handshakeType) || !s.Skip(3) || // message type and 3 byte length
!s.ReadUint16(&handshakeVersion) || !s.Skip(32) { // 32 byte random
return nil, errors.New("unable to read handshake message type, length, and random")
}
if handshakeType != typeClientHello {
return nil, errors.New("handshake message is not a ClientHello")
}
clientHelloSpec.TLSVersMin = recordVersion
clientHelloSpec.TLSVersMax = handshakeVersion
var ignoredSessionID cryptobyte.String
if !s.ReadUint8LengthPrefixed(&ignoredSessionID) {
return nil, errors.New("unable to read session id")
}
var cipherSuitesBytes cryptobyte.String
if !s.ReadUint16LengthPrefixed(&cipherSuitesBytes) {
return nil, errors.New("unable to read ciphersuites")
}
cipherSuites := []uint16{}
for !cipherSuitesBytes.Empty() {
var suite uint16
if !cipherSuitesBytes.ReadUint16(&suite) {
return nil, errors.New("unable to read ciphersuite")
}
cipherSuites = append(cipherSuites, unGREASEUint16(suite))
}
clientHelloSpec.CipherSuites = cipherSuites
if !readUint8LengthPrefixed(&s, &clientHelloSpec.CompressionMethods) {
return nil, errors.New("unable to read compression methods")
}
if s.Empty() {
// ClientHello is optionally followed by extension data
return clientHelloSpec, nil
}
var extensions cryptobyte.String
if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
return nil, errors.New("unable to read extensions data")
}
for !extensions.Empty() {
var extension uint16
var extData cryptobyte.String
if !extensions.ReadUint16(&extension) ||
!extensions.ReadUint16LengthPrefixed(&extData) {
return nil, errors.New("unable to read extension data")
}
switch extension {
case extensionServerName:
// RFC 6066, Section 3
var nameList cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
return nil, errors.New("unable to read server name extension data")
}
var serverName string
for !nameList.Empty() {
var nameType uint8
var serverNameBytes cryptobyte.String
if !nameList.ReadUint8(&nameType) ||
!nameList.ReadUint16LengthPrefixed(&serverNameBytes) ||
serverNameBytes.Empty() {
return nil, errors.New("unable to read server name extension data")
}
if nameType != 0 {
continue
}
if len(serverName) != 0 {
return nil, errors.New("multiple names of the same name_type in server name extension are prohibited")
}
serverName = string(serverNameBytes)
if strings.HasSuffix(serverName, ".") {
return nil, errors.New("SNI value may not include a trailing dot")
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SNIExtension{})
}
case extensionNextProtoNeg:
// draft-agl-tls-nextprotoneg-04
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &NPNExtension{})
case extensionStatusRequest:
// RFC 4366, Section 3.6
var statusType uint8
var ignored cryptobyte.String
if !extData.ReadUint8(&statusType) ||
!extData.ReadUint16LengthPrefixed(&ignored) ||
!extData.ReadUint16LengthPrefixed(&ignored) {
return nil, errors.New("unable to read status request extension data")
}
if statusType == statusTypeOCSP {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &StatusRequestExtension{})
} else {
return nil, errors.New("status request extension statusType is not statusTypeOCSP")
}
case extensionSupportedCurves:
// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
var curvesBytes cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&curvesBytes) || curvesBytes.Empty() {
return nil, errors.New("unable to read supported curves extension data")
}
curves := []CurveID{}
for !curvesBytes.Empty() {
var curve uint16
if !curvesBytes.ReadUint16(&curve) {
return nil, errors.New("unable to read supported curves extension data")
}
curves = append(curves, CurveID(unGREASEUint16(curve)))
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SupportedCurvesExtension{curves})
case extensionSupportedPoints:
// RFC 4492, Section 5.1.2
supportedPoints := []uint8{}
if !readUint8LengthPrefixed(&extData, &supportedPoints) ||
len(supportedPoints) == 0 {
return nil, errors.New("unable to read supported points extension data")
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SupportedPointsExtension{supportedPoints})
case extensionSessionTicket:
// RFC 5077, Section 3.2
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SessionTicketExtension{})
case extensionSignatureAlgorithms:
// RFC 5246, Section 7.4.1.4.1
var sigAndAlgs cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
return nil, errors.New("unable to read signature algorithms extension data")
}
supportedSignatureAlgorithms := []SignatureScheme{}
for !sigAndAlgs.Empty() {
var sigAndAlg uint16
if !sigAndAlgs.ReadUint16(&sigAndAlg) {
return nil, errors.New("unable to read signature algorithms extension data")
}
supportedSignatureAlgorithms = append(
supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SignatureAlgorithmsExtension{supportedSignatureAlgorithms})
case extensionSignatureAlgorithmsCert:
// RFC 8446, Section 4.2.3
if f.AllowBluntMimicry {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData})
} else {
return nil, errors.New("unsupported extension SignatureAlgorithmsCert")
}
case extensionRenegotiationInfo:
// RFC 5746, Section 3.2
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &RenegotiationInfoExtension{RenegotiateOnceAsClient})
case extensionALPN:
// RFC 7301, Section 3.1
var protoList cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
return nil, errors.New("unable to read ALPN extension data")
}
alpnProtocols := []string{}
for !protoList.Empty() {
var proto cryptobyte.String
if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
return nil, errors.New("unable to read ALPN extension data")
}
alpnProtocols = append(alpnProtocols, string(proto))
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &ALPNExtension{alpnProtocols})
case extensionSCT:
// RFC 6962, Section 3.3.1
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SCTExtension{})
case extensionSupportedVersions:
// RFC 8446, Section 4.2.1
var versList cryptobyte.String
if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
return nil, errors.New("unable to read supported versions extension data")
}
supportedVersions := []uint16{}
for !versList.Empty() {
var vers uint16
if !versList.ReadUint16(&vers) {
return nil, errors.New("unable to read supported versions extension data")
}
supportedVersions = append(supportedVersions, unGREASEUint16(vers))
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &SupportedVersionsExtension{supportedVersions})
// If SupportedVersionsExtension is present, use that instead of record+handshake versions
clientHelloSpec.TLSVersMin = 0
clientHelloSpec.TLSVersMax = 0
case extensionKeyShare:
// RFC 8446, Section 4.2.8
var clientShares cryptobyte.String
if !extData.ReadUint16LengthPrefixed(&clientShares) {
return nil, errors.New("unable to read key share extension data")
}
keyShares := []KeyShare{}
for !clientShares.Empty() {
var ks KeyShare
var group uint16
if !clientShares.ReadUint16(&group) ||
!readUint16LengthPrefixed(&clientShares, &ks.Data) ||
len(ks.Data) == 0 {
return nil, errors.New("unable to read key share extension data")
}
ks.Group = CurveID(unGREASEUint16(group))
// if not GREASE, key share data will be discarded as it should
// be generated per connection
if ks.Group != GREASE_PLACEHOLDER {
ks.Data = nil
}
keyShares = append(keyShares, ks)
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &KeyShareExtension{keyShares})
case extensionPSKModes:
// RFC 8446, Section 4.2.9
// TODO: PSK Modes have their own form of GREASE-ing which is not currently implemented
// the current functionality will NOT re-GREASE/re-randomize these values when using a fingerprinted spec
// https://github.com/refraction-networking/utls/pull/58#discussion_r522354105
// https://tools.ietf.org/html/draft-ietf-tls-grease-01#section-2
pskModes := []uint8{}
if !readUint8LengthPrefixed(&extData, &pskModes) {
return nil, errors.New("unable to read PSK extension data")
}
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &PSKKeyExchangeModesExtension{pskModes})
case utlsExtensionExtendedMasterSecret:
// https://tools.ietf.org/html/rfc7627
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &UtlsExtendedMasterSecretExtension{})
case utlsExtensionPadding:
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle})
case fakeExtensionChannelID, fakeCertCompressionAlgs, fakeRecordSizeLimit:
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData})
case extensionPreSharedKey:
// RFC 8446, Section 4.2.11
if f.KeepPSK {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData})
} else {
return nil, errors.New("unsupported extension PreSharedKey")
}
case extensionCookie:
// RFC 8446, Section 4.2.2
if f.AllowBluntMimicry {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData})
} else {
return nil, errors.New("unsupported extension Cookie")
}
case extensionEarlyData:
// RFC 8446, Section 4.2.10
if f.AllowBluntMimicry {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData})
} else {
return nil, errors.New("unsupported extension EarlyData")
}
default:
if isGREASEUint16(extension) {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &UtlsGREASEExtension{unGREASEUint16(extension), extData})
} else if f.AllowBluntMimicry {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &GenericExtension{extension, extData})
} else {
return nil, fmt.Errorf("unsupported extension %#x", extension)
}
continue
}
}
if f.AlwaysAddPadding {
alreadyHasPadding := false
for _, ext := range clientHelloSpec.Extensions {
if _, ok := ext.(*UtlsPaddingExtension); ok {
alreadyHasPadding = true
break
}
}
if !alreadyHasPadding {
clientHelloSpec.Extensions = append(clientHelloSpec.Extensions, &UtlsPaddingExtension{GetPaddingLen: BoringPaddingStyle})
}
}
return clientHelloSpec, nil
}

716
u_fingerprinter_test.go Normal file
View file

@ -0,0 +1,716 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
import (
"bytes"
"encoding/hex"
"fmt"
"io/ioutil"
"net"
"reflect"
"testing"
)
func assertEquality(t *testing.T, fieldName string, expected, actual interface{}) {
if kActual, ok := actual.(KeyShare); ok {
kExpected := expected.(KeyShare)
assertEquality(t, fieldName, kExpected.Group, kActual.Group)
return
}
if fieldName == "SupportedCurves" || fieldName == "KeyShares" {
cExpected := expected.(CurveID)
cActual := actual.(CurveID)
if isGREASEUint16(uint16(cExpected)) && isGREASEUint16(uint16(cActual)) {
return
}
}
if fieldName == "SupportedVersions" || fieldName == "CipherSuites" {
cExpected := expected.(uint16)
cActual := actual.(uint16)
if isGREASEUint16(cExpected) && isGREASEUint16(cActual) {
return
}
}
if expected != actual {
t.Errorf("%v fields not equal, expected: %v, got: %v", fieldName, expected, actual)
}
}
func compareClientHelloFields(t *testing.T, fieldName string, expected, actual *ClientHelloMsg) {
rExpected := reflect.ValueOf(expected)
if rExpected.Kind() != reflect.Ptr || rExpected.Elem().Kind() != reflect.Struct {
t.Errorf("Error using reflect to compare Hello fields")
}
rActual := reflect.ValueOf(actual)
if rActual.Kind() != reflect.Ptr || rActual.Elem().Kind() != reflect.Struct {
t.Errorf("Error using reflect to compare Hello fields")
}
rExpected = rExpected.Elem()
rActual = rActual.Elem()
fExpected := rExpected.FieldByName(fieldName)
fActual := rActual.FieldByName(fieldName)
if !(fExpected.IsValid() && fActual.IsValid()) {
t.Errorf("Error using reflect to lookup Hello field name: %v", fieldName)
}
if fExpected.Kind() == reflect.Slice {
sExpected := fExpected.Slice(0, fExpected.Len())
sActual := fActual.Slice(0, fActual.Len())
if sExpected.Len() != sActual.Len() {
t.Errorf("%v fields slice length not equal, expected: %v, got: %v", fieldName, fExpected, fActual)
}
for i := 0; i < sExpected.Len(); i++ {
assertEquality(t, fieldName, sExpected.Index(i).Interface(), sActual.Index(i).Interface())
}
} else {
assertEquality(t, fieldName, fExpected.Interface(), fActual.Interface())
}
}
func checkUTLSExtensionsEquality(t *testing.T, expected, actual TLSExtension) {
if expectedGrease, ok := expected.(*UtlsGREASEExtension); ok {
if actualGrease, ok := actual.(*UtlsGREASEExtension); ok {
if bytes.Equal(expectedGrease.Body, actualGrease.Body) {
return
}
}
}
if expected.Len() != actual.Len() {
t.Errorf("extension types length not equal\nexpected: %#v\ngot: %#v", expected, actual)
}
actualBytes, err := ioutil.ReadAll(actual)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
expectedBytes, err := ioutil.ReadAll(expected)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
logInequality := func() {
t.Errorf("extensions not equal\nexpected: %#v\nbytes:%#x\ngot: %#v\nbytes: %#x", expected, expectedBytes, actual, actualBytes)
}
if !bytes.Equal(expectedBytes, actualBytes) {
// handle all the cases where GREASE or other factors can cause byte unalignment
// at this point concrete types must match
expectedType := reflect.TypeOf(expected)
actualType := reflect.TypeOf(actual)
if expectedType != actualType {
t.Errorf("extensions not equal\nexpected: %#v\nbytes:%#x\ngot: %#v\nbytes: %#x", expected, expectedBytes, actual, actualBytes)
return
}
switch expectedExtension := expected.(type) {
case *SupportedCurvesExtension:
actualExtension := expected.(*SupportedCurvesExtension)
for i, expectedCurve := range expectedExtension.Curves {
actualCurve := actualExtension.Curves[i]
if expectedCurve == actualCurve {
continue
}
if isGREASEUint16(uint16(expectedCurve)) && isGREASEUint16(uint16(actualCurve)) {
continue
}
logInequality()
return
}
case *KeyShareExtension:
actualExtension := expected.(*KeyShareExtension)
for i, expectedKeyShare := range expectedExtension.KeyShares {
actualKeyShare := actualExtension.KeyShares[i]
// KeyShare data is unique per connection
if actualKeyShare.Group == expectedKeyShare.Group {
continue
}
if isGREASEUint16(uint16(expectedKeyShare.Group)) && isGREASEUint16(uint16(actualKeyShare.Group)) {
continue
}
logInequality()
return
}
case *SupportedVersionsExtension:
actualExtension := expected.(*SupportedVersionsExtension)
for i, expectedVersion := range expectedExtension.Versions {
actualVersion := actualExtension.Versions[i]
if isGREASEUint16(expectedVersion) && isGREASEUint16(actualVersion) || actualVersion == expectedVersion {
continue
}
logInequality()
return
}
default:
logInequality()
return
}
}
}
// Conn.vers is sometimes left to zero which is unacceptable to uTLS' SetTLSVers
// https://github.com/refraction-networking/utls/blob/f7e7360167ed2903ef12898634512b66f8c3aad0/u_conn.go#L564-L566
// https://github.com/refraction-networking/utls/blob/f7e7360167ed2903ef12898634512b66f8c3aad0/conn.go#L945-L948
func createMinTLSVersion(vers uint16) uint16 {
if vers == 0 {
return VersionTLS10
}
return vers
}
// prependRecordHeader prepends a record header to a handshake messsage
// if attempting to mimic an existing connection the minTLSVersion can be found
// in the Conn.vers field
func prependRecordHeader(hello []byte, minTLSVersion uint16) []byte {
l := len(hello)
if minTLSVersion == 0 {
minTLSVersion = VersionTLS10
}
header := []byte{
uint8(recordTypeHandshake), // type
uint8(minTLSVersion >> 8 & 0xff), uint8(minTLSVersion & 0xff), // record version is the minimum supported
uint8(l >> 8 & 0xff), uint8(l & 0xff), // length
}
return append(header, hello...)
}
func checkUTLSFingerPrintClientHello(t *testing.T, clientHelloID ClientHelloID, serverName string) {
uconn := UClient(&net.TCPConn{}, &Config{ServerName: serverName}, clientHelloID)
if err := uconn.BuildHandshakeState(); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
generatedUConn := UClient(&net.TCPConn{}, &Config{ServerName: "foobar"}, HelloCustom)
fingerprinter := &Fingerprinter{}
minTLSVers := createMinTLSVersion(uconn.vers)
generatedSpec, err := fingerprinter.FingerprintClientHello(prependRecordHeader(uconn.HandshakeState.Hello.Raw, minTLSVers))
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
if err := generatedUConn.ApplyPreset(generatedSpec); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
if err := generatedUConn.BuildHandshakeState(); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
if len(uconn.HandshakeState.Hello.Raw) != len(generatedUConn.HandshakeState.Hello.Raw) {
t.Errorf("UConn from fingerprint has %d length, should have %d", len(generatedUConn.HandshakeState.Hello.Raw), len(uconn.HandshakeState.Hello.Raw))
}
// We can't effectively check the extensions on randomized client hello ids
if !(clientHelloID == HelloRandomized || clientHelloID == HelloRandomizedALPN || clientHelloID == HelloRandomizedNoALPN) {
for i, originalExtension := range uconn.Extensions {
if _, ok := originalExtension.(*UtlsPaddingExtension); ok {
// We can't really compare padding extensions in this way
continue
}
generatedExtension := generatedUConn.Extensions[i]
checkUTLSExtensionsEquality(t, originalExtension, generatedExtension)
}
}
fieldsToTest := []string{
"Vers", "CipherSuites", "CompressionMethods", "NextProtoNeg", "ServerName", "OcspStapling", "Scts", "SupportedCurves",
"SupportedPoints", "TicketSupported", "SupportedSignatureAlgorithms", "SecureRenegotiation", "SecureRenegotiationSupported", "AlpnProtocols",
"SupportedSignatureAlgorithmsCert", "SupportedVersions", "KeyShares", "EarlyData", "PskModes", "PskIdentities", "PskBinders",
}
for _, field := range fieldsToTest {
compareClientHelloFields(t, field, uconn.HandshakeState.Hello, generatedUConn.HandshakeState.Hello)
}
}
func TestUTLSFingerprintClientHello(t *testing.T) {
clientHellosToTest := []ClientHelloID{
HelloChrome_58, HelloChrome_70, HelloChrome_83, HelloFirefox_55, HelloFirefox_63, HelloIOS_11_1, HelloIOS_12_1, HelloRandomized, HelloRandomizedALPN, HelloRandomizedNoALPN}
serverNames := []string{"foobar"}
for _, clientHello := range clientHellosToTest {
for _, serverName := range serverNames {
t.Logf("checking fingerprint generated client hello spec against %v and server name: %v", clientHello, serverName)
checkUTLSFingerPrintClientHello(t, clientHello, "foobar")
}
}
}
func TestUTLSFingerprintClientHelloBluntMimicry(t *testing.T) {
serverName := "foobar"
var extensionId uint16 = 0xfeed
extensionData := []byte("random data")
specWithGeneric, err := utlsIdToSpec(HelloChrome_Auto)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
specWithGeneric.Extensions = append(specWithGeneric.Extensions, &GenericExtension{extensionId, extensionData})
uconn := UClient(&net.TCPConn{}, &Config{ServerName: serverName}, HelloCustom)
if err := uconn.ApplyPreset(&specWithGeneric); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
if err := uconn.BuildHandshakeState(); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
f := &Fingerprinter{}
minTLSVers := createMinTLSVersion(uconn.vers)
_, err = f.FingerprintClientHello(prependRecordHeader(uconn.HandshakeState.Hello.Raw, minTLSVers))
if err == nil {
t.Errorf("expected error generating spec from client hello with GenericExtension")
}
f = &Fingerprinter{AllowBluntMimicry: true}
generatedSpec, err := f.FingerprintClientHello(prependRecordHeader(uconn.HandshakeState.Hello.Raw, minTLSVers))
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
for _, ext := range generatedSpec.Extensions {
if genericExtension, ok := (ext).(*GenericExtension); ok {
if genericExtension.Id == extensionId && bytes.Equal(genericExtension.Data, extensionData) {
return
}
}
}
t.Errorf("generated ClientHelloSpec with BluntMimicry did not correctly carry over generic extension")
}
func TestUTLSFingerprintClientHelloAlwaysAddPadding(t *testing.T) {
serverName := "foobar"
specWithoutPadding, err := utlsIdToSpec(HelloIOS_12_1)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
specWithPadding, err := utlsIdToSpec(HelloChrome_83)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
uconnWithoutPadding := UClient(&net.TCPConn{}, &Config{ServerName: serverName}, HelloCustom)
uconnWithPadding := UClient(&net.TCPConn{}, &Config{ServerName: serverName}, HelloCustom)
if err := uconnWithoutPadding.ApplyPreset(&specWithoutPadding); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
if err := uconnWithoutPadding.BuildHandshakeState(); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
if err := uconnWithPadding.ApplyPreset(&specWithPadding); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
if err := uconnWithPadding.BuildHandshakeState(); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
f := &Fingerprinter{}
minTLSVersWithoutPadding := createMinTLSVersion(uconnWithoutPadding.vers)
fingerprintedWithoutPadding, err := f.FingerprintClientHello(prependRecordHeader(uconnWithoutPadding.HandshakeState.Hello.Raw, minTLSVersWithoutPadding))
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
for _, ext := range fingerprintedWithoutPadding.Extensions {
if _, ok := ext.(*UtlsPaddingExtension); ok {
t.Errorf("padding extension should not be present on fingerprinted ClientHelloSpec without AlwaysAddPadding set")
break
}
}
f = &Fingerprinter{AlwaysAddPadding: true}
generatedSpec, err := f.FingerprintClientHello(prependRecordHeader(uconnWithoutPadding.HandshakeState.Hello.Raw, minTLSVersWithoutPadding))
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
hasPadding := false
for _, ext := range generatedSpec.Extensions {
if _, ok := ext.(*UtlsPaddingExtension); ok {
hasPadding = true
break
}
}
if !hasPadding {
t.Errorf("expected padding extension on fingerprinted ClientHelloSpec with AlwaysAddPadding set")
}
f = &Fingerprinter{AlwaysAddPadding: true}
minTLSVersWithPadding := createMinTLSVersion(uconnWithPadding.vers)
generatedSpec, err = f.FingerprintClientHello(prependRecordHeader(uconnWithPadding.HandshakeState.Hello.Raw, minTLSVersWithPadding))
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
hasPadding = false
for _, ext := range generatedSpec.Extensions {
if _, ok := ext.(*UtlsPaddingExtension); ok {
if hasPadding {
t.Errorf("found double padding extension on fingerprinted ClientHelloSpec with AlwaysAddPadding set")
}
hasPadding = true
}
}
if !hasPadding {
t.Errorf("expected padding extension on fingerprinted ClientHelloSpec with AlwaysAddPadding set")
}
}
func TestUTLSFingerprintClientHelloKeepPSK(t *testing.T) {
// TLSv1.3 Record Layer: Handshake Protocol: Client Hello
// Content Type: Handshake (22)
// Version: TLS 1.0 (0x0301)
// Length: 576
// Handshake Protocol: Client Hello
// Handshake Type: Client Hello (1)
// Length: 572
// Version: TLS 1.2 (0x0303)
// Random: 5cef5aa9122008e37f0f74d717cd4ae0f745daba4292e6fb…
// Session ID Length: 32
// Session ID: 8c4aa23444084eeb70097efe0b8f6e3a56c717abd67505c9…
// Cipher Suites Length: 32
// Cipher Suites (16 suites)
// Compression Methods Length: 1
// Compression Methods (1 method)
// Extensions Length: 467
// Extension: Reserved (GREASE) (len=0)
// Type: Reserved (GREASE) (14906)
// Length: 0
// Data: <MISSING>
// Extension: server_name (len=22)
// Type: server_name (0)
// Length: 22
// Server Name Indication extension
// Server Name list length: 20
// Server Name Type: host_name (0)
// Server Name length: 17
// Server Name: edgeapi.slack.com
// Extension: extended_master_secret (len=0)
// Type: extended_master_secret (23)
// Length: 0
// Extension: renegotiation_info (len=1)
// Type: renegotiation_info (65281)
// Length: 1
// Renegotiation Info extension
// Renegotiation info extension length: 0
// Extension: supported_groups (len=10)
// Type: supported_groups (10)
// Length: 10
// Supported Groups List Length: 8
// Supported Groups (4 groups)
// Supported Group: Reserved (GREASE) (0xdada)
// Supported Group: x25519 (0x001d)
// Supported Group: secp256r1 (0x0017)
// Supported Group: secp384r1 (0x0018)
// Extension: ec_point_formats (len=2)
// Type: ec_point_formats (11)
// Length: 2
// EC point formats Length: 1
// Elliptic curves point formats (1)
// Extension: session_ticket (len=0)
// Type: session_ticket (35)
// Length: 0
// Data (0 bytes)
// Extension: application_layer_protocol_negotiation (len=14)
// Type: application_layer_protocol_negotiation (16)
// Length: 14
// ALPN Extension Length: 12
// ALPN Protocol
// ALPN string length: 2
// ALPN Next Protocol: h2
// ALPN string length: 8
// ALPN Next Protocol: http/1.1
// Extension: status_request (len=5)
// Type: status_request (5)
// Length: 5
// Certificate Status Type: OCSP (1)
// Responder ID list Length: 0
// Request Extensions Length: 0
// Extension: signature_algorithms (len=18)
// Type: signature_algorithms (13)
// Length: 18
// Signature Hash Algorithms Length: 16
// Signature Hash Algorithms (8 algorithms)
// Extension: signed_certificate_timestamp (len=0)
// Type: signed_certificate_timestamp (18)
// Length: 0
// Extension: key_share (len=43)
// Type: key_share (51)
// Length: 43
// Key Share extension
// Client Key Share Length: 41
// Key Share Entry: Group: Reserved (GREASE), Key Exchange length: 1
// Group: Reserved (GREASE) (56026)
// Key Exchange Length: 1
// Key Exchange: 00
// Key Share Entry: Group: x25519, Key Exchange length: 32
// Group: x25519 (29)
// Key Exchange Length: 32
// Key Exchange: e35e636d4e2dcd5f39309170285dab92dbe81fefe4926826…
// Extension: psk_key_exchange_modes (len=2)
// Type: psk_key_exchange_modes (45)
// Length: 2
// PSK Key Exchange Modes Length: 1
// PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)
// Extension: supported_versions (len=11)
// Type: supported_versions (43)
// Length: 11
// Supported Versions length: 10
// Supported Version: Unknown (0x2a2a)
// Supported Version: TLS 1.3 (0x0304)
// Supported Version: TLS 1.2 (0x0303)
// Supported Version: TLS 1.1 (0x0302)
// Supported Version: TLS 1.0 (0x0301)
// Extension: compress_certificate (len=3)
// Type: compress_certificate (27)
// Length: 3
// Algorithms Length: 2
// Algorithm: brotli (2)
// Extension: Reserved (GREASE) (len=1)
// Type: Reserved (GREASE) (19018)
// Length: 1
// Data: 00
// Extension: pre_shared_key (len=267)
// Type: pre_shared_key (41)
// Length: 267
// Pre-Shared Key extension
byteString := []byte("16030102400100023c03035cef5aa9122008e37f0f74d717cd4ae0f745daba4292e6fbca3cd5bf9123498f208c4aa23444084eeb70097efe0b8f6e3a56c717abd67505c950aab314de59bd8f00204a4a130113021303c02bc02fc02cc030cca9cca8c013c014009c009d002f0035010001d33a3a0000000000160014000011656467656170692e736c61636b2e636f6d00170000ff01000100000a000a0008dada001d00170018000b00020100002300000010000e000c02683208687474702f312e31000500050100000000000d0012001004030804040105030805050108060601001200000033002b0029dada000100001d0020e35e636d4e2dcd5f39309170285dab92dbe81fefe4926826cec1ef881321687e002d00020101002b000b0a2a2a0304030303020301001b00030200024a4a0001000029010b00e600e017fab59672c1966ae78fc4dacd7efb42e735de956e3f96d342bb8e63a5233ce21c92d6d75036601d74ccbc3ca0085f3ac2ebbd83da13501ac3c6d612bcb453fb206a39a8112d768bea1976d7c14e6de9aa0ee70ea732554d3c57d1a993f1044a46c1fb371811039ef30582cacf41bd497121d67793b8ee4df7a60d525f7df052fd66cda7f141bb553d9253816752d923ac7c71426179db4f26a7d42f0d65a2dd2dbaafb86fa17b2da23fd57c5064c76551cfda86304051231e4da9e697fedbcb5ae8cb2f6cb92f71164acf2edff5bccc1266cd648a53cc46262eabf40727bcb6958a3d1300212083e99d791672d39919dcb387f2fa7aeee938ec32ecf4b861306f7df4f9a8a746")
helloBytes := make([]byte, hex.DecodedLen(len(byteString)))
_, err := hex.Decode(helloBytes, byteString)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
return
}
f := &Fingerprinter{}
_, err = f.FingerprintClientHello(helloBytes)
if err == nil {
t.Errorf("expected error generating spec from client hello with PSK")
}
f = &Fingerprinter{KeepPSK: true}
generatedSpec, err := f.FingerprintClientHello(helloBytes)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
return
}
for _, ext := range generatedSpec.Extensions {
if genericExtension, ok := (ext).(*GenericExtension); ok {
if genericExtension.Id == extensionPreSharedKey {
return
}
}
}
t.Errorf("generated ClientHelloSpec with KeepPSK does not include preshared key extension")
}
func TestUTLSHandshakeClientFingerprintedSpecFromChrome_58(t *testing.T) {
helloID := HelloChrome_58
serverName := "foobar"
originalConfig := getUTLSTestConfig()
originalConfig.ServerName = serverName
uconn := UClient(&net.TCPConn{}, originalConfig, helloID)
if err := uconn.BuildHandshakeState(); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
f := &Fingerprinter{}
minTLSVers := createMinTLSVersion(uconn.vers)
generatedSpec, err := f.FingerprintClientHello(prependRecordHeader(uconn.HandshakeState.Hello.Raw, minTLSVers))
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
hello := &helloSpec{
name: fmt.Sprintf("%v-fingerprinted", helloID.Str()),
spec: generatedSpec,
}
newConfig := getUTLSTestConfig()
newConfig.ServerName = serverName
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: newConfig,
}
runUTLSClientTestTLS12(t, test, hello)
}
func TestUTLSHandshakeClientFingerprintedSpecFromChrome_70(t *testing.T) {
helloID := HelloChrome_70
serverName := "foobar"
originalConfig := getUTLSTestConfig()
originalConfig.ServerName = serverName
uconn := UClient(&net.TCPConn{}, originalConfig, helloID)
if err := uconn.BuildHandshakeState(); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
f := &Fingerprinter{}
minTLSVers := createMinTLSVersion(uconn.vers)
generatedSpec, err := f.FingerprintClientHello(prependRecordHeader(uconn.HandshakeState.Hello.Raw, minTLSVers))
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
hello := &helloSpec{
name: fmt.Sprintf("%v-fingerprinted", helloID.Str()),
spec: generatedSpec,
}
newConfig := getUTLSTestConfig()
newConfig.ServerName = serverName
opensslCipherName := "TLS_AES_128_GCM_SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: newConfig,
}
runUTLSClientTestTLS13(t, test, hello)
}
func TestUTLSHandshakeClientFingerprintedSpecFromRaw(t *testing.T) {
// TLSv1.3 Record Layer: Handshake Protocol: Client Hello
// Content Type: Handshake (22)
// Version: TLS 1.0 (0x0301)
// Length: 512
// Handshake Protocol: Client Hello
// Handshake Type: Client Hello (1)
// Length: 508
// Version: TLS 1.2 (0x0303)
// Random: 7fd76fa530c24816ea9e4a6cf2e939f2350b9486a7bac58e…
// Session ID Length: 32
// Session ID: d9b01fc4f4b6fe14fe9ce652442d66588d982cb25913d866…
// Cipher Suites Length: 36
// Cipher Suites (18 suites)
// Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
// Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
// Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
// Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
// Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
// Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
// Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
// Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
// Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
// Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
// Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
// Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
// Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
// Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
// Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
// Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
// Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
// Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
// Compression Methods Length: 1
// Compression Methods (1 method)
// Extensions Length: 399
// Extension: server_name (len=34)
// Type: server_name (0)
// Length: 34
// Server Name Indication extension
// Extension: extended_master_secret (len=0)
// Type: extended_master_secret (23)
// Length: 0
// Extension: renegotiation_info (len=1)
// Type: renegotiation_info (65281)
// Length: 1
// Renegotiation Info extension
// Extension: supported_groups (len=14)
// Type: supported_groups (10)
// Length: 14
// Supported Groups List Length: 12
// Supported Groups (6 groups)
// Extension: ec_point_formats (len=2)
// Type: ec_point_formats (11)
// Length: 2
// EC point formats Length: 1
// Elliptic curves point formats (1)
// Extension: application_layer_protocol_negotiation (len=14)
// Type: application_layer_protocol_negotiation (16)
// Length: 14
// ALPN Extension Length: 12
// ALPN Protocol
// Extension: status_request (len=5)
// Type: status_request (5)
// Length: 5
// Certificate Status Type: OCSP (1)
// Responder ID list Length: 0
// Request Extensions Length: 0
// Extension: key_share (len=107)
// Type: key_share (51)
// Length: 107
// Key Share extension
// Extension: supported_versions (len=5)
// Type: supported_versions (43)
// Length: 5
// Supported Versions length: 4
// Supported Version: TLS 1.3 (0x0304)
// Supported Version: TLS 1.2 (0x0303)
// Extension: signature_algorithms (len=24)
// Type: signature_algorithms (13)
// Length: 24
// Signature Hash Algorithms Length: 22
// Signature Hash Algorithms (11 algorithms)
// Extension: record_size_limit (len=2)
// Type: record_size_limit (28)
// Length: 2
// Record Size Limit: 16385
// Extension: padding (len=143)
// Type: padding (21)
// Length: 143
// Padding Data: 000000000000000000000000000000000000000000000000…
byteString := []byte("1603010200010001fc03037fd76fa530c24816ea9e4a6cf2e939f2350b9486a7bac58ece5753767fb6112420d9b01fc4f4b6fe14fe9ce652442d66588d982cb25913d866348bde54d3899abe0024130113031302c02bc02fcca9cca8c02cc030c00ac009c013c014009c009d002f0035000a0100018f00000022002000001d70656f706c652d70612e636c69656e7473362e676f6f676c652e636f6d00170000ff01000100000a000e000c001d00170018001901000101000b000201000010000e000c02683208687474702f312e310005000501000000000033006b0069001d002065e566ff33dfbeb012e3b13b87d75612bd0fbc3963673df90afed533dccc9b5400170041047fcc2666d04c31272a2e39905c771a89edf5a71dae301ec2fa0e7bc4d0e06580a0d36324e3dc4f29e200a8905badd11c00daf11588977bf501597dac5fdc55bf002b00050403040303000d0018001604030503060308040805080604010501060102030201001c000240010015008f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
helloBytes := make([]byte, hex.DecodedLen(len(byteString)))
_, err := hex.Decode(helloBytes, byteString)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
return
}
f := &Fingerprinter{}
generatedSpec, err := f.FingerprintClientHello(helloBytes)
if err != nil {
t.Errorf("got error: %v; expected to succeed", err)
}
hello := &helloSpec{
name: "raw-capture-fingerprinted",
spec: generatedSpec,
}
config := getUTLSTestConfig()
opensslCipherName := "TLS_AES_128_GCM_SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
}
runUTLSClientTestTLS13(t, test, hello)
}

View file

@ -617,6 +617,9 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
uconn.Extensions = make([]TLSExtension, len(p.Extensions))
copy(uconn.Extensions, p.Extensions)
// Check whether NPN extension actually exists
var haveNPN bool
// reGrease, and point things to each other
for _, e := range uconn.Extensions {
switch ext := e.(type) {
@ -681,8 +684,15 @@ func (uconn *UConn) ApplyPreset(p *ClientHelloSpec) error {
ext.Versions[i] = GetBoringGREASEValue(uconn.greaseSeed, ssl_grease_version)
}
}
case *NPNExtension:
haveNPN = true
}
}
// The default golang behavior in makeClientHello always sets NextProtoNeg if NextProtos is set,
// but NextProtos is also used by ALPN and our spec nmay not actually have a NPN extension
hello.NextProtoNeg = haveNPN
return nil
}