blob: 323f43fa670d5729cc185da2b23ed135f265defd [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")
25
David Benjamin025b3d32014-07-01 19:53:04 -040026const (
27 rsaCertificateFile = "cert.pem"
28 ecdsaCertificateFile = "ecdsa_cert.pem"
29)
30
31const (
David Benjamina08e49d2014-08-24 01:46:07 -040032 rsaKeyFile = "key.pem"
33 ecdsaKeyFile = "ecdsa_key.pem"
34 channelIDKeyFile = "channel_id_key.pem"
David Benjamin025b3d32014-07-01 19:53:04 -040035)
36
Adam Langley95c29f32014-06-20 12:00:00 -070037var rsaCertificate, ecdsaCertificate Certificate
David Benjamina08e49d2014-08-24 01:46:07 -040038var channelIDKey *ecdsa.PrivateKey
39var channelIDBytes []byte
Adam Langley95c29f32014-06-20 12:00:00 -070040
41func initCertificates() {
42 var err error
David Benjamin025b3d32014-07-01 19:53:04 -040043 rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070044 if err != nil {
45 panic(err)
46 }
47
David Benjamin025b3d32014-07-01 19:53:04 -040048 ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
Adam Langley95c29f32014-06-20 12:00:00 -070049 if err != nil {
50 panic(err)
51 }
David Benjamina08e49d2014-08-24 01:46:07 -040052
53 channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile)
54 if err != nil {
55 panic(err)
56 }
57 channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock)
58 if channelIDDERBlock.Type != "EC PRIVATE KEY" {
59 panic("bad key type")
60 }
61 channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes)
62 if err != nil {
63 panic(err)
64 }
65 if channelIDKey.Curve != elliptic.P256() {
66 panic("bad curve")
67 }
68
69 channelIDBytes = make([]byte, 64)
70 writeIntPadded(channelIDBytes[:32], channelIDKey.X)
71 writeIntPadded(channelIDBytes[32:], channelIDKey.Y)
Adam Langley95c29f32014-06-20 12:00:00 -070072}
73
74var certificateOnce sync.Once
75
76func getRSACertificate() Certificate {
77 certificateOnce.Do(initCertificates)
78 return rsaCertificate
79}
80
81func getECDSACertificate() Certificate {
82 certificateOnce.Do(initCertificates)
83 return ecdsaCertificate
84}
85
David Benjamin025b3d32014-07-01 19:53:04 -040086type testType int
87
88const (
89 clientTest testType = iota
90 serverTest
91)
92
David Benjamin6fd297b2014-08-11 18:43:38 -040093type protocol int
94
95const (
96 tls protocol = iota
97 dtls
98)
99
David Benjaminfc7b0862014-09-06 13:21:53 -0400100const (
101 alpn = 1
102 npn = 2
103)
104
Adam Langley95c29f32014-06-20 12:00:00 -0700105type testCase struct {
David Benjamin025b3d32014-07-01 19:53:04 -0400106 testType testType
David Benjamin6fd297b2014-08-11 18:43:38 -0400107 protocol protocol
Adam Langley95c29f32014-06-20 12:00:00 -0700108 name string
109 config Config
110 shouldFail bool
111 expectedError string
Adam Langleyac61fa32014-06-23 12:03:11 -0700112 // expectedLocalError, if not empty, contains a substring that must be
113 // found in the local error.
114 expectedLocalError string
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400115 // expectedVersion, if non-zero, specifies the TLS version that must be
116 // negotiated.
117 expectedVersion uint16
David Benjamin01fe8202014-09-24 15:21:44 -0400118 // expectedResumeVersion, if non-zero, specifies the TLS version that
119 // must be negotiated on resumption. If zero, expectedVersion is used.
120 expectedResumeVersion uint16
David Benjamina08e49d2014-08-24 01:46:07 -0400121 // expectChannelID controls whether the connection should have
122 // negotiated a Channel ID with channelIDKey.
123 expectChannelID bool
David Benjaminae2888f2014-09-06 12:58:58 -0400124 // expectedNextProto controls whether the connection should
125 // negotiate a next protocol via NPN or ALPN.
126 expectedNextProto string
David Benjaminfc7b0862014-09-06 13:21:53 -0400127 // expectedNextProtoType, if non-zero, is the expected next
128 // protocol negotiation mechanism.
129 expectedNextProtoType int
Adam Langley80842bd2014-06-20 12:00:00 -0700130 // messageLen is the length, in bytes, of the test message that will be
131 // sent.
132 messageLen int
David Benjamin025b3d32014-07-01 19:53:04 -0400133 // certFile is the path to the certificate to use for the server.
134 certFile string
135 // keyFile is the path to the private key to use for the server.
136 keyFile string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400137 // resumeSession controls whether a second connection should be tested
David Benjamin01fe8202014-09-24 15:21:44 -0400138 // which attempts to resume the first session.
David Benjamin1d5c83e2014-07-22 19:20:02 -0400139 resumeSession bool
David Benjamin01fe8202014-09-24 15:21:44 -0400140 // resumeConfig, if not nil, points to a Config to be used on
141 // resumption. SessionTicketKey and ClientSessionCache are copied from
142 // the initial connection's config. If nil, the initial connection's
143 // config is used.
144 resumeConfig *Config
David Benjamin98e882e2014-08-08 13:24:34 -0400145 // sendPrefix sends a prefix on the socket before actually performing a
146 // handshake.
147 sendPrefix string
David Benjamine58c4f52014-08-24 03:47:07 -0400148 // shimWritesFirst controls whether the shim sends an initial "hello"
149 // message before doing a roundtrip with the runner.
150 shimWritesFirst bool
David Benjamin325b5c32014-07-01 19:40:31 -0400151 // flags, if not empty, contains a list of command-line flags that will
152 // be passed to the shim program.
153 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -0700154}
155
David Benjamin025b3d32014-07-01 19:53:04 -0400156var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700157 {
158 name: "BadRSASignature",
159 config: Config{
160 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
161 Bugs: ProtocolBugs{
162 InvalidSKXSignature: true,
163 },
164 },
165 shouldFail: true,
166 expectedError: ":BAD_SIGNATURE:",
167 },
168 {
169 name: "BadECDSASignature",
170 config: Config{
171 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
172 Bugs: ProtocolBugs{
173 InvalidSKXSignature: true,
174 },
175 Certificates: []Certificate{getECDSACertificate()},
176 },
177 shouldFail: true,
178 expectedError: ":BAD_SIGNATURE:",
179 },
180 {
181 name: "BadECDSACurve",
182 config: Config{
183 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
184 Bugs: ProtocolBugs{
185 InvalidSKXCurve: true,
186 },
187 Certificates: []Certificate{getECDSACertificate()},
188 },
189 shouldFail: true,
190 expectedError: ":WRONG_CURVE:",
191 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700192 {
David Benjamina8e3e0e2014-08-06 22:11:10 -0400193 testType: serverTest,
194 name: "BadRSAVersion",
195 config: Config{
196 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
197 Bugs: ProtocolBugs{
198 RsaClientKeyExchangeVersion: VersionTLS11,
199 },
200 },
201 shouldFail: true,
202 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
203 },
204 {
David Benjamin325b5c32014-07-01 19:40:31 -0400205 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700206 config: Config{
207 Bugs: ProtocolBugs{
208 FailIfNotFallbackSCSV: true,
209 },
210 },
211 shouldFail: true,
212 expectedLocalError: "no fallback SCSV found",
213 },
David Benjamin325b5c32014-07-01 19:40:31 -0400214 {
David Benjamin2a0c4962014-08-22 23:46:35 -0400215 name: "SendFallbackSCSV",
David Benjamin325b5c32014-07-01 19:40:31 -0400216 config: Config{
217 Bugs: ProtocolBugs{
218 FailIfNotFallbackSCSV: true,
219 },
220 },
221 flags: []string{"-fallback-scsv"},
222 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400223 {
David Benjamin7b030512014-07-08 17:30:11 -0400224 name: "ClientCertificateTypes",
225 config: Config{
226 ClientAuth: RequestClientCert,
227 ClientCertificateTypes: []byte{
228 CertTypeDSSSign,
229 CertTypeRSASign,
230 CertTypeECDSASign,
231 },
232 },
David Benjamin2561dc32014-08-24 01:25:27 -0400233 flags: []string{
234 "-expect-certificate-types",
235 base64.StdEncoding.EncodeToString([]byte{
236 CertTypeDSSSign,
237 CertTypeRSASign,
238 CertTypeECDSASign,
239 }),
240 },
David Benjamin7b030512014-07-08 17:30:11 -0400241 },
David Benjamin636293b2014-07-08 17:59:18 -0400242 {
243 name: "NoClientCertificate",
244 config: Config{
245 ClientAuth: RequireAnyClientCert,
246 },
247 shouldFail: true,
248 expectedLocalError: "client didn't provide a certificate",
249 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400250 {
251 name: "UnauthenticatedECDH",
252 config: Config{
253 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
254 Bugs: ProtocolBugs{
255 UnauthenticatedECDH: true,
256 },
257 },
258 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400259 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400260 },
David Benjamin9c651c92014-07-12 13:27:45 -0400261 {
262 name: "SkipServerKeyExchange",
263 config: Config{
264 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
265 Bugs: ProtocolBugs{
266 SkipServerKeyExchange: true,
267 },
268 },
269 shouldFail: true,
270 expectedError: ":UNEXPECTED_MESSAGE:",
271 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400272 {
David Benjamina0e52232014-07-19 17:39:58 -0400273 name: "SkipChangeCipherSpec-Client",
274 config: Config{
275 Bugs: ProtocolBugs{
276 SkipChangeCipherSpec: true,
277 },
278 },
279 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400280 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400281 },
282 {
283 testType: serverTest,
284 name: "SkipChangeCipherSpec-Server",
285 config: Config{
286 Bugs: ProtocolBugs{
287 SkipChangeCipherSpec: true,
288 },
289 },
290 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400291 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400292 },
David Benjamin42be6452014-07-21 14:50:23 -0400293 {
294 testType: serverTest,
295 name: "SkipChangeCipherSpec-Server-NPN",
296 config: Config{
297 NextProtos: []string{"bar"},
298 Bugs: ProtocolBugs{
299 SkipChangeCipherSpec: true,
300 },
301 },
302 flags: []string{
303 "-advertise-npn", "\x03foo\x03bar\x03baz",
304 },
305 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400306 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
307 },
308 {
309 name: "FragmentAcrossChangeCipherSpec-Client",
310 config: Config{
311 Bugs: ProtocolBugs{
312 FragmentAcrossChangeCipherSpec: true,
313 },
314 },
315 shouldFail: true,
316 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
317 },
318 {
319 testType: serverTest,
320 name: "FragmentAcrossChangeCipherSpec-Server",
321 config: Config{
322 Bugs: ProtocolBugs{
323 FragmentAcrossChangeCipherSpec: true,
324 },
325 },
326 shouldFail: true,
327 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
328 },
329 {
330 testType: serverTest,
331 name: "FragmentAcrossChangeCipherSpec-Server-NPN",
332 config: Config{
333 NextProtos: []string{"bar"},
334 Bugs: ProtocolBugs{
335 FragmentAcrossChangeCipherSpec: true,
336 },
337 },
338 flags: []string{
339 "-advertise-npn", "\x03foo\x03bar\x03baz",
340 },
341 shouldFail: true,
342 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamin42be6452014-07-21 14:50:23 -0400343 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400344 {
345 testType: serverTest,
346 name: "EarlyChangeCipherSpec-server-1",
347 config: Config{
348 Bugs: ProtocolBugs{
349 EarlyChangeCipherSpec: 1,
350 },
351 },
352 shouldFail: true,
353 expectedError: ":CCS_RECEIVED_EARLY:",
354 },
355 {
356 testType: serverTest,
357 name: "EarlyChangeCipherSpec-server-2",
358 config: Config{
359 Bugs: ProtocolBugs{
360 EarlyChangeCipherSpec: 2,
361 },
362 },
363 shouldFail: true,
364 expectedError: ":CCS_RECEIVED_EARLY:",
365 },
David Benjamind23f4122014-07-23 15:09:48 -0400366 {
David Benjamind23f4122014-07-23 15:09:48 -0400367 name: "SkipNewSessionTicket",
368 config: Config{
369 Bugs: ProtocolBugs{
370 SkipNewSessionTicket: true,
371 },
372 },
373 shouldFail: true,
374 expectedError: ":CCS_RECEIVED_EARLY:",
375 },
David Benjamin7e3305e2014-07-28 14:52:32 -0400376 {
David Benjamind86c7672014-08-02 04:07:12 -0400377 testType: serverTest,
David Benjaminbef270a2014-08-02 04:22:02 -0400378 name: "FallbackSCSV",
379 config: Config{
380 MaxVersion: VersionTLS11,
381 Bugs: ProtocolBugs{
382 SendFallbackSCSV: true,
383 },
384 },
385 shouldFail: true,
386 expectedError: ":INAPPROPRIATE_FALLBACK:",
387 },
388 {
389 testType: serverTest,
390 name: "FallbackSCSV-VersionMatch",
391 config: Config{
392 Bugs: ProtocolBugs{
393 SendFallbackSCSV: true,
394 },
395 },
396 },
David Benjamin98214542014-08-07 18:02:39 -0400397 {
398 testType: serverTest,
399 name: "FragmentedClientVersion",
400 config: Config{
401 Bugs: ProtocolBugs{
402 MaxHandshakeRecordLength: 1,
403 FragmentClientVersion: true,
404 },
405 },
406 shouldFail: true,
407 expectedError: ":RECORD_TOO_SMALL:",
408 },
David Benjamin98e882e2014-08-08 13:24:34 -0400409 {
410 testType: serverTest,
411 name: "MinorVersionTolerance",
412 config: Config{
413 Bugs: ProtocolBugs{
414 SendClientVersion: 0x03ff,
415 },
416 },
417 expectedVersion: VersionTLS12,
418 },
419 {
420 testType: serverTest,
421 name: "MajorVersionTolerance",
422 config: Config{
423 Bugs: ProtocolBugs{
424 SendClientVersion: 0x0400,
425 },
426 },
427 expectedVersion: VersionTLS12,
428 },
429 {
430 testType: serverTest,
431 name: "VersionTooLow",
432 config: Config{
433 Bugs: ProtocolBugs{
434 SendClientVersion: 0x0200,
435 },
436 },
437 shouldFail: true,
438 expectedError: ":UNSUPPORTED_PROTOCOL:",
439 },
440 {
441 testType: serverTest,
442 name: "HttpGET",
443 sendPrefix: "GET / HTTP/1.0\n",
444 shouldFail: true,
445 expectedError: ":HTTP_REQUEST:",
446 },
447 {
448 testType: serverTest,
449 name: "HttpPOST",
450 sendPrefix: "POST / HTTP/1.0\n",
451 shouldFail: true,
452 expectedError: ":HTTP_REQUEST:",
453 },
454 {
455 testType: serverTest,
456 name: "HttpHEAD",
457 sendPrefix: "HEAD / HTTP/1.0\n",
458 shouldFail: true,
459 expectedError: ":HTTP_REQUEST:",
460 },
461 {
462 testType: serverTest,
463 name: "HttpPUT",
464 sendPrefix: "PUT / HTTP/1.0\n",
465 shouldFail: true,
466 expectedError: ":HTTP_REQUEST:",
467 },
468 {
469 testType: serverTest,
470 name: "HttpCONNECT",
471 sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
472 shouldFail: true,
473 expectedError: ":HTTPS_PROXY_REQUEST:",
474 },
David Benjamin39ebf532014-08-31 02:23:49 -0400475 {
476 name: "SkipCipherVersionCheck",
477 config: Config{
478 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
479 MaxVersion: VersionTLS11,
480 Bugs: ProtocolBugs{
481 SkipCipherVersionCheck: true,
482 },
483 },
484 shouldFail: true,
485 expectedError: ":WRONG_CIPHER_RETURNED:",
486 },
Adam Langley95c29f32014-06-20 12:00:00 -0700487}
488
David Benjamin01fe8202014-09-24 15:21:44 -0400489func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
David Benjamin6fd297b2014-08-11 18:43:38 -0400490 if test.protocol == dtls {
491 conn = newPacketAdaptor(conn)
492 }
493
494 if test.sendPrefix != "" {
495 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
496 return err
497 }
David Benjamin98e882e2014-08-08 13:24:34 -0400498 }
499
David Benjamin1d5c83e2014-07-22 19:20:02 -0400500 var tlsConn *Conn
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400501 if test.testType == clientTest {
David Benjamin6fd297b2014-08-11 18:43:38 -0400502 if test.protocol == dtls {
503 tlsConn = DTLSServer(conn, config)
504 } else {
505 tlsConn = Server(conn, config)
506 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400507 } else {
508 config.InsecureSkipVerify = true
David Benjamin6fd297b2014-08-11 18:43:38 -0400509 if test.protocol == dtls {
510 tlsConn = DTLSClient(conn, config)
511 } else {
512 tlsConn = Client(conn, config)
513 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400514 }
515
Adam Langley95c29f32014-06-20 12:00:00 -0700516 if err := tlsConn.Handshake(); err != nil {
517 return err
518 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700519
David Benjamin01fe8202014-09-24 15:21:44 -0400520 // TODO(davidben): move all per-connection expectations into a dedicated
521 // expectations struct that can be specified separately for the two
522 // legs.
523 expectedVersion := test.expectedVersion
524 if isResume && test.expectedResumeVersion != 0 {
525 expectedVersion = test.expectedResumeVersion
526 }
527 if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
528 return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400529 }
530
David Benjamina08e49d2014-08-24 01:46:07 -0400531 if test.expectChannelID {
532 channelID := tlsConn.ConnectionState().ChannelID
533 if channelID == nil {
534 return fmt.Errorf("no channel ID negotiated")
535 }
536 if channelID.Curve != channelIDKey.Curve ||
537 channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
538 channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
539 return fmt.Errorf("incorrect channel ID")
540 }
541 }
542
David Benjaminae2888f2014-09-06 12:58:58 -0400543 if expected := test.expectedNextProto; expected != "" {
544 if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
545 return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
546 }
547 }
548
David Benjaminfc7b0862014-09-06 13:21:53 -0400549 if test.expectedNextProtoType != 0 {
550 if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN {
551 return fmt.Errorf("next proto type mismatch")
552 }
553 }
554
David Benjamine58c4f52014-08-24 03:47:07 -0400555 if test.shimWritesFirst {
556 var buf [5]byte
557 _, err := io.ReadFull(tlsConn, buf[:])
558 if err != nil {
559 return err
560 }
561 if string(buf[:]) != "hello" {
562 return fmt.Errorf("bad initial message")
563 }
564 }
565
Kenny Root7fdeaf12014-08-05 15:23:37 -0700566 if messageLen < 0 {
David Benjamin6fd297b2014-08-11 18:43:38 -0400567 if test.protocol == dtls {
568 return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
569 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700570 // Read until EOF.
571 _, err := io.Copy(ioutil.Discard, tlsConn)
572 return err
573 }
574
Adam Langley80842bd2014-06-20 12:00:00 -0700575 if messageLen == 0 {
576 messageLen = 32
577 }
578 testMessage := make([]byte, messageLen)
579 for i := range testMessage {
580 testMessage[i] = 0x42
581 }
Adam Langley95c29f32014-06-20 12:00:00 -0700582 tlsConn.Write(testMessage)
583
584 buf := make([]byte, len(testMessage))
David Benjamin6fd297b2014-08-11 18:43:38 -0400585 if test.protocol == dtls {
586 bufTmp := make([]byte, len(buf)+1)
587 n, err := tlsConn.Read(bufTmp)
588 if err != nil {
589 return err
590 }
591 if n != len(buf) {
592 return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
593 }
594 copy(buf, bufTmp)
595 } else {
596 _, err := io.ReadFull(tlsConn, buf)
597 if err != nil {
598 return err
599 }
Adam Langley95c29f32014-06-20 12:00:00 -0700600 }
601
602 for i, v := range buf {
603 if v != testMessage[i]^0xff {
604 return fmt.Errorf("bad reply contents at byte %d", i)
605 }
606 }
607
608 return nil
609}
610
David Benjamin325b5c32014-07-01 19:40:31 -0400611func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
612 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700613 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400614 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700615 }
David Benjamin325b5c32014-07-01 19:40:31 -0400616 valgrindArgs = append(valgrindArgs, path)
617 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700618
David Benjamin325b5c32014-07-01 19:40:31 -0400619 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700620}
621
David Benjamin325b5c32014-07-01 19:40:31 -0400622func gdbOf(path string, args ...string) *exec.Cmd {
623 xtermArgs := []string{"-e", "gdb", "--args"}
624 xtermArgs = append(xtermArgs, path)
625 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700626
David Benjamin325b5c32014-07-01 19:40:31 -0400627 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700628}
629
David Benjamin1d5c83e2014-07-22 19:20:02 -0400630func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700631 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
632 if err != nil {
633 panic(err)
634 }
635
636 syscall.CloseOnExec(socks[0])
637 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400638 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700639 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400640 conn, err = net.FileConn(connFile)
641 if err != nil {
642 panic(err)
643 }
Adam Langley95c29f32014-06-20 12:00:00 -0700644 connFile.Close()
645 if err != nil {
646 panic(err)
647 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400648 return shimEnd, conn
649}
650
David Benjamin884fdf12014-08-02 15:28:23 -0400651func runTest(test *testCase, buildDir string) error {
David Benjamin1d5c83e2014-07-22 19:20:02 -0400652 shimEnd, conn := openSocketPair()
653 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700654
David Benjamin884fdf12014-08-02 15:28:23 -0400655 shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
David Benjamin5a593af2014-08-11 19:51:50 -0400656 var flags []string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400657 if test.testType == serverTest {
David Benjamin5a593af2014-08-11 19:51:50 -0400658 flags = append(flags, "-server")
659
David Benjamin025b3d32014-07-01 19:53:04 -0400660 flags = append(flags, "-key-file")
661 if test.keyFile == "" {
662 flags = append(flags, rsaKeyFile)
663 } else {
664 flags = append(flags, test.keyFile)
665 }
666
667 flags = append(flags, "-cert-file")
668 if test.certFile == "" {
669 flags = append(flags, rsaCertificateFile)
670 } else {
671 flags = append(flags, test.certFile)
672 }
673 }
David Benjamin5a593af2014-08-11 19:51:50 -0400674
David Benjamin6fd297b2014-08-11 18:43:38 -0400675 if test.protocol == dtls {
676 flags = append(flags, "-dtls")
677 }
678
David Benjamin5a593af2014-08-11 19:51:50 -0400679 if test.resumeSession {
680 flags = append(flags, "-resume")
681 }
682
David Benjamine58c4f52014-08-24 03:47:07 -0400683 if test.shimWritesFirst {
684 flags = append(flags, "-shim-writes-first")
685 }
686
David Benjamin025b3d32014-07-01 19:53:04 -0400687 flags = append(flags, test.flags...)
688
689 var shim *exec.Cmd
690 if *useValgrind {
691 shim = valgrindOf(false, shim_path, flags...)
692 } else {
693 shim = exec.Command(shim_path, flags...)
694 }
695 // shim = gdbOf(shim_path, flags...)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400696 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400697 shim.Stdin = os.Stdin
698 var stdoutBuf, stderrBuf bytes.Buffer
699 shim.Stdout = &stdoutBuf
700 shim.Stderr = &stderrBuf
701
702 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700703 panic(err)
704 }
David Benjamin025b3d32014-07-01 19:53:04 -0400705 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400706 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700707
708 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400709 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400710 if test.testType == clientTest {
711 if len(config.Certificates) == 0 {
712 config.Certificates = []Certificate{getRSACertificate()}
713 }
David Benjamin025b3d32014-07-01 19:53:04 -0400714 }
Adam Langley95c29f32014-06-20 12:00:00 -0700715
David Benjamin01fe8202014-09-24 15:21:44 -0400716 err := doExchange(test, &config, conn, test.messageLen,
717 false /* not a resumption */)
Adam Langley95c29f32014-06-20 12:00:00 -0700718 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400719 if err == nil && test.resumeSession {
David Benjamin01fe8202014-09-24 15:21:44 -0400720 var resumeConfig Config
721 if test.resumeConfig != nil {
722 resumeConfig = *test.resumeConfig
723 if len(resumeConfig.Certificates) == 0 {
724 resumeConfig.Certificates = []Certificate{getRSACertificate()}
725 }
726 resumeConfig.SessionTicketKey = config.SessionTicketKey
727 resumeConfig.ClientSessionCache = config.ClientSessionCache
728 } else {
729 resumeConfig = config
730 }
731 err = doExchange(test, &resumeConfig, connResume, test.messageLen,
732 true /* resumption */)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400733 }
David Benjamin812152a2014-09-06 12:49:07 -0400734 connResume.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400735
David Benjamin025b3d32014-07-01 19:53:04 -0400736 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700737
738 stdout := string(stdoutBuf.Bytes())
739 stderr := string(stderrBuf.Bytes())
740 failed := err != nil || childErr != nil
741 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700742 localError := "none"
743 if err != nil {
744 localError = err.Error()
745 }
746 if len(test.expectedLocalError) != 0 {
747 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
748 }
Adam Langley95c29f32014-06-20 12:00:00 -0700749
750 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700751 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700752 if childErr != nil {
753 childError = childErr.Error()
754 }
755
756 var msg string
757 switch {
758 case failed && !test.shouldFail:
759 msg = "unexpected failure"
760 case !failed && test.shouldFail:
761 msg = "unexpected success"
762 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700763 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700764 default:
765 panic("internal error")
766 }
767
768 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
769 }
770
771 if !*useValgrind && len(stderr) > 0 {
772 println(stderr)
773 }
774
775 return nil
776}
777
778var tlsVersions = []struct {
779 name string
780 version uint16
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400781 flag string
Adam Langley95c29f32014-06-20 12:00:00 -0700782}{
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400783 {"SSL3", VersionSSL30, "-no-ssl3"},
784 {"TLS1", VersionTLS10, "-no-tls1"},
785 {"TLS11", VersionTLS11, "-no-tls11"},
786 {"TLS12", VersionTLS12, "-no-tls12"},
Adam Langley95c29f32014-06-20 12:00:00 -0700787}
788
789var testCipherSuites = []struct {
790 name string
791 id uint16
792}{
793 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400794 {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700795 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400796 {"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400797 {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700798 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400799 {"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400800 {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
801 {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400802 {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400803 {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
804 {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400805 {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700806 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
807 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400808 {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
809 {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700810 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400811 {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700812 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700813 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700814 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400815 {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400816 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700817 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400818 {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700819 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700820 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400821 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700822}
823
David Benjaminf7768e42014-08-31 02:06:47 -0400824func isTLS12Only(suiteName string) bool {
825 return strings.HasSuffix(suiteName, "-GCM") ||
826 strings.HasSuffix(suiteName, "-SHA256") ||
827 strings.HasSuffix(suiteName, "-SHA384")
828}
829
Adam Langley95c29f32014-06-20 12:00:00 -0700830func addCipherSuiteTests() {
831 for _, suite := range testCipherSuites {
832 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400833 var certFile string
834 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700835 if strings.Contains(suite.name, "ECDSA") {
836 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400837 certFile = ecdsaCertificateFile
838 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700839 } else {
840 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400841 certFile = rsaCertificateFile
842 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700843 }
844
845 for _, ver := range tlsVersions {
David Benjaminf7768e42014-08-31 02:06:47 -0400846 if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
Adam Langley95c29f32014-06-20 12:00:00 -0700847 continue
848 }
849
David Benjamin1d5c83e2014-07-22 19:20:02 -0400850 // Go's TLS implementation only implements session
851 // resumption with tickets, so SSLv3 cannot resume
852 // sessions.
853 resumeSession := ver.version != VersionSSL30
854
David Benjamin025b3d32014-07-01 19:53:04 -0400855 testCases = append(testCases, testCase{
856 testType: clientTest,
857 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700858 config: Config{
859 MinVersion: ver.version,
860 MaxVersion: ver.version,
861 CipherSuites: []uint16{suite.id},
862 Certificates: []Certificate{cert},
863 },
David Benjamin1d5c83e2014-07-22 19:20:02 -0400864 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700865 })
David Benjamin025b3d32014-07-01 19:53:04 -0400866
David Benjamin76d8abe2014-08-14 16:25:34 -0400867 testCases = append(testCases, testCase{
868 testType: serverTest,
869 name: ver.name + "-" + suite.name + "-server",
870 config: Config{
871 MinVersion: ver.version,
872 MaxVersion: ver.version,
873 CipherSuites: []uint16{suite.id},
874 Certificates: []Certificate{cert},
875 },
876 certFile: certFile,
877 keyFile: keyFile,
878 resumeSession: resumeSession,
879 })
David Benjamin6fd297b2014-08-11 18:43:38 -0400880
881 // TODO(davidben): Fix DTLS 1.2 support and test that.
882 if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
883 testCases = append(testCases, testCase{
884 testType: clientTest,
885 protocol: dtls,
886 name: "D" + ver.name + "-" + suite.name + "-client",
887 config: Config{
888 MinVersion: ver.version,
889 MaxVersion: ver.version,
890 CipherSuites: []uint16{suite.id},
891 Certificates: []Certificate{cert},
892 },
893 resumeSession: resumeSession,
894 })
895 testCases = append(testCases, testCase{
896 testType: serverTest,
897 protocol: dtls,
898 name: "D" + ver.name + "-" + suite.name + "-server",
899 config: Config{
900 MinVersion: ver.version,
901 MaxVersion: ver.version,
902 CipherSuites: []uint16{suite.id},
903 Certificates: []Certificate{cert},
904 },
905 certFile: certFile,
906 keyFile: keyFile,
907 resumeSession: resumeSession,
908 })
909 }
Adam Langley95c29f32014-06-20 12:00:00 -0700910 }
911 }
912}
913
914func addBadECDSASignatureTests() {
915 for badR := BadValue(1); badR < NumBadValues; badR++ {
916 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400917 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700918 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
919 config: Config{
920 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
921 Certificates: []Certificate{getECDSACertificate()},
922 Bugs: ProtocolBugs{
923 BadECDSAR: badR,
924 BadECDSAS: badS,
925 },
926 },
927 shouldFail: true,
928 expectedError: "SIGNATURE",
929 })
930 }
931 }
932}
933
Adam Langley80842bd2014-06-20 12:00:00 -0700934func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400935 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700936 name: "MaxCBCPadding",
937 config: Config{
938 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
939 Bugs: ProtocolBugs{
940 MaxPadding: true,
941 },
942 },
943 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
944 })
David Benjamin025b3d32014-07-01 19:53:04 -0400945 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700946 name: "BadCBCPadding",
947 config: Config{
948 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
949 Bugs: ProtocolBugs{
950 PaddingFirstByteBad: true,
951 },
952 },
953 shouldFail: true,
954 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
955 })
956 // OpenSSL previously had an issue where the first byte of padding in
957 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -0400958 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700959 name: "BadCBCPadding255",
960 config: Config{
961 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
962 Bugs: ProtocolBugs{
963 MaxPadding: true,
964 PaddingFirstByteBadIf255: true,
965 },
966 },
967 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
968 shouldFail: true,
969 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
970 })
971}
972
Kenny Root7fdeaf12014-08-05 15:23:37 -0700973func addCBCSplittingTests() {
974 testCases = append(testCases, testCase{
975 name: "CBCRecordSplitting",
976 config: Config{
977 MaxVersion: VersionTLS10,
978 MinVersion: VersionTLS10,
979 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
980 },
981 messageLen: -1, // read until EOF
982 flags: []string{
983 "-async",
984 "-write-different-record-sizes",
985 "-cbc-record-splitting",
986 },
David Benjamina8e3e0e2014-08-06 22:11:10 -0400987 })
988 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -0700989 name: "CBCRecordSplittingPartialWrite",
990 config: Config{
991 MaxVersion: VersionTLS10,
992 MinVersion: VersionTLS10,
993 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
994 },
995 messageLen: -1, // read until EOF
996 flags: []string{
997 "-async",
998 "-write-different-record-sizes",
999 "-cbc-record-splitting",
1000 "-partial-write",
1001 },
1002 })
1003}
1004
David Benjamin636293b2014-07-08 17:59:18 -04001005func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -04001006 // Add a dummy cert pool to stress certificate authority parsing.
1007 // TODO(davidben): Add tests that those values parse out correctly.
1008 certPool := x509.NewCertPool()
1009 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
1010 if err != nil {
1011 panic(err)
1012 }
1013 certPool.AddCert(cert)
1014
David Benjamin636293b2014-07-08 17:59:18 -04001015 for _, ver := range tlsVersions {
David Benjamin636293b2014-07-08 17:59:18 -04001016 testCases = append(testCases, testCase{
1017 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -04001018 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -04001019 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001020 MinVersion: ver.version,
1021 MaxVersion: ver.version,
1022 ClientAuth: RequireAnyClientCert,
1023 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -04001024 },
1025 flags: []string{
1026 "-cert-file", rsaCertificateFile,
1027 "-key-file", rsaKeyFile,
1028 },
1029 })
1030 testCases = append(testCases, testCase{
David Benjamin67666e72014-07-12 15:47:52 -04001031 testType: serverTest,
1032 name: ver.name + "-Server-ClientAuth-RSA",
1033 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001034 MinVersion: ver.version,
1035 MaxVersion: ver.version,
David Benjamin67666e72014-07-12 15:47:52 -04001036 Certificates: []Certificate{rsaCertificate},
1037 },
1038 flags: []string{"-require-any-client-certificate"},
1039 })
David Benjamine098ec22014-08-27 23:13:20 -04001040 if ver.version != VersionSSL30 {
1041 testCases = append(testCases, testCase{
1042 testType: serverTest,
1043 name: ver.name + "-Server-ClientAuth-ECDSA",
1044 config: Config{
1045 MinVersion: ver.version,
1046 MaxVersion: ver.version,
1047 Certificates: []Certificate{ecdsaCertificate},
1048 },
1049 flags: []string{"-require-any-client-certificate"},
1050 })
1051 testCases = append(testCases, testCase{
1052 testType: clientTest,
1053 name: ver.name + "-Client-ClientAuth-ECDSA",
1054 config: Config{
1055 MinVersion: ver.version,
1056 MaxVersion: ver.version,
1057 ClientAuth: RequireAnyClientCert,
1058 ClientCAs: certPool,
1059 },
1060 flags: []string{
1061 "-cert-file", ecdsaCertificateFile,
1062 "-key-file", ecdsaKeyFile,
1063 },
1064 })
1065 }
David Benjamin636293b2014-07-08 17:59:18 -04001066 }
1067}
1068
David Benjamin43ec06f2014-08-05 02:28:57 -04001069// Adds tests that try to cover the range of the handshake state machine, under
1070// various conditions. Some of these are redundant with other tests, but they
1071// only cover the synchronous case.
David Benjamin6fd297b2014-08-11 18:43:38 -04001072func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
David Benjamin43ec06f2014-08-05 02:28:57 -04001073 var suffix string
1074 var flags []string
1075 var maxHandshakeRecordLength int
David Benjamin6fd297b2014-08-11 18:43:38 -04001076 if protocol == dtls {
1077 suffix = "-DTLS"
1078 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001079 if async {
David Benjamin6fd297b2014-08-11 18:43:38 -04001080 suffix += "-Async"
David Benjamin43ec06f2014-08-05 02:28:57 -04001081 flags = append(flags, "-async")
1082 } else {
David Benjamin6fd297b2014-08-11 18:43:38 -04001083 suffix += "-Sync"
David Benjamin43ec06f2014-08-05 02:28:57 -04001084 }
1085 if splitHandshake {
1086 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -04001087 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -04001088 }
1089
1090 // Basic handshake, with resumption. Client and server.
1091 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001092 protocol: protocol,
1093 name: "Basic-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001094 config: Config{
1095 Bugs: ProtocolBugs{
1096 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1097 },
1098 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001099 flags: flags,
1100 resumeSession: true,
1101 })
1102 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001103 protocol: protocol,
1104 name: "Basic-Client-RenewTicket" + suffix,
David Benjaminbed9aae2014-08-07 19:13:38 -04001105 config: Config{
1106 Bugs: ProtocolBugs{
1107 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1108 RenewTicketOnResume: true,
1109 },
1110 },
1111 flags: flags,
1112 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001113 })
1114 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001115 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001116 testType: serverTest,
1117 name: "Basic-Server" + suffix,
1118 config: Config{
1119 Bugs: ProtocolBugs{
1120 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1121 },
1122 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001123 flags: flags,
1124 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001125 })
1126
David Benjamin6fd297b2014-08-11 18:43:38 -04001127 // TLS client auth.
1128 testCases = append(testCases, testCase{
1129 protocol: protocol,
1130 testType: clientTest,
1131 name: "ClientAuth-Client" + suffix,
1132 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001133 ClientAuth: RequireAnyClientCert,
David Benjamin6fd297b2014-08-11 18:43:38 -04001134 Bugs: ProtocolBugs{
1135 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1136 },
1137 },
1138 flags: append(flags,
1139 "-cert-file", rsaCertificateFile,
1140 "-key-file", rsaKeyFile),
1141 })
1142 testCases = append(testCases, testCase{
1143 protocol: protocol,
1144 testType: serverTest,
1145 name: "ClientAuth-Server" + suffix,
1146 config: Config{
1147 Certificates: []Certificate{rsaCertificate},
1148 },
1149 flags: append(flags, "-require-any-client-certificate"),
1150 })
1151
David Benjamin43ec06f2014-08-05 02:28:57 -04001152 // No session ticket support; server doesn't send NewSessionTicket.
1153 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001154 protocol: protocol,
1155 name: "SessionTicketsDisabled-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001156 config: Config{
1157 SessionTicketsDisabled: true,
1158 Bugs: ProtocolBugs{
1159 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1160 },
1161 },
1162 flags: flags,
1163 })
1164 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001165 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001166 testType: serverTest,
1167 name: "SessionTicketsDisabled-Server" + suffix,
1168 config: Config{
1169 SessionTicketsDisabled: true,
1170 Bugs: ProtocolBugs{
1171 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1172 },
1173 },
1174 flags: flags,
1175 })
1176
David Benjamin6fd297b2014-08-11 18:43:38 -04001177 if protocol == tls {
1178 // NPN on client and server; results in post-handshake message.
1179 testCases = append(testCases, testCase{
1180 protocol: protocol,
1181 name: "NPN-Client" + suffix,
1182 config: Config{
David Benjaminae2888f2014-09-06 12:58:58 -04001183 NextProtos: []string{"foo"},
David Benjamin6fd297b2014-08-11 18:43:38 -04001184 Bugs: ProtocolBugs{
1185 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1186 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001187 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001188 flags: append(flags, "-select-next-proto", "foo"),
1189 expectedNextProto: "foo",
1190 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001191 })
1192 testCases = append(testCases, testCase{
1193 protocol: protocol,
1194 testType: serverTest,
1195 name: "NPN-Server" + suffix,
1196 config: Config{
1197 NextProtos: []string{"bar"},
1198 Bugs: ProtocolBugs{
1199 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1200 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001201 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001202 flags: append(flags,
1203 "-advertise-npn", "\x03foo\x03bar\x03baz",
1204 "-expect-next-proto", "bar"),
David Benjaminfc7b0862014-09-06 13:21:53 -04001205 expectedNextProto: "bar",
1206 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001207 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001208
David Benjamin6fd297b2014-08-11 18:43:38 -04001209 // Client does False Start and negotiates NPN.
1210 testCases = append(testCases, testCase{
1211 protocol: protocol,
1212 name: "FalseStart" + suffix,
1213 config: Config{
1214 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1215 NextProtos: []string{"foo"},
1216 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001217 ExpectFalseStart: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001218 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1219 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001220 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001221 flags: append(flags,
1222 "-false-start",
1223 "-select-next-proto", "foo"),
David Benjamine58c4f52014-08-24 03:47:07 -04001224 shimWritesFirst: true,
1225 resumeSession: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001226 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001227
David Benjaminae2888f2014-09-06 12:58:58 -04001228 // Client does False Start and negotiates ALPN.
1229 testCases = append(testCases, testCase{
1230 protocol: protocol,
1231 name: "FalseStart-ALPN" + suffix,
1232 config: Config{
1233 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1234 NextProtos: []string{"foo"},
1235 Bugs: ProtocolBugs{
1236 ExpectFalseStart: true,
1237 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1238 },
1239 },
1240 flags: append(flags,
1241 "-false-start",
1242 "-advertise-alpn", "\x03foo"),
1243 shimWritesFirst: true,
1244 resumeSession: true,
1245 })
1246
David Benjamin6fd297b2014-08-11 18:43:38 -04001247 // False Start without session tickets.
1248 testCases = append(testCases, testCase{
1249 name: "FalseStart-SessionTicketsDisabled",
1250 config: Config{
1251 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1252 NextProtos: []string{"foo"},
1253 SessionTicketsDisabled: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001254 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001255 ExpectFalseStart: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001256 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1257 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001258 },
David Benjamin4e99c522014-08-24 01:45:30 -04001259 flags: append(flags,
David Benjamin6fd297b2014-08-11 18:43:38 -04001260 "-false-start",
1261 "-select-next-proto", "foo",
David Benjamin4e99c522014-08-24 01:45:30 -04001262 ),
David Benjamine58c4f52014-08-24 03:47:07 -04001263 shimWritesFirst: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001264 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001265
David Benjamina08e49d2014-08-24 01:46:07 -04001266 // Server parses a V2ClientHello.
David Benjamin6fd297b2014-08-11 18:43:38 -04001267 testCases = append(testCases, testCase{
1268 protocol: protocol,
1269 testType: serverTest,
1270 name: "SendV2ClientHello" + suffix,
1271 config: Config{
1272 // Choose a cipher suite that does not involve
1273 // elliptic curves, so no extensions are
1274 // involved.
1275 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1276 Bugs: ProtocolBugs{
1277 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1278 SendV2ClientHello: true,
1279 },
David Benjamin1e7f8d72014-08-08 12:27:04 -04001280 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001281 flags: flags,
1282 })
David Benjamina08e49d2014-08-24 01:46:07 -04001283
1284 // Client sends a Channel ID.
1285 testCases = append(testCases, testCase{
1286 protocol: protocol,
1287 name: "ChannelID-Client" + suffix,
1288 config: Config{
1289 RequestChannelID: true,
1290 Bugs: ProtocolBugs{
1291 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1292 },
1293 },
1294 flags: append(flags,
1295 "-send-channel-id", channelIDKeyFile,
1296 ),
1297 resumeSession: true,
1298 expectChannelID: true,
1299 })
1300
1301 // Server accepts a Channel ID.
1302 testCases = append(testCases, testCase{
1303 protocol: protocol,
1304 testType: serverTest,
1305 name: "ChannelID-Server" + suffix,
1306 config: Config{
1307 ChannelID: channelIDKey,
1308 Bugs: ProtocolBugs{
1309 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1310 },
1311 },
1312 flags: append(flags,
1313 "-expect-channel-id",
1314 base64.StdEncoding.EncodeToString(channelIDBytes),
1315 ),
1316 resumeSession: true,
1317 expectChannelID: true,
1318 })
David Benjamin6fd297b2014-08-11 18:43:38 -04001319 } else {
1320 testCases = append(testCases, testCase{
1321 protocol: protocol,
1322 name: "SkipHelloVerifyRequest" + suffix,
1323 config: Config{
1324 Bugs: ProtocolBugs{
1325 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1326 SkipHelloVerifyRequest: true,
1327 },
1328 },
1329 flags: flags,
1330 })
1331
1332 testCases = append(testCases, testCase{
1333 testType: serverTest,
1334 protocol: protocol,
1335 name: "CookieExchange" + suffix,
1336 config: Config{
1337 Bugs: ProtocolBugs{
1338 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1339 },
1340 },
1341 flags: append(flags, "-cookie-exchange"),
1342 })
1343 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001344}
1345
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001346func addVersionNegotiationTests() {
1347 for i, shimVers := range tlsVersions {
1348 // Assemble flags to disable all newer versions on the shim.
1349 var flags []string
1350 for _, vers := range tlsVersions[i+1:] {
1351 flags = append(flags, vers.flag)
1352 }
1353
1354 for _, runnerVers := range tlsVersions {
1355 expectedVersion := shimVers.version
1356 if runnerVers.version < shimVers.version {
1357 expectedVersion = runnerVers.version
1358 }
1359 suffix := shimVers.name + "-" + runnerVers.name
1360
1361 testCases = append(testCases, testCase{
1362 testType: clientTest,
1363 name: "VersionNegotiation-Client-" + suffix,
1364 config: Config{
1365 MaxVersion: runnerVers.version,
1366 },
1367 flags: flags,
1368 expectedVersion: expectedVersion,
1369 })
1370
David Benjamin76d8abe2014-08-14 16:25:34 -04001371 testCases = append(testCases, testCase{
1372 testType: serverTest,
1373 name: "VersionNegotiation-Server-" + suffix,
1374 config: Config{
1375 MaxVersion: runnerVers.version,
1376 },
1377 flags: flags,
1378 expectedVersion: expectedVersion,
1379 })
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001380 }
1381 }
1382}
1383
David Benjamin5c24a1d2014-08-31 00:59:27 -04001384func addD5BugTests() {
1385 testCases = append(testCases, testCase{
1386 testType: serverTest,
1387 name: "D5Bug-NoQuirk-Reject",
1388 config: Config{
1389 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1390 Bugs: ProtocolBugs{
1391 SSL3RSAKeyExchange: true,
1392 },
1393 },
1394 shouldFail: true,
1395 expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
1396 })
1397 testCases = append(testCases, testCase{
1398 testType: serverTest,
1399 name: "D5Bug-Quirk-Normal",
1400 config: Config{
1401 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1402 },
1403 flags: []string{"-tls-d5-bug"},
1404 })
1405 testCases = append(testCases, testCase{
1406 testType: serverTest,
1407 name: "D5Bug-Quirk-Bug",
1408 config: Config{
1409 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1410 Bugs: ProtocolBugs{
1411 SSL3RSAKeyExchange: true,
1412 },
1413 },
1414 flags: []string{"-tls-d5-bug"},
1415 })
1416}
1417
David Benjamine78bfde2014-09-06 12:45:15 -04001418func addExtensionTests() {
1419 testCases = append(testCases, testCase{
1420 testType: clientTest,
1421 name: "DuplicateExtensionClient",
1422 config: Config{
1423 Bugs: ProtocolBugs{
1424 DuplicateExtension: true,
1425 },
1426 },
1427 shouldFail: true,
1428 expectedLocalError: "remote error: error decoding message",
1429 })
1430 testCases = append(testCases, testCase{
1431 testType: serverTest,
1432 name: "DuplicateExtensionServer",
1433 config: Config{
1434 Bugs: ProtocolBugs{
1435 DuplicateExtension: true,
1436 },
1437 },
1438 shouldFail: true,
1439 expectedLocalError: "remote error: error decoding message",
1440 })
1441 testCases = append(testCases, testCase{
1442 testType: clientTest,
1443 name: "ServerNameExtensionClient",
1444 config: Config{
1445 Bugs: ProtocolBugs{
1446 ExpectServerName: "example.com",
1447 },
1448 },
1449 flags: []string{"-host-name", "example.com"},
1450 })
1451 testCases = append(testCases, testCase{
1452 testType: clientTest,
1453 name: "ServerNameExtensionClient",
1454 config: Config{
1455 Bugs: ProtocolBugs{
1456 ExpectServerName: "mismatch.com",
1457 },
1458 },
1459 flags: []string{"-host-name", "example.com"},
1460 shouldFail: true,
1461 expectedLocalError: "tls: unexpected server name",
1462 })
1463 testCases = append(testCases, testCase{
1464 testType: clientTest,
1465 name: "ServerNameExtensionClient",
1466 config: Config{
1467 Bugs: ProtocolBugs{
1468 ExpectServerName: "missing.com",
1469 },
1470 },
1471 shouldFail: true,
1472 expectedLocalError: "tls: unexpected server name",
1473 })
1474 testCases = append(testCases, testCase{
1475 testType: serverTest,
1476 name: "ServerNameExtensionServer",
1477 config: Config{
1478 ServerName: "example.com",
1479 },
1480 flags: []string{"-expect-server-name", "example.com"},
1481 resumeSession: true,
1482 })
David Benjaminae2888f2014-09-06 12:58:58 -04001483 testCases = append(testCases, testCase{
1484 testType: clientTest,
1485 name: "ALPNClient",
1486 config: Config{
1487 NextProtos: []string{"foo"},
1488 },
1489 flags: []string{
1490 "-advertise-alpn", "\x03foo\x03bar\x03baz",
1491 "-expect-alpn", "foo",
1492 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001493 expectedNextProto: "foo",
1494 expectedNextProtoType: alpn,
1495 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001496 })
1497 testCases = append(testCases, testCase{
1498 testType: serverTest,
1499 name: "ALPNServer",
1500 config: Config{
1501 NextProtos: []string{"foo", "bar", "baz"},
1502 },
1503 flags: []string{
1504 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1505 "-select-alpn", "foo",
1506 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001507 expectedNextProto: "foo",
1508 expectedNextProtoType: alpn,
1509 resumeSession: true,
1510 })
1511 // Test that the server prefers ALPN over NPN.
1512 testCases = append(testCases, testCase{
1513 testType: serverTest,
1514 name: "ALPNServer-Preferred",
1515 config: Config{
1516 NextProtos: []string{"foo", "bar", "baz"},
1517 },
1518 flags: []string{
1519 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1520 "-select-alpn", "foo",
1521 "-advertise-npn", "\x03foo\x03bar\x03baz",
1522 },
1523 expectedNextProto: "foo",
1524 expectedNextProtoType: alpn,
1525 resumeSession: true,
1526 })
1527 testCases = append(testCases, testCase{
1528 testType: serverTest,
1529 name: "ALPNServer-Preferred-Swapped",
1530 config: Config{
1531 NextProtos: []string{"foo", "bar", "baz"},
1532 Bugs: ProtocolBugs{
1533 SwapNPNAndALPN: true,
1534 },
1535 },
1536 flags: []string{
1537 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1538 "-select-alpn", "foo",
1539 "-advertise-npn", "\x03foo\x03bar\x03baz",
1540 },
1541 expectedNextProto: "foo",
1542 expectedNextProtoType: alpn,
1543 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001544 })
David Benjamine78bfde2014-09-06 12:45:15 -04001545}
1546
David Benjamin01fe8202014-09-24 15:21:44 -04001547func addResumptionVersionTests() {
1548 // TODO(davidben): Once DTLS 1.2 is working, test that as well.
1549 for _, sessionVers := range tlsVersions {
1550 // TODO(davidben): SSLv3 is omitted here because runner does not
1551 // support resumption with session IDs.
1552 if sessionVers.version == VersionSSL30 {
1553 continue
1554 }
1555 for _, resumeVers := range tlsVersions {
1556 if resumeVers.version == VersionSSL30 {
1557 continue
1558 }
1559 suffix := "-" + sessionVers.name + "-" + resumeVers.name
1560
1561 // TODO(davidben): Write equivalent tests for the server
1562 // and clean up the server's logic. This requires being
1563 // able to give the shim a different set of SSL_OP_NO_*
1564 // flags between the initial connection and the
1565 // resume. Perhaps resumption should be tested by
1566 // serializing the SSL_SESSION and starting a second
1567 // shim.
1568 testCases = append(testCases, testCase{
1569 name: "Resume-Client" + suffix,
1570 resumeSession: true,
1571 config: Config{
1572 MaxVersion: sessionVers.version,
1573 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1574 Bugs: ProtocolBugs{
1575 AllowSessionVersionMismatch: true,
1576 },
1577 },
1578 expectedVersion: sessionVers.version,
1579 resumeConfig: &Config{
1580 MaxVersion: resumeVers.version,
1581 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1582 Bugs: ProtocolBugs{
1583 AllowSessionVersionMismatch: true,
1584 },
1585 },
1586 expectedResumeVersion: resumeVers.version,
1587 })
1588
1589 testCases = append(testCases, testCase{
1590 name: "Resume-Client-NoResume" + suffix,
1591 flags: []string{"-expect-session-miss"},
1592 resumeSession: true,
1593 config: Config{
1594 MaxVersion: sessionVers.version,
1595 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1596 },
1597 expectedVersion: sessionVers.version,
1598 resumeConfig: &Config{
1599 MaxVersion: resumeVers.version,
1600 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1601 SessionTicketsDisabled: true,
1602 },
1603 expectedResumeVersion: resumeVers.version,
1604 })
1605 }
1606 }
1607}
1608
David Benjamin884fdf12014-08-02 15:28:23 -04001609func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07001610 defer wg.Done()
1611
1612 for test := range c {
1613 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04001614 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07001615 statusChan <- statusMsg{test: test, err: err}
1616 }
1617}
1618
1619type statusMsg struct {
1620 test *testCase
1621 started bool
1622 err error
1623}
1624
1625func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1626 var started, done, failed, lineLen int
1627 defer close(doneChan)
1628
1629 for msg := range statusChan {
1630 if msg.started {
1631 started++
1632 } else {
1633 done++
1634 }
1635
1636 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1637
1638 if msg.err != nil {
1639 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1640 failed++
1641 }
1642 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1643 lineLen = len(line)
1644 os.Stdout.WriteString(line)
1645 }
1646}
1647
1648func main() {
1649 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 -04001650 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04001651 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07001652
1653 flag.Parse()
1654
1655 addCipherSuiteTests()
1656 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07001657 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07001658 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04001659 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001660 addVersionNegotiationTests()
David Benjamin5c24a1d2014-08-31 00:59:27 -04001661 addD5BugTests()
David Benjamine78bfde2014-09-06 12:45:15 -04001662 addExtensionTests()
David Benjamin01fe8202014-09-24 15:21:44 -04001663 addResumptionVersionTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04001664 for _, async := range []bool{false, true} {
1665 for _, splitHandshake := range []bool{false, true} {
David Benjamin6fd297b2014-08-11 18:43:38 -04001666 for _, protocol := range []protocol{tls, dtls} {
1667 addStateMachineCoverageTests(async, splitHandshake, protocol)
1668 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001669 }
1670 }
Adam Langley95c29f32014-06-20 12:00:00 -07001671
1672 var wg sync.WaitGroup
1673
David Benjamin2bc8e6f2014-08-02 15:22:37 -04001674 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07001675
1676 statusChan := make(chan statusMsg, numWorkers)
1677 testChan := make(chan *testCase, numWorkers)
1678 doneChan := make(chan struct{})
1679
David Benjamin025b3d32014-07-01 19:53:04 -04001680 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07001681
1682 for i := 0; i < numWorkers; i++ {
1683 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04001684 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07001685 }
1686
David Benjamin025b3d32014-07-01 19:53:04 -04001687 for i := range testCases {
1688 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
1689 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07001690 }
1691 }
1692
1693 close(testChan)
1694 wg.Wait()
1695 close(statusChan)
1696 <-doneChan
1697
1698 fmt.Printf("\n")
1699}