blob: 57bcf8746c5abfc1b68427d801b4ca17688ce607 [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"
Adam Langley95c29f32014-06-20 12:00:00 -07006 "flag"
7 "fmt"
8 "io"
Kenny Root7fdeaf12014-08-05 15:23:37 -07009 "io/ioutil"
Adam Langley95c29f32014-06-20 12:00:00 -070010 "net"
11 "os"
12 "os/exec"
David Benjamin884fdf12014-08-02 15:28:23 -040013 "path"
David Benjamin2bc8e6f2014-08-02 15:22:37 -040014 "runtime"
Adam Langley95c29f32014-06-20 12:00:00 -070015 "strings"
16 "sync"
17 "syscall"
18)
19
20var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
21
David Benjamin025b3d32014-07-01 19:53:04 -040022const (
23 rsaCertificateFile = "cert.pem"
24 ecdsaCertificateFile = "ecdsa_cert.pem"
25)
26
27const (
28 rsaKeyFile = "key.pem"
29 ecdsaKeyFile = "ecdsa_key.pem"
30)
31
Adam Langley95c29f32014-06-20 12:00:00 -070032var rsaCertificate, ecdsaCertificate Certificate
33
34func initCertificates() {
35 var err error
David Benjamin025b3d32014-07-01 19:53:04 -040036 rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070037 if err != nil {
38 panic(err)
39 }
40
David Benjamin025b3d32014-07-01 19:53:04 -040041 ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070042 if err != nil {
43 panic(err)
44 }
45}
46
47var certificateOnce sync.Once
48
49func getRSACertificate() Certificate {
50 certificateOnce.Do(initCertificates)
51 return rsaCertificate
52}
53
54func getECDSACertificate() Certificate {
55 certificateOnce.Do(initCertificates)
56 return ecdsaCertificate
57}
58
David Benjamin025b3d32014-07-01 19:53:04 -040059type testType int
60
61const (
62 clientTest testType = iota
63 serverTest
64)
65
Adam Langley95c29f32014-06-20 12:00:00 -070066type testCase struct {
David Benjamin025b3d32014-07-01 19:53:04 -040067 testType testType
Adam Langley95c29f32014-06-20 12:00:00 -070068 name string
69 config Config
70 shouldFail bool
71 expectedError string
Adam Langleyac61fa32014-06-23 12:03:11 -070072 // expectedLocalError, if not empty, contains a substring that must be
73 // found in the local error.
74 expectedLocalError string
David Benjamin7e2e6cf2014-08-07 17:44:24 -040075 // expectedVersion, if non-zero, specifies the TLS version that must be
76 // negotiated.
77 expectedVersion uint16
Adam Langley80842bd2014-06-20 12:00:00 -070078 // messageLen is the length, in bytes, of the test message that will be
79 // sent.
80 messageLen int
David Benjamin025b3d32014-07-01 19:53:04 -040081 // certFile is the path to the certificate to use for the server.
82 certFile string
83 // keyFile is the path to the private key to use for the server.
84 keyFile string
David Benjamin1d5c83e2014-07-22 19:20:02 -040085 // resumeSession controls whether a second connection should be tested
86 // which resumes the first session.
87 resumeSession bool
David Benjamin98e882e2014-08-08 13:24:34 -040088 // sendPrefix sends a prefix on the socket before actually performing a
89 // handshake.
90 sendPrefix string
David Benjamin325b5c32014-07-01 19:40:31 -040091 // flags, if not empty, contains a list of command-line flags that will
92 // be passed to the shim program.
93 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -070094}
95
David Benjamin025b3d32014-07-01 19:53:04 -040096var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -070097 {
98 name: "BadRSASignature",
99 config: Config{
100 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
101 Bugs: ProtocolBugs{
102 InvalidSKXSignature: true,
103 },
104 },
105 shouldFail: true,
106 expectedError: ":BAD_SIGNATURE:",
107 },
108 {
109 name: "BadECDSASignature",
110 config: Config{
111 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
112 Bugs: ProtocolBugs{
113 InvalidSKXSignature: true,
114 },
115 Certificates: []Certificate{getECDSACertificate()},
116 },
117 shouldFail: true,
118 expectedError: ":BAD_SIGNATURE:",
119 },
120 {
121 name: "BadECDSACurve",
122 config: Config{
123 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
124 Bugs: ProtocolBugs{
125 InvalidSKXCurve: true,
126 },
127 Certificates: []Certificate{getECDSACertificate()},
128 },
129 shouldFail: true,
130 expectedError: ":WRONG_CURVE:",
131 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700132 {
David Benjamina8e3e0e2014-08-06 22:11:10 -0400133 testType: serverTest,
134 name: "BadRSAVersion",
135 config: Config{
136 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
137 Bugs: ProtocolBugs{
138 RsaClientKeyExchangeVersion: VersionTLS11,
139 },
140 },
141 shouldFail: true,
142 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
143 },
144 {
David Benjamin325b5c32014-07-01 19:40:31 -0400145 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700146 config: Config{
147 Bugs: ProtocolBugs{
148 FailIfNotFallbackSCSV: true,
149 },
150 },
151 shouldFail: true,
152 expectedLocalError: "no fallback SCSV found",
153 },
David Benjamin325b5c32014-07-01 19:40:31 -0400154 {
155 name: "FallbackSCSV",
156 config: Config{
157 Bugs: ProtocolBugs{
158 FailIfNotFallbackSCSV: true,
159 },
160 },
161 flags: []string{"-fallback-scsv"},
162 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400163 {
164 testType: serverTest,
David Benjamin35a7a442014-07-05 00:23:20 -0400165 name: "ServerNameExtension",
David Benjamin197b3ab2014-07-02 18:37:33 -0400166 config: Config{
167 ServerName: "example.com",
168 },
169 flags: []string{"-expect-server-name", "example.com"},
170 },
David Benjamin35a7a442014-07-05 00:23:20 -0400171 {
172 testType: clientTest,
173 name: "DuplicateExtensionClient",
174 config: Config{
175 Bugs: ProtocolBugs{
176 DuplicateExtension: true,
177 },
178 },
179 shouldFail: true,
180 expectedLocalError: "remote error: error decoding message",
181 },
182 {
183 testType: serverTest,
184 name: "DuplicateExtensionServer",
185 config: Config{
186 Bugs: ProtocolBugs{
187 DuplicateExtension: true,
188 },
189 },
190 shouldFail: true,
191 expectedLocalError: "remote error: error decoding message",
192 },
David Benjamin7b030512014-07-08 17:30:11 -0400193 {
194 name: "ClientCertificateTypes",
195 config: Config{
196 ClientAuth: RequestClientCert,
197 ClientCertificateTypes: []byte{
198 CertTypeDSSSign,
199 CertTypeRSASign,
200 CertTypeECDSASign,
201 },
202 },
203 flags: []string{"-expect-certificate-types", string([]byte{
204 CertTypeDSSSign,
205 CertTypeRSASign,
206 CertTypeECDSASign,
207 })},
208 },
David Benjamin636293b2014-07-08 17:59:18 -0400209 {
210 name: "NoClientCertificate",
211 config: Config{
212 ClientAuth: RequireAnyClientCert,
213 },
214 shouldFail: true,
215 expectedLocalError: "client didn't provide a certificate",
216 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400217 {
218 name: "UnauthenticatedECDH",
219 config: Config{
220 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
221 Bugs: ProtocolBugs{
222 UnauthenticatedECDH: true,
223 },
224 },
225 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400226 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400227 },
David Benjamin9c651c92014-07-12 13:27:45 -0400228 {
229 name: "SkipServerKeyExchange",
230 config: Config{
231 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
232 Bugs: ProtocolBugs{
233 SkipServerKeyExchange: true,
234 },
235 },
236 shouldFail: true,
237 expectedError: ":UNEXPECTED_MESSAGE:",
238 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400239 {
David Benjamina0e52232014-07-19 17:39:58 -0400240 name: "SkipChangeCipherSpec-Client",
241 config: Config{
242 Bugs: ProtocolBugs{
243 SkipChangeCipherSpec: true,
244 },
245 },
246 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400247 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400248 },
249 {
250 testType: serverTest,
251 name: "SkipChangeCipherSpec-Server",
252 config: Config{
253 Bugs: ProtocolBugs{
254 SkipChangeCipherSpec: true,
255 },
256 },
257 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400258 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400259 },
David Benjamin42be6452014-07-21 14:50:23 -0400260 {
261 testType: serverTest,
262 name: "SkipChangeCipherSpec-Server-NPN",
263 config: Config{
264 NextProtos: []string{"bar"},
265 Bugs: ProtocolBugs{
266 SkipChangeCipherSpec: true,
267 },
268 },
269 flags: []string{
270 "-advertise-npn", "\x03foo\x03bar\x03baz",
271 },
272 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400273 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
274 },
275 {
276 name: "FragmentAcrossChangeCipherSpec-Client",
277 config: Config{
278 Bugs: ProtocolBugs{
279 FragmentAcrossChangeCipherSpec: true,
280 },
281 },
282 shouldFail: true,
283 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
284 },
285 {
286 testType: serverTest,
287 name: "FragmentAcrossChangeCipherSpec-Server",
288 config: Config{
289 Bugs: ProtocolBugs{
290 FragmentAcrossChangeCipherSpec: true,
291 },
292 },
293 shouldFail: true,
294 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
295 },
296 {
297 testType: serverTest,
298 name: "FragmentAcrossChangeCipherSpec-Server-NPN",
299 config: Config{
300 NextProtos: []string{"bar"},
301 Bugs: ProtocolBugs{
302 FragmentAcrossChangeCipherSpec: true,
303 },
304 },
305 flags: []string{
306 "-advertise-npn", "\x03foo\x03bar\x03baz",
307 },
308 shouldFail: true,
309 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamin42be6452014-07-21 14:50:23 -0400310 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400311 {
312 testType: serverTest,
313 name: "EarlyChangeCipherSpec-server-1",
314 config: Config{
315 Bugs: ProtocolBugs{
316 EarlyChangeCipherSpec: 1,
317 },
318 },
319 shouldFail: true,
320 expectedError: ":CCS_RECEIVED_EARLY:",
321 },
322 {
323 testType: serverTest,
324 name: "EarlyChangeCipherSpec-server-2",
325 config: Config{
326 Bugs: ProtocolBugs{
327 EarlyChangeCipherSpec: 2,
328 },
329 },
330 shouldFail: true,
331 expectedError: ":CCS_RECEIVED_EARLY:",
332 },
David Benjamind23f4122014-07-23 15:09:48 -0400333 {
David Benjamind23f4122014-07-23 15:09:48 -0400334 name: "SkipNewSessionTicket",
335 config: Config{
336 Bugs: ProtocolBugs{
337 SkipNewSessionTicket: true,
338 },
339 },
340 shouldFail: true,
341 expectedError: ":CCS_RECEIVED_EARLY:",
342 },
David Benjamin7e3305e2014-07-28 14:52:32 -0400343 {
David Benjamin7e3305e2014-07-28 14:52:32 -0400344 name: "FalseStart-SessionTicketsDisabled",
345 config: Config{
David Benjamind86c7672014-08-02 04:07:12 -0400346 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
347 NextProtos: []string{"foo"},
David Benjamin7e3305e2014-07-28 14:52:32 -0400348 SessionTicketsDisabled: true,
349 },
350 flags: []string{
351 "-false-start",
352 "-select-next-proto", "foo",
353 },
354 },
David Benjamind86c7672014-08-02 04:07:12 -0400355 {
356 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 Benjamin98e882e2014-08-08 13:24:34 -0400457 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
458 return err
459 }
460
David Benjamin1d5c83e2014-07-22 19:20:02 -0400461 var tlsConn *Conn
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400462 if test.testType == clientTest {
David Benjamin1d5c83e2014-07-22 19:20:02 -0400463 tlsConn = Server(conn, config)
464 } else {
465 config.InsecureSkipVerify = true
466 tlsConn = Client(conn, config)
467 }
468
Adam Langley95c29f32014-06-20 12:00:00 -0700469 if err := tlsConn.Handshake(); err != nil {
470 return err
471 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700472
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400473 if vers := tlsConn.ConnectionState().Version; test.expectedVersion != 0 && vers != test.expectedVersion {
474 return fmt.Errorf("got version %x, expected %x", vers, test.expectedVersion)
475 }
476
Kenny Root7fdeaf12014-08-05 15:23:37 -0700477 if messageLen < 0 {
478 // Read until EOF.
479 _, err := io.Copy(ioutil.Discard, tlsConn)
480 return err
481 }
482
Adam Langley80842bd2014-06-20 12:00:00 -0700483 if messageLen == 0 {
484 messageLen = 32
485 }
486 testMessage := make([]byte, messageLen)
487 for i := range testMessage {
488 testMessage[i] = 0x42
489 }
Adam Langley95c29f32014-06-20 12:00:00 -0700490 tlsConn.Write(testMessage)
491
492 buf := make([]byte, len(testMessage))
493 _, err := io.ReadFull(tlsConn, buf)
494 if err != nil {
495 return err
496 }
497
498 for i, v := range buf {
499 if v != testMessage[i]^0xff {
500 return fmt.Errorf("bad reply contents at byte %d", i)
501 }
502 }
503
504 return nil
505}
506
David Benjamin325b5c32014-07-01 19:40:31 -0400507func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
508 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700509 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400510 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700511 }
David Benjamin325b5c32014-07-01 19:40:31 -0400512 valgrindArgs = append(valgrindArgs, path)
513 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700514
David Benjamin325b5c32014-07-01 19:40:31 -0400515 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700516}
517
David Benjamin325b5c32014-07-01 19:40:31 -0400518func gdbOf(path string, args ...string) *exec.Cmd {
519 xtermArgs := []string{"-e", "gdb", "--args"}
520 xtermArgs = append(xtermArgs, path)
521 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700522
David Benjamin325b5c32014-07-01 19:40:31 -0400523 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700524}
525
David Benjamin1d5c83e2014-07-22 19:20:02 -0400526func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700527 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
528 if err != nil {
529 panic(err)
530 }
531
532 syscall.CloseOnExec(socks[0])
533 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400534 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700535 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400536 conn, err = net.FileConn(connFile)
537 if err != nil {
538 panic(err)
539 }
Adam Langley95c29f32014-06-20 12:00:00 -0700540 connFile.Close()
541 if err != nil {
542 panic(err)
543 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400544 return shimEnd, conn
545}
546
David Benjamin884fdf12014-08-02 15:28:23 -0400547func runTest(test *testCase, buildDir string) error {
David Benjamin1d5c83e2014-07-22 19:20:02 -0400548 shimEnd, conn := openSocketPair()
549 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700550
David Benjamin884fdf12014-08-02 15:28:23 -0400551 shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
David Benjamin025b3d32014-07-01 19:53:04 -0400552 flags := []string{}
553 if test.testType == clientTest {
554 flags = append(flags, "client")
Adam Langley95c29f32014-06-20 12:00:00 -0700555 } else {
David Benjamin025b3d32014-07-01 19:53:04 -0400556 flags = append(flags, "server")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400557 }
Adam Langley95c29f32014-06-20 12:00:00 -0700558
David Benjamin1d5c83e2014-07-22 19:20:02 -0400559 if test.resumeSession {
560 flags = append(flags, "resume")
561 } else {
562 flags = append(flags, "normal")
563 }
564
565 if test.testType == serverTest {
David Benjamin025b3d32014-07-01 19:53:04 -0400566 flags = append(flags, "-key-file")
567 if test.keyFile == "" {
568 flags = append(flags, rsaKeyFile)
569 } else {
570 flags = append(flags, test.keyFile)
571 }
572
573 flags = append(flags, "-cert-file")
574 if test.certFile == "" {
575 flags = append(flags, rsaCertificateFile)
576 } else {
577 flags = append(flags, test.certFile)
578 }
579 }
580 flags = append(flags, test.flags...)
581
582 var shim *exec.Cmd
583 if *useValgrind {
584 shim = valgrindOf(false, shim_path, flags...)
585 } else {
586 shim = exec.Command(shim_path, flags...)
587 }
588 // shim = gdbOf(shim_path, flags...)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400589 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400590 shim.Stdin = os.Stdin
591 var stdoutBuf, stderrBuf bytes.Buffer
592 shim.Stdout = &stdoutBuf
593 shim.Stderr = &stderrBuf
594
595 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700596 panic(err)
597 }
David Benjamin025b3d32014-07-01 19:53:04 -0400598 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400599 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700600
601 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400602 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400603 if test.testType == clientTest {
604 if len(config.Certificates) == 0 {
605 config.Certificates = []Certificate{getRSACertificate()}
606 }
David Benjamin025b3d32014-07-01 19:53:04 -0400607 }
Adam Langley95c29f32014-06-20 12:00:00 -0700608
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400609 err := doExchange(test, &config, conn, test.messageLen)
Adam Langley95c29f32014-06-20 12:00:00 -0700610 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400611 if err == nil && test.resumeSession {
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400612 err = doExchange(test, &config, connResume, test.messageLen)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400613 connResume.Close()
614 }
615
David Benjamin025b3d32014-07-01 19:53:04 -0400616 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700617
618 stdout := string(stdoutBuf.Bytes())
619 stderr := string(stderrBuf.Bytes())
620 failed := err != nil || childErr != nil
621 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700622 localError := "none"
623 if err != nil {
624 localError = err.Error()
625 }
626 if len(test.expectedLocalError) != 0 {
627 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
628 }
Adam Langley95c29f32014-06-20 12:00:00 -0700629
630 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700631 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700632 if childErr != nil {
633 childError = childErr.Error()
634 }
635
636 var msg string
637 switch {
638 case failed && !test.shouldFail:
639 msg = "unexpected failure"
640 case !failed && test.shouldFail:
641 msg = "unexpected success"
642 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700643 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700644 default:
645 panic("internal error")
646 }
647
648 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
649 }
650
651 if !*useValgrind && len(stderr) > 0 {
652 println(stderr)
653 }
654
655 return nil
656}
657
658var tlsVersions = []struct {
659 name string
660 version uint16
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400661 flag string
Adam Langley95c29f32014-06-20 12:00:00 -0700662}{
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400663 {"SSL3", VersionSSL30, "-no-ssl3"},
664 {"TLS1", VersionTLS10, "-no-tls1"},
665 {"TLS11", VersionTLS11, "-no-tls11"},
666 {"TLS12", VersionTLS12, "-no-tls12"},
Adam Langley95c29f32014-06-20 12:00:00 -0700667}
668
669var testCipherSuites = []struct {
670 name string
671 id uint16
672}{
673 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400674 {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700675 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400676 {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700677 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400678 {"DHE-RSA-3DES-SHA", TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
679 {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
680 {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
681 {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
682 {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700683 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
684 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
685 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
686 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
687 {"ECDHE-RSA-3DES-SHA", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
688 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700689 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400690 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700691 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
692 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700693 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400694 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700695}
696
697func addCipherSuiteTests() {
698 for _, suite := range testCipherSuites {
699 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400700 var certFile string
701 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700702 if strings.Contains(suite.name, "ECDSA") {
703 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400704 certFile = ecdsaCertificateFile
705 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700706 } else {
707 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400708 certFile = rsaCertificateFile
709 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700710 }
711
712 for _, ver := range tlsVersions {
713 if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
714 continue
715 }
716
David Benjamin1d5c83e2014-07-22 19:20:02 -0400717 // Go's TLS implementation only implements session
718 // resumption with tickets, so SSLv3 cannot resume
719 // sessions.
720 resumeSession := ver.version != VersionSSL30
721
David Benjamin025b3d32014-07-01 19:53:04 -0400722 testCases = append(testCases, testCase{
723 testType: clientTest,
724 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700725 config: Config{
726 MinVersion: ver.version,
727 MaxVersion: ver.version,
728 CipherSuites: []uint16{suite.id},
729 Certificates: []Certificate{cert},
730 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400731 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700732 })
David Benjamin025b3d32014-07-01 19:53:04 -0400733
734 // Go's TLS implementation implements SSLv3 as a server,
735 // but not as a client.
736 //
737 // TODO(davidben): Implement SSLv3 as a client too to
738 // exercise that code.
739 if ver.version != VersionSSL30 {
740 testCases = append(testCases, testCase{
741 testType: serverTest,
742 name: ver.name + "-" + suite.name + "-server",
743 config: Config{
744 MinVersion: ver.version,
745 MaxVersion: ver.version,
746 CipherSuites: []uint16{suite.id},
747 Certificates: []Certificate{cert},
748 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400749 certFile: certFile,
750 keyFile: keyFile,
751 resumeSession: resumeSession,
David Benjamin025b3d32014-07-01 19:53:04 -0400752 })
753 }
Adam Langley95c29f32014-06-20 12:00:00 -0700754 }
755 }
756}
757
758func addBadECDSASignatureTests() {
759 for badR := BadValue(1); badR < NumBadValues; badR++ {
760 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400761 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700762 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
763 config: Config{
764 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
765 Certificates: []Certificate{getECDSACertificate()},
766 Bugs: ProtocolBugs{
767 BadECDSAR: badR,
768 BadECDSAS: badS,
769 },
770 },
771 shouldFail: true,
772 expectedError: "SIGNATURE",
773 })
774 }
775 }
776}
777
Adam Langley80842bd2014-06-20 12:00:00 -0700778func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400779 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700780 name: "MaxCBCPadding",
781 config: Config{
782 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
783 Bugs: ProtocolBugs{
784 MaxPadding: true,
785 },
786 },
787 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
788 })
David Benjamin025b3d32014-07-01 19:53:04 -0400789 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700790 name: "BadCBCPadding",
791 config: Config{
792 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
793 Bugs: ProtocolBugs{
794 PaddingFirstByteBad: true,
795 },
796 },
797 shouldFail: true,
798 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
799 })
800 // OpenSSL previously had an issue where the first byte of padding in
801 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400802 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700803 name: "BadCBCPadding255",
804 config: Config{
805 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
806 Bugs: ProtocolBugs{
807 MaxPadding: true,
808 PaddingFirstByteBadIf255: true,
809 },
810 },
811 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
812 shouldFail: true,
813 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
814 })
815}
816
Kenny Root7fdeaf12014-08-05 15:23:37 -0700817func addCBCSplittingTests() {
818 testCases = append(testCases, testCase{
819 name: "CBCRecordSplitting",
820 config: Config{
821 MaxVersion: VersionTLS10,
822 MinVersion: VersionTLS10,
823 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
824 },
825 messageLen: -1, // read until EOF
826 flags: []string{
827 "-async",
828 "-write-different-record-sizes",
829 "-cbc-record-splitting",
830 },
David Benjamina8e3e0e2014-08-06 22:11:10 -0400831 })
832 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -0700833 name: "CBCRecordSplittingPartialWrite",
834 config: Config{
835 MaxVersion: VersionTLS10,
836 MinVersion: VersionTLS10,
837 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
838 },
839 messageLen: -1, // read until EOF
840 flags: []string{
841 "-async",
842 "-write-different-record-sizes",
843 "-cbc-record-splitting",
844 "-partial-write",
845 },
846 })
847}
848
David Benjamin636293b2014-07-08 17:59:18 -0400849func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -0400850 // Add a dummy cert pool to stress certificate authority parsing.
851 // TODO(davidben): Add tests that those values parse out correctly.
852 certPool := x509.NewCertPool()
853 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
854 if err != nil {
855 panic(err)
856 }
857 certPool.AddCert(cert)
858
David Benjamin636293b2014-07-08 17:59:18 -0400859 for _, ver := range tlsVersions {
860 if ver.version == VersionSSL30 {
861 // TODO(davidben): The Go implementation does not
862 // correctly compute CertificateVerify hashes for SSLv3.
863 continue
864 }
865
866 var cipherSuites []uint16
867 if ver.version >= VersionTLS12 {
868 // Pick a SHA-256 cipher suite. The Go implementation
869 // does not correctly handle client auth with a SHA-384
870 // cipher suite.
871 cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
872 }
873
874 testCases = append(testCases, testCase{
875 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400876 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -0400877 config: Config{
878 MinVersion: ver.version,
879 MaxVersion: ver.version,
880 CipherSuites: cipherSuites,
881 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400882 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400883 },
884 flags: []string{
885 "-cert-file", rsaCertificateFile,
886 "-key-file", rsaKeyFile,
887 },
888 })
889 testCases = append(testCases, testCase{
890 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400891 name: ver.name + "-Client-ClientAuth-ECDSA",
David Benjamin636293b2014-07-08 17:59:18 -0400892 config: Config{
893 MinVersion: ver.version,
894 MaxVersion: ver.version,
895 CipherSuites: cipherSuites,
896 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400897 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400898 },
899 flags: []string{
900 "-cert-file", ecdsaCertificateFile,
901 "-key-file", ecdsaKeyFile,
902 },
903 })
David Benjamin67666e72014-07-12 15:47:52 -0400904 testCases = append(testCases, testCase{
905 testType: serverTest,
906 name: ver.name + "-Server-ClientAuth-RSA",
907 config: Config{
908 Certificates: []Certificate{rsaCertificate},
909 },
910 flags: []string{"-require-any-client-certificate"},
911 })
912 testCases = append(testCases, testCase{
913 testType: serverTest,
914 name: ver.name + "-Server-ClientAuth-ECDSA",
915 config: Config{
916 Certificates: []Certificate{ecdsaCertificate},
917 },
918 flags: []string{"-require-any-client-certificate"},
919 })
David Benjamin636293b2014-07-08 17:59:18 -0400920 }
921}
922
David Benjamin43ec06f2014-08-05 02:28:57 -0400923// Adds tests that try to cover the range of the handshake state machine, under
924// various conditions. Some of these are redundant with other tests, but they
925// only cover the synchronous case.
926func addStateMachineCoverageTests(async bool, splitHandshake bool) {
927 var suffix string
928 var flags []string
929 var maxHandshakeRecordLength int
930 if async {
931 suffix = "-Async"
932 flags = append(flags, "-async")
933 } else {
934 suffix = "-Sync"
935 }
936 if splitHandshake {
937 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -0400938 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -0400939 }
940
941 // Basic handshake, with resumption. Client and server.
942 testCases = append(testCases, testCase{
943 name: "Basic-Client" + suffix,
944 config: Config{
945 Bugs: ProtocolBugs{
946 MaxHandshakeRecordLength: maxHandshakeRecordLength,
947 },
948 },
David Benjaminbed9aae2014-08-07 19:13:38 -0400949 flags: flags,
950 resumeSession: true,
951 })
952 testCases = append(testCases, testCase{
953 name: "Basic-Client-RenewTicket" + suffix,
954 config: Config{
955 Bugs: ProtocolBugs{
956 MaxHandshakeRecordLength: maxHandshakeRecordLength,
957 RenewTicketOnResume: true,
958 },
959 },
960 flags: flags,
961 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -0400962 })
963 testCases = append(testCases, testCase{
964 testType: serverTest,
965 name: "Basic-Server" + suffix,
966 config: Config{
967 Bugs: ProtocolBugs{
968 MaxHandshakeRecordLength: maxHandshakeRecordLength,
969 },
970 },
David Benjaminbed9aae2014-08-07 19:13:38 -0400971 flags: flags,
972 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -0400973 })
974
975 // No session ticket support; server doesn't send NewSessionTicket.
976 testCases = append(testCases, testCase{
977 name: "SessionTicketsDisabled-Client" + suffix,
978 config: Config{
979 SessionTicketsDisabled: true,
980 Bugs: ProtocolBugs{
981 MaxHandshakeRecordLength: maxHandshakeRecordLength,
982 },
983 },
984 flags: flags,
985 })
986 testCases = append(testCases, testCase{
987 testType: serverTest,
988 name: "SessionTicketsDisabled-Server" + suffix,
989 config: Config{
990 SessionTicketsDisabled: true,
991 Bugs: ProtocolBugs{
992 MaxHandshakeRecordLength: maxHandshakeRecordLength,
993 },
994 },
995 flags: flags,
996 })
997
998 // NPN on client and server; results in post-handshake message.
999 testCases = append(testCases, testCase{
1000 name: "NPN-Client" + suffix,
1001 config: Config{
1002 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1003 NextProtos: []string{"foo"},
1004 Bugs: ProtocolBugs{
1005 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1006 },
1007 },
1008 flags: append(flags, "-select-next-proto", "foo"),
1009 })
1010 testCases = append(testCases, testCase{
1011 testType: serverTest,
1012 name: "NPN-Server" + suffix,
1013 config: Config{
1014 NextProtos: []string{"bar"},
1015 Bugs: ProtocolBugs{
1016 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1017 },
1018 },
1019 flags: append(flags,
1020 "-advertise-npn", "\x03foo\x03bar\x03baz",
1021 "-expect-next-proto", "bar"),
1022 })
1023
1024 // Client does False Start and negotiates NPN.
1025 testCases = append(testCases, testCase{
1026 name: "FalseStart" + suffix,
1027 config: Config{
1028 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1029 NextProtos: []string{"foo"},
1030 Bugs: ProtocolBugs{
1031 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1032 },
1033 },
1034 flags: append(flags,
1035 "-false-start",
1036 "-select-next-proto", "foo"),
1037 resumeSession: true,
1038 })
1039
1040 // TLS client auth.
1041 testCases = append(testCases, testCase{
1042 testType: clientTest,
1043 name: "ClientAuth-Client" + suffix,
1044 config: Config{
1045 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1046 ClientAuth: RequireAnyClientCert,
1047 Bugs: ProtocolBugs{
1048 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1049 },
1050 },
1051 flags: append(flags,
1052 "-cert-file", rsaCertificateFile,
1053 "-key-file", rsaKeyFile),
1054 })
1055 testCases = append(testCases, testCase{
1056 testType: serverTest,
1057 name: "ClientAuth-Server" + suffix,
1058 config: Config{
1059 Certificates: []Certificate{rsaCertificate},
1060 },
1061 flags: append(flags, "-require-any-client-certificate"),
1062 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001063
1064 // Client sends a V2ClientHello.
1065 testCases = append(testCases, testCase{
1066 testType: serverTest,
David Benjamin98e882e2014-08-08 13:24:34 -04001067 name: "SendV2ClientHello" + suffix,
David Benjamin1e7f8d72014-08-08 12:27:04 -04001068 config: Config{
1069 // Choose a cipher suite that does not involve
1070 // elliptic curves, so no extensions are
1071 // involved.
1072 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1073 Bugs: ProtocolBugs{
1074 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1075 SendV2ClientHello: true,
1076 },
1077 },
1078 flags: flags,
1079 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001080}
1081
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001082func addVersionNegotiationTests() {
1083 for i, shimVers := range tlsVersions {
1084 // Assemble flags to disable all newer versions on the shim.
1085 var flags []string
1086 for _, vers := range tlsVersions[i+1:] {
1087 flags = append(flags, vers.flag)
1088 }
1089
1090 for _, runnerVers := range tlsVersions {
1091 expectedVersion := shimVers.version
1092 if runnerVers.version < shimVers.version {
1093 expectedVersion = runnerVers.version
1094 }
1095 suffix := shimVers.name + "-" + runnerVers.name
1096
1097 testCases = append(testCases, testCase{
1098 testType: clientTest,
1099 name: "VersionNegotiation-Client-" + suffix,
1100 config: Config{
1101 MaxVersion: runnerVers.version,
1102 },
1103 flags: flags,
1104 expectedVersion: expectedVersion,
1105 })
1106
1107 // TODO(davidben): Implement SSLv3 as a client in the runner.
1108 if expectedVersion > VersionSSL30 {
1109 testCases = append(testCases, testCase{
1110 testType: serverTest,
1111 name: "VersionNegotiation-Server-" + suffix,
1112 config: Config{
1113 MaxVersion: runnerVers.version,
1114 },
1115 flags: flags,
1116 expectedVersion: expectedVersion,
1117 })
1118 }
1119 }
1120 }
1121}
1122
David Benjamin884fdf12014-08-02 15:28:23 -04001123func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07001124 defer wg.Done()
1125
1126 for test := range c {
1127 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04001128 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07001129 statusChan <- statusMsg{test: test, err: err}
1130 }
1131}
1132
1133type statusMsg struct {
1134 test *testCase
1135 started bool
1136 err error
1137}
1138
1139func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1140 var started, done, failed, lineLen int
1141 defer close(doneChan)
1142
1143 for msg := range statusChan {
1144 if msg.started {
1145 started++
1146 } else {
1147 done++
1148 }
1149
1150 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1151
1152 if msg.err != nil {
1153 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1154 failed++
1155 }
1156 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1157 lineLen = len(line)
1158 os.Stdout.WriteString(line)
1159 }
1160}
1161
1162func main() {
1163 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 -04001164 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04001165 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07001166
1167 flag.Parse()
1168
1169 addCipherSuiteTests()
1170 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07001171 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07001172 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04001173 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001174 addVersionNegotiationTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04001175 for _, async := range []bool{false, true} {
1176 for _, splitHandshake := range []bool{false, true} {
1177 addStateMachineCoverageTests(async, splitHandshake)
1178 }
1179 }
Adam Langley95c29f32014-06-20 12:00:00 -07001180
1181 var wg sync.WaitGroup
1182
David Benjamin2bc8e6f2014-08-02 15:22:37 -04001183 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07001184
1185 statusChan := make(chan statusMsg, numWorkers)
1186 testChan := make(chan *testCase, numWorkers)
1187 doneChan := make(chan struct{})
1188
David Benjamin025b3d32014-07-01 19:53:04 -04001189 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07001190
1191 for i := 0; i < numWorkers; i++ {
1192 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04001193 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07001194 }
1195
David Benjamin025b3d32014-07-01 19:53:04 -04001196 for i := range testCases {
1197 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
1198 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07001199 }
1200 }
1201
1202 close(testChan)
1203 wg.Wait()
1204 close(statusChan)
1205 <-doneChan
1206
1207 fmt.Printf("\n")
1208}