blob: 47af0e0d539ae7b163496116926ffb5513ba3825 [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 Benjamin1d5c83e2014-07-22 19:20:02 -040079 // resumeSession controls whether a second connection should be tested
80 // which resumes the first session.
81 resumeSession bool
David Benjamin325b5c32014-07-01 19:40:31 -040082 // flags, if not empty, contains a list of command-line flags that will
83 // be passed to the shim program.
84 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -070085}
86
David Benjamin025b3d32014-07-01 19:53:04 -040087var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -070088 {
89 name: "BadRSASignature",
90 config: Config{
91 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
92 Bugs: ProtocolBugs{
93 InvalidSKXSignature: true,
94 },
95 },
96 shouldFail: true,
97 expectedError: ":BAD_SIGNATURE:",
98 },
99 {
100 name: "BadECDSASignature",
101 config: Config{
102 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
103 Bugs: ProtocolBugs{
104 InvalidSKXSignature: true,
105 },
106 Certificates: []Certificate{getECDSACertificate()},
107 },
108 shouldFail: true,
109 expectedError: ":BAD_SIGNATURE:",
110 },
111 {
112 name: "BadECDSACurve",
113 config: Config{
114 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
115 Bugs: ProtocolBugs{
116 InvalidSKXCurve: true,
117 },
118 Certificates: []Certificate{getECDSACertificate()},
119 },
120 shouldFail: true,
121 expectedError: ":WRONG_CURVE:",
122 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700123 {
David Benjamin325b5c32014-07-01 19:40:31 -0400124 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700125 config: Config{
126 Bugs: ProtocolBugs{
127 FailIfNotFallbackSCSV: true,
128 },
129 },
130 shouldFail: true,
131 expectedLocalError: "no fallback SCSV found",
132 },
David Benjamin325b5c32014-07-01 19:40:31 -0400133 {
134 name: "FallbackSCSV",
135 config: Config{
136 Bugs: ProtocolBugs{
137 FailIfNotFallbackSCSV: true,
138 },
139 },
140 flags: []string{"-fallback-scsv"},
141 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400142 {
143 testType: serverTest,
David Benjamin35a7a442014-07-05 00:23:20 -0400144 name: "ServerNameExtension",
David Benjamin197b3ab2014-07-02 18:37:33 -0400145 config: Config{
146 ServerName: "example.com",
147 },
148 flags: []string{"-expect-server-name", "example.com"},
149 },
David Benjamin35a7a442014-07-05 00:23:20 -0400150 {
151 testType: clientTest,
152 name: "DuplicateExtensionClient",
153 config: Config{
154 Bugs: ProtocolBugs{
155 DuplicateExtension: true,
156 },
157 },
158 shouldFail: true,
159 expectedLocalError: "remote error: error decoding message",
160 },
161 {
162 testType: serverTest,
163 name: "DuplicateExtensionServer",
164 config: Config{
165 Bugs: ProtocolBugs{
166 DuplicateExtension: true,
167 },
168 },
169 shouldFail: true,
170 expectedLocalError: "remote error: error decoding message",
171 },
David Benjamin7b030512014-07-08 17:30:11 -0400172 {
173 name: "ClientCertificateTypes",
174 config: Config{
175 ClientAuth: RequestClientCert,
176 ClientCertificateTypes: []byte{
177 CertTypeDSSSign,
178 CertTypeRSASign,
179 CertTypeECDSASign,
180 },
181 },
182 flags: []string{"-expect-certificate-types", string([]byte{
183 CertTypeDSSSign,
184 CertTypeRSASign,
185 CertTypeECDSASign,
186 })},
187 },
David Benjamin636293b2014-07-08 17:59:18 -0400188 {
189 name: "NoClientCertificate",
190 config: Config{
191 ClientAuth: RequireAnyClientCert,
192 },
193 shouldFail: true,
194 expectedLocalError: "client didn't provide a certificate",
195 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400196 {
197 name: "UnauthenticatedECDH",
198 config: Config{
199 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
200 Bugs: ProtocolBugs{
201 UnauthenticatedECDH: true,
202 },
203 },
204 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400205 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400206 },
David Benjamin9c651c92014-07-12 13:27:45 -0400207 {
208 name: "SkipServerKeyExchange",
209 config: Config{
210 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
211 Bugs: ProtocolBugs{
212 SkipServerKeyExchange: true,
213 },
214 },
215 shouldFail: true,
216 expectedError: ":UNEXPECTED_MESSAGE:",
217 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400218 {
219 testType: serverTest,
220 name: "NPNServerTest",
221 config: Config{
222 NextProtos: []string{"bar"},
223 },
224 flags: []string{
225 "-advertise-npn", "\x03foo\x03bar\x03baz",
226 "-expect-next-proto", "bar",
227 },
228 },
David Benjamina0e52232014-07-19 17:39:58 -0400229 {
230 name: "SkipChangeCipherSpec-Client",
231 config: Config{
232 Bugs: ProtocolBugs{
233 SkipChangeCipherSpec: true,
234 },
235 },
236 shouldFail: true,
237 expectedError: ":GOT_A_FIN_BEFORE_A_CCS:",
238 },
239 {
240 testType: serverTest,
241 name: "SkipChangeCipherSpec-Server",
242 config: Config{
243 Bugs: ProtocolBugs{
244 SkipChangeCipherSpec: true,
245 },
246 },
247 shouldFail: true,
248 expectedError: ":GOT_A_FIN_BEFORE_A_CCS:",
249 },
David Benjamin42be6452014-07-21 14:50:23 -0400250 {
251 testType: serverTest,
252 name: "SkipChangeCipherSpec-Server-NPN",
253 config: Config{
254 NextProtos: []string{"bar"},
255 Bugs: ProtocolBugs{
256 SkipChangeCipherSpec: true,
257 },
258 },
259 flags: []string{
260 "-advertise-npn", "\x03foo\x03bar\x03baz",
261 },
262 shouldFail: true,
263 expectedError: ":GOT_NEXT_PROTO_BEFORE_A_CCS:",
264 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400265 {
266 testType: serverTest,
267 name: "EarlyChangeCipherSpec-server-1",
268 config: Config{
269 Bugs: ProtocolBugs{
270 EarlyChangeCipherSpec: 1,
271 },
272 },
273 shouldFail: true,
274 expectedError: ":CCS_RECEIVED_EARLY:",
275 },
276 {
277 testType: serverTest,
278 name: "EarlyChangeCipherSpec-server-2",
279 config: Config{
280 Bugs: ProtocolBugs{
281 EarlyChangeCipherSpec: 2,
282 },
283 },
284 shouldFail: true,
285 expectedError: ":CCS_RECEIVED_EARLY:",
286 },
Adam Langley95c29f32014-06-20 12:00:00 -0700287}
288
David Benjamin1d5c83e2014-07-22 19:20:02 -0400289func doExchange(testType testType, config *Config, conn net.Conn, messageLen int) error {
290 var tlsConn *Conn
291 if testType == clientTest {
292 tlsConn = Server(conn, config)
293 } else {
294 config.InsecureSkipVerify = true
295 tlsConn = Client(conn, config)
296 }
297
Adam Langley95c29f32014-06-20 12:00:00 -0700298 if err := tlsConn.Handshake(); err != nil {
299 return err
300 }
Adam Langley80842bd2014-06-20 12:00:00 -0700301 if messageLen == 0 {
302 messageLen = 32
303 }
304 testMessage := make([]byte, messageLen)
305 for i := range testMessage {
306 testMessage[i] = 0x42
307 }
Adam Langley95c29f32014-06-20 12:00:00 -0700308 tlsConn.Write(testMessage)
309
310 buf := make([]byte, len(testMessage))
311 _, err := io.ReadFull(tlsConn, buf)
312 if err != nil {
313 return err
314 }
315
316 for i, v := range buf {
317 if v != testMessage[i]^0xff {
318 return fmt.Errorf("bad reply contents at byte %d", i)
319 }
320 }
321
322 return nil
323}
324
David Benjamin325b5c32014-07-01 19:40:31 -0400325func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
326 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700327 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400328 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700329 }
David Benjamin325b5c32014-07-01 19:40:31 -0400330 valgrindArgs = append(valgrindArgs, path)
331 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700332
David Benjamin325b5c32014-07-01 19:40:31 -0400333 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700334}
335
David Benjamin325b5c32014-07-01 19:40:31 -0400336func gdbOf(path string, args ...string) *exec.Cmd {
337 xtermArgs := []string{"-e", "gdb", "--args"}
338 xtermArgs = append(xtermArgs, path)
339 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700340
David Benjamin325b5c32014-07-01 19:40:31 -0400341 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700342}
343
David Benjamin1d5c83e2014-07-22 19:20:02 -0400344func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700345 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
346 if err != nil {
347 panic(err)
348 }
349
350 syscall.CloseOnExec(socks[0])
351 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400352 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700353 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400354 conn, err = net.FileConn(connFile)
355 if err != nil {
356 panic(err)
357 }
Adam Langley95c29f32014-06-20 12:00:00 -0700358 connFile.Close()
359 if err != nil {
360 panic(err)
361 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400362 return shimEnd, conn
363}
364
365func runTest(test *testCase) error {
366 shimEnd, conn := openSocketPair()
367 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700368
David Benjamin025b3d32014-07-01 19:53:04 -0400369 const shim_path = "../../../build/ssl/test/bssl_shim"
370 flags := []string{}
371 if test.testType == clientTest {
372 flags = append(flags, "client")
Adam Langley95c29f32014-06-20 12:00:00 -0700373 } else {
David Benjamin025b3d32014-07-01 19:53:04 -0400374 flags = append(flags, "server")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400375 }
Adam Langley95c29f32014-06-20 12:00:00 -0700376
David Benjamin1d5c83e2014-07-22 19:20:02 -0400377 if test.resumeSession {
378 flags = append(flags, "resume")
379 } else {
380 flags = append(flags, "normal")
381 }
382
383 if test.testType == serverTest {
David Benjamin025b3d32014-07-01 19:53:04 -0400384 flags = append(flags, "-key-file")
385 if test.keyFile == "" {
386 flags = append(flags, rsaKeyFile)
387 } else {
388 flags = append(flags, test.keyFile)
389 }
390
391 flags = append(flags, "-cert-file")
392 if test.certFile == "" {
393 flags = append(flags, rsaCertificateFile)
394 } else {
395 flags = append(flags, test.certFile)
396 }
397 }
398 flags = append(flags, test.flags...)
399
400 var shim *exec.Cmd
401 if *useValgrind {
402 shim = valgrindOf(false, shim_path, flags...)
403 } else {
404 shim = exec.Command(shim_path, flags...)
405 }
406 // shim = gdbOf(shim_path, flags...)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400407 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400408 shim.Stdin = os.Stdin
409 var stdoutBuf, stderrBuf bytes.Buffer
410 shim.Stdout = &stdoutBuf
411 shim.Stderr = &stderrBuf
412
413 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700414 panic(err)
415 }
David Benjamin025b3d32014-07-01 19:53:04 -0400416 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400417 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700418
419 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400420 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400421 if test.testType == clientTest {
422 if len(config.Certificates) == 0 {
423 config.Certificates = []Certificate{getRSACertificate()}
424 }
David Benjamin025b3d32014-07-01 19:53:04 -0400425 }
Adam Langley95c29f32014-06-20 12:00:00 -0700426
David Benjamin1d5c83e2014-07-22 19:20:02 -0400427 err := doExchange(test.testType, &config, conn, test.messageLen)
Adam Langley95c29f32014-06-20 12:00:00 -0700428 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400429 if err == nil && test.resumeSession {
430 err = doExchange(test.testType, &config, connResume, test.messageLen)
431 connResume.Close()
432 }
433
David Benjamin025b3d32014-07-01 19:53:04 -0400434 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700435
436 stdout := string(stdoutBuf.Bytes())
437 stderr := string(stderrBuf.Bytes())
438 failed := err != nil || childErr != nil
439 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700440 localError := "none"
441 if err != nil {
442 localError = err.Error()
443 }
444 if len(test.expectedLocalError) != 0 {
445 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
446 }
Adam Langley95c29f32014-06-20 12:00:00 -0700447
448 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700449 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700450 if childErr != nil {
451 childError = childErr.Error()
452 }
453
454 var msg string
455 switch {
456 case failed && !test.shouldFail:
457 msg = "unexpected failure"
458 case !failed && test.shouldFail:
459 msg = "unexpected success"
460 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700461 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700462 default:
463 panic("internal error")
464 }
465
466 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
467 }
468
469 if !*useValgrind && len(stderr) > 0 {
470 println(stderr)
471 }
472
473 return nil
474}
475
476var tlsVersions = []struct {
477 name string
478 version uint16
479}{
480 {"SSL3", VersionSSL30},
481 {"TLS1", VersionTLS10},
482 {"TLS11", VersionTLS11},
483 {"TLS12", VersionTLS12},
484}
485
486var testCipherSuites = []struct {
487 name string
488 id uint16
489}{
490 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
491 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
492 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
493 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
494 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
495 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
496 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
497 {"ECDHE-RSA-3DES-SHA", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
498 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
499 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
500 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
501 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
502 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
503 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
504 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
505}
506
507func addCipherSuiteTests() {
508 for _, suite := range testCipherSuites {
509 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400510 var certFile string
511 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700512 if strings.Contains(suite.name, "ECDSA") {
513 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400514 certFile = ecdsaCertificateFile
515 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700516 } else {
517 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400518 certFile = rsaCertificateFile
519 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700520 }
521
522 for _, ver := range tlsVersions {
523 if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
524 continue
525 }
526
David Benjamin1d5c83e2014-07-22 19:20:02 -0400527 // Go's TLS implementation only implements session
528 // resumption with tickets, so SSLv3 cannot resume
529 // sessions.
530 resumeSession := ver.version != VersionSSL30
531
David Benjamin025b3d32014-07-01 19:53:04 -0400532 testCases = append(testCases, testCase{
533 testType: clientTest,
534 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700535 config: Config{
536 MinVersion: ver.version,
537 MaxVersion: ver.version,
538 CipherSuites: []uint16{suite.id},
539 Certificates: []Certificate{cert},
540 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400541 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700542 })
David Benjamin025b3d32014-07-01 19:53:04 -0400543
544 // Go's TLS implementation implements SSLv3 as a server,
545 // but not as a client.
546 //
547 // TODO(davidben): Implement SSLv3 as a client too to
548 // exercise that code.
549 if ver.version != VersionSSL30 {
550 testCases = append(testCases, testCase{
551 testType: serverTest,
552 name: ver.name + "-" + suite.name + "-server",
553 config: Config{
554 MinVersion: ver.version,
555 MaxVersion: ver.version,
556 CipherSuites: []uint16{suite.id},
557 Certificates: []Certificate{cert},
558 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400559 certFile: certFile,
560 keyFile: keyFile,
561 resumeSession: resumeSession,
David Benjamin025b3d32014-07-01 19:53:04 -0400562 })
563 }
Adam Langley95c29f32014-06-20 12:00:00 -0700564 }
565 }
566}
567
568func addBadECDSASignatureTests() {
569 for badR := BadValue(1); badR < NumBadValues; badR++ {
570 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400571 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700572 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
573 config: Config{
574 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
575 Certificates: []Certificate{getECDSACertificate()},
576 Bugs: ProtocolBugs{
577 BadECDSAR: badR,
578 BadECDSAS: badS,
579 },
580 },
581 shouldFail: true,
582 expectedError: "SIGNATURE",
583 })
584 }
585 }
586}
587
Adam Langley80842bd2014-06-20 12:00:00 -0700588func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400589 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700590 name: "MaxCBCPadding",
591 config: Config{
592 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
593 Bugs: ProtocolBugs{
594 MaxPadding: true,
595 },
596 },
597 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
598 })
David Benjamin025b3d32014-07-01 19:53:04 -0400599 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700600 name: "BadCBCPadding",
601 config: Config{
602 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
603 Bugs: ProtocolBugs{
604 PaddingFirstByteBad: true,
605 },
606 },
607 shouldFail: true,
608 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
609 })
610 // OpenSSL previously had an issue where the first byte of padding in
611 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400612 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700613 name: "BadCBCPadding255",
614 config: Config{
615 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
616 Bugs: ProtocolBugs{
617 MaxPadding: true,
618 PaddingFirstByteBadIf255: true,
619 },
620 },
621 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
622 shouldFail: true,
623 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
624 })
625}
626
David Benjamin636293b2014-07-08 17:59:18 -0400627func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -0400628 // Add a dummy cert pool to stress certificate authority parsing.
629 // TODO(davidben): Add tests that those values parse out correctly.
630 certPool := x509.NewCertPool()
631 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
632 if err != nil {
633 panic(err)
634 }
635 certPool.AddCert(cert)
636
David Benjamin636293b2014-07-08 17:59:18 -0400637 for _, ver := range tlsVersions {
638 if ver.version == VersionSSL30 {
639 // TODO(davidben): The Go implementation does not
640 // correctly compute CertificateVerify hashes for SSLv3.
641 continue
642 }
643
644 var cipherSuites []uint16
645 if ver.version >= VersionTLS12 {
646 // Pick a SHA-256 cipher suite. The Go implementation
647 // does not correctly handle client auth with a SHA-384
648 // cipher suite.
649 cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
650 }
651
652 testCases = append(testCases, testCase{
653 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400654 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -0400655 config: Config{
656 MinVersion: ver.version,
657 MaxVersion: ver.version,
658 CipherSuites: cipherSuites,
659 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400660 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400661 },
662 flags: []string{
663 "-cert-file", rsaCertificateFile,
664 "-key-file", rsaKeyFile,
665 },
666 })
667 testCases = append(testCases, testCase{
668 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400669 name: ver.name + "-Client-ClientAuth-ECDSA",
David Benjamin636293b2014-07-08 17:59:18 -0400670 config: Config{
671 MinVersion: ver.version,
672 MaxVersion: ver.version,
673 CipherSuites: cipherSuites,
674 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400675 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400676 },
677 flags: []string{
678 "-cert-file", ecdsaCertificateFile,
679 "-key-file", ecdsaKeyFile,
680 },
681 })
David Benjamin67666e72014-07-12 15:47:52 -0400682 testCases = append(testCases, testCase{
683 testType: serverTest,
684 name: ver.name + "-Server-ClientAuth-RSA",
685 config: Config{
686 Certificates: []Certificate{rsaCertificate},
687 },
688 flags: []string{"-require-any-client-certificate"},
689 })
690 testCases = append(testCases, testCase{
691 testType: serverTest,
692 name: ver.name + "-Server-ClientAuth-ECDSA",
693 config: Config{
694 Certificates: []Certificate{ecdsaCertificate},
695 },
696 flags: []string{"-require-any-client-certificate"},
697 })
David Benjamin636293b2014-07-08 17:59:18 -0400698 }
699}
700
Adam Langley95c29f32014-06-20 12:00:00 -0700701func worker(statusChan chan statusMsg, c chan *testCase, wg *sync.WaitGroup) {
702 defer wg.Done()
703
704 for test := range c {
705 statusChan <- statusMsg{test: test, started: true}
706 err := runTest(test)
707 statusChan <- statusMsg{test: test, err: err}
708 }
709}
710
711type statusMsg struct {
712 test *testCase
713 started bool
714 err error
715}
716
717func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
718 var started, done, failed, lineLen int
719 defer close(doneChan)
720
721 for msg := range statusChan {
722 if msg.started {
723 started++
724 } else {
725 done++
726 }
727
728 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
729
730 if msg.err != nil {
731 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
732 failed++
733 }
734 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
735 lineLen = len(line)
736 os.Stdout.WriteString(line)
737 }
738}
739
740func main() {
741 var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
742
743 flag.Parse()
744
745 addCipherSuiteTests()
746 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -0700747 addCBCPaddingTests()
David Benjamin636293b2014-07-08 17:59:18 -0400748 addClientAuthTests()
Adam Langley95c29f32014-06-20 12:00:00 -0700749
750 var wg sync.WaitGroup
751
752 const numWorkers = 64
753
754 statusChan := make(chan statusMsg, numWorkers)
755 testChan := make(chan *testCase, numWorkers)
756 doneChan := make(chan struct{})
757
David Benjamin025b3d32014-07-01 19:53:04 -0400758 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -0700759
760 for i := 0; i < numWorkers; i++ {
761 wg.Add(1)
762 go worker(statusChan, testChan, &wg)
763 }
764
David Benjamin025b3d32014-07-01 19:53:04 -0400765 for i := range testCases {
766 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
767 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -0700768 }
769 }
770
771 close(testChan)
772 wg.Wait()
773 close(statusChan)
774 <-doneChan
775
776 fmt.Printf("\n")
777}