Skip to content

Commit dc00dc6

Browse files
committed
crypto/tls: let HTTP/1.1 clients connect to servers with NextProtos "h2"
Fixes #46310 Change-Id: Idd5e30f05c439f736ae6f3904cbb9cc2ba772315 Reviewed-on: https://go-review.googlesource.com/c/go/+/325432 Trust: Filippo Valsorda <[email protected]> Run-TryBot: Filippo Valsorda <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]>
1 parent 27f8372 commit dc00dc6

7 files changed

+277
-50
lines changed

src/crypto/tls/handshake_client.go

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -711,17 +711,11 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
711711
}
712712
}
713713

714-
if hs.serverHello.alpnProtocol != "" {
715-
if len(hs.hello.alpnProtocols) == 0 {
716-
c.sendAlert(alertUnsupportedExtension)
717-
return false, errors.New("tls: server advertised unrequested ALPN extension")
718-
}
719-
if mutualProtocol([]string{hs.serverHello.alpnProtocol}, hs.hello.alpnProtocols) == "" {
720-
c.sendAlert(alertUnsupportedExtension)
721-
return false, errors.New("tls: server selected unadvertised ALPN protocol")
722-
}
723-
c.clientProtocol = hs.serverHello.alpnProtocol
714+
if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol); err != nil {
715+
c.sendAlert(alertUnsupportedExtension)
716+
return false, err
724717
}
718+
c.clientProtocol = hs.serverHello.alpnProtocol
725719

726720
c.scts = hs.serverHello.scts
727721

@@ -753,6 +747,23 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
753747
return true, nil
754748
}
755749

750+
// checkALPN ensure that the server's choice of ALPN protocol is compatible with
751+
// the protocols that we advertised in the Client Hello.
752+
func checkALPN(clientProtos []string, serverProto string) error {
753+
if serverProto == "" {
754+
return nil
755+
}
756+
if len(clientProtos) == 0 {
757+
return errors.New("tls: server advertised unrequested ALPN extension")
758+
}
759+
for _, proto := range clientProtos {
760+
if proto == serverProto {
761+
return nil
762+
}
763+
}
764+
return errors.New("tls: server selected unadvertised ALPN protocol")
765+
}
766+
756767
func (hs *clientHandshakeState) readFinished(out []byte) error {
757768
c := hs.c
758769

@@ -979,19 +990,6 @@ func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
979990
return serverAddr.String()
980991
}
981992

982-
// mutualProtocol finds the mutual ALPN protocol given list of possible
983-
// protocols and a list of the preference order.
984-
func mutualProtocol(protos, preferenceProtos []string) string {
985-
for _, s := range preferenceProtos {
986-
for _, c := range protos {
987-
if s == c {
988-
return s
989-
}
990-
}
991-
}
992-
return ""
993-
}
994-
995993
// hostnameInSNI converts name into an appropriate hostname for SNI.
996994
// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
997995
// See RFC 6066, Section 3.

src/crypto/tls/handshake_client_tls13.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -396,17 +396,11 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
396396
}
397397
hs.transcript.Write(encryptedExtensions.marshal())
398398

399-
if encryptedExtensions.alpnProtocol != "" {
400-
if len(hs.hello.alpnProtocols) == 0 {
401-
c.sendAlert(alertUnsupportedExtension)
402-
return errors.New("tls: server advertised unrequested ALPN extension")
403-
}
404-
if mutualProtocol([]string{encryptedExtensions.alpnProtocol}, hs.hello.alpnProtocols) == "" {
405-
c.sendAlert(alertUnsupportedExtension)
406-
return errors.New("tls: server selected unadvertised ALPN protocol")
407-
}
408-
c.clientProtocol = encryptedExtensions.alpnProtocol
399+
if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
400+
c.sendAlert(alertUnsupportedExtension)
401+
return err
409402
}
403+
c.clientProtocol = encryptedExtensions.alpnProtocol
410404

411405
return nil
412406
}

src/crypto/tls/handshake_server.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,13 @@ func (hs *serverHandshakeState) processClientHello() error {
217217
c.serverName = hs.clientHello.serverName
218218
}
219219

220-
if len(c.config.NextProtos) > 0 && len(hs.clientHello.alpnProtocols) > 0 {
221-
selectedProto := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos)
222-
if selectedProto == "" {
223-
c.sendAlert(alertNoApplicationProtocol)
224-
return fmt.Errorf("tls: client requested unsupported application protocols (%s)", hs.clientHello.alpnProtocols)
225-
}
226-
hs.hello.alpnProtocol = selectedProto
227-
c.clientProtocol = selectedProto
220+
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
221+
if err != nil {
222+
c.sendAlert(alertNoApplicationProtocol)
223+
return err
228224
}
225+
hs.hello.alpnProtocol = selectedProto
226+
c.clientProtocol = selectedProto
229227

230228
hs.cert, err = c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
231229
if err != nil {
@@ -277,6 +275,34 @@ func (hs *serverHandshakeState) processClientHello() error {
277275
return nil
278276
}
279277

278+
// negotiateALPN picks a shared ALPN protocol that both sides support in server
279+
// preference order. If ALPN is not configured or the peer doesn't support it,
280+
// it returns "" and no error.
281+
func negotiateALPN(serverProtos, clientProtos []string) (string, error) {
282+
if len(serverProtos) == 0 || len(clientProtos) == 0 {
283+
return "", nil
284+
}
285+
var http11fallback bool
286+
for _, s := range serverProtos {
287+
for _, c := range clientProtos {
288+
if s == c {
289+
return s, nil
290+
}
291+
if s == "h2" && c == "http/1.1" {
292+
http11fallback = true
293+
}
294+
}
295+
}
296+
// As a special case, let http/1.1 clients connect to h2 servers as if they
297+
// didn't support ALPN. We used not to enforce protocol overlap, so over
298+
// time a number of HTTP servers were configured with only "h2", but
299+
// expected to accept connections from "http/1.1" clients. See Issue 46310.
300+
if http11fallback {
301+
return "", nil
302+
}
303+
return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos)
304+
}
305+
280306
// supportsECDHE returns whether ECDHE key exchanges can be used with this
281307
// pre-TLS 1.3 client.
282308
func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool {

src/crypto/tls/handshake_server_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,27 @@ func TestHandshakeServerALPNNotConfigured(t *testing.T) {
949949
runServerTestTLS13(t, test)
950950
}
951951

952+
func TestHandshakeServerALPNFallback(t *testing.T) {
953+
config := testConfig.Clone()
954+
config.NextProtos = []string{"proto1", "h2", "proto2"}
955+
956+
test := &serverTest{
957+
name: "ALPN-Fallback",
958+
// Note that this needs OpenSSL 1.0.2 because that is the first
959+
// version that supports the -alpn flag.
960+
command: []string{"openssl", "s_client", "-alpn", "proto3,http/1.1,proto4", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
961+
config: config,
962+
validate: func(state ConnectionState) error {
963+
if state.NegotiatedProtocol != "" {
964+
return fmt.Errorf("Got protocol %q, wanted nothing", state.NegotiatedProtocol)
965+
}
966+
return nil
967+
},
968+
}
969+
runServerTestTLS12(t, test)
970+
runServerTestTLS13(t, test)
971+
}
972+
952973
// TestHandshakeServerSNI involves a client sending an SNI extension of
953974
// "snitest.com", which happens to match the CN of testSNICertificate. The test
954975
// verifies that the server correctly selects that certificate.

src/crypto/tls/handshake_server_tls13.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"crypto/hmac"
1212
"crypto/rsa"
1313
"errors"
14-
"fmt"
1514
"hash"
1615
"io"
1716
"sync/atomic"
@@ -551,15 +550,13 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
551550

552551
encryptedExtensions := new(encryptedExtensionsMsg)
553552

554-
if len(c.config.NextProtos) > 0 && len(hs.clientHello.alpnProtocols) > 0 {
555-
selectedProto := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos)
556-
if selectedProto == "" {
557-
c.sendAlert(alertNoApplicationProtocol)
558-
return fmt.Errorf("tls: client requested unsupported application protocols (%s)", hs.clientHello.alpnProtocols)
559-
}
560-
encryptedExtensions.alpnProtocol = selectedProto
561-
c.clientProtocol = selectedProto
553+
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
554+
if err != nil {
555+
c.sendAlert(alertNoApplicationProtocol)
556+
return err
562557
}
558+
encryptedExtensions.alpnProtocol = selectedProto
559+
c.clientProtocol = selectedProto
563560

564561
hs.transcript.Write(encryptedExtensions.marshal())
565562
if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil {
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
>>> Flow 1 (client to server)
2+
00000000 16 03 01 00 a6 01 00 00 a2 03 03 b5 c9 ab 32 7f |..............2.|
3+
00000010 e1 af 3f f2 ac 2a 11 dd 33 f9 b5 21 88 0d e4 29 |..?..*..3..!...)|
4+
00000020 e2 47 49 dc c7 31 a8 a5 25 81 0c 00 00 04 cc a8 |.GI..1..%.......|
5+
00000030 00 ff 01 00 00 75 00 0b 00 04 03 00 01 02 00 0a |.....u..........|
6+
00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
7+
00000050 00 00 00 10 00 19 00 17 06 70 72 6f 74 6f 33 08 |.........proto3.|
8+
00000060 68 74 74 70 2f 31 2e 31 06 70 72 6f 74 6f 34 00 |http/1.1.proto4.|
9+
00000070 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 05 |..........0.....|
10+
00000080 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 |................|
11+
00000090 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 |................|
12+
000000a0 01 03 02 02 02 04 02 05 02 06 02 |...........|
13+
>>> Flow 2 (server to client)
14+
00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
15+
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
16+
00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......|
17+
00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............|
18+
00000040 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0|
19+
00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............|
20+
00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..|
21+
00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.|
22+
00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....|
23+
00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010|
24+
000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101|
25+
000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U|
26+
000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...|
27+
000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...|
28+
000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
29+
000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.|
30+
00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B|
31+
00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[[email protected]..+.|
32+
00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t|
33+
00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l|
34+
00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.|
35+
00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....|
36+
00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.|
37+
00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U|
38+
00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U|
39+
00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
40+
000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.|
41+
000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...|
42+
000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..|
43+
000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...|
44+
000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{|
45+
000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa|
46+
00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*|
47+
00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0|
48+
00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(|
49+
00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C|
50+
00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..|
51+
00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.|
52+
00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.|
53+
00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |[email protected]|
54+
00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B|
55+
00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
56+
000002a0 03 00 ac 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
57+
000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
58+
000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 5f |......_X.;t...._|
59+
000002d0 37 27 84 58 1e ea 1e 40 1b de a9 8f 04 d4 94 64 |7'[email protected]|
60+
000002e0 4e 27 c7 f1 b3 30 d0 53 f5 3d 57 50 d2 17 97 c8 |N'...0.S.=WP....|
61+
000002f0 3d 61 af a6 21 ab 1c 34 47 70 f8 b1 3b 9c 06 86 |=a..!..4Gp..;...|
62+
00000300 87 00 e2 13 50 83 91 ad bc 84 bd b4 7b f3 4b ed |....P.......{.K.|
63+
00000310 ca 81 0c 94 37 a8 ec 67 ca 9c f3 00 f6 af c2 92 |....7..g........|
64+
00000320 c4 8c 78 07 18 0e 43 24 1b 98 16 50 5c 2b 75 0e |..x...C$...P\+u.|
65+
00000330 40 66 dc 40 cd 10 1a 51 25 f3 96 25 1a 3e 70 af |@[email protected]%..%.>p.|
66+
00000340 16 24 d0 1c 0e 33 f9 c1 74 cf b7 e2 28 ac 60 16 |.$...3..t...(.`.|
67+
00000350 03 03 00 04 0e 00 00 00 |........|
68+
>>> Flow 3 (client to server)
69+
00000000 16 03 03 00 25 10 00 00 21 20 30 f2 bb f7 a7 ac |....%...! 0.....|
70+
00000010 23 20 22 ee 73 0d 49 9c b3 7b c1 9a db 2c 85 f3 |# ".s.I..{...,..|
71+
00000020 c0 82 31 60 bd 8b 14 4e 73 43 14 03 03 00 01 01 |..1`...NsC......|
72+
00000030 16 03 03 00 20 09 8d c7 86 ee cc f4 c7 36 a3 49 |.... ........6.I|
73+
00000040 d3 f7 a1 4a 68 a2 1e b4 fc cc a2 15 cb 01 92 d8 |...Jh...........|
74+
00000050 72 b0 d1 6f eb |r..o.|
75+
>>> Flow 4 (server to client)
76+
00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
77+
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
78+
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
79+
00000030 6f e0 18 83 51 ed 14 ef 68 ca 42 c5 4c a2 ac 05 |o...Q...h.B.L...|
80+
00000040 9c 69 69 99 08 9f de a4 d4 e7 37 ab 14 38 4c 47 |.ii.......7..8LG|
81+
00000050 70 f0 97 1d db 2d 0a 14 c2 1e f0 16 9f 6d 37 02 |p....-.......m7.|
82+
00000060 4b f1 16 be 98 3f df 74 83 7c 19 85 61 49 38 16 |K....?.t.|..aI8.|
83+
00000070 ee 35 7a e2 3f 74 fe 8d e3 07 93 a1 5e fa f2 02 |.5z.?t......^...|
84+
00000080 e5 c8 60 3f 11 83 8b 0e 32 52 f1 aa 52 b7 0a 89 |..`?....2R..R...|
85+
00000090 14 03 03 00 01 01 16 03 03 00 20 9e 65 15 cf 45 |.......... .e..E|
86+
000000a0 a5 03 69 c9 b1 d8 9e 92 a3 a2 b0 df 2e 62 b1 3a |..i..........b.:|
87+
000000b0 17 78 cd e5 1d f3 51 42 7e 4e 25 17 03 03 00 1d |.x....QB~N%.....|
88+
000000c0 d9 ae d0 fa b7 90 a9 2f 28 8d 1d 6f 54 1f c0 1e |......./(..oT...|
89+
000000d0 4d ae b6 91 f0 e8 84 cf 86 11 22 25 ea 15 03 03 |M........."%....|
90+
000000e0 00 12 0e 71 f2 11 9e 9f 58 ad c0 d8 fc fa 34 bc |...q....X.....4.|
91+
000000f0 02 5a 60 00 |.Z`.|

0 commit comments

Comments
 (0)