blob: 10f86c97f28b78cb13066ec9c44be3128cfe9656 [file] [log] [blame]
Adam Langley95c29f32014-06-20 12:00:00 -07001package main
2
3import (
4 "bytes"
David Benjamina08e49d2014-08-24 01:46:07 -04005 "crypto/ecdsa"
6 "crypto/elliptic"
David Benjamin407a10c2014-07-16 12:58:59 -04007 "crypto/x509"
David Benjamin2561dc32014-08-24 01:25:27 -04008 "encoding/base64"
David Benjamina08e49d2014-08-24 01:46:07 -04009 "encoding/pem"
Adam Langley95c29f32014-06-20 12:00:00 -070010 "flag"
11 "fmt"
12 "io"
Kenny Root7fdeaf12014-08-05 15:23:37 -070013 "io/ioutil"
Adam Langley95c29f32014-06-20 12:00:00 -070014 "net"
15 "os"
16 "os/exec"
David Benjamin884fdf12014-08-02 15:28:23 -040017 "path"
David Benjamin2bc8e6f2014-08-02 15:22:37 -040018 "runtime"
Adam Langley95c29f32014-06-20 12:00:00 -070019 "strings"
20 "sync"
21 "syscall"
22)
23
24var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
Adam Langley75712922014-10-10 16:23:43 -070025var useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
26var flagDebug *bool = flag.Bool("debug", false, "Hexdump the contents of the connection")
Adam Langley95c29f32014-06-20 12:00:00 -070027
David Benjamin025b3d32014-07-01 19:53:04 -040028const (
29 rsaCertificateFile = "cert.pem"
30 ecdsaCertificateFile = "ecdsa_cert.pem"
31)
32
33const (
David Benjamina08e49d2014-08-24 01:46:07 -040034 rsaKeyFile = "key.pem"
35 ecdsaKeyFile = "ecdsa_key.pem"
36 channelIDKeyFile = "channel_id_key.pem"
David Benjamin025b3d32014-07-01 19:53:04 -040037)
38
Adam Langley95c29f32014-06-20 12:00:00 -070039var rsaCertificate, ecdsaCertificate Certificate
David Benjamina08e49d2014-08-24 01:46:07 -040040var channelIDKey *ecdsa.PrivateKey
41var channelIDBytes []byte
Adam Langley95c29f32014-06-20 12:00:00 -070042
43func initCertificates() {
44 var err error
David Benjamin025b3d32014-07-01 19:53:04 -040045 rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070046 if err != nil {
47 panic(err)
48 }
49
David Benjamin025b3d32014-07-01 19:53:04 -040050 ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070051 if err != nil {
52 panic(err)
53 }
David Benjamina08e49d2014-08-24 01:46:07 -040054
55 channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile)
56 if err != nil {
57 panic(err)
58 }
59 channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock)
60 if channelIDDERBlock.Type != "EC PRIVATE KEY" {
61 panic("bad key type")
62 }
63 channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes)
64 if err != nil {
65 panic(err)
66 }
67 if channelIDKey.Curve != elliptic.P256() {
68 panic("bad curve")
69 }
70
71 channelIDBytes = make([]byte, 64)
72 writeIntPadded(channelIDBytes[:32], channelIDKey.X)
73 writeIntPadded(channelIDBytes[32:], channelIDKey.Y)
Adam Langley95c29f32014-06-20 12:00:00 -070074}
75
76var certificateOnce sync.Once
77
78func getRSACertificate() Certificate {
79 certificateOnce.Do(initCertificates)
80 return rsaCertificate
81}
82
83func getECDSACertificate() Certificate {
84 certificateOnce.Do(initCertificates)
85 return ecdsaCertificate
86}
87
David Benjamin025b3d32014-07-01 19:53:04 -040088type testType int
89
90const (
91 clientTest testType = iota
92 serverTest
93)
94
David Benjamin6fd297b2014-08-11 18:43:38 -040095type protocol int
96
97const (
98 tls protocol = iota
99 dtls
100)
101
David Benjaminfc7b0862014-09-06 13:21:53 -0400102const (
103 alpn = 1
104 npn = 2
105)
106
Adam Langley95c29f32014-06-20 12:00:00 -0700107type testCase struct {
David Benjamin025b3d32014-07-01 19:53:04 -0400108 testType testType
David Benjamin6fd297b2014-08-11 18:43:38 -0400109 protocol protocol
Adam Langley95c29f32014-06-20 12:00:00 -0700110 name string
111 config Config
112 shouldFail bool
113 expectedError string
Adam Langleyac61fa32014-06-23 12:03:11 -0700114 // expectedLocalError, if not empty, contains a substring that must be
115 // found in the local error.
116 expectedLocalError string
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400117 // expectedVersion, if non-zero, specifies the TLS version that must be
118 // negotiated.
119 expectedVersion uint16
David Benjamin01fe8202014-09-24 15:21:44 -0400120 // expectedResumeVersion, if non-zero, specifies the TLS version that
121 // must be negotiated on resumption. If zero, expectedVersion is used.
122 expectedResumeVersion uint16
David Benjamina08e49d2014-08-24 01:46:07 -0400123 // expectChannelID controls whether the connection should have
124 // negotiated a Channel ID with channelIDKey.
125 expectChannelID bool
David Benjaminae2888f2014-09-06 12:58:58 -0400126 // expectedNextProto controls whether the connection should
127 // negotiate a next protocol via NPN or ALPN.
128 expectedNextProto string
David Benjaminfc7b0862014-09-06 13:21:53 -0400129 // expectedNextProtoType, if non-zero, is the expected next
130 // protocol negotiation mechanism.
131 expectedNextProtoType int
Adam Langley80842bd2014-06-20 12:00:00 -0700132 // messageLen is the length, in bytes, of the test message that will be
133 // sent.
134 messageLen int
David Benjamin025b3d32014-07-01 19:53:04 -0400135 // certFile is the path to the certificate to use for the server.
136 certFile string
137 // keyFile is the path to the private key to use for the server.
138 keyFile string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400139 // resumeSession controls whether a second connection should be tested
David Benjamin01fe8202014-09-24 15:21:44 -0400140 // which attempts to resume the first session.
David Benjamin1d5c83e2014-07-22 19:20:02 -0400141 resumeSession bool
David Benjamin01fe8202014-09-24 15:21:44 -0400142 // resumeConfig, if not nil, points to a Config to be used on
143 // resumption. SessionTicketKey and ClientSessionCache are copied from
144 // the initial connection's config. If nil, the initial connection's
145 // config is used.
146 resumeConfig *Config
David Benjamin98e882e2014-08-08 13:24:34 -0400147 // sendPrefix sends a prefix on the socket before actually performing a
148 // handshake.
149 sendPrefix string
David Benjamine58c4f52014-08-24 03:47:07 -0400150 // shimWritesFirst controls whether the shim sends an initial "hello"
151 // message before doing a roundtrip with the runner.
152 shimWritesFirst bool
David Benjamin325b5c32014-07-01 19:40:31 -0400153 // flags, if not empty, contains a list of command-line flags that will
154 // be passed to the shim program.
155 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -0700156}
157
David Benjamin025b3d32014-07-01 19:53:04 -0400158var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700159 {
160 name: "BadRSASignature",
161 config: Config{
162 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
163 Bugs: ProtocolBugs{
164 InvalidSKXSignature: true,
165 },
166 },
167 shouldFail: true,
168 expectedError: ":BAD_SIGNATURE:",
169 },
170 {
171 name: "BadECDSASignature",
172 config: Config{
173 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
174 Bugs: ProtocolBugs{
175 InvalidSKXSignature: true,
176 },
177 Certificates: []Certificate{getECDSACertificate()},
178 },
179 shouldFail: true,
180 expectedError: ":BAD_SIGNATURE:",
181 },
182 {
183 name: "BadECDSACurve",
184 config: Config{
185 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
186 Bugs: ProtocolBugs{
187 InvalidSKXCurve: true,
188 },
189 Certificates: []Certificate{getECDSACertificate()},
190 },
191 shouldFail: true,
192 expectedError: ":WRONG_CURVE:",
193 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700194 {
David Benjamina8e3e0e2014-08-06 22:11:10 -0400195 testType: serverTest,
196 name: "BadRSAVersion",
197 config: Config{
198 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
199 Bugs: ProtocolBugs{
200 RsaClientKeyExchangeVersion: VersionTLS11,
201 },
202 },
203 shouldFail: true,
204 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
205 },
206 {
David Benjamin325b5c32014-07-01 19:40:31 -0400207 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700208 config: Config{
209 Bugs: ProtocolBugs{
210 FailIfNotFallbackSCSV: true,
211 },
212 },
213 shouldFail: true,
214 expectedLocalError: "no fallback SCSV found",
215 },
David Benjamin325b5c32014-07-01 19:40:31 -0400216 {
David Benjamin2a0c4962014-08-22 23:46:35 -0400217 name: "SendFallbackSCSV",
David Benjamin325b5c32014-07-01 19:40:31 -0400218 config: Config{
219 Bugs: ProtocolBugs{
220 FailIfNotFallbackSCSV: true,
221 },
222 },
223 flags: []string{"-fallback-scsv"},
224 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400225 {
David Benjamin7b030512014-07-08 17:30:11 -0400226 name: "ClientCertificateTypes",
227 config: Config{
228 ClientAuth: RequestClientCert,
229 ClientCertificateTypes: []byte{
230 CertTypeDSSSign,
231 CertTypeRSASign,
232 CertTypeECDSASign,
233 },
234 },
David Benjamin2561dc32014-08-24 01:25:27 -0400235 flags: []string{
236 "-expect-certificate-types",
237 base64.StdEncoding.EncodeToString([]byte{
238 CertTypeDSSSign,
239 CertTypeRSASign,
240 CertTypeECDSASign,
241 }),
242 },
David Benjamin7b030512014-07-08 17:30:11 -0400243 },
David Benjamin636293b2014-07-08 17:59:18 -0400244 {
245 name: "NoClientCertificate",
246 config: Config{
247 ClientAuth: RequireAnyClientCert,
248 },
249 shouldFail: true,
250 expectedLocalError: "client didn't provide a certificate",
251 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400252 {
253 name: "UnauthenticatedECDH",
254 config: Config{
255 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
256 Bugs: ProtocolBugs{
257 UnauthenticatedECDH: true,
258 },
259 },
260 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400261 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400262 },
David Benjamin9c651c92014-07-12 13:27:45 -0400263 {
264 name: "SkipServerKeyExchange",
265 config: Config{
266 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
267 Bugs: ProtocolBugs{
268 SkipServerKeyExchange: true,
269 },
270 },
271 shouldFail: true,
272 expectedError: ":UNEXPECTED_MESSAGE:",
273 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400274 {
David Benjamina0e52232014-07-19 17:39:58 -0400275 name: "SkipChangeCipherSpec-Client",
276 config: Config{
277 Bugs: ProtocolBugs{
278 SkipChangeCipherSpec: true,
279 },
280 },
281 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400282 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400283 },
284 {
285 testType: serverTest,
286 name: "SkipChangeCipherSpec-Server",
287 config: Config{
288 Bugs: ProtocolBugs{
289 SkipChangeCipherSpec: true,
290 },
291 },
292 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400293 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400294 },
David Benjamin42be6452014-07-21 14:50:23 -0400295 {
296 testType: serverTest,
297 name: "SkipChangeCipherSpec-Server-NPN",
298 config: Config{
299 NextProtos: []string{"bar"},
300 Bugs: ProtocolBugs{
301 SkipChangeCipherSpec: true,
302 },
303 },
304 flags: []string{
305 "-advertise-npn", "\x03foo\x03bar\x03baz",
306 },
307 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400308 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
309 },
310 {
311 name: "FragmentAcrossChangeCipherSpec-Client",
312 config: Config{
313 Bugs: ProtocolBugs{
314 FragmentAcrossChangeCipherSpec: true,
315 },
316 },
317 shouldFail: true,
318 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
319 },
320 {
321 testType: serverTest,
322 name: "FragmentAcrossChangeCipherSpec-Server",
323 config: Config{
324 Bugs: ProtocolBugs{
325 FragmentAcrossChangeCipherSpec: true,
326 },
327 },
328 shouldFail: true,
329 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
330 },
331 {
332 testType: serverTest,
333 name: "FragmentAcrossChangeCipherSpec-Server-NPN",
334 config: Config{
335 NextProtos: []string{"bar"},
336 Bugs: ProtocolBugs{
337 FragmentAcrossChangeCipherSpec: true,
338 },
339 },
340 flags: []string{
341 "-advertise-npn", "\x03foo\x03bar\x03baz",
342 },
343 shouldFail: true,
344 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamin42be6452014-07-21 14:50:23 -0400345 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400346 {
347 testType: serverTest,
348 name: "EarlyChangeCipherSpec-server-1",
349 config: Config{
350 Bugs: ProtocolBugs{
351 EarlyChangeCipherSpec: 1,
352 },
353 },
354 shouldFail: true,
355 expectedError: ":CCS_RECEIVED_EARLY:",
356 },
357 {
358 testType: serverTest,
359 name: "EarlyChangeCipherSpec-server-2",
360 config: Config{
361 Bugs: ProtocolBugs{
362 EarlyChangeCipherSpec: 2,
363 },
364 },
365 shouldFail: true,
366 expectedError: ":CCS_RECEIVED_EARLY:",
367 },
David Benjamind23f4122014-07-23 15:09:48 -0400368 {
David Benjamind23f4122014-07-23 15:09:48 -0400369 name: "SkipNewSessionTicket",
370 config: Config{
371 Bugs: ProtocolBugs{
372 SkipNewSessionTicket: true,
373 },
374 },
375 shouldFail: true,
376 expectedError: ":CCS_RECEIVED_EARLY:",
377 },
David Benjamin7e3305e2014-07-28 14:52:32 -0400378 {
David Benjamind86c7672014-08-02 04:07:12 -0400379 testType: serverTest,
David Benjaminbef270a2014-08-02 04:22:02 -0400380 name: "FallbackSCSV",
381 config: Config{
382 MaxVersion: VersionTLS11,
383 Bugs: ProtocolBugs{
384 SendFallbackSCSV: true,
385 },
386 },
387 shouldFail: true,
388 expectedError: ":INAPPROPRIATE_FALLBACK:",
389 },
390 {
391 testType: serverTest,
392 name: "FallbackSCSV-VersionMatch",
393 config: Config{
394 Bugs: ProtocolBugs{
395 SendFallbackSCSV: true,
396 },
397 },
398 },
David Benjamin98214542014-08-07 18:02:39 -0400399 {
400 testType: serverTest,
401 name: "FragmentedClientVersion",
402 config: Config{
403 Bugs: ProtocolBugs{
404 MaxHandshakeRecordLength: 1,
405 FragmentClientVersion: true,
406 },
407 },
408 shouldFail: true,
409 expectedError: ":RECORD_TOO_SMALL:",
410 },
David Benjamin98e882e2014-08-08 13:24:34 -0400411 {
412 testType: serverTest,
413 name: "MinorVersionTolerance",
414 config: Config{
415 Bugs: ProtocolBugs{
416 SendClientVersion: 0x03ff,
417 },
418 },
419 expectedVersion: VersionTLS12,
420 },
421 {
422 testType: serverTest,
423 name: "MajorVersionTolerance",
424 config: Config{
425 Bugs: ProtocolBugs{
426 SendClientVersion: 0x0400,
427 },
428 },
429 expectedVersion: VersionTLS12,
430 },
431 {
432 testType: serverTest,
433 name: "VersionTooLow",
434 config: Config{
435 Bugs: ProtocolBugs{
436 SendClientVersion: 0x0200,
437 },
438 },
439 shouldFail: true,
440 expectedError: ":UNSUPPORTED_PROTOCOL:",
441 },
442 {
443 testType: serverTest,
444 name: "HttpGET",
445 sendPrefix: "GET / HTTP/1.0\n",
446 shouldFail: true,
447 expectedError: ":HTTP_REQUEST:",
448 },
449 {
450 testType: serverTest,
451 name: "HttpPOST",
452 sendPrefix: "POST / HTTP/1.0\n",
453 shouldFail: true,
454 expectedError: ":HTTP_REQUEST:",
455 },
456 {
457 testType: serverTest,
458 name: "HttpHEAD",
459 sendPrefix: "HEAD / HTTP/1.0\n",
460 shouldFail: true,
461 expectedError: ":HTTP_REQUEST:",
462 },
463 {
464 testType: serverTest,
465 name: "HttpPUT",
466 sendPrefix: "PUT / HTTP/1.0\n",
467 shouldFail: true,
468 expectedError: ":HTTP_REQUEST:",
469 },
470 {
471 testType: serverTest,
472 name: "HttpCONNECT",
473 sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
474 shouldFail: true,
475 expectedError: ":HTTPS_PROXY_REQUEST:",
476 },
David Benjamin39ebf532014-08-31 02:23:49 -0400477 {
478 name: "SkipCipherVersionCheck",
479 config: Config{
480 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
481 MaxVersion: VersionTLS11,
482 Bugs: ProtocolBugs{
483 SkipCipherVersionCheck: true,
484 },
485 },
486 shouldFail: true,
487 expectedError: ":WRONG_CIPHER_RETURNED:",
488 },
Adam Langley95c29f32014-06-20 12:00:00 -0700489}
490
David Benjamin01fe8202014-09-24 15:21:44 -0400491func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
David Benjamin6fd297b2014-08-11 18:43:38 -0400492 if test.protocol == dtls {
493 conn = newPacketAdaptor(conn)
494 }
495
496 if test.sendPrefix != "" {
497 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
498 return err
499 }
David Benjamin98e882e2014-08-08 13:24:34 -0400500 }
501
David Benjamin1d5c83e2014-07-22 19:20:02 -0400502 var tlsConn *Conn
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400503 if test.testType == clientTest {
David Benjamin6fd297b2014-08-11 18:43:38 -0400504 if test.protocol == dtls {
505 tlsConn = DTLSServer(conn, config)
506 } else {
507 tlsConn = Server(conn, config)
508 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400509 } else {
510 config.InsecureSkipVerify = true
David Benjamin6fd297b2014-08-11 18:43:38 -0400511 if test.protocol == dtls {
512 tlsConn = DTLSClient(conn, config)
513 } else {
514 tlsConn = Client(conn, config)
515 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400516 }
517
Adam Langley95c29f32014-06-20 12:00:00 -0700518 if err := tlsConn.Handshake(); err != nil {
519 return err
520 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700521
David Benjamin01fe8202014-09-24 15:21:44 -0400522 // TODO(davidben): move all per-connection expectations into a dedicated
523 // expectations struct that can be specified separately for the two
524 // legs.
525 expectedVersion := test.expectedVersion
526 if isResume && test.expectedResumeVersion != 0 {
527 expectedVersion = test.expectedResumeVersion
528 }
529 if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
530 return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400531 }
532
David Benjamina08e49d2014-08-24 01:46:07 -0400533 if test.expectChannelID {
534 channelID := tlsConn.ConnectionState().ChannelID
535 if channelID == nil {
536 return fmt.Errorf("no channel ID negotiated")
537 }
538 if channelID.Curve != channelIDKey.Curve ||
539 channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
540 channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
541 return fmt.Errorf("incorrect channel ID")
542 }
543 }
544
David Benjaminae2888f2014-09-06 12:58:58 -0400545 if expected := test.expectedNextProto; expected != "" {
546 if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
547 return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
548 }
549 }
550
David Benjaminfc7b0862014-09-06 13:21:53 -0400551 if test.expectedNextProtoType != 0 {
552 if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN {
553 return fmt.Errorf("next proto type mismatch")
554 }
555 }
556
David Benjamine58c4f52014-08-24 03:47:07 -0400557 if test.shimWritesFirst {
558 var buf [5]byte
559 _, err := io.ReadFull(tlsConn, buf[:])
560 if err != nil {
561 return err
562 }
563 if string(buf[:]) != "hello" {
564 return fmt.Errorf("bad initial message")
565 }
566 }
567
Kenny Root7fdeaf12014-08-05 15:23:37 -0700568 if messageLen < 0 {
David Benjamin6fd297b2014-08-11 18:43:38 -0400569 if test.protocol == dtls {
570 return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
571 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700572 // Read until EOF.
573 _, err := io.Copy(ioutil.Discard, tlsConn)
574 return err
575 }
576
Adam Langley80842bd2014-06-20 12:00:00 -0700577 if messageLen == 0 {
578 messageLen = 32
579 }
580 testMessage := make([]byte, messageLen)
581 for i := range testMessage {
582 testMessage[i] = 0x42
583 }
Adam Langley95c29f32014-06-20 12:00:00 -0700584 tlsConn.Write(testMessage)
585
586 buf := make([]byte, len(testMessage))
David Benjamin6fd297b2014-08-11 18:43:38 -0400587 if test.protocol == dtls {
588 bufTmp := make([]byte, len(buf)+1)
589 n, err := tlsConn.Read(bufTmp)
590 if err != nil {
591 return err
592 }
593 if n != len(buf) {
594 return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
595 }
596 copy(buf, bufTmp)
597 } else {
598 _, err := io.ReadFull(tlsConn, buf)
599 if err != nil {
600 return err
601 }
Adam Langley95c29f32014-06-20 12:00:00 -0700602 }
603
604 for i, v := range buf {
605 if v != testMessage[i]^0xff {
606 return fmt.Errorf("bad reply contents at byte %d", i)
607 }
608 }
609
610 return nil
611}
612
David Benjamin325b5c32014-07-01 19:40:31 -0400613func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
614 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700615 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400616 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700617 }
David Benjamin325b5c32014-07-01 19:40:31 -0400618 valgrindArgs = append(valgrindArgs, path)
619 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700620
David Benjamin325b5c32014-07-01 19:40:31 -0400621 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700622}
623
David Benjamin325b5c32014-07-01 19:40:31 -0400624func gdbOf(path string, args ...string) *exec.Cmd {
625 xtermArgs := []string{"-e", "gdb", "--args"}
626 xtermArgs = append(xtermArgs, path)
627 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700628
David Benjamin325b5c32014-07-01 19:40:31 -0400629 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700630}
631
David Benjamin1d5c83e2014-07-22 19:20:02 -0400632func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700633 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
634 if err != nil {
635 panic(err)
636 }
637
638 syscall.CloseOnExec(socks[0])
639 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400640 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700641 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400642 conn, err = net.FileConn(connFile)
643 if err != nil {
644 panic(err)
645 }
Adam Langley95c29f32014-06-20 12:00:00 -0700646 connFile.Close()
647 if err != nil {
648 panic(err)
649 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400650 return shimEnd, conn
651}
652
David Benjamin884fdf12014-08-02 15:28:23 -0400653func runTest(test *testCase, buildDir string) error {
Adam Langley38311732014-10-16 19:04:35 -0700654 if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
655 panic("Error expected without shouldFail in " + test.name)
656 }
657
David Benjamin1d5c83e2014-07-22 19:20:02 -0400658 shimEnd, conn := openSocketPair()
659 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700660
David Benjamin884fdf12014-08-02 15:28:23 -0400661 shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
David Benjamin5a593af2014-08-11 19:51:50 -0400662 var flags []string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400663 if test.testType == serverTest {
David Benjamin5a593af2014-08-11 19:51:50 -0400664 flags = append(flags, "-server")
665
David Benjamin025b3d32014-07-01 19:53:04 -0400666 flags = append(flags, "-key-file")
667 if test.keyFile == "" {
668 flags = append(flags, rsaKeyFile)
669 } else {
670 flags = append(flags, test.keyFile)
671 }
672
673 flags = append(flags, "-cert-file")
674 if test.certFile == "" {
675 flags = append(flags, rsaCertificateFile)
676 } else {
677 flags = append(flags, test.certFile)
678 }
679 }
David Benjamin5a593af2014-08-11 19:51:50 -0400680
David Benjamin6fd297b2014-08-11 18:43:38 -0400681 if test.protocol == dtls {
682 flags = append(flags, "-dtls")
683 }
684
David Benjamin5a593af2014-08-11 19:51:50 -0400685 if test.resumeSession {
686 flags = append(flags, "-resume")
687 }
688
David Benjamine58c4f52014-08-24 03:47:07 -0400689 if test.shimWritesFirst {
690 flags = append(flags, "-shim-writes-first")
691 }
692
David Benjamin025b3d32014-07-01 19:53:04 -0400693 flags = append(flags, test.flags...)
694
695 var shim *exec.Cmd
696 if *useValgrind {
697 shim = valgrindOf(false, shim_path, flags...)
Adam Langley75712922014-10-10 16:23:43 -0700698 } else if *useGDB {
699 shim = gdbOf(shim_path, flags...)
David Benjamin025b3d32014-07-01 19:53:04 -0400700 } else {
701 shim = exec.Command(shim_path, flags...)
702 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400703 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400704 shim.Stdin = os.Stdin
705 var stdoutBuf, stderrBuf bytes.Buffer
706 shim.Stdout = &stdoutBuf
707 shim.Stderr = &stderrBuf
708
709 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700710 panic(err)
711 }
David Benjamin025b3d32014-07-01 19:53:04 -0400712 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400713 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700714
715 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400716 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400717 if test.testType == clientTest {
718 if len(config.Certificates) == 0 {
719 config.Certificates = []Certificate{getRSACertificate()}
720 }
David Benjamin025b3d32014-07-01 19:53:04 -0400721 }
Adam Langley95c29f32014-06-20 12:00:00 -0700722
Adam Langley75712922014-10-10 16:23:43 -0700723 var connDebug *recordingConn
724 if *flagDebug {
725 connDebug = &recordingConn{Conn: conn}
726 conn = connDebug
727 }
728
David Benjamin01fe8202014-09-24 15:21:44 -0400729 err := doExchange(test, &config, conn, test.messageLen,
730 false /* not a resumption */)
Adam Langley75712922014-10-10 16:23:43 -0700731
732 if *flagDebug {
733 connDebug.WriteTo(os.Stdout)
734 }
735
Adam Langley95c29f32014-06-20 12:00:00 -0700736 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400737 if err == nil && test.resumeSession {
David Benjamin01fe8202014-09-24 15:21:44 -0400738 var resumeConfig Config
739 if test.resumeConfig != nil {
740 resumeConfig = *test.resumeConfig
741 if len(resumeConfig.Certificates) == 0 {
742 resumeConfig.Certificates = []Certificate{getRSACertificate()}
743 }
744 resumeConfig.SessionTicketKey = config.SessionTicketKey
745 resumeConfig.ClientSessionCache = config.ClientSessionCache
746 } else {
747 resumeConfig = config
748 }
749 err = doExchange(test, &resumeConfig, connResume, test.messageLen,
750 true /* resumption */)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400751 }
David Benjamin812152a2014-09-06 12:49:07 -0400752 connResume.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400753
David Benjamin025b3d32014-07-01 19:53:04 -0400754 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700755
756 stdout := string(stdoutBuf.Bytes())
757 stderr := string(stderrBuf.Bytes())
758 failed := err != nil || childErr != nil
759 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700760 localError := "none"
761 if err != nil {
762 localError = err.Error()
763 }
764 if len(test.expectedLocalError) != 0 {
765 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
766 }
Adam Langley95c29f32014-06-20 12:00:00 -0700767
768 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700769 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700770 if childErr != nil {
771 childError = childErr.Error()
772 }
773
774 var msg string
775 switch {
776 case failed && !test.shouldFail:
777 msg = "unexpected failure"
778 case !failed && test.shouldFail:
779 msg = "unexpected success"
780 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700781 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700782 default:
783 panic("internal error")
784 }
785
786 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
787 }
788
789 if !*useValgrind && len(stderr) > 0 {
790 println(stderr)
791 }
792
793 return nil
794}
795
796var tlsVersions = []struct {
797 name string
798 version uint16
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400799 flag string
Adam Langley95c29f32014-06-20 12:00:00 -0700800}{
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400801 {"SSL3", VersionSSL30, "-no-ssl3"},
802 {"TLS1", VersionTLS10, "-no-tls1"},
803 {"TLS11", VersionTLS11, "-no-tls11"},
804 {"TLS12", VersionTLS12, "-no-tls12"},
Adam Langley95c29f32014-06-20 12:00:00 -0700805}
806
807var testCipherSuites = []struct {
808 name string
809 id uint16
810}{
811 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400812 {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700813 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400814 {"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400815 {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700816 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400817 {"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400818 {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
819 {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400820 {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400821 {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
822 {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400823 {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700824 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
825 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400826 {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
827 {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700828 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400829 {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700830 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700831 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700832 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400833 {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400834 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700835 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400836 {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700837 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700838 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400839 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700840}
841
David Benjaminf7768e42014-08-31 02:06:47 -0400842func isTLS12Only(suiteName string) bool {
843 return strings.HasSuffix(suiteName, "-GCM") ||
844 strings.HasSuffix(suiteName, "-SHA256") ||
845 strings.HasSuffix(suiteName, "-SHA384")
846}
847
Adam Langley95c29f32014-06-20 12:00:00 -0700848func addCipherSuiteTests() {
849 for _, suite := range testCipherSuites {
850 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400851 var certFile string
852 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700853 if strings.Contains(suite.name, "ECDSA") {
854 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400855 certFile = ecdsaCertificateFile
856 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700857 } else {
858 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400859 certFile = rsaCertificateFile
860 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700861 }
862
863 for _, ver := range tlsVersions {
David Benjaminf7768e42014-08-31 02:06:47 -0400864 if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
Adam Langley95c29f32014-06-20 12:00:00 -0700865 continue
866 }
867
David Benjamin1d5c83e2014-07-22 19:20:02 -0400868 // Go's TLS implementation only implements session
869 // resumption with tickets, so SSLv3 cannot resume
870 // sessions.
871 resumeSession := ver.version != VersionSSL30
872
David Benjamin025b3d32014-07-01 19:53:04 -0400873 testCases = append(testCases, testCase{
874 testType: clientTest,
875 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700876 config: Config{
877 MinVersion: ver.version,
878 MaxVersion: ver.version,
879 CipherSuites: []uint16{suite.id},
880 Certificates: []Certificate{cert},
881 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400882 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700883 })
David Benjamin025b3d32014-07-01 19:53:04 -0400884
David Benjamin76d8abe2014-08-14 16:25:34 -0400885 testCases = append(testCases, testCase{
886 testType: serverTest,
887 name: ver.name + "-" + suite.name + "-server",
888 config: Config{
889 MinVersion: ver.version,
890 MaxVersion: ver.version,
891 CipherSuites: []uint16{suite.id},
892 Certificates: []Certificate{cert},
893 },
894 certFile: certFile,
895 keyFile: keyFile,
896 resumeSession: resumeSession,
897 })
David Benjamin6fd297b2014-08-11 18:43:38 -0400898
899 // TODO(davidben): Fix DTLS 1.2 support and test that.
900 if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
901 testCases = append(testCases, testCase{
902 testType: clientTest,
903 protocol: dtls,
904 name: "D" + ver.name + "-" + suite.name + "-client",
905 config: Config{
906 MinVersion: ver.version,
907 MaxVersion: ver.version,
908 CipherSuites: []uint16{suite.id},
909 Certificates: []Certificate{cert},
910 },
911 resumeSession: resumeSession,
912 })
913 testCases = append(testCases, testCase{
914 testType: serverTest,
915 protocol: dtls,
916 name: "D" + ver.name + "-" + suite.name + "-server",
917 config: Config{
918 MinVersion: ver.version,
919 MaxVersion: ver.version,
920 CipherSuites: []uint16{suite.id},
921 Certificates: []Certificate{cert},
922 },
923 certFile: certFile,
924 keyFile: keyFile,
925 resumeSession: resumeSession,
926 })
927 }
Adam Langley95c29f32014-06-20 12:00:00 -0700928 }
929 }
930}
931
932func addBadECDSASignatureTests() {
933 for badR := BadValue(1); badR < NumBadValues; badR++ {
934 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400935 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700936 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
937 config: Config{
938 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
939 Certificates: []Certificate{getECDSACertificate()},
940 Bugs: ProtocolBugs{
941 BadECDSAR: badR,
942 BadECDSAS: badS,
943 },
944 },
945 shouldFail: true,
946 expectedError: "SIGNATURE",
947 })
948 }
949 }
950}
951
Adam Langley80842bd2014-06-20 12:00:00 -0700952func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400953 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700954 name: "MaxCBCPadding",
955 config: Config{
956 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
957 Bugs: ProtocolBugs{
958 MaxPadding: true,
959 },
960 },
961 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
962 })
David Benjamin025b3d32014-07-01 19:53:04 -0400963 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700964 name: "BadCBCPadding",
965 config: Config{
966 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
967 Bugs: ProtocolBugs{
968 PaddingFirstByteBad: true,
969 },
970 },
971 shouldFail: true,
972 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
973 })
974 // OpenSSL previously had an issue where the first byte of padding in
975 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400976 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700977 name: "BadCBCPadding255",
978 config: Config{
979 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
980 Bugs: ProtocolBugs{
981 MaxPadding: true,
982 PaddingFirstByteBadIf255: true,
983 },
984 },
985 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
986 shouldFail: true,
987 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
988 })
989}
990
Kenny Root7fdeaf12014-08-05 15:23:37 -0700991func addCBCSplittingTests() {
992 testCases = append(testCases, testCase{
993 name: "CBCRecordSplitting",
994 config: Config{
995 MaxVersion: VersionTLS10,
996 MinVersion: VersionTLS10,
997 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
998 },
999 messageLen: -1, // read until EOF
1000 flags: []string{
1001 "-async",
1002 "-write-different-record-sizes",
1003 "-cbc-record-splitting",
1004 },
David Benjamina8e3e0e2014-08-06 22:11:10 -04001005 })
1006 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -07001007 name: "CBCRecordSplittingPartialWrite",
1008 config: Config{
1009 MaxVersion: VersionTLS10,
1010 MinVersion: VersionTLS10,
1011 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1012 },
1013 messageLen: -1, // read until EOF
1014 flags: []string{
1015 "-async",
1016 "-write-different-record-sizes",
1017 "-cbc-record-splitting",
1018 "-partial-write",
1019 },
1020 })
1021}
1022
David Benjamin636293b2014-07-08 17:59:18 -04001023func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -04001024 // Add a dummy cert pool to stress certificate authority parsing.
1025 // TODO(davidben): Add tests that those values parse out correctly.
1026 certPool := x509.NewCertPool()
1027 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
1028 if err != nil {
1029 panic(err)
1030 }
1031 certPool.AddCert(cert)
1032
David Benjamin636293b2014-07-08 17:59:18 -04001033 for _, ver := range tlsVersions {
David Benjamin636293b2014-07-08 17:59:18 -04001034 testCases = append(testCases, testCase{
1035 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -04001036 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -04001037 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001038 MinVersion: ver.version,
1039 MaxVersion: ver.version,
1040 ClientAuth: RequireAnyClientCert,
1041 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -04001042 },
1043 flags: []string{
1044 "-cert-file", rsaCertificateFile,
1045 "-key-file", rsaKeyFile,
1046 },
1047 })
1048 testCases = append(testCases, testCase{
David Benjamin67666e72014-07-12 15:47:52 -04001049 testType: serverTest,
1050 name: ver.name + "-Server-ClientAuth-RSA",
1051 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001052 MinVersion: ver.version,
1053 MaxVersion: ver.version,
David Benjamin67666e72014-07-12 15:47:52 -04001054 Certificates: []Certificate{rsaCertificate},
1055 },
1056 flags: []string{"-require-any-client-certificate"},
1057 })
David Benjamine098ec22014-08-27 23:13:20 -04001058 if ver.version != VersionSSL30 {
1059 testCases = append(testCases, testCase{
1060 testType: serverTest,
1061 name: ver.name + "-Server-ClientAuth-ECDSA",
1062 config: Config{
1063 MinVersion: ver.version,
1064 MaxVersion: ver.version,
1065 Certificates: []Certificate{ecdsaCertificate},
1066 },
1067 flags: []string{"-require-any-client-certificate"},
1068 })
1069 testCases = append(testCases, testCase{
1070 testType: clientTest,
1071 name: ver.name + "-Client-ClientAuth-ECDSA",
1072 config: Config{
1073 MinVersion: ver.version,
1074 MaxVersion: ver.version,
1075 ClientAuth: RequireAnyClientCert,
1076 ClientCAs: certPool,
1077 },
1078 flags: []string{
1079 "-cert-file", ecdsaCertificateFile,
1080 "-key-file", ecdsaKeyFile,
1081 },
1082 })
1083 }
David Benjamin636293b2014-07-08 17:59:18 -04001084 }
1085}
1086
Adam Langley75712922014-10-10 16:23:43 -07001087func addExtendedMasterSecretTests() {
1088 const expectEMSFlag = "-expect-extended-master-secret"
1089
1090 for _, with := range []bool{false, true} {
1091 prefix := "No"
1092 var flags []string
1093 if with {
1094 prefix = ""
1095 flags = []string{expectEMSFlag}
1096 }
1097
1098 for _, isClient := range []bool{false, true} {
1099 suffix := "-Server"
1100 testType := serverTest
1101 if isClient {
1102 suffix = "-Client"
1103 testType = clientTest
1104 }
1105
1106 for _, ver := range tlsVersions {
1107 test := testCase{
1108 testType: testType,
1109 name: prefix + "ExtendedMasterSecret-" + ver.name + suffix,
1110 config: Config{
1111 MinVersion: ver.version,
1112 MaxVersion: ver.version,
1113 Bugs: ProtocolBugs{
1114 NoExtendedMasterSecret: !with,
1115 RequireExtendedMasterSecret: with,
1116 },
1117 },
1118 flags: flags,
1119 shouldFail: ver.version == VersionSSL30 && with,
1120 }
1121 if test.shouldFail {
1122 test.expectedLocalError = "extended master secret required but not supported by peer"
1123 }
1124 testCases = append(testCases, test)
1125 }
1126 }
1127 }
1128
1129 // When a session is resumed, it should still be aware that its master
1130 // secret was generated via EMS and thus it's safe to use tls-unique.
1131 testCases = append(testCases, testCase{
1132 name: "ExtendedMasterSecret-Resume",
1133 config: Config{
1134 Bugs: ProtocolBugs{
1135 RequireExtendedMasterSecret: true,
1136 },
1137 },
1138 flags: []string{expectEMSFlag},
1139 resumeSession: true,
1140 })
1141}
1142
David Benjamin43ec06f2014-08-05 02:28:57 -04001143// Adds tests that try to cover the range of the handshake state machine, under
1144// various conditions. Some of these are redundant with other tests, but they
1145// only cover the synchronous case.
David Benjamin6fd297b2014-08-11 18:43:38 -04001146func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
David Benjamin43ec06f2014-08-05 02:28:57 -04001147 var suffix string
1148 var flags []string
1149 var maxHandshakeRecordLength int
David Benjamin6fd297b2014-08-11 18:43:38 -04001150 if protocol == dtls {
1151 suffix = "-DTLS"
1152 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001153 if async {
David Benjamin6fd297b2014-08-11 18:43:38 -04001154 suffix += "-Async"
David Benjamin43ec06f2014-08-05 02:28:57 -04001155 flags = append(flags, "-async")
1156 } else {
David Benjamin6fd297b2014-08-11 18:43:38 -04001157 suffix += "-Sync"
David Benjamin43ec06f2014-08-05 02:28:57 -04001158 }
1159 if splitHandshake {
1160 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -04001161 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -04001162 }
1163
1164 // Basic handshake, with resumption. Client and server.
1165 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001166 protocol: protocol,
1167 name: "Basic-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001168 config: Config{
1169 Bugs: ProtocolBugs{
1170 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1171 },
1172 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001173 flags: flags,
1174 resumeSession: true,
1175 })
1176 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001177 protocol: protocol,
1178 name: "Basic-Client-RenewTicket" + suffix,
David Benjaminbed9aae2014-08-07 19:13:38 -04001179 config: Config{
1180 Bugs: ProtocolBugs{
1181 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1182 RenewTicketOnResume: true,
1183 },
1184 },
1185 flags: flags,
1186 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001187 })
1188 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001189 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001190 testType: serverTest,
1191 name: "Basic-Server" + suffix,
1192 config: Config{
1193 Bugs: ProtocolBugs{
1194 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1195 },
1196 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001197 flags: flags,
1198 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001199 })
1200
David Benjamin6fd297b2014-08-11 18:43:38 -04001201 // TLS client auth.
1202 testCases = append(testCases, testCase{
1203 protocol: protocol,
1204 testType: clientTest,
1205 name: "ClientAuth-Client" + suffix,
1206 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001207 ClientAuth: RequireAnyClientCert,
David Benjamin6fd297b2014-08-11 18:43:38 -04001208 Bugs: ProtocolBugs{
1209 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1210 },
1211 },
1212 flags: append(flags,
1213 "-cert-file", rsaCertificateFile,
1214 "-key-file", rsaKeyFile),
1215 })
1216 testCases = append(testCases, testCase{
1217 protocol: protocol,
1218 testType: serverTest,
1219 name: "ClientAuth-Server" + suffix,
1220 config: Config{
1221 Certificates: []Certificate{rsaCertificate},
1222 },
1223 flags: append(flags, "-require-any-client-certificate"),
1224 })
1225
David Benjamin43ec06f2014-08-05 02:28:57 -04001226 // No session ticket support; server doesn't send NewSessionTicket.
1227 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001228 protocol: protocol,
1229 name: "SessionTicketsDisabled-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001230 config: Config{
1231 SessionTicketsDisabled: true,
1232 Bugs: ProtocolBugs{
1233 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1234 },
1235 },
1236 flags: flags,
1237 })
1238 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001239 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001240 testType: serverTest,
1241 name: "SessionTicketsDisabled-Server" + suffix,
1242 config: Config{
1243 SessionTicketsDisabled: true,
1244 Bugs: ProtocolBugs{
1245 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1246 },
1247 },
1248 flags: flags,
1249 })
1250
David Benjamin6fd297b2014-08-11 18:43:38 -04001251 if protocol == tls {
1252 // NPN on client and server; results in post-handshake message.
1253 testCases = append(testCases, testCase{
1254 protocol: protocol,
1255 name: "NPN-Client" + suffix,
1256 config: Config{
David Benjaminae2888f2014-09-06 12:58:58 -04001257 NextProtos: []string{"foo"},
David Benjamin6fd297b2014-08-11 18:43:38 -04001258 Bugs: ProtocolBugs{
1259 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1260 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001261 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001262 flags: append(flags, "-select-next-proto", "foo"),
1263 expectedNextProto: "foo",
1264 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001265 })
1266 testCases = append(testCases, testCase{
1267 protocol: protocol,
1268 testType: serverTest,
1269 name: "NPN-Server" + suffix,
1270 config: Config{
1271 NextProtos: []string{"bar"},
1272 Bugs: ProtocolBugs{
1273 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1274 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001275 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001276 flags: append(flags,
1277 "-advertise-npn", "\x03foo\x03bar\x03baz",
1278 "-expect-next-proto", "bar"),
David Benjaminfc7b0862014-09-06 13:21:53 -04001279 expectedNextProto: "bar",
1280 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001281 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001282
David Benjamin6fd297b2014-08-11 18:43:38 -04001283 // Client does False Start and negotiates NPN.
1284 testCases = append(testCases, testCase{
1285 protocol: protocol,
1286 name: "FalseStart" + suffix,
1287 config: Config{
1288 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1289 NextProtos: []string{"foo"},
1290 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001291 ExpectFalseStart: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001292 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1293 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001294 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001295 flags: append(flags,
1296 "-false-start",
1297 "-select-next-proto", "foo"),
David Benjamine58c4f52014-08-24 03:47:07 -04001298 shimWritesFirst: true,
1299 resumeSession: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001300 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001301
David Benjaminae2888f2014-09-06 12:58:58 -04001302 // Client does False Start and negotiates ALPN.
1303 testCases = append(testCases, testCase{
1304 protocol: protocol,
1305 name: "FalseStart-ALPN" + suffix,
1306 config: Config{
1307 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1308 NextProtos: []string{"foo"},
1309 Bugs: ProtocolBugs{
1310 ExpectFalseStart: true,
1311 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1312 },
1313 },
1314 flags: append(flags,
1315 "-false-start",
1316 "-advertise-alpn", "\x03foo"),
1317 shimWritesFirst: true,
1318 resumeSession: true,
1319 })
1320
David Benjamin6fd297b2014-08-11 18:43:38 -04001321 // False Start without session tickets.
1322 testCases = append(testCases, testCase{
1323 name: "FalseStart-SessionTicketsDisabled",
1324 config: Config{
1325 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1326 NextProtos: []string{"foo"},
1327 SessionTicketsDisabled: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001328 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001329 ExpectFalseStart: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001330 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1331 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001332 },
David Benjamin4e99c522014-08-24 01:45:30 -04001333 flags: append(flags,
David Benjamin6fd297b2014-08-11 18:43:38 -04001334 "-false-start",
1335 "-select-next-proto", "foo",
David Benjamin4e99c522014-08-24 01:45:30 -04001336 ),
David Benjamine58c4f52014-08-24 03:47:07 -04001337 shimWritesFirst: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001338 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001339
David Benjamina08e49d2014-08-24 01:46:07 -04001340 // Server parses a V2ClientHello.
David Benjamin6fd297b2014-08-11 18:43:38 -04001341 testCases = append(testCases, testCase{
1342 protocol: protocol,
1343 testType: serverTest,
1344 name: "SendV2ClientHello" + suffix,
1345 config: Config{
1346 // Choose a cipher suite that does not involve
1347 // elliptic curves, so no extensions are
1348 // involved.
1349 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1350 Bugs: ProtocolBugs{
1351 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1352 SendV2ClientHello: true,
1353 },
David Benjamin1e7f8d72014-08-08 12:27:04 -04001354 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001355 flags: flags,
1356 })
David Benjamina08e49d2014-08-24 01:46:07 -04001357
1358 // Client sends a Channel ID.
1359 testCases = append(testCases, testCase{
1360 protocol: protocol,
1361 name: "ChannelID-Client" + suffix,
1362 config: Config{
1363 RequestChannelID: true,
1364 Bugs: ProtocolBugs{
1365 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1366 },
1367 },
1368 flags: append(flags,
1369 "-send-channel-id", channelIDKeyFile,
1370 ),
1371 resumeSession: true,
1372 expectChannelID: true,
1373 })
1374
1375 // Server accepts a Channel ID.
1376 testCases = append(testCases, testCase{
1377 protocol: protocol,
1378 testType: serverTest,
1379 name: "ChannelID-Server" + suffix,
1380 config: Config{
1381 ChannelID: channelIDKey,
1382 Bugs: ProtocolBugs{
1383 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1384 },
1385 },
1386 flags: append(flags,
1387 "-expect-channel-id",
1388 base64.StdEncoding.EncodeToString(channelIDBytes),
1389 ),
1390 resumeSession: true,
1391 expectChannelID: true,
1392 })
David Benjamin6fd297b2014-08-11 18:43:38 -04001393 } else {
1394 testCases = append(testCases, testCase{
1395 protocol: protocol,
1396 name: "SkipHelloVerifyRequest" + suffix,
1397 config: Config{
1398 Bugs: ProtocolBugs{
1399 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1400 SkipHelloVerifyRequest: true,
1401 },
1402 },
1403 flags: flags,
1404 })
1405
1406 testCases = append(testCases, testCase{
1407 testType: serverTest,
1408 protocol: protocol,
1409 name: "CookieExchange" + suffix,
1410 config: Config{
1411 Bugs: ProtocolBugs{
1412 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1413 },
1414 },
1415 flags: append(flags, "-cookie-exchange"),
1416 })
1417 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001418}
1419
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001420func addVersionNegotiationTests() {
1421 for i, shimVers := range tlsVersions {
1422 // Assemble flags to disable all newer versions on the shim.
1423 var flags []string
1424 for _, vers := range tlsVersions[i+1:] {
1425 flags = append(flags, vers.flag)
1426 }
1427
1428 for _, runnerVers := range tlsVersions {
1429 expectedVersion := shimVers.version
1430 if runnerVers.version < shimVers.version {
1431 expectedVersion = runnerVers.version
1432 }
1433 suffix := shimVers.name + "-" + runnerVers.name
1434
1435 testCases = append(testCases, testCase{
1436 testType: clientTest,
1437 name: "VersionNegotiation-Client-" + suffix,
1438 config: Config{
1439 MaxVersion: runnerVers.version,
1440 },
1441 flags: flags,
1442 expectedVersion: expectedVersion,
1443 })
1444
David Benjamin76d8abe2014-08-14 16:25:34 -04001445 testCases = append(testCases, testCase{
1446 testType: serverTest,
1447 name: "VersionNegotiation-Server-" + suffix,
1448 config: Config{
1449 MaxVersion: runnerVers.version,
1450 },
1451 flags: flags,
1452 expectedVersion: expectedVersion,
1453 })
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001454 }
1455 }
1456}
1457
David Benjamin5c24a1d2014-08-31 00:59:27 -04001458func addD5BugTests() {
1459 testCases = append(testCases, testCase{
1460 testType: serverTest,
1461 name: "D5Bug-NoQuirk-Reject",
1462 config: Config{
1463 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1464 Bugs: ProtocolBugs{
1465 SSL3RSAKeyExchange: true,
1466 },
1467 },
1468 shouldFail: true,
1469 expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
1470 })
1471 testCases = append(testCases, testCase{
1472 testType: serverTest,
1473 name: "D5Bug-Quirk-Normal",
1474 config: Config{
1475 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1476 },
1477 flags: []string{"-tls-d5-bug"},
1478 })
1479 testCases = append(testCases, testCase{
1480 testType: serverTest,
1481 name: "D5Bug-Quirk-Bug",
1482 config: Config{
1483 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1484 Bugs: ProtocolBugs{
1485 SSL3RSAKeyExchange: true,
1486 },
1487 },
1488 flags: []string{"-tls-d5-bug"},
1489 })
1490}
1491
David Benjamine78bfde2014-09-06 12:45:15 -04001492func addExtensionTests() {
1493 testCases = append(testCases, testCase{
1494 testType: clientTest,
1495 name: "DuplicateExtensionClient",
1496 config: Config{
1497 Bugs: ProtocolBugs{
1498 DuplicateExtension: true,
1499 },
1500 },
1501 shouldFail: true,
1502 expectedLocalError: "remote error: error decoding message",
1503 })
1504 testCases = append(testCases, testCase{
1505 testType: serverTest,
1506 name: "DuplicateExtensionServer",
1507 config: Config{
1508 Bugs: ProtocolBugs{
1509 DuplicateExtension: true,
1510 },
1511 },
1512 shouldFail: true,
1513 expectedLocalError: "remote error: error decoding message",
1514 })
1515 testCases = append(testCases, testCase{
1516 testType: clientTest,
1517 name: "ServerNameExtensionClient",
1518 config: Config{
1519 Bugs: ProtocolBugs{
1520 ExpectServerName: "example.com",
1521 },
1522 },
1523 flags: []string{"-host-name", "example.com"},
1524 })
1525 testCases = append(testCases, testCase{
1526 testType: clientTest,
1527 name: "ServerNameExtensionClient",
1528 config: Config{
1529 Bugs: ProtocolBugs{
1530 ExpectServerName: "mismatch.com",
1531 },
1532 },
1533 flags: []string{"-host-name", "example.com"},
1534 shouldFail: true,
1535 expectedLocalError: "tls: unexpected server name",
1536 })
1537 testCases = append(testCases, testCase{
1538 testType: clientTest,
1539 name: "ServerNameExtensionClient",
1540 config: Config{
1541 Bugs: ProtocolBugs{
1542 ExpectServerName: "missing.com",
1543 },
1544 },
1545 shouldFail: true,
1546 expectedLocalError: "tls: unexpected server name",
1547 })
1548 testCases = append(testCases, testCase{
1549 testType: serverTest,
1550 name: "ServerNameExtensionServer",
1551 config: Config{
1552 ServerName: "example.com",
1553 },
1554 flags: []string{"-expect-server-name", "example.com"},
1555 resumeSession: true,
1556 })
David Benjaminae2888f2014-09-06 12:58:58 -04001557 testCases = append(testCases, testCase{
1558 testType: clientTest,
1559 name: "ALPNClient",
1560 config: Config{
1561 NextProtos: []string{"foo"},
1562 },
1563 flags: []string{
1564 "-advertise-alpn", "\x03foo\x03bar\x03baz",
1565 "-expect-alpn", "foo",
1566 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001567 expectedNextProto: "foo",
1568 expectedNextProtoType: alpn,
1569 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001570 })
1571 testCases = append(testCases, testCase{
1572 testType: serverTest,
1573 name: "ALPNServer",
1574 config: Config{
1575 NextProtos: []string{"foo", "bar", "baz"},
1576 },
1577 flags: []string{
1578 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1579 "-select-alpn", "foo",
1580 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001581 expectedNextProto: "foo",
1582 expectedNextProtoType: alpn,
1583 resumeSession: true,
1584 })
1585 // Test that the server prefers ALPN over NPN.
1586 testCases = append(testCases, testCase{
1587 testType: serverTest,
1588 name: "ALPNServer-Preferred",
1589 config: Config{
1590 NextProtos: []string{"foo", "bar", "baz"},
1591 },
1592 flags: []string{
1593 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1594 "-select-alpn", "foo",
1595 "-advertise-npn", "\x03foo\x03bar\x03baz",
1596 },
1597 expectedNextProto: "foo",
1598 expectedNextProtoType: alpn,
1599 resumeSession: true,
1600 })
1601 testCases = append(testCases, testCase{
1602 testType: serverTest,
1603 name: "ALPNServer-Preferred-Swapped",
1604 config: Config{
1605 NextProtos: []string{"foo", "bar", "baz"},
1606 Bugs: ProtocolBugs{
1607 SwapNPNAndALPN: true,
1608 },
1609 },
1610 flags: []string{
1611 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1612 "-select-alpn", "foo",
1613 "-advertise-npn", "\x03foo\x03bar\x03baz",
1614 },
1615 expectedNextProto: "foo",
1616 expectedNextProtoType: alpn,
1617 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001618 })
Adam Langley38311732014-10-16 19:04:35 -07001619 // Resume with a corrupt ticket.
1620 testCases = append(testCases, testCase{
1621 testType: serverTest,
1622 name: "CorruptTicket",
1623 config: Config{
1624 Bugs: ProtocolBugs{
1625 CorruptTicket: true,
1626 },
1627 },
1628 resumeSession: true,
1629 flags: []string{"-expect-session-miss"},
1630 })
1631 // Resume with an oversized session id.
1632 testCases = append(testCases, testCase{
1633 testType: serverTest,
1634 name: "OversizedSessionId",
1635 config: Config{
1636 Bugs: ProtocolBugs{
1637 OversizedSessionId: true,
1638 },
1639 },
1640 resumeSession: true,
Adam Langley75712922014-10-10 16:23:43 -07001641 shouldFail: true,
Adam Langley38311732014-10-16 19:04:35 -07001642 expectedError: ":DECODE_ERROR:",
1643 })
David Benjamine78bfde2014-09-06 12:45:15 -04001644}
1645
David Benjamin01fe8202014-09-24 15:21:44 -04001646func addResumptionVersionTests() {
1647 // TODO(davidben): Once DTLS 1.2 is working, test that as well.
1648 for _, sessionVers := range tlsVersions {
1649 // TODO(davidben): SSLv3 is omitted here because runner does not
1650 // support resumption with session IDs.
1651 if sessionVers.version == VersionSSL30 {
1652 continue
1653 }
1654 for _, resumeVers := range tlsVersions {
1655 if resumeVers.version == VersionSSL30 {
1656 continue
1657 }
1658 suffix := "-" + sessionVers.name + "-" + resumeVers.name
1659
1660 // TODO(davidben): Write equivalent tests for the server
1661 // and clean up the server's logic. This requires being
1662 // able to give the shim a different set of SSL_OP_NO_*
1663 // flags between the initial connection and the
1664 // resume. Perhaps resumption should be tested by
1665 // serializing the SSL_SESSION and starting a second
1666 // shim.
1667 testCases = append(testCases, testCase{
1668 name: "Resume-Client" + suffix,
1669 resumeSession: true,
1670 config: Config{
1671 MaxVersion: sessionVers.version,
1672 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1673 Bugs: ProtocolBugs{
1674 AllowSessionVersionMismatch: true,
1675 },
1676 },
1677 expectedVersion: sessionVers.version,
1678 resumeConfig: &Config{
1679 MaxVersion: resumeVers.version,
1680 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1681 Bugs: ProtocolBugs{
1682 AllowSessionVersionMismatch: true,
1683 },
1684 },
1685 expectedResumeVersion: resumeVers.version,
1686 })
1687
1688 testCases = append(testCases, testCase{
1689 name: "Resume-Client-NoResume" + suffix,
1690 flags: []string{"-expect-session-miss"},
1691 resumeSession: true,
1692 config: Config{
1693 MaxVersion: sessionVers.version,
1694 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1695 },
1696 expectedVersion: sessionVers.version,
1697 resumeConfig: &Config{
1698 MaxVersion: resumeVers.version,
1699 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1700 SessionTicketsDisabled: true,
1701 },
1702 expectedResumeVersion: resumeVers.version,
1703 })
1704 }
1705 }
1706}
1707
David Benjamin884fdf12014-08-02 15:28:23 -04001708func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07001709 defer wg.Done()
1710
1711 for test := range c {
1712 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04001713 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07001714 statusChan <- statusMsg{test: test, err: err}
1715 }
1716}
1717
1718type statusMsg struct {
1719 test *testCase
1720 started bool
1721 err error
1722}
1723
1724func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1725 var started, done, failed, lineLen int
1726 defer close(doneChan)
1727
1728 for msg := range statusChan {
1729 if msg.started {
1730 started++
1731 } else {
1732 done++
1733 }
1734
1735 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1736
1737 if msg.err != nil {
1738 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1739 failed++
1740 }
1741 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1742 lineLen = len(line)
1743 os.Stdout.WriteString(line)
1744 }
1745}
1746
1747func main() {
1748 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 -04001749 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04001750 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07001751
1752 flag.Parse()
1753
1754 addCipherSuiteTests()
1755 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07001756 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07001757 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04001758 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001759 addVersionNegotiationTests()
David Benjamin5c24a1d2014-08-31 00:59:27 -04001760 addD5BugTests()
David Benjamine78bfde2014-09-06 12:45:15 -04001761 addExtensionTests()
David Benjamin01fe8202014-09-24 15:21:44 -04001762 addResumptionVersionTests()
Adam Langley75712922014-10-10 16:23:43 -07001763 addExtendedMasterSecretTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04001764 for _, async := range []bool{false, true} {
1765 for _, splitHandshake := range []bool{false, true} {
David Benjamin6fd297b2014-08-11 18:43:38 -04001766 for _, protocol := range []protocol{tls, dtls} {
1767 addStateMachineCoverageTests(async, splitHandshake, protocol)
1768 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001769 }
1770 }
Adam Langley95c29f32014-06-20 12:00:00 -07001771
1772 var wg sync.WaitGroup
1773
David Benjamin2bc8e6f2014-08-02 15:22:37 -04001774 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07001775
1776 statusChan := make(chan statusMsg, numWorkers)
1777 testChan := make(chan *testCase, numWorkers)
1778 doneChan := make(chan struct{})
1779
David Benjamin025b3d32014-07-01 19:53:04 -04001780 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07001781
1782 for i := 0; i < numWorkers; i++ {
1783 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04001784 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07001785 }
1786
David Benjamin025b3d32014-07-01 19:53:04 -04001787 for i := range testCases {
1788 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
1789 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07001790 }
1791 }
1792
1793 close(testChan)
1794 wg.Wait()
1795 close(statusChan)
1796 <-doneChan
1797
1798 fmt.Printf("\n")
1799}