]>
Commit | Line | Data |
---|---|---|
4ccad563 ILT |
1 | // Copyright 2012 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | package tls | |
6 | ||
7 | import ( | |
f8d9fa9e | 8 | "bytes" |
5a8ea165 | 9 | "crypto" |
22b955cc | 10 | "crypto/x509" |
dd931d9b | 11 | "encoding/json" |
f98dd1a3 | 12 | "errors" |
00d86ac9 | 13 | "fmt" |
af146490 | 14 | "internal/testenv" |
00d86ac9 | 15 | "io" |
c2047754 | 16 | "io/ioutil" |
22b955cc | 17 | "math" |
00d86ac9 | 18 | "net" |
22b955cc ILT |
19 | "os" |
20 | "reflect" | |
00d86ac9 | 21 | "strings" |
4ccad563 | 22 | "testing" |
00d86ac9 | 23 | "time" |
4ccad563 ILT |
24 | ) |
25 | ||
fabcaa8d | 26 | var rsaCertPEM = `-----BEGIN CERTIFICATE----- |
4ccad563 ILT |
27 | MIIB0zCCAX2gAwIBAgIJAI/M7BYjwB+uMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV |
28 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX | |
29 | aWRnaXRzIFB0eSBMdGQwHhcNMTIwOTEyMjE1MjAyWhcNMTUwOTEyMjE1MjAyWjBF | |
30 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 | |
31 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANLJ | |
32 | hPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wok/4xIA+ui35/MmNa | |
33 | rtNuC+BdZ1tMuVCPFZcCAwEAAaNQME4wHQYDVR0OBBYEFJvKs8RfJaXTH08W+SGv | |
34 | zQyKn0H8MB8GA1UdIwQYMBaAFJvKs8RfJaXTH08W+SGvzQyKn0H8MAwGA1UdEwQF | |
35 | MAMBAf8wDQYJKoZIhvcNAQEFBQADQQBJlffJHybjDGxRMqaRmDhX0+6v02TUKZsW | |
36 | r5QuVbpQhH6u+0UgcW0jp9QwpxoPTLTWGXEWBBBurxFwiCBhkQ+V | |
37 | -----END CERTIFICATE----- | |
38 | ` | |
39 | ||
aa8901e9 | 40 | var rsaKeyPEM = testingKey(`-----BEGIN RSA TESTING KEY----- |
4ccad563 ILT |
41 | MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo |
42 | k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G | |
43 | 6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N | |
44 | MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW | |
45 | SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T | |
46 | xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi | |
47 | D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== | |
aa8901e9 ILT |
48 | -----END RSA TESTING KEY----- |
49 | `) | |
4ccad563 | 50 | |
a42a906c | 51 | // keyPEM is the same as rsaKeyPEM, but declares itself as just |
af146490 | 52 | // "PRIVATE KEY", not "RSA PRIVATE KEY". https://golang.org/issue/4477 |
aa8901e9 | 53 | var keyPEM = testingKey(`-----BEGIN TESTING KEY----- |
a42a906c ILT |
54 | MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo |
55 | k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G | |
56 | 6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N | |
57 | MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW | |
58 | SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T | |
59 | xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi | |
60 | D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== | |
aa8901e9 ILT |
61 | -----END TESTING KEY----- |
62 | `) | |
a42a906c | 63 | |
fabcaa8d ILT |
64 | var ecdsaCertPEM = `-----BEGIN CERTIFICATE----- |
65 | MIIB/jCCAWICCQDscdUxw16XFDAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw | |
66 | EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0 | |
67 | eSBMdGQwHhcNMTIxMTE0MTI0MDQ4WhcNMTUxMTE0MTI0MDQ4WjBFMQswCQYDVQQG | |
68 | EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk | |
69 | Z2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBY9+my9OoeSUR | |
70 | lDQdV/x8LsOuLilthhiS1Tz4aGDHIPwC1mlvnf7fg5lecYpMCrLLhauAc1UJXcgl | |
71 | 01xoLuzgtAEAgv2P/jgytzRSpUYvgLBt1UA0leLYBy6mQQbrNEuqT3INapKIcUv8 | |
72 | XxYP0xMEUksLPq6Ca+CRSqTtrd/23uTnapkwCQYHKoZIzj0EAQOBigAwgYYCQXJo | |
73 | A7Sl2nLVf+4Iu/tAX/IF4MavARKC4PPHK3zfuGfPR3oCCcsAoz3kAzOeijvd0iXb | |
74 | H5jBImIxPL4WxQNiBTexAkF8D1EtpYuWdlVQ80/h/f4pBcGiXPqX5h2PQSQY7hP1 | |
75 | +jwM1FGS4fREIOvlBYr/SzzQRtwrvrzGYxDEDbsC0ZGRnA== | |
76 | -----END CERTIFICATE----- | |
77 | ` | |
78 | ||
aa8901e9 | 79 | var ecdsaKeyPEM = testingKey(`-----BEGIN EC PARAMETERS----- |
fabcaa8d ILT |
80 | BgUrgQQAIw== |
81 | -----END EC PARAMETERS----- | |
aa8901e9 | 82 | -----BEGIN EC TESTING KEY----- |
fabcaa8d ILT |
83 | MIHcAgEBBEIBrsoKp0oqcv6/JovJJDoDVSGWdirrkgCWxrprGlzB9o0X8fV675X0 |
84 | NwuBenXFfeZvVcwluO7/Q9wkYoPd/t3jGImgBwYFK4EEACOhgYkDgYYABAFj36bL | |
85 | 06h5JRGUNB1X/Hwuw64uKW2GGJLVPPhoYMcg/ALWaW+d/t+DmV5xikwKssuFq4Bz | |
86 | VQldyCXTXGgu7OC0AQCC/Y/+ODK3NFKlRi+AsG3VQDSV4tgHLqZBBus0S6pPcg1q | |
87 | kohxS/xfFg/TEwRSSws+roJr4JFKpO2t3/be5OdqmQ== | |
aa8901e9 ILT |
88 | -----END EC TESTING KEY----- |
89 | `) | |
fabcaa8d ILT |
90 | |
91 | var keyPairTests = []struct { | |
92 | algo string | |
a42a906c ILT |
93 | cert string |
94 | key string | |
fabcaa8d | 95 | }{ |
a42a906c ILT |
96 | {"ECDSA", ecdsaCertPEM, ecdsaKeyPEM}, |
97 | {"RSA", rsaCertPEM, rsaKeyPEM}, | |
98 | {"RSA-untyped", rsaCertPEM, keyPEM}, // golang.org/issue/4477 | |
fabcaa8d ILT |
99 | } |
100 | ||
4ccad563 | 101 | func TestX509KeyPair(t *testing.T) { |
c2047754 | 102 | t.Parallel() |
fabcaa8d ILT |
103 | var pem []byte |
104 | for _, test := range keyPairTests { | |
a42a906c | 105 | pem = []byte(test.cert + test.key) |
fabcaa8d ILT |
106 | if _, err := X509KeyPair(pem, pem); err != nil { |
107 | t.Errorf("Failed to load %s cert followed by %s key: %s", test.algo, test.algo, err) | |
108 | } | |
a42a906c | 109 | pem = []byte(test.key + test.cert) |
fabcaa8d ILT |
110 | if _, err := X509KeyPair(pem, pem); err != nil { |
111 | t.Errorf("Failed to load %s key followed by %s cert: %s", test.algo, test.algo, err) | |
112 | } | |
4ccad563 | 113 | } |
fabcaa8d | 114 | } |
4ccad563 | 115 | |
f98dd1a3 ILT |
116 | func TestX509KeyPairErrors(t *testing.T) { |
117 | _, err := X509KeyPair([]byte(rsaKeyPEM), []byte(rsaCertPEM)) | |
118 | if err == nil { | |
119 | t.Fatalf("X509KeyPair didn't return an error when arguments were switched") | |
120 | } | |
121 | if subStr := "been switched"; !strings.Contains(err.Error(), subStr) { | |
122 | t.Fatalf("Expected %q in the error when switching arguments to X509KeyPair, but the error was %q", subStr, err) | |
123 | } | |
124 | ||
125 | _, err = X509KeyPair([]byte(rsaCertPEM), []byte(rsaCertPEM)) | |
126 | if err == nil { | |
127 | t.Fatalf("X509KeyPair didn't return an error when both arguments were certificates") | |
128 | } | |
129 | if subStr := "certificate"; !strings.Contains(err.Error(), subStr) { | |
130 | t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were certificates, but the error was %q", subStr, err) | |
131 | } | |
132 | ||
133 | const nonsensePEM = ` | |
134 | -----BEGIN NONSENSE----- | |
135 | Zm9vZm9vZm9v | |
136 | -----END NONSENSE----- | |
137 | ` | |
138 | ||
139 | _, err = X509KeyPair([]byte(nonsensePEM), []byte(nonsensePEM)) | |
140 | if err == nil { | |
141 | t.Fatalf("X509KeyPair didn't return an error when both arguments were nonsense") | |
142 | } | |
143 | if subStr := "NONSENSE"; !strings.Contains(err.Error(), subStr) { | |
144 | t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were nonsense, but the error was %q", subStr, err) | |
145 | } | |
146 | } | |
147 | ||
fabcaa8d ILT |
148 | func TestX509MixedKeyPair(t *testing.T) { |
149 | if _, err := X509KeyPair([]byte(rsaCertPEM), []byte(ecdsaKeyPEM)); err == nil { | |
150 | t.Error("Load of RSA certificate succeeded with ECDSA private key") | |
151 | } | |
152 | if _, err := X509KeyPair([]byte(ecdsaCertPEM), []byte(rsaKeyPEM)); err == nil { | |
153 | t.Error("Load of ECDSA certificate succeeded with RSA private key") | |
4ccad563 ILT |
154 | } |
155 | } | |
00d86ac9 | 156 | |
22b955cc | 157 | func newLocalListener(t testing.TB) net.Listener { |
00d86ac9 ILT |
158 | ln, err := net.Listen("tcp", "127.0.0.1:0") |
159 | if err != nil { | |
160 | ln, err = net.Listen("tcp6", "[::1]:0") | |
161 | } | |
162 | if err != nil { | |
163 | t.Fatal(err) | |
164 | } | |
165 | return ln | |
166 | } | |
167 | ||
168 | func TestDialTimeout(t *testing.T) { | |
169 | if testing.Short() { | |
170 | t.Skip("skipping in short mode") | |
171 | } | |
172 | listener := newLocalListener(t) | |
173 | ||
174 | addr := listener.Addr().String() | |
175 | defer listener.Close() | |
176 | ||
177 | complete := make(chan bool) | |
178 | defer close(complete) | |
179 | ||
180 | go func() { | |
181 | conn, err := listener.Accept() | |
182 | if err != nil { | |
183 | t.Error(err) | |
184 | return | |
185 | } | |
186 | <-complete | |
187 | conn.Close() | |
188 | }() | |
189 | ||
190 | dialer := &net.Dialer{ | |
191 | Timeout: 10 * time.Millisecond, | |
192 | } | |
193 | ||
194 | var err error | |
195 | if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil { | |
196 | t.Fatal("DialWithTimeout completed successfully") | |
197 | } | |
198 | ||
22b955cc ILT |
199 | if !isTimeoutError(err) { |
200 | t.Errorf("resulting error not a timeout: %v\nType %T: %#v", err, err, err) | |
00d86ac9 ILT |
201 | } |
202 | } | |
203 | ||
22b955cc ILT |
204 | func isTimeoutError(err error) bool { |
205 | if ne, ok := err.(net.Error); ok { | |
206 | return ne.Timeout() | |
207 | } | |
208 | return false | |
209 | } | |
210 | ||
00d86ac9 ILT |
211 | // tests that Conn.Read returns (non-zero, io.EOF) instead of |
212 | // (non-zero, nil) when a Close (alertCloseNotify) is sitting right | |
213 | // behind the application data in the buffer. | |
214 | func TestConnReadNonzeroAndEOF(t *testing.T) { | |
215 | // This test is racy: it assumes that after a write to a | |
216 | // localhost TCP connection, the peer TCP connection can | |
22b955cc | 217 | // immediately read it. Because it's racy, we skip this test |
00d86ac9 ILT |
218 | // in short mode, and then retry it several times with an |
219 | // increasing sleep in between our final write (via srv.Close | |
220 | // below) and the following read. | |
221 | if testing.Short() { | |
222 | t.Skip("skipping in short mode") | |
223 | } | |
224 | var err error | |
225 | for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 { | |
226 | if err = testConnReadNonzeroAndEOF(t, delay); err == nil { | |
227 | return | |
228 | } | |
229 | } | |
230 | t.Error(err) | |
231 | } | |
232 | ||
233 | func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error { | |
234 | ln := newLocalListener(t) | |
235 | defer ln.Close() | |
236 | ||
237 | srvCh := make(chan *Conn, 1) | |
238 | var serr error | |
239 | go func() { | |
240 | sconn, err := ln.Accept() | |
241 | if err != nil { | |
242 | serr = err | |
243 | srvCh <- nil | |
244 | return | |
245 | } | |
c2047754 | 246 | serverConfig := testConfig.Clone() |
22b955cc | 247 | srv := Server(sconn, serverConfig) |
00d86ac9 ILT |
248 | if err := srv.Handshake(); err != nil { |
249 | serr = fmt.Errorf("handshake: %v", err) | |
250 | srvCh <- nil | |
251 | return | |
252 | } | |
253 | srvCh <- srv | |
254 | }() | |
255 | ||
c2047754 | 256 | clientConfig := testConfig.Clone() |
4f4a855d ILT |
257 | // In TLS 1.3, alerts are encrypted and disguised as application data, so |
258 | // the opportunistic peek won't work. | |
259 | clientConfig.MaxVersion = VersionTLS12 | |
22b955cc | 260 | conn, err := Dial("tcp", ln.Addr().String(), clientConfig) |
00d86ac9 ILT |
261 | if err != nil { |
262 | t.Fatal(err) | |
263 | } | |
264 | defer conn.Close() | |
265 | ||
266 | srv := <-srvCh | |
267 | if srv == nil { | |
268 | return serr | |
269 | } | |
270 | ||
271 | buf := make([]byte, 6) | |
272 | ||
273 | srv.Write([]byte("foobar")) | |
274 | n, err := conn.Read(buf) | |
275 | if n != 6 || err != nil || string(buf) != "foobar" { | |
276 | return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf) | |
277 | } | |
278 | ||
279 | srv.Write([]byte("abcdef")) | |
280 | srv.Close() | |
281 | time.Sleep(delay) | |
282 | n, err = conn.Read(buf) | |
283 | if n != 6 || string(buf) != "abcdef" { | |
284 | return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf) | |
285 | } | |
286 | if err != io.EOF { | |
287 | return fmt.Errorf("Second Read error = %v; want io.EOF", err) | |
288 | } | |
289 | return nil | |
290 | } | |
f8d9fa9e ILT |
291 | |
292 | func TestTLSUniqueMatches(t *testing.T) { | |
293 | ln := newLocalListener(t) | |
294 | defer ln.Close() | |
295 | ||
296 | serverTLSUniques := make(chan []byte) | |
297 | go func() { | |
298 | for i := 0; i < 2; i++ { | |
299 | sconn, err := ln.Accept() | |
300 | if err != nil { | |
c2047754 ILT |
301 | t.Error(err) |
302 | return | |
f8d9fa9e | 303 | } |
c2047754 | 304 | serverConfig := testConfig.Clone() |
4f4a855d | 305 | serverConfig.MaxVersion = VersionTLS12 // TLSUnique is not defined in TLS 1.3 |
22b955cc | 306 | srv := Server(sconn, serverConfig) |
f8d9fa9e | 307 | if err := srv.Handshake(); err != nil { |
c2047754 ILT |
308 | t.Error(err) |
309 | return | |
f8d9fa9e ILT |
310 | } |
311 | serverTLSUniques <- srv.ConnectionState().TLSUnique | |
312 | } | |
313 | }() | |
314 | ||
c2047754 | 315 | clientConfig := testConfig.Clone() |
f8d9fa9e | 316 | clientConfig.ClientSessionCache = NewLRUClientSessionCache(1) |
22b955cc | 317 | conn, err := Dial("tcp", ln.Addr().String(), clientConfig) |
f8d9fa9e ILT |
318 | if err != nil { |
319 | t.Fatal(err) | |
320 | } | |
321 | if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) { | |
322 | t.Error("client and server channel bindings differ") | |
323 | } | |
324 | conn.Close() | |
325 | ||
22b955cc | 326 | conn, err = Dial("tcp", ln.Addr().String(), clientConfig) |
f8d9fa9e ILT |
327 | if err != nil { |
328 | t.Fatal(err) | |
329 | } | |
330 | defer conn.Close() | |
331 | if !conn.ConnectionState().DidResume { | |
332 | t.Error("second session did not use resumption") | |
333 | } | |
334 | if !bytes.Equal(conn.ConnectionState().TLSUnique, <-serverTLSUniques) { | |
335 | t.Error("client and server channel bindings differ when session resumption is used") | |
336 | } | |
337 | } | |
af146490 ILT |
338 | |
339 | func TestVerifyHostname(t *testing.T) { | |
340 | testenv.MustHaveExternalNetwork(t) | |
341 | ||
342 | c, err := Dial("tcp", "www.google.com:https", nil) | |
343 | if err != nil { | |
344 | t.Fatal(err) | |
345 | } | |
346 | if err := c.VerifyHostname("www.google.com"); err != nil { | |
347 | t.Fatalf("verify www.google.com: %v", err) | |
348 | } | |
349 | if err := c.VerifyHostname("www.yahoo.com"); err == nil { | |
350 | t.Fatalf("verify www.yahoo.com succeeded") | |
351 | } | |
352 | ||
353 | c, err = Dial("tcp", "www.google.com:https", &Config{InsecureSkipVerify: true}) | |
354 | if err != nil { | |
355 | t.Fatal(err) | |
356 | } | |
357 | if err := c.VerifyHostname("www.google.com"); err == nil { | |
358 | t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true") | |
359 | } | |
af146490 ILT |
360 | } |
361 | ||
f98dd1a3 ILT |
362 | func TestConnCloseBreakingWrite(t *testing.T) { |
363 | ln := newLocalListener(t) | |
364 | defer ln.Close() | |
365 | ||
366 | srvCh := make(chan *Conn, 1) | |
367 | var serr error | |
368 | var sconn net.Conn | |
369 | go func() { | |
370 | var err error | |
371 | sconn, err = ln.Accept() | |
372 | if err != nil { | |
373 | serr = err | |
374 | srvCh <- nil | |
375 | return | |
376 | } | |
c2047754 | 377 | serverConfig := testConfig.Clone() |
22b955cc | 378 | srv := Server(sconn, serverConfig) |
f98dd1a3 ILT |
379 | if err := srv.Handshake(); err != nil { |
380 | serr = fmt.Errorf("handshake: %v", err) | |
381 | srvCh <- nil | |
382 | return | |
383 | } | |
384 | srvCh <- srv | |
385 | }() | |
386 | ||
387 | cconn, err := net.Dial("tcp", ln.Addr().String()) | |
388 | if err != nil { | |
389 | t.Fatal(err) | |
390 | } | |
391 | defer cconn.Close() | |
392 | ||
393 | conn := &changeImplConn{ | |
394 | Conn: cconn, | |
395 | } | |
396 | ||
c2047754 | 397 | clientConfig := testConfig.Clone() |
22b955cc | 398 | tconn := Client(conn, clientConfig) |
f98dd1a3 ILT |
399 | if err := tconn.Handshake(); err != nil { |
400 | t.Fatal(err) | |
401 | } | |
402 | ||
403 | srv := <-srvCh | |
404 | if srv == nil { | |
405 | t.Fatal(serr) | |
406 | } | |
407 | defer sconn.Close() | |
408 | ||
409 | connClosed := make(chan struct{}) | |
410 | conn.closeFunc = func() error { | |
411 | close(connClosed) | |
412 | return nil | |
413 | } | |
414 | ||
415 | inWrite := make(chan bool, 1) | |
416 | var errConnClosed = errors.New("conn closed for test") | |
417 | conn.writeFunc = func(p []byte) (n int, err error) { | |
418 | inWrite <- true | |
419 | <-connClosed | |
420 | return 0, errConnClosed | |
421 | } | |
422 | ||
423 | closeReturned := make(chan bool, 1) | |
424 | go func() { | |
425 | <-inWrite | |
426 | tconn.Close() // test that this doesn't block forever. | |
427 | closeReturned <- true | |
428 | }() | |
429 | ||
430 | _, err = tconn.Write([]byte("foo")) | |
431 | if err != errConnClosed { | |
432 | t.Errorf("Write error = %v; want errConnClosed", err) | |
433 | } | |
434 | ||
435 | <-closeReturned | |
436 | if err := tconn.Close(); err != errClosed { | |
437 | t.Errorf("Close error = %v; want errClosed", err) | |
438 | } | |
439 | } | |
440 | ||
c2047754 ILT |
441 | func TestConnCloseWrite(t *testing.T) { |
442 | ln := newLocalListener(t) | |
443 | defer ln.Close() | |
444 | ||
445 | clientDoneChan := make(chan struct{}) | |
446 | ||
447 | serverCloseWrite := func() error { | |
448 | sconn, err := ln.Accept() | |
449 | if err != nil { | |
450 | return fmt.Errorf("accept: %v", err) | |
451 | } | |
452 | defer sconn.Close() | |
453 | ||
454 | serverConfig := testConfig.Clone() | |
455 | srv := Server(sconn, serverConfig) | |
456 | if err := srv.Handshake(); err != nil { | |
457 | return fmt.Errorf("handshake: %v", err) | |
458 | } | |
459 | defer srv.Close() | |
460 | ||
461 | data, err := ioutil.ReadAll(srv) | |
462 | if err != nil { | |
463 | return err | |
464 | } | |
465 | if len(data) > 0 { | |
466 | return fmt.Errorf("Read data = %q; want nothing", data) | |
467 | } | |
468 | ||
469 | if err := srv.CloseWrite(); err != nil { | |
470 | return fmt.Errorf("server CloseWrite: %v", err) | |
471 | } | |
472 | ||
473 | // Wait for clientCloseWrite to finish, so we know we | |
474 | // tested the CloseWrite before we defer the | |
475 | // sconn.Close above, which would also cause the | |
476 | // client to unblock like CloseWrite. | |
477 | <-clientDoneChan | |
478 | return nil | |
479 | } | |
480 | ||
481 | clientCloseWrite := func() error { | |
482 | defer close(clientDoneChan) | |
483 | ||
484 | clientConfig := testConfig.Clone() | |
485 | conn, err := Dial("tcp", ln.Addr().String(), clientConfig) | |
486 | if err != nil { | |
487 | return err | |
488 | } | |
489 | if err := conn.Handshake(); err != nil { | |
490 | return err | |
491 | } | |
492 | defer conn.Close() | |
493 | ||
494 | if err := conn.CloseWrite(); err != nil { | |
495 | return fmt.Errorf("client CloseWrite: %v", err) | |
496 | } | |
497 | ||
498 | if _, err := conn.Write([]byte{0}); err != errShutdown { | |
499 | return fmt.Errorf("CloseWrite error = %v; want errShutdown", err) | |
500 | } | |
501 | ||
502 | data, err := ioutil.ReadAll(conn) | |
503 | if err != nil { | |
504 | return err | |
505 | } | |
506 | if len(data) > 0 { | |
507 | return fmt.Errorf("Read data = %q; want nothing", data) | |
508 | } | |
509 | return nil | |
510 | } | |
511 | ||
512 | errChan := make(chan error, 2) | |
513 | ||
514 | go func() { errChan <- serverCloseWrite() }() | |
515 | go func() { errChan <- clientCloseWrite() }() | |
516 | ||
517 | for i := 0; i < 2; i++ { | |
518 | select { | |
519 | case err := <-errChan: | |
520 | if err != nil { | |
521 | t.Fatal(err) | |
522 | } | |
523 | case <-time.After(10 * time.Second): | |
524 | t.Fatal("deadlock") | |
525 | } | |
526 | } | |
527 | ||
528 | // Also test CloseWrite being called before the handshake is | |
529 | // finished: | |
530 | { | |
531 | ln2 := newLocalListener(t) | |
532 | defer ln2.Close() | |
533 | ||
534 | netConn, err := net.Dial("tcp", ln2.Addr().String()) | |
535 | if err != nil { | |
536 | t.Fatal(err) | |
537 | } | |
538 | defer netConn.Close() | |
539 | conn := Client(netConn, testConfig.Clone()) | |
540 | ||
541 | if err := conn.CloseWrite(); err != errEarlyCloseWrite { | |
542 | t.Errorf("CloseWrite error = %v; want errEarlyCloseWrite", err) | |
543 | } | |
544 | } | |
545 | } | |
546 | ||
1a2f01ef ILT |
547 | func TestWarningAlertFlood(t *testing.T) { |
548 | ln := newLocalListener(t) | |
549 | defer ln.Close() | |
550 | ||
551 | server := func() error { | |
552 | sconn, err := ln.Accept() | |
553 | if err != nil { | |
554 | return fmt.Errorf("accept: %v", err) | |
555 | } | |
556 | defer sconn.Close() | |
557 | ||
558 | serverConfig := testConfig.Clone() | |
559 | srv := Server(sconn, serverConfig) | |
560 | if err := srv.Handshake(); err != nil { | |
561 | return fmt.Errorf("handshake: %v", err) | |
562 | } | |
563 | defer srv.Close() | |
564 | ||
565 | _, err = ioutil.ReadAll(srv) | |
566 | if err == nil { | |
567 | return errors.New("unexpected lack of error from server") | |
568 | } | |
4f4a855d | 569 | const expected = "too many ignored" |
1a2f01ef ILT |
570 | if str := err.Error(); !strings.Contains(str, expected) { |
571 | return fmt.Errorf("expected error containing %q, but saw: %s", expected, str) | |
572 | } | |
573 | ||
574 | return nil | |
575 | } | |
576 | ||
577 | errChan := make(chan error, 1) | |
578 | go func() { errChan <- server() }() | |
579 | ||
580 | clientConfig := testConfig.Clone() | |
4f4a855d | 581 | clientConfig.MaxVersion = VersionTLS12 // there are no warning alerts in TLS 1.3 |
1a2f01ef ILT |
582 | conn, err := Dial("tcp", ln.Addr().String(), clientConfig) |
583 | if err != nil { | |
584 | t.Fatal(err) | |
585 | } | |
586 | defer conn.Close() | |
587 | if err := conn.Handshake(); err != nil { | |
588 | t.Fatal(err) | |
589 | } | |
590 | ||
4f4a855d | 591 | for i := 0; i < maxUselessRecords+1; i++ { |
1a2f01ef ILT |
592 | conn.sendAlert(alertNoRenegotiation) |
593 | } | |
594 | ||
595 | if err := <-errChan; err != nil { | |
596 | t.Fatal(err) | |
597 | } | |
598 | } | |
599 | ||
ea250f56 ILT |
600 | func TestCloneFuncFields(t *testing.T) { |
601 | const expectedCount = 5 | |
602 | called := 0 | |
603 | ||
604 | c1 := Config{ | |
605 | Time: func() time.Time { | |
606 | called |= 1 << 0 | |
607 | return time.Time{} | |
608 | }, | |
609 | GetCertificate: func(*ClientHelloInfo) (*Certificate, error) { | |
610 | called |= 1 << 1 | |
611 | return nil, nil | |
612 | }, | |
613 | GetClientCertificate: func(*CertificateRequestInfo) (*Certificate, error) { | |
614 | called |= 1 << 2 | |
615 | return nil, nil | |
616 | }, | |
617 | GetConfigForClient: func(*ClientHelloInfo) (*Config, error) { | |
618 | called |= 1 << 3 | |
619 | return nil, nil | |
620 | }, | |
621 | VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { | |
622 | called |= 1 << 4 | |
623 | return nil | |
624 | }, | |
625 | } | |
626 | ||
627 | c2 := c1.Clone() | |
628 | ||
629 | c2.Time() | |
630 | c2.GetCertificate(nil) | |
631 | c2.GetClientCertificate(nil) | |
632 | c2.GetConfigForClient(nil) | |
633 | c2.VerifyPeerCertificate(nil, nil) | |
634 | ||
635 | if called != (1<<expectedCount)-1 { | |
636 | t.Fatalf("expected %d calls but saw calls %b", expectedCount, called) | |
637 | } | |
638 | } | |
639 | ||
640 | func TestCloneNonFuncFields(t *testing.T) { | |
22b955cc ILT |
641 | var c1 Config |
642 | v := reflect.ValueOf(&c1).Elem() | |
643 | ||
22b955cc ILT |
644 | typ := v.Type() |
645 | for i := 0; i < typ.NumField(); i++ { | |
646 | f := v.Field(i) | |
647 | if !f.CanSet() { | |
648 | // unexported field; not cloned. | |
649 | continue | |
650 | } | |
651 | ||
ea250f56 ILT |
652 | // testing/quick can't handle functions or interfaces and so |
653 | // isn't used here. | |
654 | switch fn := typ.Field(i).Name; fn { | |
22b955cc ILT |
655 | case "Rand": |
656 | f.Set(reflect.ValueOf(io.Reader(os.Stdin))) | |
c2047754 | 657 | case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "GetClientCertificate": |
ea250f56 ILT |
658 | // DeepEqual can't compare functions. If you add a |
659 | // function field to this list, you must also change | |
660 | // TestCloneFuncFields to ensure that the func field is | |
661 | // cloned. | |
22b955cc ILT |
662 | case "Certificates": |
663 | f.Set(reflect.ValueOf([]Certificate{ | |
c2047754 | 664 | {Certificate: [][]byte{{'b'}}}, |
22b955cc | 665 | })) |
22b955cc ILT |
666 | case "NameToCertificate": |
667 | f.Set(reflect.ValueOf(map[string]*Certificate{"a": nil})) | |
22b955cc ILT |
668 | case "RootCAs", "ClientCAs": |
669 | f.Set(reflect.ValueOf(x509.NewCertPool())) | |
22b955cc ILT |
670 | case "ClientSessionCache": |
671 | f.Set(reflect.ValueOf(NewLRUClientSessionCache(10))) | |
c2047754 ILT |
672 | case "KeyLogWriter": |
673 | f.Set(reflect.ValueOf(io.Writer(os.Stdout))) | |
ea250f56 ILT |
674 | case "NextProtos": |
675 | f.Set(reflect.ValueOf([]string{"a", "b"})) | |
676 | case "ServerName": | |
677 | f.Set(reflect.ValueOf("b")) | |
678 | case "ClientAuth": | |
679 | f.Set(reflect.ValueOf(VerifyClientCertIfGiven)) | |
680 | case "InsecureSkipVerify", "SessionTicketsDisabled", "DynamicRecordSizingDisabled", "PreferServerCipherSuites": | |
681 | f.Set(reflect.ValueOf(true)) | |
682 | case "MinVersion", "MaxVersion": | |
683 | f.Set(reflect.ValueOf(uint16(VersionTLS12))) | |
684 | case "SessionTicketKey": | |
685 | f.Set(reflect.ValueOf([32]byte{})) | |
686 | case "CipherSuites": | |
687 | f.Set(reflect.ValueOf([]uint16{1, 2})) | |
688 | case "CurvePreferences": | |
689 | f.Set(reflect.ValueOf([]CurveID{CurveP256})) | |
690 | case "Renegotiation": | |
691 | f.Set(reflect.ValueOf(RenegotiateOnceAsClient)) | |
692 | default: | |
693 | t.Errorf("all fields must be accounted for, but saw unknown field %q", fn) | |
22b955cc | 694 | } |
22b955cc ILT |
695 | } |
696 | ||
c2047754 ILT |
697 | c2 := c1.Clone() |
698 | // DeepEqual also compares unexported fields, thus c2 needs to have run | |
699 | // serverInit in order to be DeepEqual to c1. Cloning it and discarding | |
700 | // the result is sufficient. | |
701 | c2.Clone() | |
22b955cc ILT |
702 | |
703 | if !reflect.DeepEqual(&c1, c2) { | |
704 | t.Errorf("clone failed to copy a field") | |
705 | } | |
706 | } | |
707 | ||
f98dd1a3 ILT |
708 | // changeImplConn is a net.Conn which can change its Write and Close |
709 | // methods. | |
710 | type changeImplConn struct { | |
711 | net.Conn | |
712 | writeFunc func([]byte) (int, error) | |
713 | closeFunc func() error | |
714 | } | |
715 | ||
716 | func (w *changeImplConn) Write(p []byte) (n int, err error) { | |
717 | if w.writeFunc != nil { | |
718 | return w.writeFunc(p) | |
719 | } | |
720 | return w.Conn.Write(p) | |
721 | } | |
722 | ||
723 | func (w *changeImplConn) Close() error { | |
724 | if w.closeFunc != nil { | |
725 | return w.closeFunc() | |
726 | } | |
727 | return w.Conn.Close() | |
728 | } | |
22b955cc | 729 | |
4f4a855d | 730 | func throughput(b *testing.B, version uint16, totalBytes int64, dynamicRecordSizingDisabled bool) { |
22b955cc ILT |
731 | ln := newLocalListener(b) |
732 | defer ln.Close() | |
733 | ||
734 | N := b.N | |
735 | ||
736 | // Less than 64KB because Windows appears to use a TCP rwin < 64KB. | |
737 | // See Issue #15899. | |
738 | const bufsize = 32 << 10 | |
739 | ||
740 | go func() { | |
741 | buf := make([]byte, bufsize) | |
742 | for i := 0; i < N; i++ { | |
743 | sconn, err := ln.Accept() | |
744 | if err != nil { | |
745 | // panic rather than synchronize to avoid benchmark overhead | |
746 | // (cannot call b.Fatal in goroutine) | |
747 | panic(fmt.Errorf("accept: %v", err)) | |
748 | } | |
c2047754 ILT |
749 | serverConfig := testConfig.Clone() |
750 | serverConfig.CipherSuites = nil // the defaults may prefer faster ciphers | |
22b955cc ILT |
751 | serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled |
752 | srv := Server(sconn, serverConfig) | |
753 | if err := srv.Handshake(); err != nil { | |
754 | panic(fmt.Errorf("handshake: %v", err)) | |
755 | } | |
756 | if _, err := io.CopyBuffer(srv, srv, buf); err != nil { | |
757 | panic(fmt.Errorf("copy buffer: %v", err)) | |
758 | } | |
759 | } | |
760 | }() | |
761 | ||
762 | b.SetBytes(totalBytes) | |
c2047754 ILT |
763 | clientConfig := testConfig.Clone() |
764 | clientConfig.CipherSuites = nil // the defaults may prefer faster ciphers | |
22b955cc | 765 | clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled |
4f4a855d | 766 | clientConfig.MaxVersion = version |
22b955cc ILT |
767 | |
768 | buf := make([]byte, bufsize) | |
769 | chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf)))) | |
770 | for i := 0; i < N; i++ { | |
771 | conn, err := Dial("tcp", ln.Addr().String(), clientConfig) | |
772 | if err != nil { | |
773 | b.Fatal(err) | |
774 | } | |
775 | for j := 0; j < chunks; j++ { | |
776 | _, err := conn.Write(buf) | |
777 | if err != nil { | |
778 | b.Fatal(err) | |
779 | } | |
780 | _, err = io.ReadFull(conn, buf) | |
781 | if err != nil { | |
782 | b.Fatal(err) | |
783 | } | |
784 | } | |
785 | conn.Close() | |
786 | } | |
787 | } | |
788 | ||
789 | func BenchmarkThroughput(b *testing.B) { | |
790 | for _, mode := range []string{"Max", "Dynamic"} { | |
791 | for size := 1; size <= 64; size <<= 1 { | |
792 | name := fmt.Sprintf("%sPacket/%dMB", mode, size) | |
793 | b.Run(name, func(b *testing.B) { | |
4f4a855d ILT |
794 | b.Run("TLSv12", func(b *testing.B) { |
795 | throughput(b, VersionTLS12, int64(size<<20), mode == "Max") | |
796 | }) | |
797 | b.Run("TLSv13", func(b *testing.B) { | |
798 | throughput(b, VersionTLS13, int64(size<<20), mode == "Max") | |
799 | }) | |
22b955cc ILT |
800 | }) |
801 | } | |
802 | } | |
803 | } | |
804 | ||
805 | type slowConn struct { | |
806 | net.Conn | |
807 | bps int | |
808 | } | |
809 | ||
810 | func (c *slowConn) Write(p []byte) (int, error) { | |
811 | if c.bps == 0 { | |
812 | panic("too slow") | |
813 | } | |
814 | t0 := time.Now() | |
815 | wrote := 0 | |
816 | for wrote < len(p) { | |
817 | time.Sleep(100 * time.Microsecond) | |
818 | allowed := int(time.Since(t0).Seconds()*float64(c.bps)) / 8 | |
819 | if allowed > len(p) { | |
820 | allowed = len(p) | |
821 | } | |
822 | if wrote < allowed { | |
823 | n, err := c.Conn.Write(p[wrote:allowed]) | |
824 | wrote += n | |
825 | if err != nil { | |
826 | return wrote, err | |
827 | } | |
828 | } | |
829 | } | |
830 | return len(p), nil | |
831 | } | |
832 | ||
4f4a855d | 833 | func latency(b *testing.B, version uint16, bps int, dynamicRecordSizingDisabled bool) { |
22b955cc ILT |
834 | ln := newLocalListener(b) |
835 | defer ln.Close() | |
836 | ||
837 | N := b.N | |
838 | ||
839 | go func() { | |
840 | for i := 0; i < N; i++ { | |
841 | sconn, err := ln.Accept() | |
842 | if err != nil { | |
843 | // panic rather than synchronize to avoid benchmark overhead | |
844 | // (cannot call b.Fatal in goroutine) | |
845 | panic(fmt.Errorf("accept: %v", err)) | |
846 | } | |
c2047754 | 847 | serverConfig := testConfig.Clone() |
22b955cc ILT |
848 | serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled |
849 | srv := Server(&slowConn{sconn, bps}, serverConfig) | |
850 | if err := srv.Handshake(); err != nil { | |
851 | panic(fmt.Errorf("handshake: %v", err)) | |
852 | } | |
853 | io.Copy(srv, srv) | |
854 | } | |
855 | }() | |
856 | ||
c2047754 | 857 | clientConfig := testConfig.Clone() |
22b955cc | 858 | clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled |
4f4a855d | 859 | clientConfig.MaxVersion = version |
22b955cc ILT |
860 | |
861 | buf := make([]byte, 16384) | |
862 | peek := make([]byte, 1) | |
863 | ||
864 | for i := 0; i < N; i++ { | |
865 | conn, err := Dial("tcp", ln.Addr().String(), clientConfig) | |
866 | if err != nil { | |
867 | b.Fatal(err) | |
868 | } | |
869 | // make sure we're connected and previous connection has stopped | |
870 | if _, err := conn.Write(buf[:1]); err != nil { | |
871 | b.Fatal(err) | |
872 | } | |
873 | if _, err := io.ReadFull(conn, peek); err != nil { | |
874 | b.Fatal(err) | |
875 | } | |
876 | if _, err := conn.Write(buf); err != nil { | |
877 | b.Fatal(err) | |
878 | } | |
879 | if _, err = io.ReadFull(conn, peek); err != nil { | |
880 | b.Fatal(err) | |
881 | } | |
882 | conn.Close() | |
883 | } | |
884 | } | |
885 | ||
886 | func BenchmarkLatency(b *testing.B) { | |
887 | for _, mode := range []string{"Max", "Dynamic"} { | |
888 | for _, kbps := range []int{200, 500, 1000, 2000, 5000} { | |
889 | name := fmt.Sprintf("%sPacket/%dkbps", mode, kbps) | |
890 | b.Run(name, func(b *testing.B) { | |
4f4a855d ILT |
891 | b.Run("TLSv12", func(b *testing.B) { |
892 | latency(b, VersionTLS12, kbps*1000, mode == "Max") | |
893 | }) | |
894 | b.Run("TLSv13", func(b *testing.B) { | |
895 | latency(b, VersionTLS13, kbps*1000, mode == "Max") | |
896 | }) | |
22b955cc ILT |
897 | }) |
898 | } | |
899 | } | |
900 | } | |
dd931d9b ILT |
901 | |
902 | func TestConnectionStateMarshal(t *testing.T) { | |
903 | cs := &ConnectionState{} | |
904 | _, err := json.Marshal(cs) | |
905 | if err != nil { | |
906 | t.Errorf("json.Marshal failed on ConnectionState: %v", err) | |
907 | } | |
908 | } | |
4f4a855d ILT |
909 | |
910 | func TestConnectionState(t *testing.T) { | |
911 | issuer, err := x509.ParseCertificate(testRSACertificateIssuer) | |
912 | if err != nil { | |
913 | panic(err) | |
914 | } | |
915 | rootCAs := x509.NewCertPool() | |
916 | rootCAs.AddCert(issuer) | |
917 | ||
918 | now := func() time.Time { return time.Unix(1476984729, 0) } | |
919 | ||
920 | const alpnProtocol = "golang" | |
921 | const serverName = "example.golang" | |
922 | var scts = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")} | |
923 | var ocsp = []byte("dummy ocsp") | |
924 | ||
925 | for _, v := range []uint16{VersionTLS12, VersionTLS13} { | |
926 | var name string | |
927 | switch v { | |
928 | case VersionTLS12: | |
929 | name = "TLSv12" | |
930 | case VersionTLS13: | |
931 | name = "TLSv13" | |
932 | } | |
933 | t.Run(name, func(t *testing.T) { | |
934 | config := &Config{ | |
935 | Time: now, | |
936 | Rand: zeroSource{}, | |
937 | Certificates: make([]Certificate, 1), | |
938 | MaxVersion: v, | |
939 | RootCAs: rootCAs, | |
940 | ClientCAs: rootCAs, | |
941 | ClientAuth: RequireAndVerifyClientCert, | |
942 | NextProtos: []string{alpnProtocol}, | |
943 | ServerName: serverName, | |
944 | } | |
945 | config.Certificates[0].Certificate = [][]byte{testRSACertificate} | |
946 | config.Certificates[0].PrivateKey = testRSAPrivateKey | |
947 | config.Certificates[0].SignedCertificateTimestamps = scts | |
948 | config.Certificates[0].OCSPStaple = ocsp | |
949 | ||
950 | ss, cs, err := testHandshake(t, config, config) | |
951 | if err != nil { | |
952 | t.Fatalf("Handshake failed: %v", err) | |
953 | } | |
954 | ||
955 | if ss.Version != v || cs.Version != v { | |
956 | t.Errorf("Got versions %x (server) and %x (client), expected %x", ss.Version, cs.Version, v) | |
957 | } | |
958 | ||
959 | if !ss.HandshakeComplete || !cs.HandshakeComplete { | |
960 | t.Errorf("Got HandshakeComplete %v (server) and %v (client), expected true", ss.HandshakeComplete, cs.HandshakeComplete) | |
961 | } | |
962 | ||
963 | if ss.DidResume || cs.DidResume { | |
964 | t.Errorf("Got DidResume %v (server) and %v (client), expected false", ss.DidResume, cs.DidResume) | |
965 | } | |
966 | ||
967 | if ss.CipherSuite == 0 || cs.CipherSuite == 0 { | |
968 | t.Errorf("Got invalid cipher suite: %v (server) and %v (client)", ss.CipherSuite, cs.CipherSuite) | |
969 | } | |
970 | ||
971 | if ss.NegotiatedProtocol != alpnProtocol || cs.NegotiatedProtocol != alpnProtocol { | |
972 | t.Errorf("Got negotiated protocol %q (server) and %q (client), expected %q", ss.NegotiatedProtocol, cs.NegotiatedProtocol, alpnProtocol) | |
973 | } | |
974 | ||
975 | if !cs.NegotiatedProtocolIsMutual { | |
976 | t.Errorf("Got false NegotiatedProtocolIsMutual on the client side") | |
977 | } | |
978 | // NegotiatedProtocolIsMutual on the server side is unspecified. | |
979 | ||
980 | if ss.ServerName != serverName { | |
981 | t.Errorf("Got server name %q, expected %q", ss.ServerName, serverName) | |
982 | } | |
983 | if cs.ServerName != "" { | |
984 | t.Errorf("Got unexpected server name on the client side") | |
985 | } | |
986 | ||
987 | if len(ss.PeerCertificates) != 1 || len(cs.PeerCertificates) != 1 { | |
988 | t.Errorf("Got %d (server) and %d (client) peer certificates, expected %d", len(ss.PeerCertificates), len(cs.PeerCertificates), 1) | |
989 | } | |
990 | ||
991 | if len(ss.VerifiedChains) != 1 || len(cs.VerifiedChains) != 1 { | |
992 | t.Errorf("Got %d (server) and %d (client) verified chains, expected %d", len(ss.VerifiedChains), len(cs.VerifiedChains), 1) | |
993 | } else if len(ss.VerifiedChains[0]) != 2 || len(cs.VerifiedChains[0]) != 2 { | |
994 | t.Errorf("Got %d (server) and %d (client) long verified chain, expected %d", len(ss.VerifiedChains[0]), len(cs.VerifiedChains[0]), 2) | |
995 | } | |
996 | ||
997 | if len(cs.SignedCertificateTimestamps) != 2 { | |
998 | t.Errorf("Got %d SCTs, expected %d", len(cs.SignedCertificateTimestamps), 2) | |
999 | } | |
1000 | if !bytes.Equal(cs.OCSPResponse, ocsp) { | |
1001 | t.Errorf("Got OCSPs %x, expected %x", cs.OCSPResponse, ocsp) | |
1002 | } | |
1003 | // Only TLS 1.3 supports OCSP and SCTs on client certs. | |
1004 | if v == VersionTLS13 { | |
1005 | if len(ss.SignedCertificateTimestamps) != 2 { | |
1006 | t.Errorf("Got %d client SCTs, expected %d", len(ss.SignedCertificateTimestamps), 2) | |
1007 | } | |
1008 | if !bytes.Equal(ss.OCSPResponse, ocsp) { | |
1009 | t.Errorf("Got client OCSPs %x, expected %x", ss.OCSPResponse, ocsp) | |
1010 | } | |
1011 | } | |
1012 | ||
1013 | if v == VersionTLS13 { | |
1014 | if ss.TLSUnique != nil || cs.TLSUnique != nil { | |
1015 | t.Errorf("Got TLSUnique %x (server) and %x (client), expected nil in TLS 1.3", ss.TLSUnique, cs.TLSUnique) | |
1016 | } | |
1017 | } else { | |
1018 | if ss.TLSUnique == nil || cs.TLSUnique == nil { | |
1019 | t.Errorf("Got TLSUnique %x (server) and %x (client), expected non-nil", ss.TLSUnique, cs.TLSUnique) | |
1020 | } | |
1021 | } | |
1022 | }) | |
1023 | } | |
1024 | } | |
1025 | ||
4f4a855d ILT |
1026 | // Issue 28744: Ensure that we don't modify memory |
1027 | // that Config doesn't own such as Certificates. | |
1028 | func TestBuildNameToCertificate_doesntModifyCertificates(t *testing.T) { | |
1029 | c0 := Certificate{ | |
1030 | Certificate: [][]byte{testRSACertificate}, | |
1031 | PrivateKey: testRSAPrivateKey, | |
1032 | } | |
1033 | c1 := Certificate{ | |
1034 | Certificate: [][]byte{testSNICertificate}, | |
1035 | PrivateKey: testRSAPrivateKey, | |
1036 | } | |
1037 | config := testConfig.Clone() | |
1038 | config.Certificates = []Certificate{c0, c1} | |
1039 | ||
1040 | config.BuildNameToCertificate() | |
1041 | got := config.Certificates | |
1042 | want := []Certificate{c0, c1} | |
1043 | if !reflect.DeepEqual(got, want) { | |
1044 | t.Fatalf("Certificates were mutated by BuildNameToCertificate\nGot: %#v\nWant: %#v\n", got, want) | |
1045 | } | |
1046 | } | |
aa8901e9 ILT |
1047 | |
1048 | func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } | |
5a8ea165 ILT |
1049 | |
1050 | func TestClientHelloInfo_SupportsCertificate(t *testing.T) { | |
1051 | rsaCert := &Certificate{ | |
1052 | Certificate: [][]byte{testRSACertificate}, | |
1053 | PrivateKey: testRSAPrivateKey, | |
1054 | } | |
1055 | pkcs1Cert := &Certificate{ | |
1056 | Certificate: [][]byte{testRSACertificate}, | |
1057 | PrivateKey: testRSAPrivateKey, | |
1058 | SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}, | |
1059 | } | |
1060 | ecdsaCert := &Certificate{ | |
1061 | // ECDSA P-256 certificate | |
1062 | Certificate: [][]byte{testP256Certificate}, | |
1063 | PrivateKey: testP256PrivateKey, | |
1064 | } | |
1065 | ed25519Cert := &Certificate{ | |
1066 | Certificate: [][]byte{testEd25519Certificate}, | |
1067 | PrivateKey: testEd25519PrivateKey, | |
1068 | } | |
1069 | ||
1070 | tests := []struct { | |
1071 | c *Certificate | |
1072 | chi *ClientHelloInfo | |
1073 | wantErr string | |
1074 | }{ | |
1075 | {rsaCert, &ClientHelloInfo{ | |
1076 | ServerName: "example.golang", | |
1077 | SignatureSchemes: []SignatureScheme{PSSWithSHA256}, | |
1078 | SupportedVersions: []uint16{VersionTLS13}, | |
1079 | }, ""}, | |
1080 | {ecdsaCert, &ClientHelloInfo{ | |
1081 | SignatureSchemes: []SignatureScheme{PSSWithSHA256, ECDSAWithP256AndSHA256}, | |
1082 | SupportedVersions: []uint16{VersionTLS13, VersionTLS12}, | |
1083 | }, ""}, | |
1084 | {rsaCert, &ClientHelloInfo{ | |
1085 | ServerName: "example.com", | |
1086 | SignatureSchemes: []SignatureScheme{PSSWithSHA256}, | |
1087 | SupportedVersions: []uint16{VersionTLS13}, | |
1088 | }, "not valid for requested server name"}, | |
1089 | {ecdsaCert, &ClientHelloInfo{ | |
1090 | SignatureSchemes: []SignatureScheme{ECDSAWithP384AndSHA384}, | |
1091 | SupportedVersions: []uint16{VersionTLS13}, | |
1092 | }, "signature algorithms"}, | |
1093 | {pkcs1Cert, &ClientHelloInfo{ | |
1094 | SignatureSchemes: []SignatureScheme{PSSWithSHA256, ECDSAWithP256AndSHA256}, | |
1095 | SupportedVersions: []uint16{VersionTLS13}, | |
1096 | }, "signature algorithms"}, | |
1097 | ||
1098 | {rsaCert, &ClientHelloInfo{ | |
1099 | CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, | |
1100 | SignatureSchemes: []SignatureScheme{PKCS1WithSHA1}, | |
1101 | SupportedVersions: []uint16{VersionTLS13, VersionTLS12}, | |
1102 | }, "signature algorithms"}, | |
1103 | {rsaCert, &ClientHelloInfo{ | |
1104 | CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, | |
1105 | SignatureSchemes: []SignatureScheme{PKCS1WithSHA1}, | |
1106 | SupportedVersions: []uint16{VersionTLS13, VersionTLS12}, | |
1107 | config: &Config{ | |
1108 | MaxVersion: VersionTLS12, | |
1109 | }, | |
1110 | }, ""}, // Check that mutual version selection works. | |
1111 | ||
1112 | {ecdsaCert, &ClientHelloInfo{ | |
1113 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1114 | SupportedCurves: []CurveID{CurveP256}, | |
1115 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1116 | SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256}, | |
1117 | SupportedVersions: []uint16{VersionTLS12}, | |
1118 | }, ""}, | |
1119 | {ecdsaCert, &ClientHelloInfo{ | |
1120 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1121 | SupportedCurves: []CurveID{CurveP256}, | |
1122 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1123 | SignatureSchemes: []SignatureScheme{ECDSAWithP384AndSHA384}, | |
1124 | SupportedVersions: []uint16{VersionTLS12}, | |
1125 | }, ""}, // TLS 1.2 does not restrict curves based on the SignatureScheme. | |
1126 | {ecdsaCert, &ClientHelloInfo{ | |
1127 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1128 | SupportedCurves: []CurveID{CurveP256}, | |
1129 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1130 | SignatureSchemes: nil, | |
1131 | SupportedVersions: []uint16{VersionTLS12}, | |
1132 | }, ""}, // TLS 1.2 comes with default signature schemes. | |
1133 | {ecdsaCert, &ClientHelloInfo{ | |
1134 | CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, | |
1135 | SupportedCurves: []CurveID{CurveP256}, | |
1136 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1137 | SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256}, | |
1138 | SupportedVersions: []uint16{VersionTLS12}, | |
1139 | }, "cipher suite"}, | |
1140 | {ecdsaCert, &ClientHelloInfo{ | |
1141 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1142 | SupportedCurves: []CurveID{CurveP256}, | |
1143 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1144 | SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256}, | |
1145 | SupportedVersions: []uint16{VersionTLS12}, | |
1146 | config: &Config{ | |
1147 | CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, | |
1148 | }, | |
1149 | }, "cipher suite"}, | |
1150 | {ecdsaCert, &ClientHelloInfo{ | |
1151 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1152 | SupportedCurves: []CurveID{CurveP384}, | |
1153 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1154 | SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256}, | |
1155 | SupportedVersions: []uint16{VersionTLS12}, | |
1156 | }, "certificate curve"}, | |
1157 | {ecdsaCert, &ClientHelloInfo{ | |
1158 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1159 | SupportedCurves: []CurveID{CurveP256}, | |
1160 | SupportedPoints: []uint8{1}, | |
1161 | SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256}, | |
1162 | SupportedVersions: []uint16{VersionTLS12}, | |
1163 | }, "doesn't support ECDHE"}, | |
1164 | {ecdsaCert, &ClientHelloInfo{ | |
1165 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1166 | SupportedCurves: []CurveID{CurveP256}, | |
1167 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1168 | SignatureSchemes: []SignatureScheme{PSSWithSHA256}, | |
1169 | SupportedVersions: []uint16{VersionTLS12}, | |
1170 | }, "signature algorithms"}, | |
1171 | ||
1172 | {ed25519Cert, &ClientHelloInfo{ | |
1173 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1174 | SupportedCurves: []CurveID{CurveP256}, // only relevant for ECDHE support | |
1175 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1176 | SignatureSchemes: []SignatureScheme{Ed25519}, | |
1177 | SupportedVersions: []uint16{VersionTLS12}, | |
1178 | }, ""}, | |
1179 | {ed25519Cert, &ClientHelloInfo{ | |
1180 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1181 | SupportedCurves: []CurveID{CurveP256}, // only relevant for ECDHE support | |
1182 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1183 | SignatureSchemes: []SignatureScheme{Ed25519}, | |
1184 | SupportedVersions: []uint16{VersionTLS10}, | |
1185 | }, "doesn't support Ed25519"}, | |
1186 | {ed25519Cert, &ClientHelloInfo{ | |
1187 | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |
1188 | SupportedCurves: []CurveID{}, | |
1189 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1190 | SignatureSchemes: []SignatureScheme{Ed25519}, | |
1191 | SupportedVersions: []uint16{VersionTLS12}, | |
1192 | }, "doesn't support ECDHE"}, | |
1193 | ||
1194 | {rsaCert, &ClientHelloInfo{ | |
1195 | CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, | |
1196 | SupportedCurves: []CurveID{CurveP256}, // only relevant for ECDHE support | |
1197 | SupportedPoints: []uint8{pointFormatUncompressed}, | |
1198 | SupportedVersions: []uint16{VersionTLS10}, | |
1199 | }, ""}, | |
1200 | {rsaCert, &ClientHelloInfo{ | |
1201 | CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, | |
1202 | SupportedVersions: []uint16{VersionTLS12}, | |
1203 | }, ""}, // static RSA fallback | |
1204 | } | |
1205 | for i, tt := range tests { | |
1206 | err := tt.chi.SupportsCertificate(tt.c) | |
1207 | switch { | |
1208 | case tt.wantErr == "" && err != nil: | |
1209 | t.Errorf("%d: unexpected error: %v", i, err) | |
1210 | case tt.wantErr != "" && err == nil: | |
1211 | t.Errorf("%d: unexpected success", i) | |
1212 | case tt.wantErr != "" && !strings.Contains(err.Error(), tt.wantErr): | |
1213 | t.Errorf("%d: got error %q, expected %q", i, err, tt.wantErr) | |
1214 | } | |
1215 | } | |
1216 | } | |
1217 | ||
1218 | func TestCipherSuites(t *testing.T) { | |
1219 | var lastID uint16 | |
1220 | for _, c := range CipherSuites() { | |
1221 | if lastID > c.ID { | |
1222 | t.Errorf("CipherSuites are not ordered by ID: got %#04x after %#04x", c.ID, lastID) | |
1223 | } else { | |
1224 | lastID = c.ID | |
1225 | } | |
1226 | ||
1227 | if c.Insecure { | |
1228 | t.Errorf("%#04x: Insecure CipherSuite returned by CipherSuites()", c.ID) | |
1229 | } | |
1230 | } | |
1231 | lastID = 0 | |
1232 | for _, c := range InsecureCipherSuites() { | |
1233 | if lastID > c.ID { | |
1234 | t.Errorf("InsecureCipherSuites are not ordered by ID: got %#04x after %#04x", c.ID, lastID) | |
1235 | } else { | |
1236 | lastID = c.ID | |
1237 | } | |
1238 | ||
1239 | if !c.Insecure { | |
1240 | t.Errorf("%#04x: not Insecure CipherSuite returned by InsecureCipherSuites()", c.ID) | |
1241 | } | |
1242 | } | |
1243 | ||
1244 | cipherSuiteByID := func(id uint16) *CipherSuite { | |
1245 | for _, c := range CipherSuites() { | |
1246 | if c.ID == id { | |
1247 | return c | |
1248 | } | |
1249 | } | |
1250 | for _, c := range InsecureCipherSuites() { | |
1251 | if c.ID == id { | |
1252 | return c | |
1253 | } | |
1254 | } | |
1255 | return nil | |
1256 | } | |
1257 | ||
1258 | for _, c := range cipherSuites { | |
1259 | cc := cipherSuiteByID(c.id) | |
1260 | if cc == nil { | |
1261 | t.Errorf("%#04x: no CipherSuite entry", c.id) | |
1262 | continue | |
1263 | } | |
1264 | ||
1265 | if defaultOff := c.flags&suiteDefaultOff != 0; defaultOff != cc.Insecure { | |
1266 | t.Errorf("%#04x: Insecure %v, expected %v", c.id, cc.Insecure, defaultOff) | |
1267 | } | |
1268 | if tls12Only := c.flags&suiteTLS12 != 0; tls12Only && len(cc.SupportedVersions) != 1 { | |
1269 | t.Errorf("%#04x: suite is TLS 1.2 only, but SupportedVersions is %v", c.id, cc.SupportedVersions) | |
1270 | } else if !tls12Only && len(cc.SupportedVersions) != 3 { | |
1271 | t.Errorf("%#04x: suite TLS 1.0-1.2, but SupportedVersions is %v", c.id, cc.SupportedVersions) | |
1272 | } | |
1273 | ||
1274 | if got := CipherSuiteName(c.id); got != cc.Name { | |
1275 | t.Errorf("%#04x: unexpected CipherSuiteName: got %q, expected %q", c.id, got, cc.Name) | |
1276 | } | |
1277 | } | |
1278 | for _, c := range cipherSuitesTLS13 { | |
1279 | cc := cipherSuiteByID(c.id) | |
1280 | if cc == nil { | |
1281 | t.Errorf("%#04x: no CipherSuite entry", c.id) | |
1282 | continue | |
1283 | } | |
1284 | ||
1285 | if cc.Insecure { | |
1286 | t.Errorf("%#04x: Insecure %v, expected false", c.id, cc.Insecure) | |
1287 | } | |
1288 | if len(cc.SupportedVersions) != 1 || cc.SupportedVersions[0] != VersionTLS13 { | |
1289 | t.Errorf("%#04x: suite is TLS 1.3 only, but SupportedVersions is %v", c.id, cc.SupportedVersions) | |
1290 | } | |
1291 | ||
1292 | if got := CipherSuiteName(c.id); got != cc.Name { | |
1293 | t.Errorf("%#04x: unexpected CipherSuiteName: got %q, expected %q", c.id, got, cc.Name) | |
1294 | } | |
1295 | } | |
1296 | ||
1297 | if got := CipherSuiteName(0xabc); got != "0x0ABC" { | |
1298 | t.Errorf("unexpected fallback CipherSuiteName: got %q, expected 0x0ABC", got) | |
1299 | } | |
1300 | } | |
1301 | ||
1302 | type brokenSigner struct{ crypto.Signer } | |
1303 | ||
1304 | func (s brokenSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) { | |
1305 | // Replace opts with opts.HashFunc(), so rsa.PSSOptions are discarded. | |
1306 | return s.Signer.Sign(rand, digest, opts.HashFunc()) | |
1307 | } | |
1308 | ||
1309 | // TestPKCS1OnlyCert uses a client certificate with a broken crypto.Signer that | |
1310 | // always makes PKCS#1 v1.5 signatures, so can't be used with RSA-PSS. | |
1311 | func TestPKCS1OnlyCert(t *testing.T) { | |
1312 | clientConfig := testConfig.Clone() | |
1313 | clientConfig.Certificates = []Certificate{{ | |
1314 | Certificate: [][]byte{testRSACertificate}, | |
1315 | PrivateKey: brokenSigner{testRSAPrivateKey}, | |
1316 | }} | |
1317 | serverConfig := testConfig.Clone() | |
1318 | serverConfig.MaxVersion = VersionTLS12 // TLS 1.3 doesn't support PKCS#1 v1.5 | |
1319 | serverConfig.ClientAuth = RequireAnyClientCert | |
1320 | ||
1321 | // If RSA-PSS is selected, the handshake should fail. | |
1322 | if _, _, err := testHandshake(t, clientConfig, serverConfig); err == nil { | |
1323 | t.Fatal("expected broken certificate to cause connection to fail") | |
1324 | } | |
1325 | ||
1326 | clientConfig.Certificates[0].SupportedSignatureAlgorithms = | |
1327 | []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256} | |
1328 | ||
1329 | // But if the certificate restricts supported algorithms, RSA-PSS should not | |
1330 | // be selected, and the handshake should succeed. | |
1331 | if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil { | |
1332 | t.Error(err) | |
1333 | } | |
1334 | } |