blob: dca0479b77306731f942e12894453f1177d07f36 [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
David Benjaminca6c8262014-11-15 19:06:08 -0500132 // expectedSRTPProtectionProfile is the DTLS-SRTP profile that
133 // should be negotiated. If zero, none should be negotiated.
134 expectedSRTPProtectionProfile uint16
Adam Langley80842bd2014-06-20 12:00:00 -0700135 // messageLen is the length, in bytes, of the test message that will be
136 // sent.
137 messageLen int
David Benjamin025b3d32014-07-01 19:53:04 -0400138 // certFile is the path to the certificate to use for the server.
139 certFile string
140 // keyFile is the path to the private key to use for the server.
141 keyFile string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400142 // resumeSession controls whether a second connection should be tested
David Benjamin01fe8202014-09-24 15:21:44 -0400143 // which attempts to resume the first session.
David Benjamin1d5c83e2014-07-22 19:20:02 -0400144 resumeSession bool
David Benjamin01fe8202014-09-24 15:21:44 -0400145 // resumeConfig, if not nil, points to a Config to be used on
146 // resumption. SessionTicketKey and ClientSessionCache are copied from
147 // the initial connection's config. If nil, the initial connection's
148 // config is used.
149 resumeConfig *Config
David Benjamin98e882e2014-08-08 13:24:34 -0400150 // sendPrefix sends a prefix on the socket before actually performing a
151 // handshake.
152 sendPrefix string
David Benjamine58c4f52014-08-24 03:47:07 -0400153 // shimWritesFirst controls whether the shim sends an initial "hello"
154 // message before doing a roundtrip with the runner.
155 shimWritesFirst bool
Adam Langleycf2d4f42014-10-28 19:06:14 -0700156 // renegotiate indicates the the connection should be renegotiated
157 // during the exchange.
158 renegotiate bool
159 // renegotiateCiphers is a list of ciphersuite ids that will be
160 // switched in just before renegotiation.
161 renegotiateCiphers []uint16
David Benjamin5e961c12014-11-07 01:48:35 -0500162 // replayWrites, if true, configures the underlying transport
163 // to replay every write it makes in DTLS tests.
164 replayWrites bool
David Benjamin325b5c32014-07-01 19:40:31 -0400165 // flags, if not empty, contains a list of command-line flags that will
166 // be passed to the shim program.
167 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -0700168}
169
David Benjamin025b3d32014-07-01 19:53:04 -0400170var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700171 {
172 name: "BadRSASignature",
173 config: Config{
174 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
175 Bugs: ProtocolBugs{
176 InvalidSKXSignature: true,
177 },
178 },
179 shouldFail: true,
180 expectedError: ":BAD_SIGNATURE:",
181 },
182 {
183 name: "BadECDSASignature",
184 config: Config{
185 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
186 Bugs: ProtocolBugs{
187 InvalidSKXSignature: true,
188 },
189 Certificates: []Certificate{getECDSACertificate()},
190 },
191 shouldFail: true,
192 expectedError: ":BAD_SIGNATURE:",
193 },
194 {
195 name: "BadECDSACurve",
196 config: Config{
197 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
198 Bugs: ProtocolBugs{
199 InvalidSKXCurve: true,
200 },
201 Certificates: []Certificate{getECDSACertificate()},
202 },
203 shouldFail: true,
204 expectedError: ":WRONG_CURVE:",
205 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700206 {
David Benjamina8e3e0e2014-08-06 22:11:10 -0400207 testType: serverTest,
208 name: "BadRSAVersion",
209 config: Config{
210 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
211 Bugs: ProtocolBugs{
212 RsaClientKeyExchangeVersion: VersionTLS11,
213 },
214 },
215 shouldFail: true,
216 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
217 },
218 {
David Benjamin325b5c32014-07-01 19:40:31 -0400219 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700220 config: Config{
221 Bugs: ProtocolBugs{
222 FailIfNotFallbackSCSV: true,
223 },
224 },
225 shouldFail: true,
226 expectedLocalError: "no fallback SCSV found",
227 },
David Benjamin325b5c32014-07-01 19:40:31 -0400228 {
David Benjamin2a0c4962014-08-22 23:46:35 -0400229 name: "SendFallbackSCSV",
David Benjamin325b5c32014-07-01 19:40:31 -0400230 config: Config{
231 Bugs: ProtocolBugs{
232 FailIfNotFallbackSCSV: true,
233 },
234 },
235 flags: []string{"-fallback-scsv"},
236 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400237 {
David Benjamin7b030512014-07-08 17:30:11 -0400238 name: "ClientCertificateTypes",
239 config: Config{
240 ClientAuth: RequestClientCert,
241 ClientCertificateTypes: []byte{
242 CertTypeDSSSign,
243 CertTypeRSASign,
244 CertTypeECDSASign,
245 },
246 },
David Benjamin2561dc32014-08-24 01:25:27 -0400247 flags: []string{
248 "-expect-certificate-types",
249 base64.StdEncoding.EncodeToString([]byte{
250 CertTypeDSSSign,
251 CertTypeRSASign,
252 CertTypeECDSASign,
253 }),
254 },
David Benjamin7b030512014-07-08 17:30:11 -0400255 },
David Benjamin636293b2014-07-08 17:59:18 -0400256 {
257 name: "NoClientCertificate",
258 config: Config{
259 ClientAuth: RequireAnyClientCert,
260 },
261 shouldFail: true,
262 expectedLocalError: "client didn't provide a certificate",
263 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400264 {
265 name: "UnauthenticatedECDH",
266 config: Config{
267 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
268 Bugs: ProtocolBugs{
269 UnauthenticatedECDH: true,
270 },
271 },
272 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400273 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400274 },
David Benjamin9c651c92014-07-12 13:27:45 -0400275 {
276 name: "SkipServerKeyExchange",
277 config: Config{
278 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
279 Bugs: ProtocolBugs{
280 SkipServerKeyExchange: true,
281 },
282 },
283 shouldFail: true,
284 expectedError: ":UNEXPECTED_MESSAGE:",
285 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400286 {
David Benjamina0e52232014-07-19 17:39:58 -0400287 name: "SkipChangeCipherSpec-Client",
288 config: Config{
289 Bugs: ProtocolBugs{
290 SkipChangeCipherSpec: true,
291 },
292 },
293 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400294 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400295 },
296 {
297 testType: serverTest,
298 name: "SkipChangeCipherSpec-Server",
299 config: Config{
300 Bugs: ProtocolBugs{
301 SkipChangeCipherSpec: true,
302 },
303 },
304 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400305 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400306 },
David Benjamin42be6452014-07-21 14:50:23 -0400307 {
308 testType: serverTest,
309 name: "SkipChangeCipherSpec-Server-NPN",
310 config: Config{
311 NextProtos: []string{"bar"},
312 Bugs: ProtocolBugs{
313 SkipChangeCipherSpec: true,
314 },
315 },
316 flags: []string{
317 "-advertise-npn", "\x03foo\x03bar\x03baz",
318 },
319 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400320 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
321 },
322 {
323 name: "FragmentAcrossChangeCipherSpec-Client",
324 config: Config{
325 Bugs: ProtocolBugs{
326 FragmentAcrossChangeCipherSpec: true,
327 },
328 },
329 shouldFail: true,
330 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
331 },
332 {
333 testType: serverTest,
334 name: "FragmentAcrossChangeCipherSpec-Server",
335 config: Config{
336 Bugs: ProtocolBugs{
337 FragmentAcrossChangeCipherSpec: true,
338 },
339 },
340 shouldFail: true,
341 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
342 },
343 {
344 testType: serverTest,
345 name: "FragmentAcrossChangeCipherSpec-Server-NPN",
346 config: Config{
347 NextProtos: []string{"bar"},
348 Bugs: ProtocolBugs{
349 FragmentAcrossChangeCipherSpec: true,
350 },
351 },
352 flags: []string{
353 "-advertise-npn", "\x03foo\x03bar\x03baz",
354 },
355 shouldFail: true,
356 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamin42be6452014-07-21 14:50:23 -0400357 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400358 {
359 testType: serverTest,
Alex Chernyakhovsky4cd8c432014-11-01 19:39:08 -0400360 name: "FragmentAlert",
361 config: Config{
362 Bugs: ProtocolBugs{
David Benjaminca6c8262014-11-15 19:06:08 -0500363 FragmentAlert: true,
Alex Chernyakhovsky4cd8c432014-11-01 19:39:08 -0400364 SendSpuriousAlert: true,
365 },
366 },
367 shouldFail: true,
368 expectedError: ":BAD_ALERT:",
369 },
370 {
371 testType: serverTest,
David Benjaminf3ec83d2014-07-21 22:42:34 -0400372 name: "EarlyChangeCipherSpec-server-1",
373 config: Config{
374 Bugs: ProtocolBugs{
375 EarlyChangeCipherSpec: 1,
376 },
377 },
378 shouldFail: true,
379 expectedError: ":CCS_RECEIVED_EARLY:",
380 },
381 {
382 testType: serverTest,
383 name: "EarlyChangeCipherSpec-server-2",
384 config: Config{
385 Bugs: ProtocolBugs{
386 EarlyChangeCipherSpec: 2,
387 },
388 },
389 shouldFail: true,
390 expectedError: ":CCS_RECEIVED_EARLY:",
391 },
David Benjamind23f4122014-07-23 15:09:48 -0400392 {
David Benjamind23f4122014-07-23 15:09:48 -0400393 name: "SkipNewSessionTicket",
394 config: Config{
395 Bugs: ProtocolBugs{
396 SkipNewSessionTicket: true,
397 },
398 },
399 shouldFail: true,
400 expectedError: ":CCS_RECEIVED_EARLY:",
401 },
David Benjamin7e3305e2014-07-28 14:52:32 -0400402 {
David Benjamind86c7672014-08-02 04:07:12 -0400403 testType: serverTest,
David Benjaminbef270a2014-08-02 04:22:02 -0400404 name: "FallbackSCSV",
405 config: Config{
406 MaxVersion: VersionTLS11,
407 Bugs: ProtocolBugs{
408 SendFallbackSCSV: true,
409 },
410 },
411 shouldFail: true,
412 expectedError: ":INAPPROPRIATE_FALLBACK:",
413 },
414 {
415 testType: serverTest,
416 name: "FallbackSCSV-VersionMatch",
417 config: Config{
418 Bugs: ProtocolBugs{
419 SendFallbackSCSV: true,
420 },
421 },
422 },
David Benjamin98214542014-08-07 18:02:39 -0400423 {
424 testType: serverTest,
425 name: "FragmentedClientVersion",
426 config: Config{
427 Bugs: ProtocolBugs{
428 MaxHandshakeRecordLength: 1,
429 FragmentClientVersion: true,
430 },
431 },
432 shouldFail: true,
433 expectedError: ":RECORD_TOO_SMALL:",
434 },
David Benjamin98e882e2014-08-08 13:24:34 -0400435 {
436 testType: serverTest,
437 name: "MinorVersionTolerance",
438 config: Config{
439 Bugs: ProtocolBugs{
440 SendClientVersion: 0x03ff,
441 },
442 },
443 expectedVersion: VersionTLS12,
444 },
445 {
446 testType: serverTest,
447 name: "MajorVersionTolerance",
448 config: Config{
449 Bugs: ProtocolBugs{
450 SendClientVersion: 0x0400,
451 },
452 },
453 expectedVersion: VersionTLS12,
454 },
455 {
456 testType: serverTest,
457 name: "VersionTooLow",
458 config: Config{
459 Bugs: ProtocolBugs{
460 SendClientVersion: 0x0200,
461 },
462 },
463 shouldFail: true,
464 expectedError: ":UNSUPPORTED_PROTOCOL:",
465 },
466 {
467 testType: serverTest,
468 name: "HttpGET",
469 sendPrefix: "GET / HTTP/1.0\n",
470 shouldFail: true,
471 expectedError: ":HTTP_REQUEST:",
472 },
473 {
474 testType: serverTest,
475 name: "HttpPOST",
476 sendPrefix: "POST / HTTP/1.0\n",
477 shouldFail: true,
478 expectedError: ":HTTP_REQUEST:",
479 },
480 {
481 testType: serverTest,
482 name: "HttpHEAD",
483 sendPrefix: "HEAD / HTTP/1.0\n",
484 shouldFail: true,
485 expectedError: ":HTTP_REQUEST:",
486 },
487 {
488 testType: serverTest,
489 name: "HttpPUT",
490 sendPrefix: "PUT / HTTP/1.0\n",
491 shouldFail: true,
492 expectedError: ":HTTP_REQUEST:",
493 },
494 {
495 testType: serverTest,
496 name: "HttpCONNECT",
497 sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
498 shouldFail: true,
499 expectedError: ":HTTPS_PROXY_REQUEST:",
500 },
David Benjamin39ebf532014-08-31 02:23:49 -0400501 {
502 name: "SkipCipherVersionCheck",
503 config: Config{
504 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
505 MaxVersion: VersionTLS11,
506 Bugs: ProtocolBugs{
507 SkipCipherVersionCheck: true,
508 },
509 },
510 shouldFail: true,
511 expectedError: ":WRONG_CIPHER_RETURNED:",
512 },
David Benjamin9114fae2014-11-08 11:41:14 -0500513 {
514 name: "RSAServerKeyExchange",
515 config: Config{
516 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
517 Bugs: ProtocolBugs{
518 RSAServerKeyExchange: true,
519 },
520 },
521 shouldFail: true,
522 expectedError: ":UNEXPECTED_MESSAGE:",
523 },
Adam Langley95c29f32014-06-20 12:00:00 -0700524}
525
David Benjamin01fe8202014-09-24 15:21:44 -0400526func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
David Benjamin6fd297b2014-08-11 18:43:38 -0400527 if test.protocol == dtls {
528 conn = newPacketAdaptor(conn)
David Benjamin5e961c12014-11-07 01:48:35 -0500529 if test.replayWrites {
530 conn = newReplayAdaptor(conn)
531 }
David Benjamin6fd297b2014-08-11 18:43:38 -0400532 }
533
534 if test.sendPrefix != "" {
535 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
536 return err
537 }
David Benjamin98e882e2014-08-08 13:24:34 -0400538 }
539
David Benjamin1d5c83e2014-07-22 19:20:02 -0400540 var tlsConn *Conn
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400541 if test.testType == clientTest {
David Benjamin6fd297b2014-08-11 18:43:38 -0400542 if test.protocol == dtls {
543 tlsConn = DTLSServer(conn, config)
544 } else {
545 tlsConn = Server(conn, config)
546 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400547 } else {
548 config.InsecureSkipVerify = true
David Benjamin6fd297b2014-08-11 18:43:38 -0400549 if test.protocol == dtls {
550 tlsConn = DTLSClient(conn, config)
551 } else {
552 tlsConn = Client(conn, config)
553 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400554 }
555
Adam Langley95c29f32014-06-20 12:00:00 -0700556 if err := tlsConn.Handshake(); err != nil {
557 return err
558 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700559
David Benjamin01fe8202014-09-24 15:21:44 -0400560 // TODO(davidben): move all per-connection expectations into a dedicated
561 // expectations struct that can be specified separately for the two
562 // legs.
563 expectedVersion := test.expectedVersion
564 if isResume && test.expectedResumeVersion != 0 {
565 expectedVersion = test.expectedResumeVersion
566 }
567 if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
568 return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400569 }
570
David Benjamina08e49d2014-08-24 01:46:07 -0400571 if test.expectChannelID {
572 channelID := tlsConn.ConnectionState().ChannelID
573 if channelID == nil {
574 return fmt.Errorf("no channel ID negotiated")
575 }
576 if channelID.Curve != channelIDKey.Curve ||
577 channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
578 channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
579 return fmt.Errorf("incorrect channel ID")
580 }
581 }
582
David Benjaminae2888f2014-09-06 12:58:58 -0400583 if expected := test.expectedNextProto; expected != "" {
584 if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
585 return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
586 }
587 }
588
David Benjaminfc7b0862014-09-06 13:21:53 -0400589 if test.expectedNextProtoType != 0 {
590 if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN {
591 return fmt.Errorf("next proto type mismatch")
592 }
593 }
594
David Benjaminca6c8262014-11-15 19:06:08 -0500595 if p := tlsConn.ConnectionState().SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile {
596 return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile)
597 }
598
David Benjamine58c4f52014-08-24 03:47:07 -0400599 if test.shimWritesFirst {
600 var buf [5]byte
601 _, err := io.ReadFull(tlsConn, buf[:])
602 if err != nil {
603 return err
604 }
605 if string(buf[:]) != "hello" {
606 return fmt.Errorf("bad initial message")
607 }
608 }
609
Adam Langleycf2d4f42014-10-28 19:06:14 -0700610 if test.renegotiate {
611 if test.renegotiateCiphers != nil {
612 config.CipherSuites = test.renegotiateCiphers
613 }
614 if err := tlsConn.Renegotiate(); err != nil {
615 return err
616 }
617 } else if test.renegotiateCiphers != nil {
618 panic("renegotiateCiphers without renegotiate")
619 }
620
Kenny Root7fdeaf12014-08-05 15:23:37 -0700621 if messageLen < 0 {
David Benjamin6fd297b2014-08-11 18:43:38 -0400622 if test.protocol == dtls {
623 return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
624 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700625 // Read until EOF.
626 _, err := io.Copy(ioutil.Discard, tlsConn)
627 return err
628 }
629
Adam Langley80842bd2014-06-20 12:00:00 -0700630 if messageLen == 0 {
631 messageLen = 32
632 }
633 testMessage := make([]byte, messageLen)
634 for i := range testMessage {
635 testMessage[i] = 0x42
636 }
Adam Langley95c29f32014-06-20 12:00:00 -0700637 tlsConn.Write(testMessage)
638
639 buf := make([]byte, len(testMessage))
David Benjamin6fd297b2014-08-11 18:43:38 -0400640 if test.protocol == dtls {
641 bufTmp := make([]byte, len(buf)+1)
642 n, err := tlsConn.Read(bufTmp)
643 if err != nil {
644 return err
645 }
646 if n != len(buf) {
647 return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
648 }
649 copy(buf, bufTmp)
650 } else {
651 _, err := io.ReadFull(tlsConn, buf)
652 if err != nil {
653 return err
654 }
Adam Langley95c29f32014-06-20 12:00:00 -0700655 }
656
657 for i, v := range buf {
658 if v != testMessage[i]^0xff {
659 return fmt.Errorf("bad reply contents at byte %d", i)
660 }
661 }
662
663 return nil
664}
665
David Benjamin325b5c32014-07-01 19:40:31 -0400666func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
667 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700668 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400669 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700670 }
David Benjamin325b5c32014-07-01 19:40:31 -0400671 valgrindArgs = append(valgrindArgs, path)
672 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700673
David Benjamin325b5c32014-07-01 19:40:31 -0400674 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700675}
676
David Benjamin325b5c32014-07-01 19:40:31 -0400677func gdbOf(path string, args ...string) *exec.Cmd {
678 xtermArgs := []string{"-e", "gdb", "--args"}
679 xtermArgs = append(xtermArgs, path)
680 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700681
David Benjamin325b5c32014-07-01 19:40:31 -0400682 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700683}
684
David Benjamin1d5c83e2014-07-22 19:20:02 -0400685func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700686 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
687 if err != nil {
688 panic(err)
689 }
690
691 syscall.CloseOnExec(socks[0])
692 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400693 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700694 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400695 conn, err = net.FileConn(connFile)
696 if err != nil {
697 panic(err)
698 }
Adam Langley95c29f32014-06-20 12:00:00 -0700699 connFile.Close()
700 if err != nil {
701 panic(err)
702 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400703 return shimEnd, conn
704}
705
David Benjamin884fdf12014-08-02 15:28:23 -0400706func runTest(test *testCase, buildDir string) error {
Adam Langley38311732014-10-16 19:04:35 -0700707 if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
708 panic("Error expected without shouldFail in " + test.name)
709 }
710
David Benjamin1d5c83e2014-07-22 19:20:02 -0400711 shimEnd, conn := openSocketPair()
712 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700713
David Benjamin884fdf12014-08-02 15:28:23 -0400714 shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
David Benjamin5a593af2014-08-11 19:51:50 -0400715 var flags []string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400716 if test.testType == serverTest {
David Benjamin5a593af2014-08-11 19:51:50 -0400717 flags = append(flags, "-server")
718
David Benjamin025b3d32014-07-01 19:53:04 -0400719 flags = append(flags, "-key-file")
720 if test.keyFile == "" {
721 flags = append(flags, rsaKeyFile)
722 } else {
723 flags = append(flags, test.keyFile)
724 }
725
726 flags = append(flags, "-cert-file")
727 if test.certFile == "" {
728 flags = append(flags, rsaCertificateFile)
729 } else {
730 flags = append(flags, test.certFile)
731 }
732 }
David Benjamin5a593af2014-08-11 19:51:50 -0400733
David Benjamin6fd297b2014-08-11 18:43:38 -0400734 if test.protocol == dtls {
735 flags = append(flags, "-dtls")
736 }
737
David Benjamin5a593af2014-08-11 19:51:50 -0400738 if test.resumeSession {
739 flags = append(flags, "-resume")
740 }
741
David Benjamine58c4f52014-08-24 03:47:07 -0400742 if test.shimWritesFirst {
743 flags = append(flags, "-shim-writes-first")
744 }
745
David Benjamin025b3d32014-07-01 19:53:04 -0400746 flags = append(flags, test.flags...)
747
748 var shim *exec.Cmd
749 if *useValgrind {
750 shim = valgrindOf(false, shim_path, flags...)
Adam Langley75712922014-10-10 16:23:43 -0700751 } else if *useGDB {
752 shim = gdbOf(shim_path, flags...)
David Benjamin025b3d32014-07-01 19:53:04 -0400753 } else {
754 shim = exec.Command(shim_path, flags...)
755 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400756 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400757 shim.Stdin = os.Stdin
758 var stdoutBuf, stderrBuf bytes.Buffer
759 shim.Stdout = &stdoutBuf
760 shim.Stderr = &stderrBuf
761
762 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700763 panic(err)
764 }
David Benjamin025b3d32014-07-01 19:53:04 -0400765 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400766 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700767
768 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400769 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400770 if test.testType == clientTest {
771 if len(config.Certificates) == 0 {
772 config.Certificates = []Certificate{getRSACertificate()}
773 }
David Benjamin025b3d32014-07-01 19:53:04 -0400774 }
Adam Langley95c29f32014-06-20 12:00:00 -0700775
Adam Langley75712922014-10-10 16:23:43 -0700776 var connDebug *recordingConn
777 if *flagDebug {
778 connDebug = &recordingConn{Conn: conn}
779 conn = connDebug
780 }
781
David Benjamin01fe8202014-09-24 15:21:44 -0400782 err := doExchange(test, &config, conn, test.messageLen,
783 false /* not a resumption */)
Adam Langley75712922014-10-10 16:23:43 -0700784
785 if *flagDebug {
786 connDebug.WriteTo(os.Stdout)
787 }
788
Adam Langley95c29f32014-06-20 12:00:00 -0700789 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400790 if err == nil && test.resumeSession {
David Benjamin01fe8202014-09-24 15:21:44 -0400791 var resumeConfig Config
792 if test.resumeConfig != nil {
793 resumeConfig = *test.resumeConfig
794 if len(resumeConfig.Certificates) == 0 {
795 resumeConfig.Certificates = []Certificate{getRSACertificate()}
796 }
797 resumeConfig.SessionTicketKey = config.SessionTicketKey
798 resumeConfig.ClientSessionCache = config.ClientSessionCache
799 } else {
800 resumeConfig = config
801 }
802 err = doExchange(test, &resumeConfig, connResume, test.messageLen,
803 true /* resumption */)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400804 }
David Benjamin812152a2014-09-06 12:49:07 -0400805 connResume.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400806
David Benjamin025b3d32014-07-01 19:53:04 -0400807 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700808
809 stdout := string(stdoutBuf.Bytes())
810 stderr := string(stderrBuf.Bytes())
811 failed := err != nil || childErr != nil
812 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700813 localError := "none"
814 if err != nil {
815 localError = err.Error()
816 }
817 if len(test.expectedLocalError) != 0 {
818 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
819 }
Adam Langley95c29f32014-06-20 12:00:00 -0700820
821 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700822 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700823 if childErr != nil {
824 childError = childErr.Error()
825 }
826
827 var msg string
828 switch {
829 case failed && !test.shouldFail:
830 msg = "unexpected failure"
831 case !failed && test.shouldFail:
832 msg = "unexpected success"
833 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700834 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700835 default:
836 panic("internal error")
837 }
838
839 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
840 }
841
842 if !*useValgrind && len(stderr) > 0 {
843 println(stderr)
844 }
845
846 return nil
847}
848
849var tlsVersions = []struct {
850 name string
851 version uint16
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400852 flag string
Adam Langley95c29f32014-06-20 12:00:00 -0700853}{
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400854 {"SSL3", VersionSSL30, "-no-ssl3"},
855 {"TLS1", VersionTLS10, "-no-tls1"},
856 {"TLS11", VersionTLS11, "-no-tls11"},
857 {"TLS12", VersionTLS12, "-no-tls12"},
Adam Langley95c29f32014-06-20 12:00:00 -0700858}
859
860var testCipherSuites = []struct {
861 name string
862 id uint16
863}{
864 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400865 {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700866 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400867 {"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400868 {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700869 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400870 {"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400871 {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
872 {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400873 {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400874 {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
875 {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400876 {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700877 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
878 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400879 {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
880 {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700881 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400882 {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700883 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
David Benjamin2af684f2014-10-27 02:23:15 -0400884 {"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700885 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700886 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400887 {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400888 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700889 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400890 {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700891 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
David Benjamin48cae082014-10-27 01:06:24 -0400892 {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
893 {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
894 {"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700895 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400896 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700897}
898
David Benjaminf7768e42014-08-31 02:06:47 -0400899func isTLS12Only(suiteName string) bool {
900 return strings.HasSuffix(suiteName, "-GCM") ||
901 strings.HasSuffix(suiteName, "-SHA256") ||
902 strings.HasSuffix(suiteName, "-SHA384")
903}
904
Adam Langley95c29f32014-06-20 12:00:00 -0700905func addCipherSuiteTests() {
906 for _, suite := range testCipherSuites {
David Benjamin48cae082014-10-27 01:06:24 -0400907 const psk = "12345"
908 const pskIdentity = "luggage combo"
909
Adam Langley95c29f32014-06-20 12:00:00 -0700910 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400911 var certFile string
912 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700913 if strings.Contains(suite.name, "ECDSA") {
914 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400915 certFile = ecdsaCertificateFile
916 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700917 } else {
918 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400919 certFile = rsaCertificateFile
920 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700921 }
922
David Benjamin48cae082014-10-27 01:06:24 -0400923 var flags []string
924 if strings.HasPrefix(suite.name, "PSK-") || strings.Contains(suite.name, "-PSK-") {
925 flags = append(flags,
926 "-psk", psk,
927 "-psk-identity", pskIdentity)
928 }
929
Adam Langley95c29f32014-06-20 12:00:00 -0700930 for _, ver := range tlsVersions {
David Benjaminf7768e42014-08-31 02:06:47 -0400931 if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
Adam Langley95c29f32014-06-20 12:00:00 -0700932 continue
933 }
934
David Benjamin1d5c83e2014-07-22 19:20:02 -0400935 // Go's TLS implementation only implements session
936 // resumption with tickets, so SSLv3 cannot resume
937 // sessions.
938 resumeSession := ver.version != VersionSSL30
939
David Benjamin025b3d32014-07-01 19:53:04 -0400940 testCases = append(testCases, testCase{
941 testType: clientTest,
942 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700943 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400944 MinVersion: ver.version,
945 MaxVersion: ver.version,
946 CipherSuites: []uint16{suite.id},
947 Certificates: []Certificate{cert},
948 PreSharedKey: []byte(psk),
949 PreSharedKeyIdentity: pskIdentity,
Adam Langley95c29f32014-06-20 12:00:00 -0700950 },
David Benjamin48cae082014-10-27 01:06:24 -0400951 flags: flags,
David Benjamin1d5c83e2014-07-22 19:20:02 -0400952 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700953 })
David Benjamin025b3d32014-07-01 19:53:04 -0400954
David Benjamin76d8abe2014-08-14 16:25:34 -0400955 testCases = append(testCases, testCase{
956 testType: serverTest,
957 name: ver.name + "-" + suite.name + "-server",
958 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400959 MinVersion: ver.version,
960 MaxVersion: ver.version,
961 CipherSuites: []uint16{suite.id},
962 Certificates: []Certificate{cert},
963 PreSharedKey: []byte(psk),
964 PreSharedKeyIdentity: pskIdentity,
David Benjamin76d8abe2014-08-14 16:25:34 -0400965 },
966 certFile: certFile,
967 keyFile: keyFile,
David Benjamin48cae082014-10-27 01:06:24 -0400968 flags: flags,
David Benjamin76d8abe2014-08-14 16:25:34 -0400969 resumeSession: resumeSession,
970 })
David Benjamin6fd297b2014-08-11 18:43:38 -0400971
972 // TODO(davidben): Fix DTLS 1.2 support and test that.
973 if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
974 testCases = append(testCases, testCase{
975 testType: clientTest,
976 protocol: dtls,
977 name: "D" + ver.name + "-" + suite.name + "-client",
978 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400979 MinVersion: ver.version,
980 MaxVersion: ver.version,
981 CipherSuites: []uint16{suite.id},
982 Certificates: []Certificate{cert},
983 PreSharedKey: []byte(psk),
984 PreSharedKeyIdentity: pskIdentity,
David Benjamin6fd297b2014-08-11 18:43:38 -0400985 },
David Benjamin48cae082014-10-27 01:06:24 -0400986 flags: flags,
David Benjamin6fd297b2014-08-11 18:43:38 -0400987 resumeSession: resumeSession,
988 })
989 testCases = append(testCases, testCase{
990 testType: serverTest,
991 protocol: dtls,
992 name: "D" + ver.name + "-" + suite.name + "-server",
993 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400994 MinVersion: ver.version,
995 MaxVersion: ver.version,
996 CipherSuites: []uint16{suite.id},
997 Certificates: []Certificate{cert},
998 PreSharedKey: []byte(psk),
999 PreSharedKeyIdentity: pskIdentity,
David Benjamin6fd297b2014-08-11 18:43:38 -04001000 },
1001 certFile: certFile,
1002 keyFile: keyFile,
David Benjamin48cae082014-10-27 01:06:24 -04001003 flags: flags,
David Benjamin6fd297b2014-08-11 18:43:38 -04001004 resumeSession: resumeSession,
1005 })
1006 }
Adam Langley95c29f32014-06-20 12:00:00 -07001007 }
1008 }
1009}
1010
1011func addBadECDSASignatureTests() {
1012 for badR := BadValue(1); badR < NumBadValues; badR++ {
1013 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -04001014 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -07001015 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
1016 config: Config{
1017 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
1018 Certificates: []Certificate{getECDSACertificate()},
1019 Bugs: ProtocolBugs{
1020 BadECDSAR: badR,
1021 BadECDSAS: badS,
1022 },
1023 },
1024 shouldFail: true,
1025 expectedError: "SIGNATURE",
1026 })
1027 }
1028 }
1029}
1030
Adam Langley80842bd2014-06-20 12:00:00 -07001031func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -04001032 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -07001033 name: "MaxCBCPadding",
1034 config: Config{
1035 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1036 Bugs: ProtocolBugs{
1037 MaxPadding: true,
1038 },
1039 },
1040 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
1041 })
David Benjamin025b3d32014-07-01 19:53:04 -04001042 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -07001043 name: "BadCBCPadding",
1044 config: Config{
1045 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1046 Bugs: ProtocolBugs{
1047 PaddingFirstByteBad: true,
1048 },
1049 },
1050 shouldFail: true,
1051 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1052 })
1053 // OpenSSL previously had an issue where the first byte of padding in
1054 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -04001055 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -07001056 name: "BadCBCPadding255",
1057 config: Config{
1058 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1059 Bugs: ProtocolBugs{
1060 MaxPadding: true,
1061 PaddingFirstByteBadIf255: true,
1062 },
1063 },
1064 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
1065 shouldFail: true,
1066 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1067 })
1068}
1069
Kenny Root7fdeaf12014-08-05 15:23:37 -07001070func addCBCSplittingTests() {
1071 testCases = append(testCases, testCase{
1072 name: "CBCRecordSplitting",
1073 config: Config{
1074 MaxVersion: VersionTLS10,
1075 MinVersion: VersionTLS10,
1076 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1077 },
1078 messageLen: -1, // read until EOF
1079 flags: []string{
1080 "-async",
1081 "-write-different-record-sizes",
1082 "-cbc-record-splitting",
1083 },
David Benjamina8e3e0e2014-08-06 22:11:10 -04001084 })
1085 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -07001086 name: "CBCRecordSplittingPartialWrite",
1087 config: Config{
1088 MaxVersion: VersionTLS10,
1089 MinVersion: VersionTLS10,
1090 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1091 },
1092 messageLen: -1, // read until EOF
1093 flags: []string{
1094 "-async",
1095 "-write-different-record-sizes",
1096 "-cbc-record-splitting",
1097 "-partial-write",
1098 },
1099 })
1100}
1101
David Benjamin636293b2014-07-08 17:59:18 -04001102func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -04001103 // Add a dummy cert pool to stress certificate authority parsing.
1104 // TODO(davidben): Add tests that those values parse out correctly.
1105 certPool := x509.NewCertPool()
1106 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
1107 if err != nil {
1108 panic(err)
1109 }
1110 certPool.AddCert(cert)
1111
David Benjamin636293b2014-07-08 17:59:18 -04001112 for _, ver := range tlsVersions {
David Benjamin636293b2014-07-08 17:59:18 -04001113 testCases = append(testCases, testCase{
1114 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -04001115 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -04001116 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001117 MinVersion: ver.version,
1118 MaxVersion: ver.version,
1119 ClientAuth: RequireAnyClientCert,
1120 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -04001121 },
1122 flags: []string{
1123 "-cert-file", rsaCertificateFile,
1124 "-key-file", rsaKeyFile,
1125 },
1126 })
1127 testCases = append(testCases, testCase{
David Benjamin67666e72014-07-12 15:47:52 -04001128 testType: serverTest,
1129 name: ver.name + "-Server-ClientAuth-RSA",
1130 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001131 MinVersion: ver.version,
1132 MaxVersion: ver.version,
David Benjamin67666e72014-07-12 15:47:52 -04001133 Certificates: []Certificate{rsaCertificate},
1134 },
1135 flags: []string{"-require-any-client-certificate"},
1136 })
David Benjamine098ec22014-08-27 23:13:20 -04001137 if ver.version != VersionSSL30 {
1138 testCases = append(testCases, testCase{
1139 testType: serverTest,
1140 name: ver.name + "-Server-ClientAuth-ECDSA",
1141 config: Config{
1142 MinVersion: ver.version,
1143 MaxVersion: ver.version,
1144 Certificates: []Certificate{ecdsaCertificate},
1145 },
1146 flags: []string{"-require-any-client-certificate"},
1147 })
1148 testCases = append(testCases, testCase{
1149 testType: clientTest,
1150 name: ver.name + "-Client-ClientAuth-ECDSA",
1151 config: Config{
1152 MinVersion: ver.version,
1153 MaxVersion: ver.version,
1154 ClientAuth: RequireAnyClientCert,
1155 ClientCAs: certPool,
1156 },
1157 flags: []string{
1158 "-cert-file", ecdsaCertificateFile,
1159 "-key-file", ecdsaKeyFile,
1160 },
1161 })
1162 }
David Benjamin636293b2014-07-08 17:59:18 -04001163 }
1164}
1165
Adam Langley75712922014-10-10 16:23:43 -07001166func addExtendedMasterSecretTests() {
1167 const expectEMSFlag = "-expect-extended-master-secret"
1168
1169 for _, with := range []bool{false, true} {
1170 prefix := "No"
1171 var flags []string
1172 if with {
1173 prefix = ""
1174 flags = []string{expectEMSFlag}
1175 }
1176
1177 for _, isClient := range []bool{false, true} {
1178 suffix := "-Server"
1179 testType := serverTest
1180 if isClient {
1181 suffix = "-Client"
1182 testType = clientTest
1183 }
1184
1185 for _, ver := range tlsVersions {
1186 test := testCase{
1187 testType: testType,
1188 name: prefix + "ExtendedMasterSecret-" + ver.name + suffix,
1189 config: Config{
1190 MinVersion: ver.version,
1191 MaxVersion: ver.version,
1192 Bugs: ProtocolBugs{
1193 NoExtendedMasterSecret: !with,
1194 RequireExtendedMasterSecret: with,
1195 },
1196 },
David Benjamin48cae082014-10-27 01:06:24 -04001197 flags: flags,
1198 shouldFail: ver.version == VersionSSL30 && with,
Adam Langley75712922014-10-10 16:23:43 -07001199 }
1200 if test.shouldFail {
1201 test.expectedLocalError = "extended master secret required but not supported by peer"
1202 }
1203 testCases = append(testCases, test)
1204 }
1205 }
1206 }
1207
1208 // When a session is resumed, it should still be aware that its master
1209 // secret was generated via EMS and thus it's safe to use tls-unique.
1210 testCases = append(testCases, testCase{
1211 name: "ExtendedMasterSecret-Resume",
1212 config: Config{
1213 Bugs: ProtocolBugs{
1214 RequireExtendedMasterSecret: true,
1215 },
1216 },
1217 flags: []string{expectEMSFlag},
1218 resumeSession: true,
1219 })
1220}
1221
David Benjamin43ec06f2014-08-05 02:28:57 -04001222// Adds tests that try to cover the range of the handshake state machine, under
1223// various conditions. Some of these are redundant with other tests, but they
1224// only cover the synchronous case.
David Benjamin6fd297b2014-08-11 18:43:38 -04001225func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
David Benjamin43ec06f2014-08-05 02:28:57 -04001226 var suffix string
1227 var flags []string
1228 var maxHandshakeRecordLength int
David Benjamin6fd297b2014-08-11 18:43:38 -04001229 if protocol == dtls {
1230 suffix = "-DTLS"
1231 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001232 if async {
David Benjamin6fd297b2014-08-11 18:43:38 -04001233 suffix += "-Async"
David Benjamin43ec06f2014-08-05 02:28:57 -04001234 flags = append(flags, "-async")
1235 } else {
David Benjamin6fd297b2014-08-11 18:43:38 -04001236 suffix += "-Sync"
David Benjamin43ec06f2014-08-05 02:28:57 -04001237 }
1238 if splitHandshake {
1239 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -04001240 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -04001241 }
1242
1243 // Basic handshake, with resumption. Client and server.
1244 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001245 protocol: protocol,
1246 name: "Basic-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001247 config: Config{
1248 Bugs: ProtocolBugs{
1249 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1250 },
1251 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001252 flags: flags,
1253 resumeSession: true,
1254 })
1255 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001256 protocol: protocol,
1257 name: "Basic-Client-RenewTicket" + suffix,
David Benjaminbed9aae2014-08-07 19:13:38 -04001258 config: Config{
1259 Bugs: ProtocolBugs{
1260 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1261 RenewTicketOnResume: true,
1262 },
1263 },
1264 flags: flags,
1265 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001266 })
1267 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001268 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001269 testType: serverTest,
1270 name: "Basic-Server" + suffix,
1271 config: Config{
1272 Bugs: ProtocolBugs{
1273 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1274 },
1275 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001276 flags: flags,
1277 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001278 })
1279
David Benjamin6fd297b2014-08-11 18:43:38 -04001280 // TLS client auth.
1281 testCases = append(testCases, testCase{
1282 protocol: protocol,
1283 testType: clientTest,
1284 name: "ClientAuth-Client" + suffix,
1285 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001286 ClientAuth: RequireAnyClientCert,
David Benjamin6fd297b2014-08-11 18:43:38 -04001287 Bugs: ProtocolBugs{
1288 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1289 },
1290 },
1291 flags: append(flags,
1292 "-cert-file", rsaCertificateFile,
1293 "-key-file", rsaKeyFile),
1294 })
1295 testCases = append(testCases, testCase{
1296 protocol: protocol,
1297 testType: serverTest,
1298 name: "ClientAuth-Server" + suffix,
1299 config: Config{
1300 Certificates: []Certificate{rsaCertificate},
1301 },
1302 flags: append(flags, "-require-any-client-certificate"),
1303 })
1304
David Benjamin43ec06f2014-08-05 02:28:57 -04001305 // No session ticket support; server doesn't send NewSessionTicket.
1306 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001307 protocol: protocol,
1308 name: "SessionTicketsDisabled-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001309 config: Config{
1310 SessionTicketsDisabled: true,
1311 Bugs: ProtocolBugs{
1312 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1313 },
1314 },
1315 flags: flags,
1316 })
1317 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001318 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001319 testType: serverTest,
1320 name: "SessionTicketsDisabled-Server" + suffix,
1321 config: Config{
1322 SessionTicketsDisabled: true,
1323 Bugs: ProtocolBugs{
1324 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1325 },
1326 },
1327 flags: flags,
1328 })
1329
David Benjamin48cae082014-10-27 01:06:24 -04001330 // Skip ServerKeyExchange in PSK key exchange if there's no
1331 // identity hint.
1332 testCases = append(testCases, testCase{
1333 protocol: protocol,
1334 name: "EmptyPSKHint-Client" + suffix,
1335 config: Config{
1336 CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1337 PreSharedKey: []byte("secret"),
1338 Bugs: ProtocolBugs{
1339 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1340 },
1341 },
1342 flags: append(flags, "-psk", "secret"),
1343 })
1344 testCases = append(testCases, testCase{
1345 protocol: protocol,
1346 testType: serverTest,
1347 name: "EmptyPSKHint-Server" + suffix,
1348 config: Config{
1349 CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1350 PreSharedKey: []byte("secret"),
1351 Bugs: ProtocolBugs{
1352 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1353 },
1354 },
1355 flags: append(flags, "-psk", "secret"),
1356 })
1357
David Benjamin6fd297b2014-08-11 18:43:38 -04001358 if protocol == tls {
1359 // NPN on client and server; results in post-handshake message.
1360 testCases = append(testCases, testCase{
1361 protocol: protocol,
1362 name: "NPN-Client" + suffix,
1363 config: Config{
David Benjaminae2888f2014-09-06 12:58:58 -04001364 NextProtos: []string{"foo"},
David Benjamin6fd297b2014-08-11 18:43:38 -04001365 Bugs: ProtocolBugs{
1366 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1367 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001368 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001369 flags: append(flags, "-select-next-proto", "foo"),
1370 expectedNextProto: "foo",
1371 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001372 })
1373 testCases = append(testCases, testCase{
1374 protocol: protocol,
1375 testType: serverTest,
1376 name: "NPN-Server" + suffix,
1377 config: Config{
1378 NextProtos: []string{"bar"},
1379 Bugs: ProtocolBugs{
1380 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1381 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001382 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001383 flags: append(flags,
1384 "-advertise-npn", "\x03foo\x03bar\x03baz",
1385 "-expect-next-proto", "bar"),
David Benjaminfc7b0862014-09-06 13:21:53 -04001386 expectedNextProto: "bar",
1387 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001388 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001389
David Benjamin6fd297b2014-08-11 18:43:38 -04001390 // Client does False Start and negotiates NPN.
1391 testCases = append(testCases, testCase{
1392 protocol: protocol,
1393 name: "FalseStart" + suffix,
1394 config: Config{
1395 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1396 NextProtos: []string{"foo"},
1397 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001398 ExpectFalseStart: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001399 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1400 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001401 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001402 flags: append(flags,
1403 "-false-start",
1404 "-select-next-proto", "foo"),
David Benjamine58c4f52014-08-24 03:47:07 -04001405 shimWritesFirst: true,
1406 resumeSession: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001407 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001408
David Benjaminae2888f2014-09-06 12:58:58 -04001409 // Client does False Start and negotiates ALPN.
1410 testCases = append(testCases, testCase{
1411 protocol: protocol,
1412 name: "FalseStart-ALPN" + suffix,
1413 config: Config{
1414 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1415 NextProtos: []string{"foo"},
1416 Bugs: ProtocolBugs{
1417 ExpectFalseStart: true,
1418 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1419 },
1420 },
1421 flags: append(flags,
1422 "-false-start",
1423 "-advertise-alpn", "\x03foo"),
1424 shimWritesFirst: true,
1425 resumeSession: true,
1426 })
1427
David Benjamin6fd297b2014-08-11 18:43:38 -04001428 // False Start without session tickets.
1429 testCases = append(testCases, testCase{
1430 name: "FalseStart-SessionTicketsDisabled",
1431 config: Config{
1432 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1433 NextProtos: []string{"foo"},
1434 SessionTicketsDisabled: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001435 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001436 ExpectFalseStart: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001437 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1438 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001439 },
David Benjamin4e99c522014-08-24 01:45:30 -04001440 flags: append(flags,
David Benjamin6fd297b2014-08-11 18:43:38 -04001441 "-false-start",
1442 "-select-next-proto", "foo",
David Benjamin4e99c522014-08-24 01:45:30 -04001443 ),
David Benjamine58c4f52014-08-24 03:47:07 -04001444 shimWritesFirst: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001445 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001446
David Benjamina08e49d2014-08-24 01:46:07 -04001447 // Server parses a V2ClientHello.
David Benjamin6fd297b2014-08-11 18:43:38 -04001448 testCases = append(testCases, testCase{
1449 protocol: protocol,
1450 testType: serverTest,
1451 name: "SendV2ClientHello" + suffix,
1452 config: Config{
1453 // Choose a cipher suite that does not involve
1454 // elliptic curves, so no extensions are
1455 // involved.
1456 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1457 Bugs: ProtocolBugs{
1458 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1459 SendV2ClientHello: true,
1460 },
David Benjamin1e7f8d72014-08-08 12:27:04 -04001461 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001462 flags: flags,
1463 })
David Benjamina08e49d2014-08-24 01:46:07 -04001464
1465 // Client sends a Channel ID.
1466 testCases = append(testCases, testCase{
1467 protocol: protocol,
1468 name: "ChannelID-Client" + suffix,
1469 config: Config{
1470 RequestChannelID: true,
1471 Bugs: ProtocolBugs{
1472 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1473 },
1474 },
1475 flags: append(flags,
1476 "-send-channel-id", channelIDKeyFile,
1477 ),
1478 resumeSession: true,
1479 expectChannelID: true,
1480 })
1481
1482 // Server accepts a Channel ID.
1483 testCases = append(testCases, testCase{
1484 protocol: protocol,
1485 testType: serverTest,
1486 name: "ChannelID-Server" + suffix,
1487 config: Config{
1488 ChannelID: channelIDKey,
1489 Bugs: ProtocolBugs{
1490 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1491 },
1492 },
1493 flags: append(flags,
1494 "-expect-channel-id",
1495 base64.StdEncoding.EncodeToString(channelIDBytes),
1496 ),
1497 resumeSession: true,
1498 expectChannelID: true,
1499 })
David Benjamin6fd297b2014-08-11 18:43:38 -04001500 } else {
1501 testCases = append(testCases, testCase{
1502 protocol: protocol,
1503 name: "SkipHelloVerifyRequest" + suffix,
1504 config: Config{
1505 Bugs: ProtocolBugs{
1506 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1507 SkipHelloVerifyRequest: true,
1508 },
1509 },
1510 flags: flags,
1511 })
1512
1513 testCases = append(testCases, testCase{
1514 testType: serverTest,
1515 protocol: protocol,
1516 name: "CookieExchange" + suffix,
1517 config: Config{
1518 Bugs: ProtocolBugs{
1519 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1520 },
1521 },
1522 flags: append(flags, "-cookie-exchange"),
1523 })
1524 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001525}
1526
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001527func addVersionNegotiationTests() {
1528 for i, shimVers := range tlsVersions {
1529 // Assemble flags to disable all newer versions on the shim.
1530 var flags []string
1531 for _, vers := range tlsVersions[i+1:] {
1532 flags = append(flags, vers.flag)
1533 }
1534
1535 for _, runnerVers := range tlsVersions {
1536 expectedVersion := shimVers.version
1537 if runnerVers.version < shimVers.version {
1538 expectedVersion = runnerVers.version
1539 }
1540 suffix := shimVers.name + "-" + runnerVers.name
1541
1542 testCases = append(testCases, testCase{
1543 testType: clientTest,
1544 name: "VersionNegotiation-Client-" + suffix,
1545 config: Config{
1546 MaxVersion: runnerVers.version,
1547 },
1548 flags: flags,
1549 expectedVersion: expectedVersion,
1550 })
1551
David Benjamin76d8abe2014-08-14 16:25:34 -04001552 testCases = append(testCases, testCase{
1553 testType: serverTest,
1554 name: "VersionNegotiation-Server-" + suffix,
1555 config: Config{
1556 MaxVersion: runnerVers.version,
1557 },
1558 flags: flags,
1559 expectedVersion: expectedVersion,
1560 })
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001561 }
1562 }
1563}
1564
David Benjamin5c24a1d2014-08-31 00:59:27 -04001565func addD5BugTests() {
1566 testCases = append(testCases, testCase{
1567 testType: serverTest,
1568 name: "D5Bug-NoQuirk-Reject",
1569 config: Config{
1570 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1571 Bugs: ProtocolBugs{
1572 SSL3RSAKeyExchange: true,
1573 },
1574 },
1575 shouldFail: true,
1576 expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
1577 })
1578 testCases = append(testCases, testCase{
1579 testType: serverTest,
1580 name: "D5Bug-Quirk-Normal",
1581 config: Config{
1582 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1583 },
1584 flags: []string{"-tls-d5-bug"},
1585 })
1586 testCases = append(testCases, testCase{
1587 testType: serverTest,
1588 name: "D5Bug-Quirk-Bug",
1589 config: Config{
1590 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1591 Bugs: ProtocolBugs{
1592 SSL3RSAKeyExchange: true,
1593 },
1594 },
1595 flags: []string{"-tls-d5-bug"},
1596 })
1597}
1598
David Benjamine78bfde2014-09-06 12:45:15 -04001599func addExtensionTests() {
1600 testCases = append(testCases, testCase{
1601 testType: clientTest,
1602 name: "DuplicateExtensionClient",
1603 config: Config{
1604 Bugs: ProtocolBugs{
1605 DuplicateExtension: true,
1606 },
1607 },
1608 shouldFail: true,
1609 expectedLocalError: "remote error: error decoding message",
1610 })
1611 testCases = append(testCases, testCase{
1612 testType: serverTest,
1613 name: "DuplicateExtensionServer",
1614 config: Config{
1615 Bugs: ProtocolBugs{
1616 DuplicateExtension: true,
1617 },
1618 },
1619 shouldFail: true,
1620 expectedLocalError: "remote error: error decoding message",
1621 })
1622 testCases = append(testCases, testCase{
1623 testType: clientTest,
1624 name: "ServerNameExtensionClient",
1625 config: Config{
1626 Bugs: ProtocolBugs{
1627 ExpectServerName: "example.com",
1628 },
1629 },
1630 flags: []string{"-host-name", "example.com"},
1631 })
1632 testCases = append(testCases, testCase{
1633 testType: clientTest,
1634 name: "ServerNameExtensionClient",
1635 config: Config{
1636 Bugs: ProtocolBugs{
1637 ExpectServerName: "mismatch.com",
1638 },
1639 },
1640 flags: []string{"-host-name", "example.com"},
1641 shouldFail: true,
1642 expectedLocalError: "tls: unexpected server name",
1643 })
1644 testCases = append(testCases, testCase{
1645 testType: clientTest,
1646 name: "ServerNameExtensionClient",
1647 config: Config{
1648 Bugs: ProtocolBugs{
1649 ExpectServerName: "missing.com",
1650 },
1651 },
1652 shouldFail: true,
1653 expectedLocalError: "tls: unexpected server name",
1654 })
1655 testCases = append(testCases, testCase{
1656 testType: serverTest,
1657 name: "ServerNameExtensionServer",
1658 config: Config{
1659 ServerName: "example.com",
1660 },
1661 flags: []string{"-expect-server-name", "example.com"},
1662 resumeSession: true,
1663 })
David Benjaminae2888f2014-09-06 12:58:58 -04001664 testCases = append(testCases, testCase{
1665 testType: clientTest,
1666 name: "ALPNClient",
1667 config: Config{
1668 NextProtos: []string{"foo"},
1669 },
1670 flags: []string{
1671 "-advertise-alpn", "\x03foo\x03bar\x03baz",
1672 "-expect-alpn", "foo",
1673 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001674 expectedNextProto: "foo",
1675 expectedNextProtoType: alpn,
1676 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001677 })
1678 testCases = append(testCases, testCase{
1679 testType: serverTest,
1680 name: "ALPNServer",
1681 config: Config{
1682 NextProtos: []string{"foo", "bar", "baz"},
1683 },
1684 flags: []string{
1685 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1686 "-select-alpn", "foo",
1687 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001688 expectedNextProto: "foo",
1689 expectedNextProtoType: alpn,
1690 resumeSession: true,
1691 })
1692 // Test that the server prefers ALPN over NPN.
1693 testCases = append(testCases, testCase{
1694 testType: serverTest,
1695 name: "ALPNServer-Preferred",
1696 config: Config{
1697 NextProtos: []string{"foo", "bar", "baz"},
1698 },
1699 flags: []string{
1700 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1701 "-select-alpn", "foo",
1702 "-advertise-npn", "\x03foo\x03bar\x03baz",
1703 },
1704 expectedNextProto: "foo",
1705 expectedNextProtoType: alpn,
1706 resumeSession: true,
1707 })
1708 testCases = append(testCases, testCase{
1709 testType: serverTest,
1710 name: "ALPNServer-Preferred-Swapped",
1711 config: Config{
1712 NextProtos: []string{"foo", "bar", "baz"},
1713 Bugs: ProtocolBugs{
1714 SwapNPNAndALPN: true,
1715 },
1716 },
1717 flags: []string{
1718 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1719 "-select-alpn", "foo",
1720 "-advertise-npn", "\x03foo\x03bar\x03baz",
1721 },
1722 expectedNextProto: "foo",
1723 expectedNextProtoType: alpn,
1724 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001725 })
Adam Langley38311732014-10-16 19:04:35 -07001726 // Resume with a corrupt ticket.
1727 testCases = append(testCases, testCase{
1728 testType: serverTest,
1729 name: "CorruptTicket",
1730 config: Config{
1731 Bugs: ProtocolBugs{
1732 CorruptTicket: true,
1733 },
1734 },
1735 resumeSession: true,
1736 flags: []string{"-expect-session-miss"},
1737 })
1738 // Resume with an oversized session id.
1739 testCases = append(testCases, testCase{
1740 testType: serverTest,
1741 name: "OversizedSessionId",
1742 config: Config{
1743 Bugs: ProtocolBugs{
1744 OversizedSessionId: true,
1745 },
1746 },
1747 resumeSession: true,
Adam Langley75712922014-10-10 16:23:43 -07001748 shouldFail: true,
Adam Langley38311732014-10-16 19:04:35 -07001749 expectedError: ":DECODE_ERROR:",
1750 })
David Benjaminca6c8262014-11-15 19:06:08 -05001751 // Basic DTLS-SRTP tests. Include fake profiles to ensure they
1752 // are ignored.
1753 testCases = append(testCases, testCase{
1754 protocol: dtls,
1755 name: "SRTP-Client",
1756 config: Config{
1757 SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
1758 },
1759 flags: []string{
1760 "-srtp-profiles",
1761 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
1762 },
1763 expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
1764 })
1765 testCases = append(testCases, testCase{
1766 protocol: dtls,
1767 testType: serverTest,
1768 name: "SRTP-Server",
1769 config: Config{
1770 SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
1771 },
1772 flags: []string{
1773 "-srtp-profiles",
1774 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
1775 },
1776 expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
1777 })
1778 // Test that the MKI is ignored.
1779 testCases = append(testCases, testCase{
1780 protocol: dtls,
1781 testType: serverTest,
1782 name: "SRTP-Server-IgnoreMKI",
1783 config: Config{
1784 SRTPProtectionProfiles: []uint16{SRTP_AES128_CM_HMAC_SHA1_80},
1785 Bugs: ProtocolBugs{
1786 SRTPMasterKeyIdentifer: "bogus",
1787 },
1788 },
1789 flags: []string{
1790 "-srtp-profiles",
1791 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
1792 },
1793 expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
1794 })
1795 // Test that SRTP isn't negotiated on the server if there were
1796 // no matching profiles.
1797 testCases = append(testCases, testCase{
1798 protocol: dtls,
1799 testType: serverTest,
1800 name: "SRTP-Server-NoMatch",
1801 config: Config{
1802 SRTPProtectionProfiles: []uint16{100, 101, 102},
1803 },
1804 flags: []string{
1805 "-srtp-profiles",
1806 "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
1807 },
1808 expectedSRTPProtectionProfile: 0,
1809 })
1810 // Test that the server returning an invalid SRTP profile is
1811 // flagged as an error by the client.
1812 testCases = append(testCases, testCase{
1813 protocol: dtls,
1814 name: "SRTP-Client-NoMatch",
1815 config: Config{
1816 Bugs: ProtocolBugs{
1817 SendSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_32,
1818 },
1819 },
1820 flags: []string{
1821 "-srtp-profiles",
1822 "SRTP_AES128_CM_SHA1_80",
1823 },
1824 shouldFail: true,
1825 expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:",
1826 })
David Benjamine78bfde2014-09-06 12:45:15 -04001827}
1828
David Benjamin01fe8202014-09-24 15:21:44 -04001829func addResumptionVersionTests() {
1830 // TODO(davidben): Once DTLS 1.2 is working, test that as well.
1831 for _, sessionVers := range tlsVersions {
1832 // TODO(davidben): SSLv3 is omitted here because runner does not
1833 // support resumption with session IDs.
1834 if sessionVers.version == VersionSSL30 {
1835 continue
1836 }
1837 for _, resumeVers := range tlsVersions {
1838 if resumeVers.version == VersionSSL30 {
1839 continue
1840 }
1841 suffix := "-" + sessionVers.name + "-" + resumeVers.name
1842
David Benjamin01fe8202014-09-24 15:21:44 -04001843 testCases = append(testCases, testCase{
1844 name: "Resume-Client" + suffix,
1845 resumeSession: true,
1846 config: Config{
1847 MaxVersion: sessionVers.version,
1848 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1849 Bugs: ProtocolBugs{
1850 AllowSessionVersionMismatch: true,
1851 },
1852 },
1853 expectedVersion: sessionVers.version,
1854 resumeConfig: &Config{
1855 MaxVersion: resumeVers.version,
1856 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1857 Bugs: ProtocolBugs{
1858 AllowSessionVersionMismatch: true,
1859 },
1860 },
1861 expectedResumeVersion: resumeVers.version,
1862 })
1863
1864 testCases = append(testCases, testCase{
1865 name: "Resume-Client-NoResume" + suffix,
1866 flags: []string{"-expect-session-miss"},
1867 resumeSession: true,
1868 config: Config{
1869 MaxVersion: sessionVers.version,
1870 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1871 },
1872 expectedVersion: sessionVers.version,
1873 resumeConfig: &Config{
1874 MaxVersion: resumeVers.version,
1875 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1876 SessionTicketsDisabled: true,
1877 },
1878 expectedResumeVersion: resumeVers.version,
1879 })
David Benjaminbdf5e722014-11-11 00:52:15 -05001880
1881 var flags []string
1882 if sessionVers.version != resumeVers.version {
1883 flags = append(flags, "-expect-session-miss")
1884 }
1885 testCases = append(testCases, testCase{
1886 testType: serverTest,
1887 name: "Resume-Server" + suffix,
1888 flags: flags,
1889 resumeSession: true,
1890 config: Config{
1891 MaxVersion: sessionVers.version,
1892 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1893 },
1894 expectedVersion: sessionVers.version,
1895 resumeConfig: &Config{
1896 MaxVersion: resumeVers.version,
1897 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1898 },
1899 expectedResumeVersion: resumeVers.version,
1900 })
David Benjamin01fe8202014-09-24 15:21:44 -04001901 }
1902 }
1903}
1904
Adam Langley2ae77d22014-10-28 17:29:33 -07001905func addRenegotiationTests() {
1906 testCases = append(testCases, testCase{
1907 testType: serverTest,
1908 name: "Renegotiate-Server",
1909 flags: []string{"-renegotiate"},
1910 shimWritesFirst: true,
1911 })
1912 testCases = append(testCases, testCase{
1913 testType: serverTest,
1914 name: "Renegotiate-Server-EmptyExt",
1915 config: Config{
1916 Bugs: ProtocolBugs{
1917 EmptyRenegotiationInfo: true,
1918 },
1919 },
1920 flags: []string{"-renegotiate"},
1921 shimWritesFirst: true,
1922 shouldFail: true,
1923 expectedError: ":RENEGOTIATION_MISMATCH:",
1924 })
1925 testCases = append(testCases, testCase{
1926 testType: serverTest,
1927 name: "Renegotiate-Server-BadExt",
1928 config: Config{
1929 Bugs: ProtocolBugs{
1930 BadRenegotiationInfo: true,
1931 },
1932 },
1933 flags: []string{"-renegotiate"},
1934 shimWritesFirst: true,
1935 shouldFail: true,
1936 expectedError: ":RENEGOTIATION_MISMATCH:",
1937 })
David Benjaminca6554b2014-11-08 12:31:52 -05001938 testCases = append(testCases, testCase{
1939 testType: serverTest,
1940 name: "Renegotiate-Server-ClientInitiated",
1941 renegotiate: true,
1942 })
1943 testCases = append(testCases, testCase{
1944 testType: serverTest,
1945 name: "Renegotiate-Server-ClientInitiated-NoExt",
1946 renegotiate: true,
1947 config: Config{
1948 Bugs: ProtocolBugs{
1949 NoRenegotiationInfo: true,
1950 },
1951 },
1952 shouldFail: true,
1953 expectedError: ":UNSAFE_LEGACY_RENEGOTIATION_DISABLED:",
1954 })
1955 testCases = append(testCases, testCase{
1956 testType: serverTest,
1957 name: "Renegotiate-Server-ClientInitiated-NoExt-Allowed",
1958 renegotiate: true,
1959 config: Config{
1960 Bugs: ProtocolBugs{
1961 NoRenegotiationInfo: true,
1962 },
1963 },
1964 flags: []string{"-allow-unsafe-legacy-renegotiation"},
1965 })
Adam Langley2ae77d22014-10-28 17:29:33 -07001966 // TODO(agl): test the renegotiation info SCSV.
Adam Langleycf2d4f42014-10-28 19:06:14 -07001967 testCases = append(testCases, testCase{
1968 name: "Renegotiate-Client",
1969 renegotiate: true,
1970 })
1971 testCases = append(testCases, testCase{
1972 name: "Renegotiate-Client-EmptyExt",
1973 renegotiate: true,
1974 config: Config{
1975 Bugs: ProtocolBugs{
1976 EmptyRenegotiationInfo: true,
1977 },
1978 },
1979 shouldFail: true,
1980 expectedError: ":RENEGOTIATION_MISMATCH:",
1981 })
1982 testCases = append(testCases, testCase{
1983 name: "Renegotiate-Client-BadExt",
1984 renegotiate: true,
1985 config: Config{
1986 Bugs: ProtocolBugs{
1987 BadRenegotiationInfo: true,
1988 },
1989 },
1990 shouldFail: true,
1991 expectedError: ":RENEGOTIATION_MISMATCH:",
1992 })
1993 testCases = append(testCases, testCase{
1994 name: "Renegotiate-Client-SwitchCiphers",
1995 renegotiate: true,
1996 config: Config{
1997 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1998 },
1999 renegotiateCiphers: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2000 })
2001 testCases = append(testCases, testCase{
2002 name: "Renegotiate-Client-SwitchCiphers2",
2003 renegotiate: true,
2004 config: Config{
2005 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2006 },
2007 renegotiateCiphers: []uint16{TLS_RSA_WITH_RC4_128_SHA},
2008 })
Adam Langley2ae77d22014-10-28 17:29:33 -07002009}
2010
David Benjamin5e961c12014-11-07 01:48:35 -05002011func addDTLSReplayTests() {
2012 // Test that sequence number replays are detected.
2013 testCases = append(testCases, testCase{
2014 protocol: dtls,
2015 name: "DTLS-Replay",
2016 replayWrites: true,
2017 })
2018
2019 // Test the outgoing sequence number skipping by values larger
2020 // than the retransmit window.
2021 testCases = append(testCases, testCase{
2022 protocol: dtls,
2023 name: "DTLS-Replay-LargeGaps",
2024 config: Config{
2025 Bugs: ProtocolBugs{
2026 SequenceNumberIncrement: 127,
2027 },
2028 },
2029 replayWrites: true,
2030 })
2031}
2032
David Benjamin000800a2014-11-14 01:43:59 -05002033var testHashes = []struct {
2034 name string
2035 id uint8
2036}{
2037 {"SHA1", hashSHA1},
2038 {"SHA224", hashSHA224},
2039 {"SHA256", hashSHA256},
2040 {"SHA384", hashSHA384},
2041 {"SHA512", hashSHA512},
2042}
2043
2044func addSigningHashTests() {
2045 // Make sure each hash works. Include some fake hashes in the list and
2046 // ensure they're ignored.
2047 for _, hash := range testHashes {
2048 testCases = append(testCases, testCase{
2049 name: "SigningHash-ClientAuth-" + hash.name,
2050 config: Config{
2051 ClientAuth: RequireAnyClientCert,
2052 SignatureAndHashes: []signatureAndHash{
2053 {signatureRSA, 42},
2054 {signatureRSA, hash.id},
2055 {signatureRSA, 255},
2056 },
2057 },
2058 flags: []string{
2059 "-cert-file", rsaCertificateFile,
2060 "-key-file", rsaKeyFile,
2061 },
2062 })
2063
2064 testCases = append(testCases, testCase{
2065 testType: serverTest,
2066 name: "SigningHash-ServerKeyExchange-Sign-" + hash.name,
2067 config: Config{
2068 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2069 SignatureAndHashes: []signatureAndHash{
2070 {signatureRSA, 42},
2071 {signatureRSA, hash.id},
2072 {signatureRSA, 255},
2073 },
2074 },
2075 })
2076 }
2077
2078 // Test that hash resolution takes the signature type into account.
2079 testCases = append(testCases, testCase{
2080 name: "SigningHash-ClientAuth-SignatureType",
2081 config: Config{
2082 ClientAuth: RequireAnyClientCert,
2083 SignatureAndHashes: []signatureAndHash{
2084 {signatureECDSA, hashSHA512},
2085 {signatureRSA, hashSHA384},
2086 {signatureECDSA, hashSHA1},
2087 },
2088 },
2089 flags: []string{
2090 "-cert-file", rsaCertificateFile,
2091 "-key-file", rsaKeyFile,
2092 },
2093 })
2094
2095 testCases = append(testCases, testCase{
2096 testType: serverTest,
2097 name: "SigningHash-ServerKeyExchange-SignatureType",
2098 config: Config{
2099 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2100 SignatureAndHashes: []signatureAndHash{
2101 {signatureECDSA, hashSHA512},
2102 {signatureRSA, hashSHA384},
2103 {signatureECDSA, hashSHA1},
2104 },
2105 },
2106 })
2107
2108 // Test that, if the list is missing, the peer falls back to SHA-1.
2109 testCases = append(testCases, testCase{
2110 name: "SigningHash-ClientAuth-Fallback",
2111 config: Config{
2112 ClientAuth: RequireAnyClientCert,
2113 SignatureAndHashes: []signatureAndHash{
2114 {signatureRSA, hashSHA1},
2115 },
2116 Bugs: ProtocolBugs{
2117 NoSignatureAndHashes: true,
2118 },
2119 },
2120 flags: []string{
2121 "-cert-file", rsaCertificateFile,
2122 "-key-file", rsaKeyFile,
2123 },
2124 })
2125
2126 testCases = append(testCases, testCase{
2127 testType: serverTest,
2128 name: "SigningHash-ServerKeyExchange-Fallback",
2129 config: Config{
2130 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2131 SignatureAndHashes: []signatureAndHash{
2132 {signatureRSA, hashSHA1},
2133 },
2134 Bugs: ProtocolBugs{
2135 NoSignatureAndHashes: true,
2136 },
2137 },
2138 })
2139}
2140
David Benjamin884fdf12014-08-02 15:28:23 -04002141func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07002142 defer wg.Done()
2143
2144 for test := range c {
2145 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04002146 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07002147 statusChan <- statusMsg{test: test, err: err}
2148 }
2149}
2150
2151type statusMsg struct {
2152 test *testCase
2153 started bool
2154 err error
2155}
2156
2157func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
2158 var started, done, failed, lineLen int
2159 defer close(doneChan)
2160
2161 for msg := range statusChan {
2162 if msg.started {
2163 started++
2164 } else {
2165 done++
2166 }
2167
2168 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
2169
2170 if msg.err != nil {
2171 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
2172 failed++
2173 }
2174 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
2175 lineLen = len(line)
2176 os.Stdout.WriteString(line)
2177 }
2178}
2179
2180func main() {
2181 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 -04002182 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04002183 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07002184
2185 flag.Parse()
2186
2187 addCipherSuiteTests()
2188 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07002189 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07002190 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04002191 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04002192 addVersionNegotiationTests()
David Benjamin5c24a1d2014-08-31 00:59:27 -04002193 addD5BugTests()
David Benjamine78bfde2014-09-06 12:45:15 -04002194 addExtensionTests()
David Benjamin01fe8202014-09-24 15:21:44 -04002195 addResumptionVersionTests()
Adam Langley75712922014-10-10 16:23:43 -07002196 addExtendedMasterSecretTests()
Adam Langley2ae77d22014-10-28 17:29:33 -07002197 addRenegotiationTests()
David Benjamin5e961c12014-11-07 01:48:35 -05002198 addDTLSReplayTests()
David Benjamin000800a2014-11-14 01:43:59 -05002199 addSigningHashTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04002200 for _, async := range []bool{false, true} {
2201 for _, splitHandshake := range []bool{false, true} {
David Benjamin6fd297b2014-08-11 18:43:38 -04002202 for _, protocol := range []protocol{tls, dtls} {
2203 addStateMachineCoverageTests(async, splitHandshake, protocol)
2204 }
David Benjamin43ec06f2014-08-05 02:28:57 -04002205 }
2206 }
Adam Langley95c29f32014-06-20 12:00:00 -07002207
2208 var wg sync.WaitGroup
2209
David Benjamin2bc8e6f2014-08-02 15:22:37 -04002210 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07002211
2212 statusChan := make(chan statusMsg, numWorkers)
2213 testChan := make(chan *testCase, numWorkers)
2214 doneChan := make(chan struct{})
2215
David Benjamin025b3d32014-07-01 19:53:04 -04002216 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07002217
2218 for i := 0; i < numWorkers; i++ {
2219 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04002220 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07002221 }
2222
David Benjamin025b3d32014-07-01 19:53:04 -04002223 for i := range testCases {
2224 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
2225 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07002226 }
2227 }
2228
2229 close(testChan)
2230 wg.Wait()
2231 close(statusChan)
2232 <-doneChan
2233
2234 fmt.Printf("\n")
2235}