blob: 360de1255f7d7e13d0a0d03bff7d5e14eb6f8cbe [file] [log] [blame]
Adam Langley95c29f32014-06-20 12:00:00 -07001package main
2
3import (
4 "bytes"
David Benjamin407a10c2014-07-16 12:58:59 -04005 "crypto/x509"
David Benjamin2561dc32014-08-24 01:25:27 -04006 "encoding/base64"
Adam Langley95c29f32014-06-20 12:00:00 -07007 "flag"
8 "fmt"
9 "io"
Kenny Root7fdeaf12014-08-05 15:23:37 -070010 "io/ioutil"
Adam Langley95c29f32014-06-20 12:00:00 -070011 "net"
12 "os"
13 "os/exec"
David Benjamin884fdf12014-08-02 15:28:23 -040014 "path"
David Benjamin2bc8e6f2014-08-02 15:22:37 -040015 "runtime"
Adam Langley95c29f32014-06-20 12:00:00 -070016 "strings"
17 "sync"
18 "syscall"
19)
20
21var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
22
David Benjamin025b3d32014-07-01 19:53:04 -040023const (
24 rsaCertificateFile = "cert.pem"
25 ecdsaCertificateFile = "ecdsa_cert.pem"
26)
27
28const (
29 rsaKeyFile = "key.pem"
30 ecdsaKeyFile = "ecdsa_key.pem"
31)
32
Adam Langley95c29f32014-06-20 12:00:00 -070033var rsaCertificate, ecdsaCertificate Certificate
34
35func initCertificates() {
36 var err error
David Benjamin025b3d32014-07-01 19:53:04 -040037 rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070038 if err != nil {
39 panic(err)
40 }
41
David Benjamin025b3d32014-07-01 19:53:04 -040042 ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070043 if err != nil {
44 panic(err)
45 }
46}
47
48var certificateOnce sync.Once
49
50func getRSACertificate() Certificate {
51 certificateOnce.Do(initCertificates)
52 return rsaCertificate
53}
54
55func getECDSACertificate() Certificate {
56 certificateOnce.Do(initCertificates)
57 return ecdsaCertificate
58}
59
David Benjamin025b3d32014-07-01 19:53:04 -040060type testType int
61
62const (
63 clientTest testType = iota
64 serverTest
65)
66
David Benjamin6fd297b2014-08-11 18:43:38 -040067type protocol int
68
69const (
70 tls protocol = iota
71 dtls
72)
73
Adam Langley95c29f32014-06-20 12:00:00 -070074type testCase struct {
David Benjamin025b3d32014-07-01 19:53:04 -040075 testType testType
David Benjamin6fd297b2014-08-11 18:43:38 -040076 protocol protocol
Adam Langley95c29f32014-06-20 12:00:00 -070077 name string
78 config Config
79 shouldFail bool
80 expectedError string
Adam Langleyac61fa32014-06-23 12:03:11 -070081 // expectedLocalError, if not empty, contains a substring that must be
82 // found in the local error.
83 expectedLocalError string
David Benjamin7e2e6cf2014-08-07 17:44:24 -040084 // expectedVersion, if non-zero, specifies the TLS version that must be
85 // negotiated.
86 expectedVersion uint16
Adam Langley80842bd2014-06-20 12:00:00 -070087 // messageLen is the length, in bytes, of the test message that will be
88 // sent.
89 messageLen int
David Benjamin025b3d32014-07-01 19:53:04 -040090 // certFile is the path to the certificate to use for the server.
91 certFile string
92 // keyFile is the path to the private key to use for the server.
93 keyFile string
David Benjamin1d5c83e2014-07-22 19:20:02 -040094 // resumeSession controls whether a second connection should be tested
95 // which resumes the first session.
96 resumeSession bool
David Benjamin98e882e2014-08-08 13:24:34 -040097 // sendPrefix sends a prefix on the socket before actually performing a
98 // handshake.
99 sendPrefix string
David Benjamin325b5c32014-07-01 19:40:31 -0400100 // flags, if not empty, contains a list of command-line flags that will
101 // be passed to the shim program.
102 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -0700103}
104
David Benjamin025b3d32014-07-01 19:53:04 -0400105var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700106 {
107 name: "BadRSASignature",
108 config: Config{
109 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
110 Bugs: ProtocolBugs{
111 InvalidSKXSignature: true,
112 },
113 },
114 shouldFail: true,
115 expectedError: ":BAD_SIGNATURE:",
116 },
117 {
118 name: "BadECDSASignature",
119 config: Config{
120 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
121 Bugs: ProtocolBugs{
122 InvalidSKXSignature: true,
123 },
124 Certificates: []Certificate{getECDSACertificate()},
125 },
126 shouldFail: true,
127 expectedError: ":BAD_SIGNATURE:",
128 },
129 {
130 name: "BadECDSACurve",
131 config: Config{
132 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
133 Bugs: ProtocolBugs{
134 InvalidSKXCurve: true,
135 },
136 Certificates: []Certificate{getECDSACertificate()},
137 },
138 shouldFail: true,
139 expectedError: ":WRONG_CURVE:",
140 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700141 {
David Benjamina8e3e0e2014-08-06 22:11:10 -0400142 testType: serverTest,
143 name: "BadRSAVersion",
144 config: Config{
145 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
146 Bugs: ProtocolBugs{
147 RsaClientKeyExchangeVersion: VersionTLS11,
148 },
149 },
150 shouldFail: true,
151 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
152 },
153 {
David Benjamin325b5c32014-07-01 19:40:31 -0400154 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700155 config: Config{
156 Bugs: ProtocolBugs{
157 FailIfNotFallbackSCSV: true,
158 },
159 },
160 shouldFail: true,
161 expectedLocalError: "no fallback SCSV found",
162 },
David Benjamin325b5c32014-07-01 19:40:31 -0400163 {
David Benjamin2a0c4962014-08-22 23:46:35 -0400164 name: "SendFallbackSCSV",
David Benjamin325b5c32014-07-01 19:40:31 -0400165 config: Config{
166 Bugs: ProtocolBugs{
167 FailIfNotFallbackSCSV: true,
168 },
169 },
170 flags: []string{"-fallback-scsv"},
171 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400172 {
173 testType: serverTest,
David Benjamin35a7a442014-07-05 00:23:20 -0400174 name: "ServerNameExtension",
David Benjamin197b3ab2014-07-02 18:37:33 -0400175 config: Config{
176 ServerName: "example.com",
177 },
178 flags: []string{"-expect-server-name", "example.com"},
179 },
David Benjamin35a7a442014-07-05 00:23:20 -0400180 {
181 testType: clientTest,
182 name: "DuplicateExtensionClient",
183 config: Config{
184 Bugs: ProtocolBugs{
185 DuplicateExtension: true,
186 },
187 },
188 shouldFail: true,
189 expectedLocalError: "remote error: error decoding message",
190 },
191 {
192 testType: serverTest,
193 name: "DuplicateExtensionServer",
194 config: Config{
195 Bugs: ProtocolBugs{
196 DuplicateExtension: true,
197 },
198 },
199 shouldFail: true,
200 expectedLocalError: "remote error: error decoding message",
201 },
David Benjamin7b030512014-07-08 17:30:11 -0400202 {
203 name: "ClientCertificateTypes",
204 config: Config{
205 ClientAuth: RequestClientCert,
206 ClientCertificateTypes: []byte{
207 CertTypeDSSSign,
208 CertTypeRSASign,
209 CertTypeECDSASign,
210 },
211 },
David Benjamin2561dc32014-08-24 01:25:27 -0400212 flags: []string{
213 "-expect-certificate-types",
214 base64.StdEncoding.EncodeToString([]byte{
215 CertTypeDSSSign,
216 CertTypeRSASign,
217 CertTypeECDSASign,
218 }),
219 },
David Benjamin7b030512014-07-08 17:30:11 -0400220 },
David Benjamin636293b2014-07-08 17:59:18 -0400221 {
222 name: "NoClientCertificate",
223 config: Config{
224 ClientAuth: RequireAnyClientCert,
225 },
226 shouldFail: true,
227 expectedLocalError: "client didn't provide a certificate",
228 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400229 {
230 name: "UnauthenticatedECDH",
231 config: Config{
232 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
233 Bugs: ProtocolBugs{
234 UnauthenticatedECDH: true,
235 },
236 },
237 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400238 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400239 },
David Benjamin9c651c92014-07-12 13:27:45 -0400240 {
241 name: "SkipServerKeyExchange",
242 config: Config{
243 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
244 Bugs: ProtocolBugs{
245 SkipServerKeyExchange: true,
246 },
247 },
248 shouldFail: true,
249 expectedError: ":UNEXPECTED_MESSAGE:",
250 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400251 {
David Benjamina0e52232014-07-19 17:39:58 -0400252 name: "SkipChangeCipherSpec-Client",
253 config: Config{
254 Bugs: ProtocolBugs{
255 SkipChangeCipherSpec: true,
256 },
257 },
258 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400259 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400260 },
261 {
262 testType: serverTest,
263 name: "SkipChangeCipherSpec-Server",
264 config: Config{
265 Bugs: ProtocolBugs{
266 SkipChangeCipherSpec: true,
267 },
268 },
269 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400270 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400271 },
David Benjamin42be6452014-07-21 14:50:23 -0400272 {
273 testType: serverTest,
274 name: "SkipChangeCipherSpec-Server-NPN",
275 config: Config{
276 NextProtos: []string{"bar"},
277 Bugs: ProtocolBugs{
278 SkipChangeCipherSpec: true,
279 },
280 },
281 flags: []string{
282 "-advertise-npn", "\x03foo\x03bar\x03baz",
283 },
284 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400285 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
286 },
287 {
288 name: "FragmentAcrossChangeCipherSpec-Client",
289 config: Config{
290 Bugs: ProtocolBugs{
291 FragmentAcrossChangeCipherSpec: true,
292 },
293 },
294 shouldFail: true,
295 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
296 },
297 {
298 testType: serverTest,
299 name: "FragmentAcrossChangeCipherSpec-Server",
300 config: Config{
301 Bugs: ProtocolBugs{
302 FragmentAcrossChangeCipherSpec: true,
303 },
304 },
305 shouldFail: true,
306 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
307 },
308 {
309 testType: serverTest,
310 name: "FragmentAcrossChangeCipherSpec-Server-NPN",
311 config: Config{
312 NextProtos: []string{"bar"},
313 Bugs: ProtocolBugs{
314 FragmentAcrossChangeCipherSpec: true,
315 },
316 },
317 flags: []string{
318 "-advertise-npn", "\x03foo\x03bar\x03baz",
319 },
320 shouldFail: true,
321 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamin42be6452014-07-21 14:50:23 -0400322 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400323 {
324 testType: serverTest,
325 name: "EarlyChangeCipherSpec-server-1",
326 config: Config{
327 Bugs: ProtocolBugs{
328 EarlyChangeCipherSpec: 1,
329 },
330 },
331 shouldFail: true,
332 expectedError: ":CCS_RECEIVED_EARLY:",
333 },
334 {
335 testType: serverTest,
336 name: "EarlyChangeCipherSpec-server-2",
337 config: Config{
338 Bugs: ProtocolBugs{
339 EarlyChangeCipherSpec: 2,
340 },
341 },
342 shouldFail: true,
343 expectedError: ":CCS_RECEIVED_EARLY:",
344 },
David Benjamind23f4122014-07-23 15:09:48 -0400345 {
David Benjamind23f4122014-07-23 15:09:48 -0400346 name: "SkipNewSessionTicket",
347 config: Config{
348 Bugs: ProtocolBugs{
349 SkipNewSessionTicket: true,
350 },
351 },
352 shouldFail: true,
353 expectedError: ":CCS_RECEIVED_EARLY:",
354 },
David Benjamin7e3305e2014-07-28 14:52:32 -0400355 {
David Benjamind86c7672014-08-02 04:07:12 -0400356 testType: serverTest,
David Benjaminbef270a2014-08-02 04:22:02 -0400357 name: "FallbackSCSV",
358 config: Config{
359 MaxVersion: VersionTLS11,
360 Bugs: ProtocolBugs{
361 SendFallbackSCSV: true,
362 },
363 },
364 shouldFail: true,
365 expectedError: ":INAPPROPRIATE_FALLBACK:",
366 },
367 {
368 testType: serverTest,
369 name: "FallbackSCSV-VersionMatch",
370 config: Config{
371 Bugs: ProtocolBugs{
372 SendFallbackSCSV: true,
373 },
374 },
375 },
David Benjamin98214542014-08-07 18:02:39 -0400376 {
377 testType: serverTest,
378 name: "FragmentedClientVersion",
379 config: Config{
380 Bugs: ProtocolBugs{
381 MaxHandshakeRecordLength: 1,
382 FragmentClientVersion: true,
383 },
384 },
385 shouldFail: true,
386 expectedError: ":RECORD_TOO_SMALL:",
387 },
David Benjamin98e882e2014-08-08 13:24:34 -0400388 {
389 testType: serverTest,
390 name: "MinorVersionTolerance",
391 config: Config{
392 Bugs: ProtocolBugs{
393 SendClientVersion: 0x03ff,
394 },
395 },
396 expectedVersion: VersionTLS12,
397 },
398 {
399 testType: serverTest,
400 name: "MajorVersionTolerance",
401 config: Config{
402 Bugs: ProtocolBugs{
403 SendClientVersion: 0x0400,
404 },
405 },
406 expectedVersion: VersionTLS12,
407 },
408 {
409 testType: serverTest,
410 name: "VersionTooLow",
411 config: Config{
412 Bugs: ProtocolBugs{
413 SendClientVersion: 0x0200,
414 },
415 },
416 shouldFail: true,
417 expectedError: ":UNSUPPORTED_PROTOCOL:",
418 },
419 {
420 testType: serverTest,
421 name: "HttpGET",
422 sendPrefix: "GET / HTTP/1.0\n",
423 shouldFail: true,
424 expectedError: ":HTTP_REQUEST:",
425 },
426 {
427 testType: serverTest,
428 name: "HttpPOST",
429 sendPrefix: "POST / HTTP/1.0\n",
430 shouldFail: true,
431 expectedError: ":HTTP_REQUEST:",
432 },
433 {
434 testType: serverTest,
435 name: "HttpHEAD",
436 sendPrefix: "HEAD / HTTP/1.0\n",
437 shouldFail: true,
438 expectedError: ":HTTP_REQUEST:",
439 },
440 {
441 testType: serverTest,
442 name: "HttpPUT",
443 sendPrefix: "PUT / HTTP/1.0\n",
444 shouldFail: true,
445 expectedError: ":HTTP_REQUEST:",
446 },
447 {
448 testType: serverTest,
449 name: "HttpCONNECT",
450 sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
451 shouldFail: true,
452 expectedError: ":HTTPS_PROXY_REQUEST:",
453 },
Adam Langley95c29f32014-06-20 12:00:00 -0700454}
455
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400456func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error {
David Benjamin6fd297b2014-08-11 18:43:38 -0400457 if test.protocol == dtls {
458 conn = newPacketAdaptor(conn)
459 }
460
461 if test.sendPrefix != "" {
462 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
463 return err
464 }
David Benjamin98e882e2014-08-08 13:24:34 -0400465 }
466
David Benjamin1d5c83e2014-07-22 19:20:02 -0400467 var tlsConn *Conn
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400468 if test.testType == clientTest {
David Benjamin6fd297b2014-08-11 18:43:38 -0400469 if test.protocol == dtls {
470 tlsConn = DTLSServer(conn, config)
471 } else {
472 tlsConn = Server(conn, config)
473 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400474 } else {
475 config.InsecureSkipVerify = true
David Benjamin6fd297b2014-08-11 18:43:38 -0400476 if test.protocol == dtls {
477 tlsConn = DTLSClient(conn, config)
478 } else {
479 tlsConn = Client(conn, config)
480 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400481 }
482
Adam Langley95c29f32014-06-20 12:00:00 -0700483 if err := tlsConn.Handshake(); err != nil {
484 return err
485 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700486
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400487 if vers := tlsConn.ConnectionState().Version; test.expectedVersion != 0 && vers != test.expectedVersion {
488 return fmt.Errorf("got version %x, expected %x", vers, test.expectedVersion)
489 }
490
Kenny Root7fdeaf12014-08-05 15:23:37 -0700491 if messageLen < 0 {
David Benjamin6fd297b2014-08-11 18:43:38 -0400492 if test.protocol == dtls {
493 return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
494 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700495 // Read until EOF.
496 _, err := io.Copy(ioutil.Discard, tlsConn)
497 return err
498 }
499
Adam Langley80842bd2014-06-20 12:00:00 -0700500 if messageLen == 0 {
501 messageLen = 32
502 }
503 testMessage := make([]byte, messageLen)
504 for i := range testMessage {
505 testMessage[i] = 0x42
506 }
Adam Langley95c29f32014-06-20 12:00:00 -0700507 tlsConn.Write(testMessage)
508
509 buf := make([]byte, len(testMessage))
David Benjamin6fd297b2014-08-11 18:43:38 -0400510 if test.protocol == dtls {
511 bufTmp := make([]byte, len(buf)+1)
512 n, err := tlsConn.Read(bufTmp)
513 if err != nil {
514 return err
515 }
516 if n != len(buf) {
517 return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
518 }
519 copy(buf, bufTmp)
520 } else {
521 _, err := io.ReadFull(tlsConn, buf)
522 if err != nil {
523 return err
524 }
Adam Langley95c29f32014-06-20 12:00:00 -0700525 }
526
527 for i, v := range buf {
528 if v != testMessage[i]^0xff {
529 return fmt.Errorf("bad reply contents at byte %d", i)
530 }
531 }
532
533 return nil
534}
535
David Benjamin325b5c32014-07-01 19:40:31 -0400536func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
537 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700538 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400539 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700540 }
David Benjamin325b5c32014-07-01 19:40:31 -0400541 valgrindArgs = append(valgrindArgs, path)
542 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700543
David Benjamin325b5c32014-07-01 19:40:31 -0400544 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700545}
546
David Benjamin325b5c32014-07-01 19:40:31 -0400547func gdbOf(path string, args ...string) *exec.Cmd {
548 xtermArgs := []string{"-e", "gdb", "--args"}
549 xtermArgs = append(xtermArgs, path)
550 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700551
David Benjamin325b5c32014-07-01 19:40:31 -0400552 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700553}
554
David Benjamin1d5c83e2014-07-22 19:20:02 -0400555func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700556 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
557 if err != nil {
558 panic(err)
559 }
560
561 syscall.CloseOnExec(socks[0])
562 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400563 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700564 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400565 conn, err = net.FileConn(connFile)
566 if err != nil {
567 panic(err)
568 }
Adam Langley95c29f32014-06-20 12:00:00 -0700569 connFile.Close()
570 if err != nil {
571 panic(err)
572 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400573 return shimEnd, conn
574}
575
David Benjamin884fdf12014-08-02 15:28:23 -0400576func runTest(test *testCase, buildDir string) error {
David Benjamin1d5c83e2014-07-22 19:20:02 -0400577 shimEnd, conn := openSocketPair()
578 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700579
David Benjamin884fdf12014-08-02 15:28:23 -0400580 shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
David Benjamin5a593af2014-08-11 19:51:50 -0400581 var flags []string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400582 if test.testType == serverTest {
David Benjamin5a593af2014-08-11 19:51:50 -0400583 flags = append(flags, "-server")
584
David Benjamin025b3d32014-07-01 19:53:04 -0400585 flags = append(flags, "-key-file")
586 if test.keyFile == "" {
587 flags = append(flags, rsaKeyFile)
588 } else {
589 flags = append(flags, test.keyFile)
590 }
591
592 flags = append(flags, "-cert-file")
593 if test.certFile == "" {
594 flags = append(flags, rsaCertificateFile)
595 } else {
596 flags = append(flags, test.certFile)
597 }
598 }
David Benjamin5a593af2014-08-11 19:51:50 -0400599
David Benjamin6fd297b2014-08-11 18:43:38 -0400600 if test.protocol == dtls {
601 flags = append(flags, "-dtls")
602 }
603
David Benjamin5a593af2014-08-11 19:51:50 -0400604 if test.resumeSession {
605 flags = append(flags, "-resume")
606 }
607
David Benjamin025b3d32014-07-01 19:53:04 -0400608 flags = append(flags, test.flags...)
609
610 var shim *exec.Cmd
611 if *useValgrind {
612 shim = valgrindOf(false, shim_path, flags...)
613 } else {
614 shim = exec.Command(shim_path, flags...)
615 }
616 // shim = gdbOf(shim_path, flags...)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400617 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400618 shim.Stdin = os.Stdin
619 var stdoutBuf, stderrBuf bytes.Buffer
620 shim.Stdout = &stdoutBuf
621 shim.Stderr = &stderrBuf
622
623 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700624 panic(err)
625 }
David Benjamin025b3d32014-07-01 19:53:04 -0400626 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400627 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700628
629 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400630 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400631 if test.testType == clientTest {
632 if len(config.Certificates) == 0 {
633 config.Certificates = []Certificate{getRSACertificate()}
634 }
David Benjamin025b3d32014-07-01 19:53:04 -0400635 }
Adam Langley95c29f32014-06-20 12:00:00 -0700636
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400637 err := doExchange(test, &config, conn, test.messageLen)
Adam Langley95c29f32014-06-20 12:00:00 -0700638 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400639 if err == nil && test.resumeSession {
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400640 err = doExchange(test, &config, connResume, test.messageLen)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400641 connResume.Close()
642 }
643
David Benjamin025b3d32014-07-01 19:53:04 -0400644 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700645
646 stdout := string(stdoutBuf.Bytes())
647 stderr := string(stderrBuf.Bytes())
648 failed := err != nil || childErr != nil
649 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700650 localError := "none"
651 if err != nil {
652 localError = err.Error()
653 }
654 if len(test.expectedLocalError) != 0 {
655 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
656 }
Adam Langley95c29f32014-06-20 12:00:00 -0700657
658 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700659 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700660 if childErr != nil {
661 childError = childErr.Error()
662 }
663
664 var msg string
665 switch {
666 case failed && !test.shouldFail:
667 msg = "unexpected failure"
668 case !failed && test.shouldFail:
669 msg = "unexpected success"
670 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700671 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700672 default:
673 panic("internal error")
674 }
675
676 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
677 }
678
679 if !*useValgrind && len(stderr) > 0 {
680 println(stderr)
681 }
682
683 return nil
684}
685
686var tlsVersions = []struct {
687 name string
688 version uint16
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400689 flag string
Adam Langley95c29f32014-06-20 12:00:00 -0700690}{
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400691 {"SSL3", VersionSSL30, "-no-ssl3"},
692 {"TLS1", VersionTLS10, "-no-tls1"},
693 {"TLS11", VersionTLS11, "-no-tls11"},
694 {"TLS12", VersionTLS12, "-no-tls12"},
Adam Langley95c29f32014-06-20 12:00:00 -0700695}
696
697var testCipherSuites = []struct {
698 name string
699 id uint16
700}{
701 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400702 {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700703 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400704 {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700705 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400706 {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
707 {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
708 {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
709 {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700710 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
711 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
712 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
713 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700714 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700715 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400716 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700717 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
718 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700719 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400720 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700721}
722
723func addCipherSuiteTests() {
724 for _, suite := range testCipherSuites {
725 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400726 var certFile string
727 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700728 if strings.Contains(suite.name, "ECDSA") {
729 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400730 certFile = ecdsaCertificateFile
731 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700732 } else {
733 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400734 certFile = rsaCertificateFile
735 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700736 }
737
738 for _, ver := range tlsVersions {
739 if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
740 continue
741 }
742
David Benjamin1d5c83e2014-07-22 19:20:02 -0400743 // Go's TLS implementation only implements session
744 // resumption with tickets, so SSLv3 cannot resume
745 // sessions.
746 resumeSession := ver.version != VersionSSL30
747
David Benjamin025b3d32014-07-01 19:53:04 -0400748 testCases = append(testCases, testCase{
749 testType: clientTest,
750 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700751 config: Config{
752 MinVersion: ver.version,
753 MaxVersion: ver.version,
754 CipherSuites: []uint16{suite.id},
755 Certificates: []Certificate{cert},
756 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400757 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700758 })
David Benjamin025b3d32014-07-01 19:53:04 -0400759
David Benjamin76d8abe2014-08-14 16:25:34 -0400760 testCases = append(testCases, testCase{
761 testType: serverTest,
762 name: ver.name + "-" + suite.name + "-server",
763 config: Config{
764 MinVersion: ver.version,
765 MaxVersion: ver.version,
766 CipherSuites: []uint16{suite.id},
767 Certificates: []Certificate{cert},
768 },
769 certFile: certFile,
770 keyFile: keyFile,
771 resumeSession: resumeSession,
772 })
David Benjamin6fd297b2014-08-11 18:43:38 -0400773
774 // TODO(davidben): Fix DTLS 1.2 support and test that.
775 if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
776 testCases = append(testCases, testCase{
777 testType: clientTest,
778 protocol: dtls,
779 name: "D" + ver.name + "-" + suite.name + "-client",
780 config: Config{
781 MinVersion: ver.version,
782 MaxVersion: ver.version,
783 CipherSuites: []uint16{suite.id},
784 Certificates: []Certificate{cert},
785 },
786 resumeSession: resumeSession,
787 })
788 testCases = append(testCases, testCase{
789 testType: serverTest,
790 protocol: dtls,
791 name: "D" + ver.name + "-" + suite.name + "-server",
792 config: Config{
793 MinVersion: ver.version,
794 MaxVersion: ver.version,
795 CipherSuites: []uint16{suite.id},
796 Certificates: []Certificate{cert},
797 },
798 certFile: certFile,
799 keyFile: keyFile,
800 resumeSession: resumeSession,
801 })
802 }
Adam Langley95c29f32014-06-20 12:00:00 -0700803 }
804 }
805}
806
807func addBadECDSASignatureTests() {
808 for badR := BadValue(1); badR < NumBadValues; badR++ {
809 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400810 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700811 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
812 config: Config{
813 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
814 Certificates: []Certificate{getECDSACertificate()},
815 Bugs: ProtocolBugs{
816 BadECDSAR: badR,
817 BadECDSAS: badS,
818 },
819 },
820 shouldFail: true,
821 expectedError: "SIGNATURE",
822 })
823 }
824 }
825}
826
Adam Langley80842bd2014-06-20 12:00:00 -0700827func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400828 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700829 name: "MaxCBCPadding",
830 config: Config{
831 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
832 Bugs: ProtocolBugs{
833 MaxPadding: true,
834 },
835 },
836 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
837 })
David Benjamin025b3d32014-07-01 19:53:04 -0400838 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700839 name: "BadCBCPadding",
840 config: Config{
841 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
842 Bugs: ProtocolBugs{
843 PaddingFirstByteBad: true,
844 },
845 },
846 shouldFail: true,
847 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
848 })
849 // OpenSSL previously had an issue where the first byte of padding in
850 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400851 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700852 name: "BadCBCPadding255",
853 config: Config{
854 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
855 Bugs: ProtocolBugs{
856 MaxPadding: true,
857 PaddingFirstByteBadIf255: true,
858 },
859 },
860 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
861 shouldFail: true,
862 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
863 })
864}
865
Kenny Root7fdeaf12014-08-05 15:23:37 -0700866func addCBCSplittingTests() {
867 testCases = append(testCases, testCase{
868 name: "CBCRecordSplitting",
869 config: Config{
870 MaxVersion: VersionTLS10,
871 MinVersion: VersionTLS10,
872 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
873 },
874 messageLen: -1, // read until EOF
875 flags: []string{
876 "-async",
877 "-write-different-record-sizes",
878 "-cbc-record-splitting",
879 },
David Benjamina8e3e0e2014-08-06 22:11:10 -0400880 })
881 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -0700882 name: "CBCRecordSplittingPartialWrite",
883 config: Config{
884 MaxVersion: VersionTLS10,
885 MinVersion: VersionTLS10,
886 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
887 },
888 messageLen: -1, // read until EOF
889 flags: []string{
890 "-async",
891 "-write-different-record-sizes",
892 "-cbc-record-splitting",
893 "-partial-write",
894 },
895 })
896}
897
David Benjamin636293b2014-07-08 17:59:18 -0400898func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -0400899 // Add a dummy cert pool to stress certificate authority parsing.
900 // TODO(davidben): Add tests that those values parse out correctly.
901 certPool := x509.NewCertPool()
902 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
903 if err != nil {
904 panic(err)
905 }
906 certPool.AddCert(cert)
907
David Benjamin636293b2014-07-08 17:59:18 -0400908 for _, ver := range tlsVersions {
909 if ver.version == VersionSSL30 {
910 // TODO(davidben): The Go implementation does not
911 // correctly compute CertificateVerify hashes for SSLv3.
912 continue
913 }
914
915 var cipherSuites []uint16
916 if ver.version >= VersionTLS12 {
917 // Pick a SHA-256 cipher suite. The Go implementation
918 // does not correctly handle client auth with a SHA-384
919 // cipher suite.
920 cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
921 }
922
923 testCases = append(testCases, testCase{
924 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400925 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -0400926 config: Config{
927 MinVersion: ver.version,
928 MaxVersion: ver.version,
929 CipherSuites: cipherSuites,
930 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400931 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400932 },
933 flags: []string{
934 "-cert-file", rsaCertificateFile,
935 "-key-file", rsaKeyFile,
936 },
937 })
938 testCases = append(testCases, testCase{
939 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400940 name: ver.name + "-Client-ClientAuth-ECDSA",
David Benjamin636293b2014-07-08 17:59:18 -0400941 config: Config{
942 MinVersion: ver.version,
943 MaxVersion: ver.version,
944 CipherSuites: cipherSuites,
945 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400946 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400947 },
948 flags: []string{
949 "-cert-file", ecdsaCertificateFile,
950 "-key-file", ecdsaKeyFile,
951 },
952 })
David Benjamin67666e72014-07-12 15:47:52 -0400953 testCases = append(testCases, testCase{
954 testType: serverTest,
955 name: ver.name + "-Server-ClientAuth-RSA",
956 config: Config{
957 Certificates: []Certificate{rsaCertificate},
958 },
959 flags: []string{"-require-any-client-certificate"},
960 })
961 testCases = append(testCases, testCase{
962 testType: serverTest,
963 name: ver.name + "-Server-ClientAuth-ECDSA",
964 config: Config{
965 Certificates: []Certificate{ecdsaCertificate},
966 },
967 flags: []string{"-require-any-client-certificate"},
968 })
David Benjamin636293b2014-07-08 17:59:18 -0400969 }
970}
971
David Benjamin43ec06f2014-08-05 02:28:57 -0400972// Adds tests that try to cover the range of the handshake state machine, under
973// various conditions. Some of these are redundant with other tests, but they
974// only cover the synchronous case.
David Benjamin6fd297b2014-08-11 18:43:38 -0400975func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
David Benjamin43ec06f2014-08-05 02:28:57 -0400976 var suffix string
977 var flags []string
978 var maxHandshakeRecordLength int
David Benjamin6fd297b2014-08-11 18:43:38 -0400979 if protocol == dtls {
980 suffix = "-DTLS"
981 }
David Benjamin43ec06f2014-08-05 02:28:57 -0400982 if async {
David Benjamin6fd297b2014-08-11 18:43:38 -0400983 suffix += "-Async"
David Benjamin43ec06f2014-08-05 02:28:57 -0400984 flags = append(flags, "-async")
985 } else {
David Benjamin6fd297b2014-08-11 18:43:38 -0400986 suffix += "-Sync"
David Benjamin43ec06f2014-08-05 02:28:57 -0400987 }
988 if splitHandshake {
989 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -0400990 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -0400991 }
992
993 // Basic handshake, with resumption. Client and server.
994 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -0400995 protocol: protocol,
996 name: "Basic-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -0400997 config: Config{
998 Bugs: ProtocolBugs{
999 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1000 },
1001 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001002 flags: flags,
1003 resumeSession: true,
1004 })
1005 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001006 protocol: protocol,
1007 name: "Basic-Client-RenewTicket" + suffix,
David Benjaminbed9aae2014-08-07 19:13:38 -04001008 config: Config{
1009 Bugs: ProtocolBugs{
1010 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1011 RenewTicketOnResume: true,
1012 },
1013 },
1014 flags: flags,
1015 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001016 })
1017 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001018 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001019 testType: serverTest,
1020 name: "Basic-Server" + suffix,
1021 config: Config{
1022 Bugs: ProtocolBugs{
1023 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1024 },
1025 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001026 flags: flags,
1027 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001028 })
1029
David Benjamin6fd297b2014-08-11 18:43:38 -04001030 // TLS client auth.
1031 testCases = append(testCases, testCase{
1032 protocol: protocol,
1033 testType: clientTest,
1034 name: "ClientAuth-Client" + suffix,
1035 config: Config{
1036 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1037 ClientAuth: RequireAnyClientCert,
1038 Bugs: ProtocolBugs{
1039 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1040 },
1041 },
1042 flags: append(flags,
1043 "-cert-file", rsaCertificateFile,
1044 "-key-file", rsaKeyFile),
1045 })
1046 testCases = append(testCases, testCase{
1047 protocol: protocol,
1048 testType: serverTest,
1049 name: "ClientAuth-Server" + suffix,
1050 config: Config{
1051 Certificates: []Certificate{rsaCertificate},
1052 },
1053 flags: append(flags, "-require-any-client-certificate"),
1054 })
1055
David Benjamin43ec06f2014-08-05 02:28:57 -04001056 // No session ticket support; server doesn't send NewSessionTicket.
1057 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001058 protocol: protocol,
1059 name: "SessionTicketsDisabled-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001060 config: Config{
1061 SessionTicketsDisabled: true,
1062 Bugs: ProtocolBugs{
1063 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1064 },
1065 },
1066 flags: flags,
1067 })
1068 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001069 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001070 testType: serverTest,
1071 name: "SessionTicketsDisabled-Server" + suffix,
1072 config: Config{
1073 SessionTicketsDisabled: true,
1074 Bugs: ProtocolBugs{
1075 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1076 },
1077 },
1078 flags: flags,
1079 })
1080
David Benjamin6fd297b2014-08-11 18:43:38 -04001081 if protocol == tls {
1082 // NPN on client and server; results in post-handshake message.
1083 testCases = append(testCases, testCase{
1084 protocol: protocol,
1085 name: "NPN-Client" + suffix,
1086 config: Config{
1087 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1088 NextProtos: []string{"foo"},
1089 Bugs: ProtocolBugs{
1090 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1091 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001092 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001093 flags: append(flags, "-select-next-proto", "foo"),
1094 })
1095 testCases = append(testCases, testCase{
1096 protocol: protocol,
1097 testType: serverTest,
1098 name: "NPN-Server" + suffix,
1099 config: Config{
1100 NextProtos: []string{"bar"},
1101 Bugs: ProtocolBugs{
1102 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1103 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001104 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001105 flags: append(flags,
1106 "-advertise-npn", "\x03foo\x03bar\x03baz",
1107 "-expect-next-proto", "bar"),
1108 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001109
David Benjamin6fd297b2014-08-11 18:43:38 -04001110 // Client does False Start and negotiates NPN.
1111 testCases = append(testCases, testCase{
1112 protocol: protocol,
1113 name: "FalseStart" + suffix,
1114 config: Config{
1115 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1116 NextProtos: []string{"foo"},
1117 Bugs: ProtocolBugs{
1118 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1119 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001120 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001121 flags: append(flags,
1122 "-false-start",
1123 "-select-next-proto", "foo"),
1124 resumeSession: true,
1125 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001126
David Benjamin6fd297b2014-08-11 18:43:38 -04001127 // False Start without session tickets.
1128 testCases = append(testCases, testCase{
1129 name: "FalseStart-SessionTicketsDisabled",
1130 config: Config{
1131 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1132 NextProtos: []string{"foo"},
1133 SessionTicketsDisabled: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001134 Bugs: ProtocolBugs{
1135 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1136 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001137 },
David Benjamin4e99c522014-08-24 01:45:30 -04001138 flags: append(flags,
David Benjamin6fd297b2014-08-11 18:43:38 -04001139 "-false-start",
1140 "-select-next-proto", "foo",
David Benjamin4e99c522014-08-24 01:45:30 -04001141 ),
David Benjamin6fd297b2014-08-11 18:43:38 -04001142 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001143
David Benjamin6fd297b2014-08-11 18:43:38 -04001144 // Client sends a V2ClientHello.
1145 testCases = append(testCases, testCase{
1146 protocol: protocol,
1147 testType: serverTest,
1148 name: "SendV2ClientHello" + suffix,
1149 config: Config{
1150 // Choose a cipher suite that does not involve
1151 // elliptic curves, so no extensions are
1152 // involved.
1153 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1154 Bugs: ProtocolBugs{
1155 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1156 SendV2ClientHello: true,
1157 },
David Benjamin1e7f8d72014-08-08 12:27:04 -04001158 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001159 flags: flags,
1160 })
1161 } else {
1162 testCases = append(testCases, testCase{
1163 protocol: protocol,
1164 name: "SkipHelloVerifyRequest" + suffix,
1165 config: Config{
1166 Bugs: ProtocolBugs{
1167 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1168 SkipHelloVerifyRequest: true,
1169 },
1170 },
1171 flags: flags,
1172 })
1173
1174 testCases = append(testCases, testCase{
1175 testType: serverTest,
1176 protocol: protocol,
1177 name: "CookieExchange" + suffix,
1178 config: Config{
1179 Bugs: ProtocolBugs{
1180 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1181 },
1182 },
1183 flags: append(flags, "-cookie-exchange"),
1184 })
1185 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001186}
1187
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001188func addVersionNegotiationTests() {
1189 for i, shimVers := range tlsVersions {
1190 // Assemble flags to disable all newer versions on the shim.
1191 var flags []string
1192 for _, vers := range tlsVersions[i+1:] {
1193 flags = append(flags, vers.flag)
1194 }
1195
1196 for _, runnerVers := range tlsVersions {
1197 expectedVersion := shimVers.version
1198 if runnerVers.version < shimVers.version {
1199 expectedVersion = runnerVers.version
1200 }
1201 suffix := shimVers.name + "-" + runnerVers.name
1202
1203 testCases = append(testCases, testCase{
1204 testType: clientTest,
1205 name: "VersionNegotiation-Client-" + suffix,
1206 config: Config{
1207 MaxVersion: runnerVers.version,
1208 },
1209 flags: flags,
1210 expectedVersion: expectedVersion,
1211 })
1212
David Benjamin76d8abe2014-08-14 16:25:34 -04001213 testCases = append(testCases, testCase{
1214 testType: serverTest,
1215 name: "VersionNegotiation-Server-" + suffix,
1216 config: Config{
1217 MaxVersion: runnerVers.version,
1218 },
1219 flags: flags,
1220 expectedVersion: expectedVersion,
1221 })
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001222 }
1223 }
1224}
1225
David Benjamin884fdf12014-08-02 15:28:23 -04001226func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07001227 defer wg.Done()
1228
1229 for test := range c {
1230 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04001231 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07001232 statusChan <- statusMsg{test: test, err: err}
1233 }
1234}
1235
1236type statusMsg struct {
1237 test *testCase
1238 started bool
1239 err error
1240}
1241
1242func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1243 var started, done, failed, lineLen int
1244 defer close(doneChan)
1245
1246 for msg := range statusChan {
1247 if msg.started {
1248 started++
1249 } else {
1250 done++
1251 }
1252
1253 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1254
1255 if msg.err != nil {
1256 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1257 failed++
1258 }
1259 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1260 lineLen = len(line)
1261 os.Stdout.WriteString(line)
1262 }
1263}
1264
1265func main() {
1266 var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
David Benjamin2bc8e6f2014-08-02 15:22:37 -04001267 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04001268 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07001269
1270 flag.Parse()
1271
1272 addCipherSuiteTests()
1273 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07001274 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07001275 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04001276 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001277 addVersionNegotiationTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04001278 for _, async := range []bool{false, true} {
1279 for _, splitHandshake := range []bool{false, true} {
David Benjamin6fd297b2014-08-11 18:43:38 -04001280 for _, protocol := range []protocol{tls, dtls} {
1281 addStateMachineCoverageTests(async, splitHandshake, protocol)
1282 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001283 }
1284 }
Adam Langley95c29f32014-06-20 12:00:00 -07001285
1286 var wg sync.WaitGroup
1287
David Benjamin2bc8e6f2014-08-02 15:22:37 -04001288 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07001289
1290 statusChan := make(chan statusMsg, numWorkers)
1291 testChan := make(chan *testCase, numWorkers)
1292 doneChan := make(chan struct{})
1293
David Benjamin025b3d32014-07-01 19:53:04 -04001294 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07001295
1296 for i := 0; i < numWorkers; i++ {
1297 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04001298 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07001299 }
1300
David Benjamin025b3d32014-07-01 19:53:04 -04001301 for i := range testCases {
1302 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
1303 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07001304 }
1305 }
1306
1307 close(testChan)
1308 wg.Wait()
1309 close(statusChan)
1310 <-doneChan
1311
1312 fmt.Printf("\n")
1313}