blob: 06ca860ab8bcda89b77151e892879c250faca74b [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 },
David Benjamina0e52232014-07-19 17:39:58 -0400226 {
227 name: "SkipChangeCipherSpec-Client",
228 config: Config{
229 Bugs: ProtocolBugs{
230 SkipChangeCipherSpec: true,
231 },
232 },
233 shouldFail: true,
234 expectedError: ":GOT_A_FIN_BEFORE_A_CCS:",
235 },
236 {
237 testType: serverTest,
238 name: "SkipChangeCipherSpec-Server",
239 config: Config{
240 Bugs: ProtocolBugs{
241 SkipChangeCipherSpec: true,
242 },
243 },
244 shouldFail: true,
245 expectedError: ":GOT_A_FIN_BEFORE_A_CCS:",
246 },
David Benjamin42be6452014-07-21 14:50:23 -0400247 {
248 testType: serverTest,
249 name: "SkipChangeCipherSpec-Server-NPN",
250 config: Config{
251 NextProtos: []string{"bar"},
252 Bugs: ProtocolBugs{
253 SkipChangeCipherSpec: true,
254 },
255 },
256 flags: []string{
257 "-advertise-npn", "\x03foo\x03bar\x03baz",
258 },
259 shouldFail: true,
260 expectedError: ":GOT_NEXT_PROTO_BEFORE_A_CCS:",
261 },
Adam Langley95c29f32014-06-20 12:00:00 -0700262}
263
Adam Langley80842bd2014-06-20 12:00:00 -0700264func doExchange(tlsConn *Conn, messageLen int) error {
Adam Langley95c29f32014-06-20 12:00:00 -0700265 if err := tlsConn.Handshake(); err != nil {
266 return err
267 }
Adam Langley80842bd2014-06-20 12:00:00 -0700268 if messageLen == 0 {
269 messageLen = 32
270 }
271 testMessage := make([]byte, messageLen)
272 for i := range testMessage {
273 testMessage[i] = 0x42
274 }
Adam Langley95c29f32014-06-20 12:00:00 -0700275 tlsConn.Write(testMessage)
276
277 buf := make([]byte, len(testMessage))
278 _, err := io.ReadFull(tlsConn, buf)
279 if err != nil {
280 return err
281 }
282
283 for i, v := range buf {
284 if v != testMessage[i]^0xff {
285 return fmt.Errorf("bad reply contents at byte %d", i)
286 }
287 }
288
289 return nil
290}
291
David Benjamin325b5c32014-07-01 19:40:31 -0400292func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
293 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700294 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400295 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700296 }
David Benjamin325b5c32014-07-01 19:40:31 -0400297 valgrindArgs = append(valgrindArgs, path)
298 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700299
David Benjamin325b5c32014-07-01 19:40:31 -0400300 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700301}
302
David Benjamin325b5c32014-07-01 19:40:31 -0400303func gdbOf(path string, args ...string) *exec.Cmd {
304 xtermArgs := []string{"-e", "gdb", "--args"}
305 xtermArgs = append(xtermArgs, path)
306 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700307
David Benjamin325b5c32014-07-01 19:40:31 -0400308 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700309}
310
311func runTest(test *testCase) error {
312 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
313 if err != nil {
314 panic(err)
315 }
316
317 syscall.CloseOnExec(socks[0])
318 syscall.CloseOnExec(socks[1])
David Benjamin025b3d32014-07-01 19:53:04 -0400319 shimEnd := os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700320 connFile := os.NewFile(uintptr(socks[1]), "our end")
321 conn, err := net.FileConn(connFile)
322 connFile.Close()
323 if err != nil {
324 panic(err)
325 }
326
David Benjamin025b3d32014-07-01 19:53:04 -0400327 const shim_path = "../../../build/ssl/test/bssl_shim"
328 flags := []string{}
329 if test.testType == clientTest {
330 flags = append(flags, "client")
Adam Langley95c29f32014-06-20 12:00:00 -0700331 } else {
David Benjamin025b3d32014-07-01 19:53:04 -0400332 flags = append(flags, "server")
Adam Langley95c29f32014-06-20 12:00:00 -0700333
David Benjamin025b3d32014-07-01 19:53:04 -0400334 flags = append(flags, "-key-file")
335 if test.keyFile == "" {
336 flags = append(flags, rsaKeyFile)
337 } else {
338 flags = append(flags, test.keyFile)
339 }
340
341 flags = append(flags, "-cert-file")
342 if test.certFile == "" {
343 flags = append(flags, rsaCertificateFile)
344 } else {
345 flags = append(flags, test.certFile)
346 }
347 }
348 flags = append(flags, test.flags...)
349
350 var shim *exec.Cmd
351 if *useValgrind {
352 shim = valgrindOf(false, shim_path, flags...)
353 } else {
354 shim = exec.Command(shim_path, flags...)
355 }
356 // shim = gdbOf(shim_path, flags...)
357 shim.ExtraFiles = []*os.File{shimEnd}
358 shim.Stdin = os.Stdin
359 var stdoutBuf, stderrBuf bytes.Buffer
360 shim.Stdout = &stdoutBuf
361 shim.Stderr = &stderrBuf
362
363 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700364 panic(err)
365 }
David Benjamin025b3d32014-07-01 19:53:04 -0400366 shimEnd.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700367
368 config := test.config
Adam Langley95c29f32014-06-20 12:00:00 -0700369
David Benjamin025b3d32014-07-01 19:53:04 -0400370 var tlsConn *Conn
371 if test.testType == clientTest {
372 if len(config.Certificates) == 0 {
373 config.Certificates = []Certificate{getRSACertificate()}
374 }
375 tlsConn = Server(conn, &config)
376 } else {
377 config.InsecureSkipVerify = true
378 tlsConn = Client(conn, &config)
379 }
Adam Langley80842bd2014-06-20 12:00:00 -0700380 err = doExchange(tlsConn, test.messageLen)
Adam Langley95c29f32014-06-20 12:00:00 -0700381
382 conn.Close()
David Benjamin025b3d32014-07-01 19:53:04 -0400383 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700384
385 stdout := string(stdoutBuf.Bytes())
386 stderr := string(stderrBuf.Bytes())
387 failed := err != nil || childErr != nil
388 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700389 localError := "none"
390 if err != nil {
391 localError = err.Error()
392 }
393 if len(test.expectedLocalError) != 0 {
394 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
395 }
Adam Langley95c29f32014-06-20 12:00:00 -0700396
397 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700398 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700399 if childErr != nil {
400 childError = childErr.Error()
401 }
402
403 var msg string
404 switch {
405 case failed && !test.shouldFail:
406 msg = "unexpected failure"
407 case !failed && test.shouldFail:
408 msg = "unexpected success"
409 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700410 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700411 default:
412 panic("internal error")
413 }
414
415 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
416 }
417
418 if !*useValgrind && len(stderr) > 0 {
419 println(stderr)
420 }
421
422 return nil
423}
424
425var tlsVersions = []struct {
426 name string
427 version uint16
428}{
429 {"SSL3", VersionSSL30},
430 {"TLS1", VersionTLS10},
431 {"TLS11", VersionTLS11},
432 {"TLS12", VersionTLS12},
433}
434
435var testCipherSuites = []struct {
436 name string
437 id uint16
438}{
439 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
440 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
441 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
442 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
443 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
444 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
445 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
446 {"ECDHE-RSA-3DES-SHA", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
447 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
448 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
449 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
450 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
451 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
452 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
453 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
454}
455
456func addCipherSuiteTests() {
457 for _, suite := range testCipherSuites {
458 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400459 var certFile string
460 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700461 if strings.Contains(suite.name, "ECDSA") {
462 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400463 certFile = ecdsaCertificateFile
464 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700465 } else {
466 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400467 certFile = rsaCertificateFile
468 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700469 }
470
471 for _, ver := range tlsVersions {
472 if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
473 continue
474 }
475
David Benjamin025b3d32014-07-01 19:53:04 -0400476 testCases = append(testCases, testCase{
477 testType: clientTest,
478 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700479 config: Config{
480 MinVersion: ver.version,
481 MaxVersion: ver.version,
482 CipherSuites: []uint16{suite.id},
483 Certificates: []Certificate{cert},
484 },
485 })
David Benjamin025b3d32014-07-01 19:53:04 -0400486
487 // Go's TLS implementation implements SSLv3 as a server,
488 // but not as a client.
489 //
490 // TODO(davidben): Implement SSLv3 as a client too to
491 // exercise that code.
492 if ver.version != VersionSSL30 {
493 testCases = append(testCases, testCase{
494 testType: serverTest,
495 name: ver.name + "-" + suite.name + "-server",
496 config: Config{
497 MinVersion: ver.version,
498 MaxVersion: ver.version,
499 CipherSuites: []uint16{suite.id},
500 Certificates: []Certificate{cert},
501 },
502 certFile: certFile,
503 keyFile: keyFile,
504 })
505 }
Adam Langley95c29f32014-06-20 12:00:00 -0700506 }
507 }
508}
509
510func addBadECDSASignatureTests() {
511 for badR := BadValue(1); badR < NumBadValues; badR++ {
512 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400513 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700514 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
515 config: Config{
516 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
517 Certificates: []Certificate{getECDSACertificate()},
518 Bugs: ProtocolBugs{
519 BadECDSAR: badR,
520 BadECDSAS: badS,
521 },
522 },
523 shouldFail: true,
524 expectedError: "SIGNATURE",
525 })
526 }
527 }
528}
529
Adam Langley80842bd2014-06-20 12:00:00 -0700530func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400531 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700532 name: "MaxCBCPadding",
533 config: Config{
534 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
535 Bugs: ProtocolBugs{
536 MaxPadding: true,
537 },
538 },
539 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
540 })
David Benjamin025b3d32014-07-01 19:53:04 -0400541 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700542 name: "BadCBCPadding",
543 config: Config{
544 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
545 Bugs: ProtocolBugs{
546 PaddingFirstByteBad: true,
547 },
548 },
549 shouldFail: true,
550 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
551 })
552 // OpenSSL previously had an issue where the first byte of padding in
553 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400554 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700555 name: "BadCBCPadding255",
556 config: Config{
557 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
558 Bugs: ProtocolBugs{
559 MaxPadding: true,
560 PaddingFirstByteBadIf255: true,
561 },
562 },
563 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
564 shouldFail: true,
565 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
566 })
567}
568
David Benjamin636293b2014-07-08 17:59:18 -0400569func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -0400570 // Add a dummy cert pool to stress certificate authority parsing.
571 // TODO(davidben): Add tests that those values parse out correctly.
572 certPool := x509.NewCertPool()
573 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
574 if err != nil {
575 panic(err)
576 }
577 certPool.AddCert(cert)
578
David Benjamin636293b2014-07-08 17:59:18 -0400579 for _, ver := range tlsVersions {
580 if ver.version == VersionSSL30 {
581 // TODO(davidben): The Go implementation does not
582 // correctly compute CertificateVerify hashes for SSLv3.
583 continue
584 }
585
586 var cipherSuites []uint16
587 if ver.version >= VersionTLS12 {
588 // Pick a SHA-256 cipher suite. The Go implementation
589 // does not correctly handle client auth with a SHA-384
590 // cipher suite.
591 cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
592 }
593
594 testCases = append(testCases, testCase{
595 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400596 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -0400597 config: Config{
598 MinVersion: ver.version,
599 MaxVersion: ver.version,
600 CipherSuites: cipherSuites,
601 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400602 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400603 },
604 flags: []string{
605 "-cert-file", rsaCertificateFile,
606 "-key-file", rsaKeyFile,
607 },
608 })
609 testCases = append(testCases, testCase{
610 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400611 name: ver.name + "-Client-ClientAuth-ECDSA",
David Benjamin636293b2014-07-08 17:59:18 -0400612 config: Config{
613 MinVersion: ver.version,
614 MaxVersion: ver.version,
615 CipherSuites: cipherSuites,
616 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400617 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400618 },
619 flags: []string{
620 "-cert-file", ecdsaCertificateFile,
621 "-key-file", ecdsaKeyFile,
622 },
623 })
David Benjamin67666e72014-07-12 15:47:52 -0400624 testCases = append(testCases, testCase{
625 testType: serverTest,
626 name: ver.name + "-Server-ClientAuth-RSA",
627 config: Config{
628 Certificates: []Certificate{rsaCertificate},
629 },
630 flags: []string{"-require-any-client-certificate"},
631 })
632 testCases = append(testCases, testCase{
633 testType: serverTest,
634 name: ver.name + "-Server-ClientAuth-ECDSA",
635 config: Config{
636 Certificates: []Certificate{ecdsaCertificate},
637 },
638 flags: []string{"-require-any-client-certificate"},
639 })
David Benjamin636293b2014-07-08 17:59:18 -0400640 }
641}
642
Adam Langley95c29f32014-06-20 12:00:00 -0700643func worker(statusChan chan statusMsg, c chan *testCase, wg *sync.WaitGroup) {
644 defer wg.Done()
645
646 for test := range c {
647 statusChan <- statusMsg{test: test, started: true}
648 err := runTest(test)
649 statusChan <- statusMsg{test: test, err: err}
650 }
651}
652
653type statusMsg struct {
654 test *testCase
655 started bool
656 err error
657}
658
659func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
660 var started, done, failed, lineLen int
661 defer close(doneChan)
662
663 for msg := range statusChan {
664 if msg.started {
665 started++
666 } else {
667 done++
668 }
669
670 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
671
672 if msg.err != nil {
673 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
674 failed++
675 }
676 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
677 lineLen = len(line)
678 os.Stdout.WriteString(line)
679 }
680}
681
682func main() {
683 var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
684
685 flag.Parse()
686
687 addCipherSuiteTests()
688 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -0700689 addCBCPaddingTests()
David Benjamin636293b2014-07-08 17:59:18 -0400690 addClientAuthTests()
Adam Langley95c29f32014-06-20 12:00:00 -0700691
692 var wg sync.WaitGroup
693
694 const numWorkers = 64
695
696 statusChan := make(chan statusMsg, numWorkers)
697 testChan := make(chan *testCase, numWorkers)
698 doneChan := make(chan struct{})
699
David Benjamin025b3d32014-07-01 19:53:04 -0400700 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -0700701
702 for i := 0; i < numWorkers; i++ {
703 wg.Add(1)
704 go worker(statusChan, testChan, &wg)
705 }
706
David Benjamin025b3d32014-07-01 19:53:04 -0400707 for i := range testCases {
708 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
709 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -0700710 }
711 }
712
713 close(testChan)
714 wg.Wait()
715 close(statusChan)
716 <-doneChan
717
718 fmt.Printf("\n")
719}