blob: e025859fcdb1b396e1e67a8a8f2b1931a82d0c16 [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"
9 "net"
10 "os"
11 "os/exec"
12 "strings"
13 "sync"
14 "syscall"
15)
16
17var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
18
David Benjamin025b3d32014-07-01 19:53:04 -040019const (
20 rsaCertificateFile = "cert.pem"
21 ecdsaCertificateFile = "ecdsa_cert.pem"
22)
23
24const (
25 rsaKeyFile = "key.pem"
26 ecdsaKeyFile = "ecdsa_key.pem"
27)
28
Adam Langley95c29f32014-06-20 12:00:00 -070029var rsaCertificate, ecdsaCertificate Certificate
30
31func initCertificates() {
32 var err error
David Benjamin025b3d32014-07-01 19:53:04 -040033 rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070034 if err != nil {
35 panic(err)
36 }
37
David Benjamin025b3d32014-07-01 19:53:04 -040038 ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070039 if err != nil {
40 panic(err)
41 }
42}
43
44var certificateOnce sync.Once
45
46func getRSACertificate() Certificate {
47 certificateOnce.Do(initCertificates)
48 return rsaCertificate
49}
50
51func getECDSACertificate() Certificate {
52 certificateOnce.Do(initCertificates)
53 return ecdsaCertificate
54}
55
David Benjamin025b3d32014-07-01 19:53:04 -040056type testType int
57
58const (
59 clientTest testType = iota
60 serverTest
61)
62
Adam Langley95c29f32014-06-20 12:00:00 -070063type testCase struct {
David Benjamin025b3d32014-07-01 19:53:04 -040064 testType testType
Adam Langley95c29f32014-06-20 12:00:00 -070065 name string
66 config Config
67 shouldFail bool
68 expectedError string
Adam Langleyac61fa32014-06-23 12:03:11 -070069 // expectedLocalError, if not empty, contains a substring that must be
70 // found in the local error.
71 expectedLocalError string
Adam Langley80842bd2014-06-20 12:00:00 -070072 // messageLen is the length, in bytes, of the test message that will be
73 // sent.
74 messageLen int
David Benjamin025b3d32014-07-01 19:53:04 -040075 // certFile is the path to the certificate to use for the server.
76 certFile string
77 // keyFile is the path to the private key to use for the server.
78 keyFile string
David Benjamin325b5c32014-07-01 19:40:31 -040079 // flags, if not empty, contains a list of command-line flags that will
80 // be passed to the shim program.
81 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -070082}
83
David Benjamin025b3d32014-07-01 19:53:04 -040084var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -070085 {
86 name: "BadRSASignature",
87 config: Config{
88 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
89 Bugs: ProtocolBugs{
90 InvalidSKXSignature: true,
91 },
92 },
93 shouldFail: true,
94 expectedError: ":BAD_SIGNATURE:",
95 },
96 {
97 name: "BadECDSASignature",
98 config: Config{
99 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
100 Bugs: ProtocolBugs{
101 InvalidSKXSignature: true,
102 },
103 Certificates: []Certificate{getECDSACertificate()},
104 },
105 shouldFail: true,
106 expectedError: ":BAD_SIGNATURE:",
107 },
108 {
109 name: "BadECDSACurve",
110 config: Config{
111 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
112 Bugs: ProtocolBugs{
113 InvalidSKXCurve: true,
114 },
115 Certificates: []Certificate{getECDSACertificate()},
116 },
117 shouldFail: true,
118 expectedError: ":WRONG_CURVE:",
119 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700120 {
David Benjamin325b5c32014-07-01 19:40:31 -0400121 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700122 config: Config{
123 Bugs: ProtocolBugs{
124 FailIfNotFallbackSCSV: true,
125 },
126 },
127 shouldFail: true,
128 expectedLocalError: "no fallback SCSV found",
129 },
David Benjamin325b5c32014-07-01 19:40:31 -0400130 {
131 name: "FallbackSCSV",
132 config: Config{
133 Bugs: ProtocolBugs{
134 FailIfNotFallbackSCSV: true,
135 },
136 },
137 flags: []string{"-fallback-scsv"},
138 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400139 {
140 testType: serverTest,
David Benjamin35a7a442014-07-05 00:23:20 -0400141 name: "ServerNameExtension",
David Benjamin197b3ab2014-07-02 18:37:33 -0400142 config: Config{
143 ServerName: "example.com",
144 },
145 flags: []string{"-expect-server-name", "example.com"},
146 },
David Benjamin35a7a442014-07-05 00:23:20 -0400147 {
148 testType: clientTest,
149 name: "DuplicateExtensionClient",
150 config: Config{
151 Bugs: ProtocolBugs{
152 DuplicateExtension: true,
153 },
154 },
155 shouldFail: true,
156 expectedLocalError: "remote error: error decoding message",
157 },
158 {
159 testType: serverTest,
160 name: "DuplicateExtensionServer",
161 config: Config{
162 Bugs: ProtocolBugs{
163 DuplicateExtension: true,
164 },
165 },
166 shouldFail: true,
167 expectedLocalError: "remote error: error decoding message",
168 },
David Benjamin7b030512014-07-08 17:30:11 -0400169 {
170 name: "ClientCertificateTypes",
171 config: Config{
172 ClientAuth: RequestClientCert,
173 ClientCertificateTypes: []byte{
174 CertTypeDSSSign,
175 CertTypeRSASign,
176 CertTypeECDSASign,
177 },
178 },
179 flags: []string{"-expect-certificate-types", string([]byte{
180 CertTypeDSSSign,
181 CertTypeRSASign,
182 CertTypeECDSASign,
183 })},
184 },
David Benjamin636293b2014-07-08 17:59:18 -0400185 {
186 name: "NoClientCertificate",
187 config: Config{
188 ClientAuth: RequireAnyClientCert,
189 },
190 shouldFail: true,
191 expectedLocalError: "client didn't provide a certificate",
192 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400193 {
194 name: "UnauthenticatedECDH",
195 config: Config{
196 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
197 Bugs: ProtocolBugs{
198 UnauthenticatedECDH: true,
199 },
200 },
201 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400202 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400203 },
David Benjamin9c651c92014-07-12 13:27:45 -0400204 {
205 name: "SkipServerKeyExchange",
206 config: Config{
207 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
208 Bugs: ProtocolBugs{
209 SkipServerKeyExchange: true,
210 },
211 },
212 shouldFail: true,
213 expectedError: ":UNEXPECTED_MESSAGE:",
214 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400215 {
216 testType: serverTest,
217 name: "NPNServerTest",
218 config: Config{
219 NextProtos: []string{"bar"},
220 },
221 flags: []string{
222 "-advertise-npn", "\x03foo\x03bar\x03baz",
223 "-expect-next-proto", "bar",
224 },
225 },
Adam Langley95c29f32014-06-20 12:00:00 -0700226}
227
Adam Langley80842bd2014-06-20 12:00:00 -0700228func doExchange(tlsConn *Conn, messageLen int) error {
Adam Langley95c29f32014-06-20 12:00:00 -0700229 if err := tlsConn.Handshake(); err != nil {
230 return err
231 }
Adam Langley80842bd2014-06-20 12:00:00 -0700232 if messageLen == 0 {
233 messageLen = 32
234 }
235 testMessage := make([]byte, messageLen)
236 for i := range testMessage {
237 testMessage[i] = 0x42
238 }
Adam Langley95c29f32014-06-20 12:00:00 -0700239 tlsConn.Write(testMessage)
240
241 buf := make([]byte, len(testMessage))
242 _, err := io.ReadFull(tlsConn, buf)
243 if err != nil {
244 return err
245 }
246
247 for i, v := range buf {
248 if v != testMessage[i]^0xff {
249 return fmt.Errorf("bad reply contents at byte %d", i)
250 }
251 }
252
253 return nil
254}
255
David Benjamin325b5c32014-07-01 19:40:31 -0400256func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
257 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700258 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400259 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700260 }
David Benjamin325b5c32014-07-01 19:40:31 -0400261 valgrindArgs = append(valgrindArgs, path)
262 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700263
David Benjamin325b5c32014-07-01 19:40:31 -0400264 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700265}
266
David Benjamin325b5c32014-07-01 19:40:31 -0400267func gdbOf(path string, args ...string) *exec.Cmd {
268 xtermArgs := []string{"-e", "gdb", "--args"}
269 xtermArgs = append(xtermArgs, path)
270 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700271
David Benjamin325b5c32014-07-01 19:40:31 -0400272 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700273}
274
275func runTest(test *testCase) error {
276 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
277 if err != nil {
278 panic(err)
279 }
280
281 syscall.CloseOnExec(socks[0])
282 syscall.CloseOnExec(socks[1])
David Benjamin025b3d32014-07-01 19:53:04 -0400283 shimEnd := os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700284 connFile := os.NewFile(uintptr(socks[1]), "our end")
285 conn, err := net.FileConn(connFile)
286 connFile.Close()
287 if err != nil {
288 panic(err)
289 }
290
David Benjamin025b3d32014-07-01 19:53:04 -0400291 const shim_path = "../../../build/ssl/test/bssl_shim"
292 flags := []string{}
293 if test.testType == clientTest {
294 flags = append(flags, "client")
Adam Langley95c29f32014-06-20 12:00:00 -0700295 } else {
David Benjamin025b3d32014-07-01 19:53:04 -0400296 flags = append(flags, "server")
Adam Langley95c29f32014-06-20 12:00:00 -0700297
David Benjamin025b3d32014-07-01 19:53:04 -0400298 flags = append(flags, "-key-file")
299 if test.keyFile == "" {
300 flags = append(flags, rsaKeyFile)
301 } else {
302 flags = append(flags, test.keyFile)
303 }
304
305 flags = append(flags, "-cert-file")
306 if test.certFile == "" {
307 flags = append(flags, rsaCertificateFile)
308 } else {
309 flags = append(flags, test.certFile)
310 }
311 }
312 flags = append(flags, test.flags...)
313
314 var shim *exec.Cmd
315 if *useValgrind {
316 shim = valgrindOf(false, shim_path, flags...)
317 } else {
318 shim = exec.Command(shim_path, flags...)
319 }
320 // shim = gdbOf(shim_path, flags...)
321 shim.ExtraFiles = []*os.File{shimEnd}
322 shim.Stdin = os.Stdin
323 var stdoutBuf, stderrBuf bytes.Buffer
324 shim.Stdout = &stdoutBuf
325 shim.Stderr = &stderrBuf
326
327 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700328 panic(err)
329 }
David Benjamin025b3d32014-07-01 19:53:04 -0400330 shimEnd.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700331
332 config := test.config
Adam Langley95c29f32014-06-20 12:00:00 -0700333
David Benjamin025b3d32014-07-01 19:53:04 -0400334 var tlsConn *Conn
335 if test.testType == clientTest {
336 if len(config.Certificates) == 0 {
337 config.Certificates = []Certificate{getRSACertificate()}
338 }
339 tlsConn = Server(conn, &config)
340 } else {
341 config.InsecureSkipVerify = true
342 tlsConn = Client(conn, &config)
343 }
Adam Langley80842bd2014-06-20 12:00:00 -0700344 err = doExchange(tlsConn, test.messageLen)
Adam Langley95c29f32014-06-20 12:00:00 -0700345
346 conn.Close()
David Benjamin025b3d32014-07-01 19:53:04 -0400347 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700348
349 stdout := string(stdoutBuf.Bytes())
350 stderr := string(stderrBuf.Bytes())
351 failed := err != nil || childErr != nil
352 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700353 localError := "none"
354 if err != nil {
355 localError = err.Error()
356 }
357 if len(test.expectedLocalError) != 0 {
358 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
359 }
Adam Langley95c29f32014-06-20 12:00:00 -0700360
361 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700362 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700363 if childErr != nil {
364 childError = childErr.Error()
365 }
366
367 var msg string
368 switch {
369 case failed && !test.shouldFail:
370 msg = "unexpected failure"
371 case !failed && test.shouldFail:
372 msg = "unexpected success"
373 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700374 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700375 default:
376 panic("internal error")
377 }
378
379 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
380 }
381
382 if !*useValgrind && len(stderr) > 0 {
383 println(stderr)
384 }
385
386 return nil
387}
388
389var tlsVersions = []struct {
390 name string
391 version uint16
392}{
393 {"SSL3", VersionSSL30},
394 {"TLS1", VersionTLS10},
395 {"TLS11", VersionTLS11},
396 {"TLS12", VersionTLS12},
397}
398
399var testCipherSuites = []struct {
400 name string
401 id uint16
402}{
403 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
404 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
405 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
406 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
407 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
408 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
409 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
410 {"ECDHE-RSA-3DES-SHA", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
411 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
412 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
413 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
414 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
415 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
416 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
417 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
418}
419
420func addCipherSuiteTests() {
421 for _, suite := range testCipherSuites {
422 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400423 var certFile string
424 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700425 if strings.Contains(suite.name, "ECDSA") {
426 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400427 certFile = ecdsaCertificateFile
428 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700429 } else {
430 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400431 certFile = rsaCertificateFile
432 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700433 }
434
435 for _, ver := range tlsVersions {
436 if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
437 continue
438 }
439
David Benjamin025b3d32014-07-01 19:53:04 -0400440 testCases = append(testCases, testCase{
441 testType: clientTest,
442 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700443 config: Config{
444 MinVersion: ver.version,
445 MaxVersion: ver.version,
446 CipherSuites: []uint16{suite.id},
447 Certificates: []Certificate{cert},
448 },
449 })
David Benjamin025b3d32014-07-01 19:53:04 -0400450
451 // Go's TLS implementation implements SSLv3 as a server,
452 // but not as a client.
453 //
454 // TODO(davidben): Implement SSLv3 as a client too to
455 // exercise that code.
456 if ver.version != VersionSSL30 {
457 testCases = append(testCases, testCase{
458 testType: serverTest,
459 name: ver.name + "-" + suite.name + "-server",
460 config: Config{
461 MinVersion: ver.version,
462 MaxVersion: ver.version,
463 CipherSuites: []uint16{suite.id},
464 Certificates: []Certificate{cert},
465 },
466 certFile: certFile,
467 keyFile: keyFile,
468 })
469 }
Adam Langley95c29f32014-06-20 12:00:00 -0700470 }
471 }
472}
473
474func addBadECDSASignatureTests() {
475 for badR := BadValue(1); badR < NumBadValues; badR++ {
476 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400477 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700478 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
479 config: Config{
480 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
481 Certificates: []Certificate{getECDSACertificate()},
482 Bugs: ProtocolBugs{
483 BadECDSAR: badR,
484 BadECDSAS: badS,
485 },
486 },
487 shouldFail: true,
488 expectedError: "SIGNATURE",
489 })
490 }
491 }
492}
493
Adam Langley80842bd2014-06-20 12:00:00 -0700494func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400495 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700496 name: "MaxCBCPadding",
497 config: Config{
498 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
499 Bugs: ProtocolBugs{
500 MaxPadding: true,
501 },
502 },
503 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
504 })
David Benjamin025b3d32014-07-01 19:53:04 -0400505 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700506 name: "BadCBCPadding",
507 config: Config{
508 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
509 Bugs: ProtocolBugs{
510 PaddingFirstByteBad: true,
511 },
512 },
513 shouldFail: true,
514 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
515 })
516 // OpenSSL previously had an issue where the first byte of padding in
517 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400518 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700519 name: "BadCBCPadding255",
520 config: Config{
521 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
522 Bugs: ProtocolBugs{
523 MaxPadding: true,
524 PaddingFirstByteBadIf255: true,
525 },
526 },
527 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
528 shouldFail: true,
529 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
530 })
531}
532
David Benjamin636293b2014-07-08 17:59:18 -0400533func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -0400534 // Add a dummy cert pool to stress certificate authority parsing.
535 // TODO(davidben): Add tests that those values parse out correctly.
536 certPool := x509.NewCertPool()
537 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
538 if err != nil {
539 panic(err)
540 }
541 certPool.AddCert(cert)
542
David Benjamin636293b2014-07-08 17:59:18 -0400543 for _, ver := range tlsVersions {
544 if ver.version == VersionSSL30 {
545 // TODO(davidben): The Go implementation does not
546 // correctly compute CertificateVerify hashes for SSLv3.
547 continue
548 }
549
550 var cipherSuites []uint16
551 if ver.version >= VersionTLS12 {
552 // Pick a SHA-256 cipher suite. The Go implementation
553 // does not correctly handle client auth with a SHA-384
554 // cipher suite.
555 cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
556 }
557
558 testCases = append(testCases, testCase{
559 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400560 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -0400561 config: Config{
562 MinVersion: ver.version,
563 MaxVersion: ver.version,
564 CipherSuites: cipherSuites,
565 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400566 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400567 },
568 flags: []string{
569 "-cert-file", rsaCertificateFile,
570 "-key-file", rsaKeyFile,
571 },
572 })
573 testCases = append(testCases, testCase{
574 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400575 name: ver.name + "-Client-ClientAuth-ECDSA",
David Benjamin636293b2014-07-08 17:59:18 -0400576 config: Config{
577 MinVersion: ver.version,
578 MaxVersion: ver.version,
579 CipherSuites: cipherSuites,
580 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400581 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400582 },
583 flags: []string{
584 "-cert-file", ecdsaCertificateFile,
585 "-key-file", ecdsaKeyFile,
586 },
587 })
David Benjamin67666e72014-07-12 15:47:52 -0400588 testCases = append(testCases, testCase{
589 testType: serverTest,
590 name: ver.name + "-Server-ClientAuth-RSA",
591 config: Config{
592 Certificates: []Certificate{rsaCertificate},
593 },
594 flags: []string{"-require-any-client-certificate"},
595 })
596 testCases = append(testCases, testCase{
597 testType: serverTest,
598 name: ver.name + "-Server-ClientAuth-ECDSA",
599 config: Config{
600 Certificates: []Certificate{ecdsaCertificate},
601 },
602 flags: []string{"-require-any-client-certificate"},
603 })
David Benjamin636293b2014-07-08 17:59:18 -0400604 }
605}
606
Adam Langley95c29f32014-06-20 12:00:00 -0700607func worker(statusChan chan statusMsg, c chan *testCase, wg *sync.WaitGroup) {
608 defer wg.Done()
609
610 for test := range c {
611 statusChan <- statusMsg{test: test, started: true}
612 err := runTest(test)
613 statusChan <- statusMsg{test: test, err: err}
614 }
615}
616
617type statusMsg struct {
618 test *testCase
619 started bool
620 err error
621}
622
623func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
624 var started, done, failed, lineLen int
625 defer close(doneChan)
626
627 for msg := range statusChan {
628 if msg.started {
629 started++
630 } else {
631 done++
632 }
633
634 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
635
636 if msg.err != nil {
637 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
638 failed++
639 }
640 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
641 lineLen = len(line)
642 os.Stdout.WriteString(line)
643 }
644}
645
646func main() {
647 var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
648
649 flag.Parse()
650
651 addCipherSuiteTests()
652 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -0700653 addCBCPaddingTests()
David Benjamin636293b2014-07-08 17:59:18 -0400654 addClientAuthTests()
Adam Langley95c29f32014-06-20 12:00:00 -0700655
656 var wg sync.WaitGroup
657
658 const numWorkers = 64
659
660 statusChan := make(chan statusMsg, numWorkers)
661 testChan := make(chan *testCase, numWorkers)
662 doneChan := make(chan struct{})
663
David Benjamin025b3d32014-07-01 19:53:04 -0400664 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -0700665
666 for i := 0; i < numWorkers; i++ {
667 wg.Add(1)
668 go worker(statusChan, testChan, &wg)
669 }
670
David Benjamin025b3d32014-07-01 19:53:04 -0400671 for i := range testCases {
672 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
673 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -0700674 }
675 }
676
677 close(testChan)
678 wg.Wait()
679 close(statusChan)
680 <-doneChan
681
682 fmt.Printf("\n")
683}