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