blob: ef723743776182b60219b45f4c6696032512f397 [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},
David Benjamin2af684f2014-10-27 02:23:15 -0400831 {"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700832 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700833 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400834 {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400835 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700836 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400837 {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700838 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
David Benjamin48cae082014-10-27 01:06:24 -0400839 {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
840 {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
841 {"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700842 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400843 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700844}
845
David Benjaminf7768e42014-08-31 02:06:47 -0400846func isTLS12Only(suiteName string) bool {
847 return strings.HasSuffix(suiteName, "-GCM") ||
848 strings.HasSuffix(suiteName, "-SHA256") ||
849 strings.HasSuffix(suiteName, "-SHA384")
850}
851
Adam Langley95c29f32014-06-20 12:00:00 -0700852func addCipherSuiteTests() {
853 for _, suite := range testCipherSuites {
David Benjamin48cae082014-10-27 01:06:24 -0400854 const psk = "12345"
855 const pskIdentity = "luggage combo"
856
Adam Langley95c29f32014-06-20 12:00:00 -0700857 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400858 var certFile string
859 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700860 if strings.Contains(suite.name, "ECDSA") {
861 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400862 certFile = ecdsaCertificateFile
863 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700864 } else {
865 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400866 certFile = rsaCertificateFile
867 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700868 }
869
David Benjamin48cae082014-10-27 01:06:24 -0400870 var flags []string
871 if strings.HasPrefix(suite.name, "PSK-") || strings.Contains(suite.name, "-PSK-") {
872 flags = append(flags,
873 "-psk", psk,
874 "-psk-identity", pskIdentity)
875 }
876
Adam Langley95c29f32014-06-20 12:00:00 -0700877 for _, ver := range tlsVersions {
David Benjaminf7768e42014-08-31 02:06:47 -0400878 if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
Adam Langley95c29f32014-06-20 12:00:00 -0700879 continue
880 }
881
David Benjamin1d5c83e2014-07-22 19:20:02 -0400882 // Go's TLS implementation only implements session
883 // resumption with tickets, so SSLv3 cannot resume
884 // sessions.
885 resumeSession := ver.version != VersionSSL30
886
David Benjamin025b3d32014-07-01 19:53:04 -0400887 testCases = append(testCases, testCase{
888 testType: clientTest,
889 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700890 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400891 MinVersion: ver.version,
892 MaxVersion: ver.version,
893 CipherSuites: []uint16{suite.id},
894 Certificates: []Certificate{cert},
895 PreSharedKey: []byte(psk),
896 PreSharedKeyIdentity: pskIdentity,
Adam Langley95c29f32014-06-20 12:00:00 -0700897 },
David Benjamin48cae082014-10-27 01:06:24 -0400898 flags: flags,
David Benjamin1d5c83e2014-07-22 19:20:02 -0400899 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700900 })
David Benjamin025b3d32014-07-01 19:53:04 -0400901
David Benjamin76d8abe2014-08-14 16:25:34 -0400902 testCases = append(testCases, testCase{
903 testType: serverTest,
904 name: ver.name + "-" + suite.name + "-server",
905 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400906 MinVersion: ver.version,
907 MaxVersion: ver.version,
908 CipherSuites: []uint16{suite.id},
909 Certificates: []Certificate{cert},
910 PreSharedKey: []byte(psk),
911 PreSharedKeyIdentity: pskIdentity,
David Benjamin76d8abe2014-08-14 16:25:34 -0400912 },
913 certFile: certFile,
914 keyFile: keyFile,
David Benjamin48cae082014-10-27 01:06:24 -0400915 flags: flags,
David Benjamin76d8abe2014-08-14 16:25:34 -0400916 resumeSession: resumeSession,
917 })
David Benjamin6fd297b2014-08-11 18:43:38 -0400918
919 // TODO(davidben): Fix DTLS 1.2 support and test that.
920 if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
921 testCases = append(testCases, testCase{
922 testType: clientTest,
923 protocol: dtls,
924 name: "D" + ver.name + "-" + suite.name + "-client",
925 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400926 MinVersion: ver.version,
927 MaxVersion: ver.version,
928 CipherSuites: []uint16{suite.id},
929 Certificates: []Certificate{cert},
930 PreSharedKey: []byte(psk),
931 PreSharedKeyIdentity: pskIdentity,
David Benjamin6fd297b2014-08-11 18:43:38 -0400932 },
David Benjamin48cae082014-10-27 01:06:24 -0400933 flags: flags,
David Benjamin6fd297b2014-08-11 18:43:38 -0400934 resumeSession: resumeSession,
935 })
936 testCases = append(testCases, testCase{
937 testType: serverTest,
938 protocol: dtls,
939 name: "D" + ver.name + "-" + suite.name + "-server",
940 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400941 MinVersion: ver.version,
942 MaxVersion: ver.version,
943 CipherSuites: []uint16{suite.id},
944 Certificates: []Certificate{cert},
945 PreSharedKey: []byte(psk),
946 PreSharedKeyIdentity: pskIdentity,
David Benjamin6fd297b2014-08-11 18:43:38 -0400947 },
948 certFile: certFile,
949 keyFile: keyFile,
David Benjamin48cae082014-10-27 01:06:24 -0400950 flags: flags,
David Benjamin6fd297b2014-08-11 18:43:38 -0400951 resumeSession: resumeSession,
952 })
953 }
Adam Langley95c29f32014-06-20 12:00:00 -0700954 }
955 }
956}
957
958func addBadECDSASignatureTests() {
959 for badR := BadValue(1); badR < NumBadValues; badR++ {
960 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -0400961 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700962 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
963 config: Config{
964 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
965 Certificates: []Certificate{getECDSACertificate()},
966 Bugs: ProtocolBugs{
967 BadECDSAR: badR,
968 BadECDSAS: badS,
969 },
970 },
971 shouldFail: true,
972 expectedError: "SIGNATURE",
973 })
974 }
975 }
976}
977
Adam Langley80842bd2014-06-20 12:00:00 -0700978func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -0400979 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700980 name: "MaxCBCPadding",
981 config: Config{
982 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
983 Bugs: ProtocolBugs{
984 MaxPadding: true,
985 },
986 },
987 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
988 })
David Benjamin025b3d32014-07-01 19:53:04 -0400989 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -0700990 name: "BadCBCPadding",
991 config: Config{
992 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
993 Bugs: ProtocolBugs{
994 PaddingFirstByteBad: true,
995 },
996 },
997 shouldFail: true,
998 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
999 })
1000 // OpenSSL previously had an issue where the first byte of padding in
1001 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -04001002 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -07001003 name: "BadCBCPadding255",
1004 config: Config{
1005 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1006 Bugs: ProtocolBugs{
1007 MaxPadding: true,
1008 PaddingFirstByteBadIf255: true,
1009 },
1010 },
1011 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
1012 shouldFail: true,
1013 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1014 })
1015}
1016
Kenny Root7fdeaf12014-08-05 15:23:37 -07001017func addCBCSplittingTests() {
1018 testCases = append(testCases, testCase{
1019 name: "CBCRecordSplitting",
1020 config: Config{
1021 MaxVersion: VersionTLS10,
1022 MinVersion: VersionTLS10,
1023 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1024 },
1025 messageLen: -1, // read until EOF
1026 flags: []string{
1027 "-async",
1028 "-write-different-record-sizes",
1029 "-cbc-record-splitting",
1030 },
David Benjamina8e3e0e2014-08-06 22:11:10 -04001031 })
1032 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -07001033 name: "CBCRecordSplittingPartialWrite",
1034 config: Config{
1035 MaxVersion: VersionTLS10,
1036 MinVersion: VersionTLS10,
1037 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1038 },
1039 messageLen: -1, // read until EOF
1040 flags: []string{
1041 "-async",
1042 "-write-different-record-sizes",
1043 "-cbc-record-splitting",
1044 "-partial-write",
1045 },
1046 })
1047}
1048
David Benjamin636293b2014-07-08 17:59:18 -04001049func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -04001050 // Add a dummy cert pool to stress certificate authority parsing.
1051 // TODO(davidben): Add tests that those values parse out correctly.
1052 certPool := x509.NewCertPool()
1053 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
1054 if err != nil {
1055 panic(err)
1056 }
1057 certPool.AddCert(cert)
1058
David Benjamin636293b2014-07-08 17:59:18 -04001059 for _, ver := range tlsVersions {
David Benjamin636293b2014-07-08 17:59:18 -04001060 testCases = append(testCases, testCase{
1061 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -04001062 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -04001063 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001064 MinVersion: ver.version,
1065 MaxVersion: ver.version,
1066 ClientAuth: RequireAnyClientCert,
1067 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -04001068 },
1069 flags: []string{
1070 "-cert-file", rsaCertificateFile,
1071 "-key-file", rsaKeyFile,
1072 },
1073 })
1074 testCases = append(testCases, testCase{
David Benjamin67666e72014-07-12 15:47:52 -04001075 testType: serverTest,
1076 name: ver.name + "-Server-ClientAuth-RSA",
1077 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001078 MinVersion: ver.version,
1079 MaxVersion: ver.version,
David Benjamin67666e72014-07-12 15:47:52 -04001080 Certificates: []Certificate{rsaCertificate},
1081 },
1082 flags: []string{"-require-any-client-certificate"},
1083 })
David Benjamine098ec22014-08-27 23:13:20 -04001084 if ver.version != VersionSSL30 {
1085 testCases = append(testCases, testCase{
1086 testType: serverTest,
1087 name: ver.name + "-Server-ClientAuth-ECDSA",
1088 config: Config{
1089 MinVersion: ver.version,
1090 MaxVersion: ver.version,
1091 Certificates: []Certificate{ecdsaCertificate},
1092 },
1093 flags: []string{"-require-any-client-certificate"},
1094 })
1095 testCases = append(testCases, testCase{
1096 testType: clientTest,
1097 name: ver.name + "-Client-ClientAuth-ECDSA",
1098 config: Config{
1099 MinVersion: ver.version,
1100 MaxVersion: ver.version,
1101 ClientAuth: RequireAnyClientCert,
1102 ClientCAs: certPool,
1103 },
1104 flags: []string{
1105 "-cert-file", ecdsaCertificateFile,
1106 "-key-file", ecdsaKeyFile,
1107 },
1108 })
1109 }
David Benjamin636293b2014-07-08 17:59:18 -04001110 }
1111}
1112
Adam Langley75712922014-10-10 16:23:43 -07001113func addExtendedMasterSecretTests() {
1114 const expectEMSFlag = "-expect-extended-master-secret"
1115
1116 for _, with := range []bool{false, true} {
1117 prefix := "No"
1118 var flags []string
1119 if with {
1120 prefix = ""
1121 flags = []string{expectEMSFlag}
1122 }
1123
1124 for _, isClient := range []bool{false, true} {
1125 suffix := "-Server"
1126 testType := serverTest
1127 if isClient {
1128 suffix = "-Client"
1129 testType = clientTest
1130 }
1131
1132 for _, ver := range tlsVersions {
1133 test := testCase{
1134 testType: testType,
1135 name: prefix + "ExtendedMasterSecret-" + ver.name + suffix,
1136 config: Config{
1137 MinVersion: ver.version,
1138 MaxVersion: ver.version,
1139 Bugs: ProtocolBugs{
1140 NoExtendedMasterSecret: !with,
1141 RequireExtendedMasterSecret: with,
1142 },
1143 },
David Benjamin48cae082014-10-27 01:06:24 -04001144 flags: flags,
1145 shouldFail: ver.version == VersionSSL30 && with,
Adam Langley75712922014-10-10 16:23:43 -07001146 }
1147 if test.shouldFail {
1148 test.expectedLocalError = "extended master secret required but not supported by peer"
1149 }
1150 testCases = append(testCases, test)
1151 }
1152 }
1153 }
1154
1155 // When a session is resumed, it should still be aware that its master
1156 // secret was generated via EMS and thus it's safe to use tls-unique.
1157 testCases = append(testCases, testCase{
1158 name: "ExtendedMasterSecret-Resume",
1159 config: Config{
1160 Bugs: ProtocolBugs{
1161 RequireExtendedMasterSecret: true,
1162 },
1163 },
1164 flags: []string{expectEMSFlag},
1165 resumeSession: true,
1166 })
1167}
1168
David Benjamin43ec06f2014-08-05 02:28:57 -04001169// Adds tests that try to cover the range of the handshake state machine, under
1170// various conditions. Some of these are redundant with other tests, but they
1171// only cover the synchronous case.
David Benjamin6fd297b2014-08-11 18:43:38 -04001172func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
David Benjamin43ec06f2014-08-05 02:28:57 -04001173 var suffix string
1174 var flags []string
1175 var maxHandshakeRecordLength int
David Benjamin6fd297b2014-08-11 18:43:38 -04001176 if protocol == dtls {
1177 suffix = "-DTLS"
1178 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001179 if async {
David Benjamin6fd297b2014-08-11 18:43:38 -04001180 suffix += "-Async"
David Benjamin43ec06f2014-08-05 02:28:57 -04001181 flags = append(flags, "-async")
1182 } else {
David Benjamin6fd297b2014-08-11 18:43:38 -04001183 suffix += "-Sync"
David Benjamin43ec06f2014-08-05 02:28:57 -04001184 }
1185 if splitHandshake {
1186 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -04001187 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -04001188 }
1189
1190 // Basic handshake, with resumption. Client and server.
1191 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001192 protocol: protocol,
1193 name: "Basic-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001194 config: Config{
1195 Bugs: ProtocolBugs{
1196 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1197 },
1198 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001199 flags: flags,
1200 resumeSession: true,
1201 })
1202 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001203 protocol: protocol,
1204 name: "Basic-Client-RenewTicket" + suffix,
David Benjaminbed9aae2014-08-07 19:13:38 -04001205 config: Config{
1206 Bugs: ProtocolBugs{
1207 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1208 RenewTicketOnResume: true,
1209 },
1210 },
1211 flags: flags,
1212 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001213 })
1214 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001215 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001216 testType: serverTest,
1217 name: "Basic-Server" + suffix,
1218 config: Config{
1219 Bugs: ProtocolBugs{
1220 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1221 },
1222 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001223 flags: flags,
1224 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001225 })
1226
David Benjamin6fd297b2014-08-11 18:43:38 -04001227 // TLS client auth.
1228 testCases = append(testCases, testCase{
1229 protocol: protocol,
1230 testType: clientTest,
1231 name: "ClientAuth-Client" + suffix,
1232 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001233 ClientAuth: RequireAnyClientCert,
David Benjamin6fd297b2014-08-11 18:43:38 -04001234 Bugs: ProtocolBugs{
1235 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1236 },
1237 },
1238 flags: append(flags,
1239 "-cert-file", rsaCertificateFile,
1240 "-key-file", rsaKeyFile),
1241 })
1242 testCases = append(testCases, testCase{
1243 protocol: protocol,
1244 testType: serverTest,
1245 name: "ClientAuth-Server" + suffix,
1246 config: Config{
1247 Certificates: []Certificate{rsaCertificate},
1248 },
1249 flags: append(flags, "-require-any-client-certificate"),
1250 })
1251
David Benjamin43ec06f2014-08-05 02:28:57 -04001252 // No session ticket support; server doesn't send NewSessionTicket.
1253 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001254 protocol: protocol,
1255 name: "SessionTicketsDisabled-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001256 config: Config{
1257 SessionTicketsDisabled: true,
1258 Bugs: ProtocolBugs{
1259 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1260 },
1261 },
1262 flags: flags,
1263 })
1264 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001265 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001266 testType: serverTest,
1267 name: "SessionTicketsDisabled-Server" + suffix,
1268 config: Config{
1269 SessionTicketsDisabled: true,
1270 Bugs: ProtocolBugs{
1271 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1272 },
1273 },
1274 flags: flags,
1275 })
1276
David Benjamin48cae082014-10-27 01:06:24 -04001277 // Skip ServerKeyExchange in PSK key exchange if there's no
1278 // identity hint.
1279 testCases = append(testCases, testCase{
1280 protocol: protocol,
1281 name: "EmptyPSKHint-Client" + suffix,
1282 config: Config{
1283 CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1284 PreSharedKey: []byte("secret"),
1285 Bugs: ProtocolBugs{
1286 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1287 },
1288 },
1289 flags: append(flags, "-psk", "secret"),
1290 })
1291 testCases = append(testCases, testCase{
1292 protocol: protocol,
1293 testType: serverTest,
1294 name: "EmptyPSKHint-Server" + suffix,
1295 config: Config{
1296 CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1297 PreSharedKey: []byte("secret"),
1298 Bugs: ProtocolBugs{
1299 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1300 },
1301 },
1302 flags: append(flags, "-psk", "secret"),
1303 })
1304
David Benjamin6fd297b2014-08-11 18:43:38 -04001305 if protocol == tls {
1306 // NPN on client and server; results in post-handshake message.
1307 testCases = append(testCases, testCase{
1308 protocol: protocol,
1309 name: "NPN-Client" + suffix,
1310 config: Config{
David Benjaminae2888f2014-09-06 12:58:58 -04001311 NextProtos: []string{"foo"},
David Benjamin6fd297b2014-08-11 18:43:38 -04001312 Bugs: ProtocolBugs{
1313 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1314 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001315 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001316 flags: append(flags, "-select-next-proto", "foo"),
1317 expectedNextProto: "foo",
1318 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001319 })
1320 testCases = append(testCases, testCase{
1321 protocol: protocol,
1322 testType: serverTest,
1323 name: "NPN-Server" + suffix,
1324 config: Config{
1325 NextProtos: []string{"bar"},
1326 Bugs: ProtocolBugs{
1327 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1328 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001329 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001330 flags: append(flags,
1331 "-advertise-npn", "\x03foo\x03bar\x03baz",
1332 "-expect-next-proto", "bar"),
David Benjaminfc7b0862014-09-06 13:21:53 -04001333 expectedNextProto: "bar",
1334 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001335 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001336
David Benjamin6fd297b2014-08-11 18:43:38 -04001337 // Client does False Start and negotiates NPN.
1338 testCases = append(testCases, testCase{
1339 protocol: protocol,
1340 name: "FalseStart" + suffix,
1341 config: Config{
1342 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1343 NextProtos: []string{"foo"},
1344 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001345 ExpectFalseStart: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001346 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1347 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001348 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001349 flags: append(flags,
1350 "-false-start",
1351 "-select-next-proto", "foo"),
David Benjamine58c4f52014-08-24 03:47:07 -04001352 shimWritesFirst: true,
1353 resumeSession: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001354 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001355
David Benjaminae2888f2014-09-06 12:58:58 -04001356 // Client does False Start and negotiates ALPN.
1357 testCases = append(testCases, testCase{
1358 protocol: protocol,
1359 name: "FalseStart-ALPN" + suffix,
1360 config: Config{
1361 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1362 NextProtos: []string{"foo"},
1363 Bugs: ProtocolBugs{
1364 ExpectFalseStart: true,
1365 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1366 },
1367 },
1368 flags: append(flags,
1369 "-false-start",
1370 "-advertise-alpn", "\x03foo"),
1371 shimWritesFirst: true,
1372 resumeSession: true,
1373 })
1374
David Benjamin6fd297b2014-08-11 18:43:38 -04001375 // False Start without session tickets.
1376 testCases = append(testCases, testCase{
1377 name: "FalseStart-SessionTicketsDisabled",
1378 config: Config{
1379 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1380 NextProtos: []string{"foo"},
1381 SessionTicketsDisabled: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001382 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001383 ExpectFalseStart: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001384 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1385 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001386 },
David Benjamin4e99c522014-08-24 01:45:30 -04001387 flags: append(flags,
David Benjamin6fd297b2014-08-11 18:43:38 -04001388 "-false-start",
1389 "-select-next-proto", "foo",
David Benjamin4e99c522014-08-24 01:45:30 -04001390 ),
David Benjamine58c4f52014-08-24 03:47:07 -04001391 shimWritesFirst: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001392 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001393
David Benjamina08e49d2014-08-24 01:46:07 -04001394 // Server parses a V2ClientHello.
David Benjamin6fd297b2014-08-11 18:43:38 -04001395 testCases = append(testCases, testCase{
1396 protocol: protocol,
1397 testType: serverTest,
1398 name: "SendV2ClientHello" + suffix,
1399 config: Config{
1400 // Choose a cipher suite that does not involve
1401 // elliptic curves, so no extensions are
1402 // involved.
1403 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1404 Bugs: ProtocolBugs{
1405 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1406 SendV2ClientHello: true,
1407 },
David Benjamin1e7f8d72014-08-08 12:27:04 -04001408 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001409 flags: flags,
1410 })
David Benjamina08e49d2014-08-24 01:46:07 -04001411
1412 // Client sends a Channel ID.
1413 testCases = append(testCases, testCase{
1414 protocol: protocol,
1415 name: "ChannelID-Client" + suffix,
1416 config: Config{
1417 RequestChannelID: true,
1418 Bugs: ProtocolBugs{
1419 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1420 },
1421 },
1422 flags: append(flags,
1423 "-send-channel-id", channelIDKeyFile,
1424 ),
1425 resumeSession: true,
1426 expectChannelID: true,
1427 })
1428
1429 // Server accepts a Channel ID.
1430 testCases = append(testCases, testCase{
1431 protocol: protocol,
1432 testType: serverTest,
1433 name: "ChannelID-Server" + suffix,
1434 config: Config{
1435 ChannelID: channelIDKey,
1436 Bugs: ProtocolBugs{
1437 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1438 },
1439 },
1440 flags: append(flags,
1441 "-expect-channel-id",
1442 base64.StdEncoding.EncodeToString(channelIDBytes),
1443 ),
1444 resumeSession: true,
1445 expectChannelID: true,
1446 })
David Benjamin6fd297b2014-08-11 18:43:38 -04001447 } else {
1448 testCases = append(testCases, testCase{
1449 protocol: protocol,
1450 name: "SkipHelloVerifyRequest" + suffix,
1451 config: Config{
1452 Bugs: ProtocolBugs{
1453 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1454 SkipHelloVerifyRequest: true,
1455 },
1456 },
1457 flags: flags,
1458 })
1459
1460 testCases = append(testCases, testCase{
1461 testType: serverTest,
1462 protocol: protocol,
1463 name: "CookieExchange" + suffix,
1464 config: Config{
1465 Bugs: ProtocolBugs{
1466 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1467 },
1468 },
1469 flags: append(flags, "-cookie-exchange"),
1470 })
1471 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001472}
1473
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001474func addVersionNegotiationTests() {
1475 for i, shimVers := range tlsVersions {
1476 // Assemble flags to disable all newer versions on the shim.
1477 var flags []string
1478 for _, vers := range tlsVersions[i+1:] {
1479 flags = append(flags, vers.flag)
1480 }
1481
1482 for _, runnerVers := range tlsVersions {
1483 expectedVersion := shimVers.version
1484 if runnerVers.version < shimVers.version {
1485 expectedVersion = runnerVers.version
1486 }
1487 suffix := shimVers.name + "-" + runnerVers.name
1488
1489 testCases = append(testCases, testCase{
1490 testType: clientTest,
1491 name: "VersionNegotiation-Client-" + suffix,
1492 config: Config{
1493 MaxVersion: runnerVers.version,
1494 },
1495 flags: flags,
1496 expectedVersion: expectedVersion,
1497 })
1498
David Benjamin76d8abe2014-08-14 16:25:34 -04001499 testCases = append(testCases, testCase{
1500 testType: serverTest,
1501 name: "VersionNegotiation-Server-" + suffix,
1502 config: Config{
1503 MaxVersion: runnerVers.version,
1504 },
1505 flags: flags,
1506 expectedVersion: expectedVersion,
1507 })
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001508 }
1509 }
1510}
1511
David Benjamin5c24a1d2014-08-31 00:59:27 -04001512func addD5BugTests() {
1513 testCases = append(testCases, testCase{
1514 testType: serverTest,
1515 name: "D5Bug-NoQuirk-Reject",
1516 config: Config{
1517 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1518 Bugs: ProtocolBugs{
1519 SSL3RSAKeyExchange: true,
1520 },
1521 },
1522 shouldFail: true,
1523 expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
1524 })
1525 testCases = append(testCases, testCase{
1526 testType: serverTest,
1527 name: "D5Bug-Quirk-Normal",
1528 config: Config{
1529 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1530 },
1531 flags: []string{"-tls-d5-bug"},
1532 })
1533 testCases = append(testCases, testCase{
1534 testType: serverTest,
1535 name: "D5Bug-Quirk-Bug",
1536 config: Config{
1537 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1538 Bugs: ProtocolBugs{
1539 SSL3RSAKeyExchange: true,
1540 },
1541 },
1542 flags: []string{"-tls-d5-bug"},
1543 })
1544}
1545
David Benjamine78bfde2014-09-06 12:45:15 -04001546func addExtensionTests() {
1547 testCases = append(testCases, testCase{
1548 testType: clientTest,
1549 name: "DuplicateExtensionClient",
1550 config: Config{
1551 Bugs: ProtocolBugs{
1552 DuplicateExtension: true,
1553 },
1554 },
1555 shouldFail: true,
1556 expectedLocalError: "remote error: error decoding message",
1557 })
1558 testCases = append(testCases, testCase{
1559 testType: serverTest,
1560 name: "DuplicateExtensionServer",
1561 config: Config{
1562 Bugs: ProtocolBugs{
1563 DuplicateExtension: true,
1564 },
1565 },
1566 shouldFail: true,
1567 expectedLocalError: "remote error: error decoding message",
1568 })
1569 testCases = append(testCases, testCase{
1570 testType: clientTest,
1571 name: "ServerNameExtensionClient",
1572 config: Config{
1573 Bugs: ProtocolBugs{
1574 ExpectServerName: "example.com",
1575 },
1576 },
1577 flags: []string{"-host-name", "example.com"},
1578 })
1579 testCases = append(testCases, testCase{
1580 testType: clientTest,
1581 name: "ServerNameExtensionClient",
1582 config: Config{
1583 Bugs: ProtocolBugs{
1584 ExpectServerName: "mismatch.com",
1585 },
1586 },
1587 flags: []string{"-host-name", "example.com"},
1588 shouldFail: true,
1589 expectedLocalError: "tls: unexpected server name",
1590 })
1591 testCases = append(testCases, testCase{
1592 testType: clientTest,
1593 name: "ServerNameExtensionClient",
1594 config: Config{
1595 Bugs: ProtocolBugs{
1596 ExpectServerName: "missing.com",
1597 },
1598 },
1599 shouldFail: true,
1600 expectedLocalError: "tls: unexpected server name",
1601 })
1602 testCases = append(testCases, testCase{
1603 testType: serverTest,
1604 name: "ServerNameExtensionServer",
1605 config: Config{
1606 ServerName: "example.com",
1607 },
1608 flags: []string{"-expect-server-name", "example.com"},
1609 resumeSession: true,
1610 })
David Benjaminae2888f2014-09-06 12:58:58 -04001611 testCases = append(testCases, testCase{
1612 testType: clientTest,
1613 name: "ALPNClient",
1614 config: Config{
1615 NextProtos: []string{"foo"},
1616 },
1617 flags: []string{
1618 "-advertise-alpn", "\x03foo\x03bar\x03baz",
1619 "-expect-alpn", "foo",
1620 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001621 expectedNextProto: "foo",
1622 expectedNextProtoType: alpn,
1623 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001624 })
1625 testCases = append(testCases, testCase{
1626 testType: serverTest,
1627 name: "ALPNServer",
1628 config: Config{
1629 NextProtos: []string{"foo", "bar", "baz"},
1630 },
1631 flags: []string{
1632 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1633 "-select-alpn", "foo",
1634 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001635 expectedNextProto: "foo",
1636 expectedNextProtoType: alpn,
1637 resumeSession: true,
1638 })
1639 // Test that the server prefers ALPN over NPN.
1640 testCases = append(testCases, testCase{
1641 testType: serverTest,
1642 name: "ALPNServer-Preferred",
1643 config: Config{
1644 NextProtos: []string{"foo", "bar", "baz"},
1645 },
1646 flags: []string{
1647 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1648 "-select-alpn", "foo",
1649 "-advertise-npn", "\x03foo\x03bar\x03baz",
1650 },
1651 expectedNextProto: "foo",
1652 expectedNextProtoType: alpn,
1653 resumeSession: true,
1654 })
1655 testCases = append(testCases, testCase{
1656 testType: serverTest,
1657 name: "ALPNServer-Preferred-Swapped",
1658 config: Config{
1659 NextProtos: []string{"foo", "bar", "baz"},
1660 Bugs: ProtocolBugs{
1661 SwapNPNAndALPN: true,
1662 },
1663 },
1664 flags: []string{
1665 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1666 "-select-alpn", "foo",
1667 "-advertise-npn", "\x03foo\x03bar\x03baz",
1668 },
1669 expectedNextProto: "foo",
1670 expectedNextProtoType: alpn,
1671 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001672 })
Adam Langley38311732014-10-16 19:04:35 -07001673 // Resume with a corrupt ticket.
1674 testCases = append(testCases, testCase{
1675 testType: serverTest,
1676 name: "CorruptTicket",
1677 config: Config{
1678 Bugs: ProtocolBugs{
1679 CorruptTicket: true,
1680 },
1681 },
1682 resumeSession: true,
1683 flags: []string{"-expect-session-miss"},
1684 })
1685 // Resume with an oversized session id.
1686 testCases = append(testCases, testCase{
1687 testType: serverTest,
1688 name: "OversizedSessionId",
1689 config: Config{
1690 Bugs: ProtocolBugs{
1691 OversizedSessionId: true,
1692 },
1693 },
1694 resumeSession: true,
Adam Langley75712922014-10-10 16:23:43 -07001695 shouldFail: true,
Adam Langley38311732014-10-16 19:04:35 -07001696 expectedError: ":DECODE_ERROR:",
1697 })
David Benjamine78bfde2014-09-06 12:45:15 -04001698}
1699
David Benjamin01fe8202014-09-24 15:21:44 -04001700func addResumptionVersionTests() {
1701 // TODO(davidben): Once DTLS 1.2 is working, test that as well.
1702 for _, sessionVers := range tlsVersions {
1703 // TODO(davidben): SSLv3 is omitted here because runner does not
1704 // support resumption with session IDs.
1705 if sessionVers.version == VersionSSL30 {
1706 continue
1707 }
1708 for _, resumeVers := range tlsVersions {
1709 if resumeVers.version == VersionSSL30 {
1710 continue
1711 }
1712 suffix := "-" + sessionVers.name + "-" + resumeVers.name
1713
1714 // TODO(davidben): Write equivalent tests for the server
1715 // and clean up the server's logic. This requires being
1716 // able to give the shim a different set of SSL_OP_NO_*
1717 // flags between the initial connection and the
1718 // resume. Perhaps resumption should be tested by
1719 // serializing the SSL_SESSION and starting a second
1720 // shim.
1721 testCases = append(testCases, testCase{
1722 name: "Resume-Client" + suffix,
1723 resumeSession: true,
1724 config: Config{
1725 MaxVersion: sessionVers.version,
1726 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1727 Bugs: ProtocolBugs{
1728 AllowSessionVersionMismatch: true,
1729 },
1730 },
1731 expectedVersion: sessionVers.version,
1732 resumeConfig: &Config{
1733 MaxVersion: resumeVers.version,
1734 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1735 Bugs: ProtocolBugs{
1736 AllowSessionVersionMismatch: true,
1737 },
1738 },
1739 expectedResumeVersion: resumeVers.version,
1740 })
1741
1742 testCases = append(testCases, testCase{
1743 name: "Resume-Client-NoResume" + suffix,
1744 flags: []string{"-expect-session-miss"},
1745 resumeSession: true,
1746 config: Config{
1747 MaxVersion: sessionVers.version,
1748 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1749 },
1750 expectedVersion: sessionVers.version,
1751 resumeConfig: &Config{
1752 MaxVersion: resumeVers.version,
1753 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1754 SessionTicketsDisabled: true,
1755 },
1756 expectedResumeVersion: resumeVers.version,
1757 })
1758 }
1759 }
1760}
1761
Adam Langley2ae77d22014-10-28 17:29:33 -07001762func addRenegotiationTests() {
1763 testCases = append(testCases, testCase{
1764 testType: serverTest,
1765 name: "Renegotiate-Server",
1766 flags: []string{"-renegotiate"},
1767 shimWritesFirst: true,
1768 })
1769 testCases = append(testCases, testCase{
1770 testType: serverTest,
1771 name: "Renegotiate-Server-EmptyExt",
1772 config: Config{
1773 Bugs: ProtocolBugs{
1774 EmptyRenegotiationInfo: true,
1775 },
1776 },
1777 flags: []string{"-renegotiate"},
1778 shimWritesFirst: true,
1779 shouldFail: true,
1780 expectedError: ":RENEGOTIATION_MISMATCH:",
1781 })
1782 testCases = append(testCases, testCase{
1783 testType: serverTest,
1784 name: "Renegotiate-Server-BadExt",
1785 config: Config{
1786 Bugs: ProtocolBugs{
1787 BadRenegotiationInfo: true,
1788 },
1789 },
1790 flags: []string{"-renegotiate"},
1791 shimWritesFirst: true,
1792 shouldFail: true,
1793 expectedError: ":RENEGOTIATION_MISMATCH:",
1794 })
1795 // TODO(agl): test the renegotiation info SCSV.
1796}
1797
David Benjamin884fdf12014-08-02 15:28:23 -04001798func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07001799 defer wg.Done()
1800
1801 for test := range c {
1802 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04001803 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07001804 statusChan <- statusMsg{test: test, err: err}
1805 }
1806}
1807
1808type statusMsg struct {
1809 test *testCase
1810 started bool
1811 err error
1812}
1813
1814func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1815 var started, done, failed, lineLen int
1816 defer close(doneChan)
1817
1818 for msg := range statusChan {
1819 if msg.started {
1820 started++
1821 } else {
1822 done++
1823 }
1824
1825 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1826
1827 if msg.err != nil {
1828 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1829 failed++
1830 }
1831 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1832 lineLen = len(line)
1833 os.Stdout.WriteString(line)
1834 }
1835}
1836
1837func main() {
1838 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 -04001839 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04001840 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07001841
1842 flag.Parse()
1843
1844 addCipherSuiteTests()
1845 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07001846 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07001847 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04001848 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001849 addVersionNegotiationTests()
David Benjamin5c24a1d2014-08-31 00:59:27 -04001850 addD5BugTests()
David Benjamine78bfde2014-09-06 12:45:15 -04001851 addExtensionTests()
David Benjamin01fe8202014-09-24 15:21:44 -04001852 addResumptionVersionTests()
Adam Langley75712922014-10-10 16:23:43 -07001853 addExtendedMasterSecretTests()
Adam Langley2ae77d22014-10-28 17:29:33 -07001854 addRenegotiationTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04001855 for _, async := range []bool{false, true} {
1856 for _, splitHandshake := range []bool{false, true} {
David Benjamin6fd297b2014-08-11 18:43:38 -04001857 for _, protocol := range []protocol{tls, dtls} {
1858 addStateMachineCoverageTests(async, splitHandshake, protocol)
1859 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001860 }
1861 }
Adam Langley95c29f32014-06-20 12:00:00 -07001862
1863 var wg sync.WaitGroup
1864
David Benjamin2bc8e6f2014-08-02 15:22:37 -04001865 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07001866
1867 statusChan := make(chan statusMsg, numWorkers)
1868 testChan := make(chan *testCase, numWorkers)
1869 doneChan := make(chan struct{})
1870
David Benjamin025b3d32014-07-01 19:53:04 -04001871 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07001872
1873 for i := 0; i < numWorkers; i++ {
1874 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04001875 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07001876 }
1877
David Benjamin025b3d32014-07-01 19:53:04 -04001878 for i := range testCases {
1879 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
1880 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07001881 }
1882 }
1883
1884 close(testChan)
1885 wg.Wait()
1886 close(statusChan)
1887 <-doneChan
1888
1889 fmt.Printf("\n")
1890}