blob: 4a5b762afb2af796d08c80384decf78b06854d83 [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
David Benjamin6fd297b2014-08-11 18:43:38 -040066type protocol int
67
68const (
69 tls protocol = iota
70 dtls
71)
72
Adam Langley95c29f32014-06-20 12:00:00 -070073type testCase struct {
David Benjamin025b3d32014-07-01 19:53:04 -040074 testType testType
David Benjamin6fd297b2014-08-11 18:43:38 -040075 protocol protocol
Adam Langley95c29f32014-06-20 12:00:00 -070076 name string
77 config Config
78 shouldFail bool
79 expectedError string
Adam Langleyac61fa32014-06-23 12:03:11 -070080 // expectedLocalError, if not empty, contains a substring that must be
81 // found in the local error.
82 expectedLocalError string
David Benjamin7e2e6cf2014-08-07 17:44:24 -040083 // expectedVersion, if non-zero, specifies the TLS version that must be
84 // negotiated.
85 expectedVersion uint16
Adam Langley80842bd2014-06-20 12:00:00 -070086 // messageLen is the length, in bytes, of the test message that will be
87 // sent.
88 messageLen int
David Benjamin025b3d32014-07-01 19:53:04 -040089 // certFile is the path to the certificate to use for the server.
90 certFile string
91 // keyFile is the path to the private key to use for the server.
92 keyFile string
David Benjamin1d5c83e2014-07-22 19:20:02 -040093 // resumeSession controls whether a second connection should be tested
94 // which resumes the first session.
95 resumeSession bool
David Benjamin98e882e2014-08-08 13:24:34 -040096 // sendPrefix sends a prefix on the socket before actually performing a
97 // handshake.
98 sendPrefix string
David Benjamin325b5c32014-07-01 19:40:31 -040099 // flags, if not empty, contains a list of command-line flags that will
100 // be passed to the shim program.
101 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -0700102}
103
David Benjamin025b3d32014-07-01 19:53:04 -0400104var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700105 {
106 name: "BadRSASignature",
107 config: Config{
108 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
109 Bugs: ProtocolBugs{
110 InvalidSKXSignature: true,
111 },
112 },
113 shouldFail: true,
114 expectedError: ":BAD_SIGNATURE:",
115 },
116 {
117 name: "BadECDSASignature",
118 config: Config{
119 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
120 Bugs: ProtocolBugs{
121 InvalidSKXSignature: true,
122 },
123 Certificates: []Certificate{getECDSACertificate()},
124 },
125 shouldFail: true,
126 expectedError: ":BAD_SIGNATURE:",
127 },
128 {
129 name: "BadECDSACurve",
130 config: Config{
131 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
132 Bugs: ProtocolBugs{
133 InvalidSKXCurve: true,
134 },
135 Certificates: []Certificate{getECDSACertificate()},
136 },
137 shouldFail: true,
138 expectedError: ":WRONG_CURVE:",
139 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700140 {
David Benjamina8e3e0e2014-08-06 22:11:10 -0400141 testType: serverTest,
142 name: "BadRSAVersion",
143 config: Config{
144 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
145 Bugs: ProtocolBugs{
146 RsaClientKeyExchangeVersion: VersionTLS11,
147 },
148 },
149 shouldFail: true,
150 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
151 },
152 {
David Benjamin325b5c32014-07-01 19:40:31 -0400153 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700154 config: Config{
155 Bugs: ProtocolBugs{
156 FailIfNotFallbackSCSV: true,
157 },
158 },
159 shouldFail: true,
160 expectedLocalError: "no fallback SCSV found",
161 },
David Benjamin325b5c32014-07-01 19:40:31 -0400162 {
163 name: "FallbackSCSV",
164 config: Config{
165 Bugs: ProtocolBugs{
166 FailIfNotFallbackSCSV: true,
167 },
168 },
169 flags: []string{"-fallback-scsv"},
170 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400171 {
172 testType: serverTest,
David Benjamin35a7a442014-07-05 00:23:20 -0400173 name: "ServerNameExtension",
David Benjamin197b3ab2014-07-02 18:37:33 -0400174 config: Config{
175 ServerName: "example.com",
176 },
177 flags: []string{"-expect-server-name", "example.com"},
178 },
David Benjamin35a7a442014-07-05 00:23:20 -0400179 {
180 testType: clientTest,
181 name: "DuplicateExtensionClient",
182 config: Config{
183 Bugs: ProtocolBugs{
184 DuplicateExtension: true,
185 },
186 },
187 shouldFail: true,
188 expectedLocalError: "remote error: error decoding message",
189 },
190 {
191 testType: serverTest,
192 name: "DuplicateExtensionServer",
193 config: Config{
194 Bugs: ProtocolBugs{
195 DuplicateExtension: true,
196 },
197 },
198 shouldFail: true,
199 expectedLocalError: "remote error: error decoding message",
200 },
David Benjamin7b030512014-07-08 17:30:11 -0400201 {
202 name: "ClientCertificateTypes",
203 config: Config{
204 ClientAuth: RequestClientCert,
205 ClientCertificateTypes: []byte{
206 CertTypeDSSSign,
207 CertTypeRSASign,
208 CertTypeECDSASign,
209 },
210 },
211 flags: []string{"-expect-certificate-types", string([]byte{
212 CertTypeDSSSign,
213 CertTypeRSASign,
214 CertTypeECDSASign,
215 })},
216 },
David Benjamin636293b2014-07-08 17:59:18 -0400217 {
218 name: "NoClientCertificate",
219 config: Config{
220 ClientAuth: RequireAnyClientCert,
221 },
222 shouldFail: true,
223 expectedLocalError: "client didn't provide a certificate",
224 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400225 {
226 name: "UnauthenticatedECDH",
227 config: Config{
228 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
229 Bugs: ProtocolBugs{
230 UnauthenticatedECDH: true,
231 },
232 },
233 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400234 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400235 },
David Benjamin9c651c92014-07-12 13:27:45 -0400236 {
237 name: "SkipServerKeyExchange",
238 config: Config{
239 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
240 Bugs: ProtocolBugs{
241 SkipServerKeyExchange: true,
242 },
243 },
244 shouldFail: true,
245 expectedError: ":UNEXPECTED_MESSAGE:",
246 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400247 {
David Benjamina0e52232014-07-19 17:39:58 -0400248 name: "SkipChangeCipherSpec-Client",
249 config: Config{
250 Bugs: ProtocolBugs{
251 SkipChangeCipherSpec: true,
252 },
253 },
254 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400255 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400256 },
257 {
258 testType: serverTest,
259 name: "SkipChangeCipherSpec-Server",
260 config: Config{
261 Bugs: ProtocolBugs{
262 SkipChangeCipherSpec: true,
263 },
264 },
265 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400266 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400267 },
David Benjamin42be6452014-07-21 14:50:23 -0400268 {
269 testType: serverTest,
270 name: "SkipChangeCipherSpec-Server-NPN",
271 config: Config{
272 NextProtos: []string{"bar"},
273 Bugs: ProtocolBugs{
274 SkipChangeCipherSpec: true,
275 },
276 },
277 flags: []string{
278 "-advertise-npn", "\x03foo\x03bar\x03baz",
279 },
280 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400281 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
282 },
283 {
284 name: "FragmentAcrossChangeCipherSpec-Client",
285 config: Config{
286 Bugs: ProtocolBugs{
287 FragmentAcrossChangeCipherSpec: true,
288 },
289 },
290 shouldFail: true,
291 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
292 },
293 {
294 testType: serverTest,
295 name: "FragmentAcrossChangeCipherSpec-Server",
296 config: Config{
297 Bugs: ProtocolBugs{
298 FragmentAcrossChangeCipherSpec: true,
299 },
300 },
301 shouldFail: true,
302 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
303 },
304 {
305 testType: serverTest,
306 name: "FragmentAcrossChangeCipherSpec-Server-NPN",
307 config: Config{
308 NextProtos: []string{"bar"},
309 Bugs: ProtocolBugs{
310 FragmentAcrossChangeCipherSpec: true,
311 },
312 },
313 flags: []string{
314 "-advertise-npn", "\x03foo\x03bar\x03baz",
315 },
316 shouldFail: true,
317 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamin42be6452014-07-21 14:50:23 -0400318 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400319 {
320 testType: serverTest,
321 name: "EarlyChangeCipherSpec-server-1",
322 config: Config{
323 Bugs: ProtocolBugs{
324 EarlyChangeCipherSpec: 1,
325 },
326 },
327 shouldFail: true,
328 expectedError: ":CCS_RECEIVED_EARLY:",
329 },
330 {
331 testType: serverTest,
332 name: "EarlyChangeCipherSpec-server-2",
333 config: Config{
334 Bugs: ProtocolBugs{
335 EarlyChangeCipherSpec: 2,
336 },
337 },
338 shouldFail: true,
339 expectedError: ":CCS_RECEIVED_EARLY:",
340 },
David Benjamind23f4122014-07-23 15:09:48 -0400341 {
David Benjamind23f4122014-07-23 15:09:48 -0400342 name: "SkipNewSessionTicket",
343 config: Config{
344 Bugs: ProtocolBugs{
345 SkipNewSessionTicket: true,
346 },
347 },
348 shouldFail: true,
349 expectedError: ":CCS_RECEIVED_EARLY:",
350 },
David Benjamin7e3305e2014-07-28 14:52:32 -0400351 {
David Benjamind86c7672014-08-02 04:07:12 -0400352 testType: serverTest,
David Benjaminbef270a2014-08-02 04:22:02 -0400353 name: "FallbackSCSV",
354 config: Config{
355 MaxVersion: VersionTLS11,
356 Bugs: ProtocolBugs{
357 SendFallbackSCSV: true,
358 },
359 },
360 shouldFail: true,
361 expectedError: ":INAPPROPRIATE_FALLBACK:",
362 },
363 {
364 testType: serverTest,
365 name: "FallbackSCSV-VersionMatch",
366 config: Config{
367 Bugs: ProtocolBugs{
368 SendFallbackSCSV: true,
369 },
370 },
371 },
David Benjamin98214542014-08-07 18:02:39 -0400372 {
373 testType: serverTest,
374 name: "FragmentedClientVersion",
375 config: Config{
376 Bugs: ProtocolBugs{
377 MaxHandshakeRecordLength: 1,
378 FragmentClientVersion: true,
379 },
380 },
381 shouldFail: true,
382 expectedError: ":RECORD_TOO_SMALL:",
383 },
David Benjamin98e882e2014-08-08 13:24:34 -0400384 {
385 testType: serverTest,
386 name: "MinorVersionTolerance",
387 config: Config{
388 Bugs: ProtocolBugs{
389 SendClientVersion: 0x03ff,
390 },
391 },
392 expectedVersion: VersionTLS12,
393 },
394 {
395 testType: serverTest,
396 name: "MajorVersionTolerance",
397 config: Config{
398 Bugs: ProtocolBugs{
399 SendClientVersion: 0x0400,
400 },
401 },
402 expectedVersion: VersionTLS12,
403 },
404 {
405 testType: serverTest,
406 name: "VersionTooLow",
407 config: Config{
408 Bugs: ProtocolBugs{
409 SendClientVersion: 0x0200,
410 },
411 },
412 shouldFail: true,
413 expectedError: ":UNSUPPORTED_PROTOCOL:",
414 },
415 {
416 testType: serverTest,
417 name: "HttpGET",
418 sendPrefix: "GET / HTTP/1.0\n",
419 shouldFail: true,
420 expectedError: ":HTTP_REQUEST:",
421 },
422 {
423 testType: serverTest,
424 name: "HttpPOST",
425 sendPrefix: "POST / HTTP/1.0\n",
426 shouldFail: true,
427 expectedError: ":HTTP_REQUEST:",
428 },
429 {
430 testType: serverTest,
431 name: "HttpHEAD",
432 sendPrefix: "HEAD / HTTP/1.0\n",
433 shouldFail: true,
434 expectedError: ":HTTP_REQUEST:",
435 },
436 {
437 testType: serverTest,
438 name: "HttpPUT",
439 sendPrefix: "PUT / HTTP/1.0\n",
440 shouldFail: true,
441 expectedError: ":HTTP_REQUEST:",
442 },
443 {
444 testType: serverTest,
445 name: "HttpCONNECT",
446 sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
447 shouldFail: true,
448 expectedError: ":HTTPS_PROXY_REQUEST:",
449 },
Adam Langley95c29f32014-06-20 12:00:00 -0700450}
451
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400452func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error {
David Benjamin6fd297b2014-08-11 18:43:38 -0400453 if test.protocol == dtls {
454 conn = newPacketAdaptor(conn)
455 }
456
457 if test.sendPrefix != "" {
458 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
459 return err
460 }
David Benjamin98e882e2014-08-08 13:24:34 -0400461 }
462
David Benjamin1d5c83e2014-07-22 19:20:02 -0400463 var tlsConn *Conn
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400464 if test.testType == clientTest {
David Benjamin6fd297b2014-08-11 18:43:38 -0400465 if test.protocol == dtls {
466 tlsConn = DTLSServer(conn, config)
467 } else {
468 tlsConn = Server(conn, config)
469 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400470 } else {
471 config.InsecureSkipVerify = true
David Benjamin6fd297b2014-08-11 18:43:38 -0400472 if test.protocol == dtls {
473 tlsConn = DTLSClient(conn, config)
474 } else {
475 tlsConn = Client(conn, config)
476 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400477 }
478
Adam Langley95c29f32014-06-20 12:00:00 -0700479 if err := tlsConn.Handshake(); err != nil {
480 return err
481 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700482
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400483 if vers := tlsConn.ConnectionState().Version; test.expectedVersion != 0 && vers != test.expectedVersion {
484 return fmt.Errorf("got version %x, expected %x", vers, test.expectedVersion)
485 }
486
Kenny Root7fdeaf12014-08-05 15:23:37 -0700487 if messageLen < 0 {
David Benjamin6fd297b2014-08-11 18:43:38 -0400488 if test.protocol == dtls {
489 return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
490 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700491 // Read until EOF.
492 _, err := io.Copy(ioutil.Discard, tlsConn)
493 return err
494 }
495
Adam Langley80842bd2014-06-20 12:00:00 -0700496 if messageLen == 0 {
497 messageLen = 32
498 }
499 testMessage := make([]byte, messageLen)
500 for i := range testMessage {
501 testMessage[i] = 0x42
502 }
Adam Langley95c29f32014-06-20 12:00:00 -0700503 tlsConn.Write(testMessage)
504
505 buf := make([]byte, len(testMessage))
David Benjamin6fd297b2014-08-11 18:43:38 -0400506 if test.protocol == dtls {
507 bufTmp := make([]byte, len(buf)+1)
508 n, err := tlsConn.Read(bufTmp)
509 if err != nil {
510 return err
511 }
512 if n != len(buf) {
513 return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
514 }
515 copy(buf, bufTmp)
516 } else {
517 _, err := io.ReadFull(tlsConn, buf)
518 if err != nil {
519 return err
520 }
Adam Langley95c29f32014-06-20 12:00:00 -0700521 }
522
523 for i, v := range buf {
524 if v != testMessage[i]^0xff {
525 return fmt.Errorf("bad reply contents at byte %d", i)
526 }
527 }
528
529 return nil
530}
531
David Benjamin325b5c32014-07-01 19:40:31 -0400532func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
533 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700534 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400535 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700536 }
David Benjamin325b5c32014-07-01 19:40:31 -0400537 valgrindArgs = append(valgrindArgs, path)
538 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700539
David Benjamin325b5c32014-07-01 19:40:31 -0400540 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700541}
542
David Benjamin325b5c32014-07-01 19:40:31 -0400543func gdbOf(path string, args ...string) *exec.Cmd {
544 xtermArgs := []string{"-e", "gdb", "--args"}
545 xtermArgs = append(xtermArgs, path)
546 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700547
David Benjamin325b5c32014-07-01 19:40:31 -0400548 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700549}
550
David Benjamin1d5c83e2014-07-22 19:20:02 -0400551func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700552 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
553 if err != nil {
554 panic(err)
555 }
556
557 syscall.CloseOnExec(socks[0])
558 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400559 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700560 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400561 conn, err = net.FileConn(connFile)
562 if err != nil {
563 panic(err)
564 }
Adam Langley95c29f32014-06-20 12:00:00 -0700565 connFile.Close()
566 if err != nil {
567 panic(err)
568 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400569 return shimEnd, conn
570}
571
David Benjamin884fdf12014-08-02 15:28:23 -0400572func runTest(test *testCase, buildDir string) error {
David Benjamin1d5c83e2014-07-22 19:20:02 -0400573 shimEnd, conn := openSocketPair()
574 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700575
David Benjamin884fdf12014-08-02 15:28:23 -0400576 shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
David Benjamin5a593af2014-08-11 19:51:50 -0400577 var flags []string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400578 if test.testType == serverTest {
David Benjamin5a593af2014-08-11 19:51:50 -0400579 flags = append(flags, "-server")
580
David Benjamin025b3d32014-07-01 19:53:04 -0400581 flags = append(flags, "-key-file")
582 if test.keyFile == "" {
583 flags = append(flags, rsaKeyFile)
584 } else {
585 flags = append(flags, test.keyFile)
586 }
587
588 flags = append(flags, "-cert-file")
589 if test.certFile == "" {
590 flags = append(flags, rsaCertificateFile)
591 } else {
592 flags = append(flags, test.certFile)
593 }
594 }
David Benjamin5a593af2014-08-11 19:51:50 -0400595
David Benjamin6fd297b2014-08-11 18:43:38 -0400596 if test.protocol == dtls {
597 flags = append(flags, "-dtls")
598 }
599
David Benjamin5a593af2014-08-11 19:51:50 -0400600 if test.resumeSession {
601 flags = append(flags, "-resume")
602 }
603
David Benjamin025b3d32014-07-01 19:53:04 -0400604 flags = append(flags, test.flags...)
605
606 var shim *exec.Cmd
607 if *useValgrind {
608 shim = valgrindOf(false, shim_path, flags...)
609 } else {
610 shim = exec.Command(shim_path, flags...)
611 }
612 // shim = gdbOf(shim_path, flags...)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400613 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400614 shim.Stdin = os.Stdin
615 var stdoutBuf, stderrBuf bytes.Buffer
616 shim.Stdout = &stdoutBuf
617 shim.Stderr = &stderrBuf
618
619 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700620 panic(err)
621 }
David Benjamin025b3d32014-07-01 19:53:04 -0400622 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400623 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700624
625 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400626 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400627 if test.testType == clientTest {
628 if len(config.Certificates) == 0 {
629 config.Certificates = []Certificate{getRSACertificate()}
630 }
David Benjamin025b3d32014-07-01 19:53:04 -0400631 }
Adam Langley95c29f32014-06-20 12:00:00 -0700632
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400633 err := doExchange(test, &config, conn, test.messageLen)
Adam Langley95c29f32014-06-20 12:00:00 -0700634 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400635 if err == nil && test.resumeSession {
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400636 err = doExchange(test, &config, connResume, test.messageLen)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400637 connResume.Close()
638 }
639
David Benjamin025b3d32014-07-01 19:53:04 -0400640 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700641
642 stdout := string(stdoutBuf.Bytes())
643 stderr := string(stderrBuf.Bytes())
644 failed := err != nil || childErr != nil
645 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700646 localError := "none"
647 if err != nil {
648 localError = err.Error()
649 }
650 if len(test.expectedLocalError) != 0 {
651 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
652 }
Adam Langley95c29f32014-06-20 12:00:00 -0700653
654 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700655 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700656 if childErr != nil {
657 childError = childErr.Error()
658 }
659
660 var msg string
661 switch {
662 case failed && !test.shouldFail:
663 msg = "unexpected failure"
664 case !failed && test.shouldFail:
665 msg = "unexpected success"
666 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700667 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700668 default:
669 panic("internal error")
670 }
671
672 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
673 }
674
675 if !*useValgrind && len(stderr) > 0 {
676 println(stderr)
677 }
678
679 return nil
680}
681
682var tlsVersions = []struct {
683 name string
684 version uint16
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400685 flag string
Adam Langley95c29f32014-06-20 12:00:00 -0700686}{
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400687 {"SSL3", VersionSSL30, "-no-ssl3"},
688 {"TLS1", VersionTLS10, "-no-tls1"},
689 {"TLS11", VersionTLS11, "-no-tls11"},
690 {"TLS12", VersionTLS12, "-no-tls12"},
Adam Langley95c29f32014-06-20 12:00:00 -0700691}
692
693var testCipherSuites = []struct {
694 name string
695 id uint16
696}{
697 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400698 {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700699 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400700 {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700701 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400702 {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
703 {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
704 {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
705 {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700706 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
707 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
708 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
709 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700710 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700711 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400712 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700713 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
714 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700715 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400716 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700717}
718
719func addCipherSuiteTests() {
720 for _, suite := range testCipherSuites {
721 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400722 var certFile string
723 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700724 if strings.Contains(suite.name, "ECDSA") {
725 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400726 certFile = ecdsaCertificateFile
727 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700728 } else {
729 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400730 certFile = rsaCertificateFile
731 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700732 }
733
734 for _, ver := range tlsVersions {
735 if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
736 continue
737 }
738
David Benjamin1d5c83e2014-07-22 19:20:02 -0400739 // Go's TLS implementation only implements session
740 // resumption with tickets, so SSLv3 cannot resume
741 // sessions.
742 resumeSession := ver.version != VersionSSL30
743
David Benjamin025b3d32014-07-01 19:53:04 -0400744 testCases = append(testCases, testCase{
745 testType: clientTest,
746 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700747 config: Config{
748 MinVersion: ver.version,
749 MaxVersion: ver.version,
750 CipherSuites: []uint16{suite.id},
751 Certificates: []Certificate{cert},
752 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400753 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700754 })
David Benjamin025b3d32014-07-01 19:53:04 -0400755
David Benjamin76d8abe2014-08-14 16:25:34 -0400756 testCases = append(testCases, testCase{
757 testType: serverTest,
758 name: ver.name + "-" + suite.name + "-server",
759 config: Config{
760 MinVersion: ver.version,
761 MaxVersion: ver.version,
762 CipherSuites: []uint16{suite.id},
763 Certificates: []Certificate{cert},
764 },
765 certFile: certFile,
766 keyFile: keyFile,
767 resumeSession: resumeSession,
768 })
David Benjamin6fd297b2014-08-11 18:43:38 -0400769
770 // TODO(davidben): Fix DTLS 1.2 support and test that.
771 if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
772 testCases = append(testCases, testCase{
773 testType: clientTest,
774 protocol: dtls,
775 name: "D" + ver.name + "-" + suite.name + "-client",
776 config: Config{
777 MinVersion: ver.version,
778 MaxVersion: ver.version,
779 CipherSuites: []uint16{suite.id},
780 Certificates: []Certificate{cert},
781 },
782 resumeSession: resumeSession,
783 })
784 testCases = append(testCases, testCase{
785 testType: serverTest,
786 protocol: dtls,
787 name: "D" + ver.name + "-" + suite.name + "-server",
788 config: Config{
789 MinVersion: ver.version,
790 MaxVersion: ver.version,
791 CipherSuites: []uint16{suite.id},
792 Certificates: []Certificate{cert},
793 },
794 certFile: certFile,
795 keyFile: keyFile,
796 resumeSession: resumeSession,
797 })
798 }
Adam Langley95c29f32014-06-20 12:00:00 -0700799 }
800 }
801}
802
803func addBadECDSASignatureTests() {
804 for badR := BadValue(1); badR < NumBadValues; badR++ {
805 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400806 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700807 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
808 config: Config{
809 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
810 Certificates: []Certificate{getECDSACertificate()},
811 Bugs: ProtocolBugs{
812 BadECDSAR: badR,
813 BadECDSAS: badS,
814 },
815 },
816 shouldFail: true,
817 expectedError: "SIGNATURE",
818 })
819 }
820 }
821}
822
Adam Langley80842bd2014-06-20 12:00:00 -0700823func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400824 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700825 name: "MaxCBCPadding",
826 config: Config{
827 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
828 Bugs: ProtocolBugs{
829 MaxPadding: true,
830 },
831 },
832 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
833 })
David Benjamin025b3d32014-07-01 19:53:04 -0400834 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700835 name: "BadCBCPadding",
836 config: Config{
837 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
838 Bugs: ProtocolBugs{
839 PaddingFirstByteBad: true,
840 },
841 },
842 shouldFail: true,
843 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
844 })
845 // OpenSSL previously had an issue where the first byte of padding in
846 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400847 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700848 name: "BadCBCPadding255",
849 config: Config{
850 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
851 Bugs: ProtocolBugs{
852 MaxPadding: true,
853 PaddingFirstByteBadIf255: true,
854 },
855 },
856 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
857 shouldFail: true,
858 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
859 })
860}
861
Kenny Root7fdeaf12014-08-05 15:23:37 -0700862func addCBCSplittingTests() {
863 testCases = append(testCases, testCase{
864 name: "CBCRecordSplitting",
865 config: Config{
866 MaxVersion: VersionTLS10,
867 MinVersion: VersionTLS10,
868 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
869 },
870 messageLen: -1, // read until EOF
871 flags: []string{
872 "-async",
873 "-write-different-record-sizes",
874 "-cbc-record-splitting",
875 },
David Benjamina8e3e0e2014-08-06 22:11:10 -0400876 })
877 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -0700878 name: "CBCRecordSplittingPartialWrite",
879 config: Config{
880 MaxVersion: VersionTLS10,
881 MinVersion: VersionTLS10,
882 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
883 },
884 messageLen: -1, // read until EOF
885 flags: []string{
886 "-async",
887 "-write-different-record-sizes",
888 "-cbc-record-splitting",
889 "-partial-write",
890 },
891 })
892}
893
David Benjamin636293b2014-07-08 17:59:18 -0400894func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -0400895 // Add a dummy cert pool to stress certificate authority parsing.
896 // TODO(davidben): Add tests that those values parse out correctly.
897 certPool := x509.NewCertPool()
898 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
899 if err != nil {
900 panic(err)
901 }
902 certPool.AddCert(cert)
903
David Benjamin636293b2014-07-08 17:59:18 -0400904 for _, ver := range tlsVersions {
905 if ver.version == VersionSSL30 {
906 // TODO(davidben): The Go implementation does not
907 // correctly compute CertificateVerify hashes for SSLv3.
908 continue
909 }
910
911 var cipherSuites []uint16
912 if ver.version >= VersionTLS12 {
913 // Pick a SHA-256 cipher suite. The Go implementation
914 // does not correctly handle client auth with a SHA-384
915 // cipher suite.
916 cipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
917 }
918
919 testCases = append(testCases, testCase{
920 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400921 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -0400922 config: Config{
923 MinVersion: ver.version,
924 MaxVersion: ver.version,
925 CipherSuites: cipherSuites,
926 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400927 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400928 },
929 flags: []string{
930 "-cert-file", rsaCertificateFile,
931 "-key-file", rsaKeyFile,
932 },
933 })
934 testCases = append(testCases, testCase{
935 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -0400936 name: ver.name + "-Client-ClientAuth-ECDSA",
David Benjamin636293b2014-07-08 17:59:18 -0400937 config: Config{
938 MinVersion: ver.version,
939 MaxVersion: ver.version,
940 CipherSuites: cipherSuites,
941 ClientAuth: RequireAnyClientCert,
David Benjamin407a10c2014-07-16 12:58:59 -0400942 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -0400943 },
944 flags: []string{
945 "-cert-file", ecdsaCertificateFile,
946 "-key-file", ecdsaKeyFile,
947 },
948 })
David Benjamin67666e72014-07-12 15:47:52 -0400949 testCases = append(testCases, testCase{
950 testType: serverTest,
951 name: ver.name + "-Server-ClientAuth-RSA",
952 config: Config{
953 Certificates: []Certificate{rsaCertificate},
954 },
955 flags: []string{"-require-any-client-certificate"},
956 })
957 testCases = append(testCases, testCase{
958 testType: serverTest,
959 name: ver.name + "-Server-ClientAuth-ECDSA",
960 config: Config{
961 Certificates: []Certificate{ecdsaCertificate},
962 },
963 flags: []string{"-require-any-client-certificate"},
964 })
David Benjamin636293b2014-07-08 17:59:18 -0400965 }
966}
967
David Benjamin43ec06f2014-08-05 02:28:57 -0400968// Adds tests that try to cover the range of the handshake state machine, under
969// various conditions. Some of these are redundant with other tests, but they
970// only cover the synchronous case.
David Benjamin6fd297b2014-08-11 18:43:38 -0400971func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
David Benjamin43ec06f2014-08-05 02:28:57 -0400972 var suffix string
973 var flags []string
974 var maxHandshakeRecordLength int
David Benjamin6fd297b2014-08-11 18:43:38 -0400975 if protocol == dtls {
976 suffix = "-DTLS"
977 }
David Benjamin43ec06f2014-08-05 02:28:57 -0400978 if async {
David Benjamin6fd297b2014-08-11 18:43:38 -0400979 suffix += "-Async"
David Benjamin43ec06f2014-08-05 02:28:57 -0400980 flags = append(flags, "-async")
981 } else {
David Benjamin6fd297b2014-08-11 18:43:38 -0400982 suffix += "-Sync"
David Benjamin43ec06f2014-08-05 02:28:57 -0400983 }
984 if splitHandshake {
985 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -0400986 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -0400987 }
988
989 // Basic handshake, with resumption. Client and server.
990 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -0400991 protocol: protocol,
992 name: "Basic-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -0400993 config: Config{
994 Bugs: ProtocolBugs{
995 MaxHandshakeRecordLength: maxHandshakeRecordLength,
996 },
997 },
David Benjaminbed9aae2014-08-07 19:13:38 -0400998 flags: flags,
999 resumeSession: true,
1000 })
1001 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001002 protocol: protocol,
1003 name: "Basic-Client-RenewTicket" + suffix,
David Benjaminbed9aae2014-08-07 19:13:38 -04001004 config: Config{
1005 Bugs: ProtocolBugs{
1006 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1007 RenewTicketOnResume: true,
1008 },
1009 },
1010 flags: flags,
1011 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001012 })
1013 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001014 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001015 testType: serverTest,
1016 name: "Basic-Server" + suffix,
1017 config: Config{
1018 Bugs: ProtocolBugs{
1019 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1020 },
1021 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001022 flags: flags,
1023 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001024 })
1025
David Benjamin6fd297b2014-08-11 18:43:38 -04001026 // TLS client auth.
1027 testCases = append(testCases, testCase{
1028 protocol: protocol,
1029 testType: clientTest,
1030 name: "ClientAuth-Client" + suffix,
1031 config: Config{
1032 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1033 ClientAuth: RequireAnyClientCert,
1034 Bugs: ProtocolBugs{
1035 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1036 },
1037 },
1038 flags: append(flags,
1039 "-cert-file", rsaCertificateFile,
1040 "-key-file", rsaKeyFile),
1041 })
1042 testCases = append(testCases, testCase{
1043 protocol: protocol,
1044 testType: serverTest,
1045 name: "ClientAuth-Server" + suffix,
1046 config: Config{
1047 Certificates: []Certificate{rsaCertificate},
1048 },
1049 flags: append(flags, "-require-any-client-certificate"),
1050 })
1051
David Benjamin43ec06f2014-08-05 02:28:57 -04001052 // No session ticket support; server doesn't send NewSessionTicket.
1053 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001054 protocol: protocol,
1055 name: "SessionTicketsDisabled-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001056 config: Config{
1057 SessionTicketsDisabled: true,
1058 Bugs: ProtocolBugs{
1059 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1060 },
1061 },
1062 flags: flags,
1063 })
1064 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001065 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001066 testType: serverTest,
1067 name: "SessionTicketsDisabled-Server" + suffix,
1068 config: Config{
1069 SessionTicketsDisabled: true,
1070 Bugs: ProtocolBugs{
1071 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1072 },
1073 },
1074 flags: flags,
1075 })
1076
David Benjamin6fd297b2014-08-11 18:43:38 -04001077 if protocol == tls {
1078 // NPN on client and server; results in post-handshake message.
1079 testCases = append(testCases, testCase{
1080 protocol: protocol,
1081 name: "NPN-Client" + suffix,
1082 config: Config{
1083 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1084 NextProtos: []string{"foo"},
1085 Bugs: ProtocolBugs{
1086 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1087 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001088 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001089 flags: append(flags, "-select-next-proto", "foo"),
1090 })
1091 testCases = append(testCases, testCase{
1092 protocol: protocol,
1093 testType: serverTest,
1094 name: "NPN-Server" + suffix,
1095 config: Config{
1096 NextProtos: []string{"bar"},
1097 Bugs: ProtocolBugs{
1098 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1099 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001100 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001101 flags: append(flags,
1102 "-advertise-npn", "\x03foo\x03bar\x03baz",
1103 "-expect-next-proto", "bar"),
1104 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001105
David Benjamin6fd297b2014-08-11 18:43:38 -04001106 // Client does False Start and negotiates NPN.
1107 testCases = append(testCases, testCase{
1108 protocol: protocol,
1109 name: "FalseStart" + suffix,
1110 config: Config{
1111 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1112 NextProtos: []string{"foo"},
1113 Bugs: ProtocolBugs{
1114 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1115 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001116 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001117 flags: append(flags,
1118 "-false-start",
1119 "-select-next-proto", "foo"),
1120 resumeSession: true,
1121 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001122
David Benjamin6fd297b2014-08-11 18:43:38 -04001123 // False Start without session tickets.
1124 testCases = append(testCases, testCase{
1125 name: "FalseStart-SessionTicketsDisabled",
1126 config: Config{
1127 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1128 NextProtos: []string{"foo"},
1129 SessionTicketsDisabled: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001130 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001131 flags: []string{
1132 "-false-start",
1133 "-select-next-proto", "foo",
1134 },
1135 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001136
David Benjamin6fd297b2014-08-11 18:43:38 -04001137 // Client sends a V2ClientHello.
1138 testCases = append(testCases, testCase{
1139 protocol: protocol,
1140 testType: serverTest,
1141 name: "SendV2ClientHello" + suffix,
1142 config: Config{
1143 // Choose a cipher suite that does not involve
1144 // elliptic curves, so no extensions are
1145 // involved.
1146 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1147 Bugs: ProtocolBugs{
1148 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1149 SendV2ClientHello: true,
1150 },
David Benjamin1e7f8d72014-08-08 12:27:04 -04001151 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001152 flags: flags,
1153 })
1154 } else {
1155 testCases = append(testCases, testCase{
1156 protocol: protocol,
1157 name: "SkipHelloVerifyRequest" + suffix,
1158 config: Config{
1159 Bugs: ProtocolBugs{
1160 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1161 SkipHelloVerifyRequest: true,
1162 },
1163 },
1164 flags: flags,
1165 })
1166
1167 testCases = append(testCases, testCase{
1168 testType: serverTest,
1169 protocol: protocol,
1170 name: "CookieExchange" + suffix,
1171 config: Config{
1172 Bugs: ProtocolBugs{
1173 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1174 },
1175 },
1176 flags: append(flags, "-cookie-exchange"),
1177 })
1178 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001179}
1180
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001181func addVersionNegotiationTests() {
1182 for i, shimVers := range tlsVersions {
1183 // Assemble flags to disable all newer versions on the shim.
1184 var flags []string
1185 for _, vers := range tlsVersions[i+1:] {
1186 flags = append(flags, vers.flag)
1187 }
1188
1189 for _, runnerVers := range tlsVersions {
1190 expectedVersion := shimVers.version
1191 if runnerVers.version < shimVers.version {
1192 expectedVersion = runnerVers.version
1193 }
1194 suffix := shimVers.name + "-" + runnerVers.name
1195
1196 testCases = append(testCases, testCase{
1197 testType: clientTest,
1198 name: "VersionNegotiation-Client-" + suffix,
1199 config: Config{
1200 MaxVersion: runnerVers.version,
1201 },
1202 flags: flags,
1203 expectedVersion: expectedVersion,
1204 })
1205
David Benjamin76d8abe2014-08-14 16:25:34 -04001206 testCases = append(testCases, testCase{
1207 testType: serverTest,
1208 name: "VersionNegotiation-Server-" + suffix,
1209 config: Config{
1210 MaxVersion: runnerVers.version,
1211 },
1212 flags: flags,
1213 expectedVersion: expectedVersion,
1214 })
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001215 }
1216 }
1217}
1218
David Benjamin884fdf12014-08-02 15:28:23 -04001219func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07001220 defer wg.Done()
1221
1222 for test := range c {
1223 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04001224 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07001225 statusChan <- statusMsg{test: test, err: err}
1226 }
1227}
1228
1229type statusMsg struct {
1230 test *testCase
1231 started bool
1232 err error
1233}
1234
1235func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1236 var started, done, failed, lineLen int
1237 defer close(doneChan)
1238
1239 for msg := range statusChan {
1240 if msg.started {
1241 started++
1242 } else {
1243 done++
1244 }
1245
1246 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1247
1248 if msg.err != nil {
1249 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1250 failed++
1251 }
1252 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1253 lineLen = len(line)
1254 os.Stdout.WriteString(line)
1255 }
1256}
1257
1258func main() {
1259 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 -04001260 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04001261 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07001262
1263 flag.Parse()
1264
1265 addCipherSuiteTests()
1266 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07001267 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07001268 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04001269 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001270 addVersionNegotiationTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04001271 for _, async := range []bool{false, true} {
1272 for _, splitHandshake := range []bool{false, true} {
David Benjamin6fd297b2014-08-11 18:43:38 -04001273 for _, protocol := range []protocol{tls, dtls} {
1274 addStateMachineCoverageTests(async, splitHandshake, protocol)
1275 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001276 }
1277 }
Adam Langley95c29f32014-06-20 12:00:00 -07001278
1279 var wg sync.WaitGroup
1280
David Benjamin2bc8e6f2014-08-02 15:22:37 -04001281 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07001282
1283 statusChan := make(chan statusMsg, numWorkers)
1284 testChan := make(chan *testCase, numWorkers)
1285 doneChan := make(chan struct{})
1286
David Benjamin025b3d32014-07-01 19:53:04 -04001287 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07001288
1289 for i := 0; i < numWorkers; i++ {
1290 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04001291 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07001292 }
1293
David Benjamin025b3d32014-07-01 19:53:04 -04001294 for i := range testCases {
1295 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
1296 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07001297 }
1298 }
1299
1300 close(testChan)
1301 wg.Wait()
1302 close(statusChan)
1303 <-doneChan
1304
1305 fmt.Printf("\n")
1306}