blob: a3026877fbffa35b113e320d7d21ff669246cb72 [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
Adam Langleycf2d4f42014-10-28 19:06:14 -0700153 // renegotiate indicates the the connection should be renegotiated
154 // during the exchange.
155 renegotiate bool
156 // renegotiateCiphers is a list of ciphersuite ids that will be
157 // switched in just before renegotiation.
158 renegotiateCiphers []uint16
David Benjamin5e961c12014-11-07 01:48:35 -0500159 // replayWrites, if true, configures the underlying transport
160 // to replay every write it makes in DTLS tests.
161 replayWrites bool
David Benjamin325b5c32014-07-01 19:40:31 -0400162 // flags, if not empty, contains a list of command-line flags that will
163 // be passed to the shim program.
164 flags []string
Adam Langley95c29f32014-06-20 12:00:00 -0700165}
166
David Benjamin025b3d32014-07-01 19:53:04 -0400167var testCases = []testCase{
Adam Langley95c29f32014-06-20 12:00:00 -0700168 {
169 name: "BadRSASignature",
170 config: Config{
171 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
172 Bugs: ProtocolBugs{
173 InvalidSKXSignature: true,
174 },
175 },
176 shouldFail: true,
177 expectedError: ":BAD_SIGNATURE:",
178 },
179 {
180 name: "BadECDSASignature",
181 config: Config{
182 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
183 Bugs: ProtocolBugs{
184 InvalidSKXSignature: true,
185 },
186 Certificates: []Certificate{getECDSACertificate()},
187 },
188 shouldFail: true,
189 expectedError: ":BAD_SIGNATURE:",
190 },
191 {
192 name: "BadECDSACurve",
193 config: Config{
194 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
195 Bugs: ProtocolBugs{
196 InvalidSKXCurve: true,
197 },
198 Certificates: []Certificate{getECDSACertificate()},
199 },
200 shouldFail: true,
201 expectedError: ":WRONG_CURVE:",
202 },
Adam Langleyac61fa32014-06-23 12:03:11 -0700203 {
David Benjamina8e3e0e2014-08-06 22:11:10 -0400204 testType: serverTest,
205 name: "BadRSAVersion",
206 config: Config{
207 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
208 Bugs: ProtocolBugs{
209 RsaClientKeyExchangeVersion: VersionTLS11,
210 },
211 },
212 shouldFail: true,
213 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
214 },
215 {
David Benjamin325b5c32014-07-01 19:40:31 -0400216 name: "NoFallbackSCSV",
Adam Langleyac61fa32014-06-23 12:03:11 -0700217 config: Config{
218 Bugs: ProtocolBugs{
219 FailIfNotFallbackSCSV: true,
220 },
221 },
222 shouldFail: true,
223 expectedLocalError: "no fallback SCSV found",
224 },
David Benjamin325b5c32014-07-01 19:40:31 -0400225 {
David Benjamin2a0c4962014-08-22 23:46:35 -0400226 name: "SendFallbackSCSV",
David Benjamin325b5c32014-07-01 19:40:31 -0400227 config: Config{
228 Bugs: ProtocolBugs{
229 FailIfNotFallbackSCSV: true,
230 },
231 },
232 flags: []string{"-fallback-scsv"},
233 },
David Benjamin197b3ab2014-07-02 18:37:33 -0400234 {
David Benjamin7b030512014-07-08 17:30:11 -0400235 name: "ClientCertificateTypes",
236 config: Config{
237 ClientAuth: RequestClientCert,
238 ClientCertificateTypes: []byte{
239 CertTypeDSSSign,
240 CertTypeRSASign,
241 CertTypeECDSASign,
242 },
243 },
David Benjamin2561dc32014-08-24 01:25:27 -0400244 flags: []string{
245 "-expect-certificate-types",
246 base64.StdEncoding.EncodeToString([]byte{
247 CertTypeDSSSign,
248 CertTypeRSASign,
249 CertTypeECDSASign,
250 }),
251 },
David Benjamin7b030512014-07-08 17:30:11 -0400252 },
David Benjamin636293b2014-07-08 17:59:18 -0400253 {
254 name: "NoClientCertificate",
255 config: Config{
256 ClientAuth: RequireAnyClientCert,
257 },
258 shouldFail: true,
259 expectedLocalError: "client didn't provide a certificate",
260 },
David Benjamin1c375dd2014-07-12 00:48:23 -0400261 {
262 name: "UnauthenticatedECDH",
263 config: Config{
264 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
265 Bugs: ProtocolBugs{
266 UnauthenticatedECDH: true,
267 },
268 },
269 shouldFail: true,
David Benjamine8f3d662014-07-12 01:10:19 -0400270 expectedError: ":UNEXPECTED_MESSAGE:",
David Benjamin1c375dd2014-07-12 00:48:23 -0400271 },
David Benjamin9c651c92014-07-12 13:27:45 -0400272 {
273 name: "SkipServerKeyExchange",
274 config: Config{
275 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
276 Bugs: ProtocolBugs{
277 SkipServerKeyExchange: true,
278 },
279 },
280 shouldFail: true,
281 expectedError: ":UNEXPECTED_MESSAGE:",
282 },
David Benjamin1f5f62b2014-07-12 16:18:02 -0400283 {
David Benjamina0e52232014-07-19 17:39:58 -0400284 name: "SkipChangeCipherSpec-Client",
285 config: Config{
286 Bugs: ProtocolBugs{
287 SkipChangeCipherSpec: true,
288 },
289 },
290 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400291 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400292 },
293 {
294 testType: serverTest,
295 name: "SkipChangeCipherSpec-Server",
296 config: Config{
297 Bugs: ProtocolBugs{
298 SkipChangeCipherSpec: true,
299 },
300 },
301 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400302 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamina0e52232014-07-19 17:39:58 -0400303 },
David Benjamin42be6452014-07-21 14:50:23 -0400304 {
305 testType: serverTest,
306 name: "SkipChangeCipherSpec-Server-NPN",
307 config: Config{
308 NextProtos: []string{"bar"},
309 Bugs: ProtocolBugs{
310 SkipChangeCipherSpec: true,
311 },
312 },
313 flags: []string{
314 "-advertise-npn", "\x03foo\x03bar\x03baz",
315 },
316 shouldFail: true,
David Benjamin86271ee2014-07-21 16:14:03 -0400317 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
318 },
319 {
320 name: "FragmentAcrossChangeCipherSpec-Client",
321 config: Config{
322 Bugs: ProtocolBugs{
323 FragmentAcrossChangeCipherSpec: true,
324 },
325 },
326 shouldFail: true,
327 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
328 },
329 {
330 testType: serverTest,
331 name: "FragmentAcrossChangeCipherSpec-Server",
332 config: Config{
333 Bugs: ProtocolBugs{
334 FragmentAcrossChangeCipherSpec: true,
335 },
336 },
337 shouldFail: true,
338 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
339 },
340 {
341 testType: serverTest,
342 name: "FragmentAcrossChangeCipherSpec-Server-NPN",
343 config: Config{
344 NextProtos: []string{"bar"},
345 Bugs: ProtocolBugs{
346 FragmentAcrossChangeCipherSpec: true,
347 },
348 },
349 flags: []string{
350 "-advertise-npn", "\x03foo\x03bar\x03baz",
351 },
352 shouldFail: true,
353 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
David Benjamin42be6452014-07-21 14:50:23 -0400354 },
David Benjaminf3ec83d2014-07-21 22:42:34 -0400355 {
356 testType: serverTest,
Alex Chernyakhovsky4cd8c432014-11-01 19:39:08 -0400357 name: "FragmentAlert",
358 config: Config{
359 Bugs: ProtocolBugs{
360 FragmentAlert: true,
361 SendSpuriousAlert: true,
362 },
363 },
364 shouldFail: true,
365 expectedError: ":BAD_ALERT:",
366 },
367 {
368 testType: serverTest,
David Benjaminf3ec83d2014-07-21 22:42:34 -0400369 name: "EarlyChangeCipherSpec-server-1",
370 config: Config{
371 Bugs: ProtocolBugs{
372 EarlyChangeCipherSpec: 1,
373 },
374 },
375 shouldFail: true,
376 expectedError: ":CCS_RECEIVED_EARLY:",
377 },
378 {
379 testType: serverTest,
380 name: "EarlyChangeCipherSpec-server-2",
381 config: Config{
382 Bugs: ProtocolBugs{
383 EarlyChangeCipherSpec: 2,
384 },
385 },
386 shouldFail: true,
387 expectedError: ":CCS_RECEIVED_EARLY:",
388 },
David Benjamind23f4122014-07-23 15:09:48 -0400389 {
David Benjamind23f4122014-07-23 15:09:48 -0400390 name: "SkipNewSessionTicket",
391 config: Config{
392 Bugs: ProtocolBugs{
393 SkipNewSessionTicket: true,
394 },
395 },
396 shouldFail: true,
397 expectedError: ":CCS_RECEIVED_EARLY:",
398 },
David Benjamin7e3305e2014-07-28 14:52:32 -0400399 {
David Benjamind86c7672014-08-02 04:07:12 -0400400 testType: serverTest,
David Benjaminbef270a2014-08-02 04:22:02 -0400401 name: "FallbackSCSV",
402 config: Config{
403 MaxVersion: VersionTLS11,
404 Bugs: ProtocolBugs{
405 SendFallbackSCSV: true,
406 },
407 },
408 shouldFail: true,
409 expectedError: ":INAPPROPRIATE_FALLBACK:",
410 },
411 {
412 testType: serverTest,
413 name: "FallbackSCSV-VersionMatch",
414 config: Config{
415 Bugs: ProtocolBugs{
416 SendFallbackSCSV: true,
417 },
418 },
419 },
David Benjamin98214542014-08-07 18:02:39 -0400420 {
421 testType: serverTest,
422 name: "FragmentedClientVersion",
423 config: Config{
424 Bugs: ProtocolBugs{
425 MaxHandshakeRecordLength: 1,
426 FragmentClientVersion: true,
427 },
428 },
429 shouldFail: true,
430 expectedError: ":RECORD_TOO_SMALL:",
431 },
David Benjamin98e882e2014-08-08 13:24:34 -0400432 {
433 testType: serverTest,
434 name: "MinorVersionTolerance",
435 config: Config{
436 Bugs: ProtocolBugs{
437 SendClientVersion: 0x03ff,
438 },
439 },
440 expectedVersion: VersionTLS12,
441 },
442 {
443 testType: serverTest,
444 name: "MajorVersionTolerance",
445 config: Config{
446 Bugs: ProtocolBugs{
447 SendClientVersion: 0x0400,
448 },
449 },
450 expectedVersion: VersionTLS12,
451 },
452 {
453 testType: serverTest,
454 name: "VersionTooLow",
455 config: Config{
456 Bugs: ProtocolBugs{
457 SendClientVersion: 0x0200,
458 },
459 },
460 shouldFail: true,
461 expectedError: ":UNSUPPORTED_PROTOCOL:",
462 },
463 {
464 testType: serverTest,
465 name: "HttpGET",
466 sendPrefix: "GET / HTTP/1.0\n",
467 shouldFail: true,
468 expectedError: ":HTTP_REQUEST:",
469 },
470 {
471 testType: serverTest,
472 name: "HttpPOST",
473 sendPrefix: "POST / HTTP/1.0\n",
474 shouldFail: true,
475 expectedError: ":HTTP_REQUEST:",
476 },
477 {
478 testType: serverTest,
479 name: "HttpHEAD",
480 sendPrefix: "HEAD / HTTP/1.0\n",
481 shouldFail: true,
482 expectedError: ":HTTP_REQUEST:",
483 },
484 {
485 testType: serverTest,
486 name: "HttpPUT",
487 sendPrefix: "PUT / HTTP/1.0\n",
488 shouldFail: true,
489 expectedError: ":HTTP_REQUEST:",
490 },
491 {
492 testType: serverTest,
493 name: "HttpCONNECT",
494 sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n",
495 shouldFail: true,
496 expectedError: ":HTTPS_PROXY_REQUEST:",
497 },
David Benjamin39ebf532014-08-31 02:23:49 -0400498 {
499 name: "SkipCipherVersionCheck",
500 config: Config{
501 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
502 MaxVersion: VersionTLS11,
503 Bugs: ProtocolBugs{
504 SkipCipherVersionCheck: true,
505 },
506 },
507 shouldFail: true,
508 expectedError: ":WRONG_CIPHER_RETURNED:",
509 },
David Benjamin9114fae2014-11-08 11:41:14 -0500510 {
511 name: "RSAServerKeyExchange",
512 config: Config{
513 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
514 Bugs: ProtocolBugs{
515 RSAServerKeyExchange: true,
516 },
517 },
518 shouldFail: true,
519 expectedError: ":UNEXPECTED_MESSAGE:",
520 },
Adam Langley95c29f32014-06-20 12:00:00 -0700521}
522
David Benjamin01fe8202014-09-24 15:21:44 -0400523func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
David Benjamin6fd297b2014-08-11 18:43:38 -0400524 if test.protocol == dtls {
525 conn = newPacketAdaptor(conn)
David Benjamin5e961c12014-11-07 01:48:35 -0500526 if test.replayWrites {
527 conn = newReplayAdaptor(conn)
528 }
David Benjamin6fd297b2014-08-11 18:43:38 -0400529 }
530
531 if test.sendPrefix != "" {
532 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
533 return err
534 }
David Benjamin98e882e2014-08-08 13:24:34 -0400535 }
536
David Benjamin1d5c83e2014-07-22 19:20:02 -0400537 var tlsConn *Conn
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400538 if test.testType == clientTest {
David Benjamin6fd297b2014-08-11 18:43:38 -0400539 if test.protocol == dtls {
540 tlsConn = DTLSServer(conn, config)
541 } else {
542 tlsConn = Server(conn, config)
543 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400544 } else {
545 config.InsecureSkipVerify = true
David Benjamin6fd297b2014-08-11 18:43:38 -0400546 if test.protocol == dtls {
547 tlsConn = DTLSClient(conn, config)
548 } else {
549 tlsConn = Client(conn, config)
550 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400551 }
552
Adam Langley95c29f32014-06-20 12:00:00 -0700553 if err := tlsConn.Handshake(); err != nil {
554 return err
555 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700556
David Benjamin01fe8202014-09-24 15:21:44 -0400557 // TODO(davidben): move all per-connection expectations into a dedicated
558 // expectations struct that can be specified separately for the two
559 // legs.
560 expectedVersion := test.expectedVersion
561 if isResume && test.expectedResumeVersion != 0 {
562 expectedVersion = test.expectedResumeVersion
563 }
564 if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
565 return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400566 }
567
David Benjamina08e49d2014-08-24 01:46:07 -0400568 if test.expectChannelID {
569 channelID := tlsConn.ConnectionState().ChannelID
570 if channelID == nil {
571 return fmt.Errorf("no channel ID negotiated")
572 }
573 if channelID.Curve != channelIDKey.Curve ||
574 channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
575 channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
576 return fmt.Errorf("incorrect channel ID")
577 }
578 }
579
David Benjaminae2888f2014-09-06 12:58:58 -0400580 if expected := test.expectedNextProto; expected != "" {
581 if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
582 return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
583 }
584 }
585
David Benjaminfc7b0862014-09-06 13:21:53 -0400586 if test.expectedNextProtoType != 0 {
587 if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN {
588 return fmt.Errorf("next proto type mismatch")
589 }
590 }
591
David Benjamine58c4f52014-08-24 03:47:07 -0400592 if test.shimWritesFirst {
593 var buf [5]byte
594 _, err := io.ReadFull(tlsConn, buf[:])
595 if err != nil {
596 return err
597 }
598 if string(buf[:]) != "hello" {
599 return fmt.Errorf("bad initial message")
600 }
601 }
602
Adam Langleycf2d4f42014-10-28 19:06:14 -0700603 if test.renegotiate {
604 if test.renegotiateCiphers != nil {
605 config.CipherSuites = test.renegotiateCiphers
606 }
607 if err := tlsConn.Renegotiate(); err != nil {
608 return err
609 }
610 } else if test.renegotiateCiphers != nil {
611 panic("renegotiateCiphers without renegotiate")
612 }
613
Kenny Root7fdeaf12014-08-05 15:23:37 -0700614 if messageLen < 0 {
David Benjamin6fd297b2014-08-11 18:43:38 -0400615 if test.protocol == dtls {
616 return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
617 }
Kenny Root7fdeaf12014-08-05 15:23:37 -0700618 // Read until EOF.
619 _, err := io.Copy(ioutil.Discard, tlsConn)
620 return err
621 }
622
Adam Langley80842bd2014-06-20 12:00:00 -0700623 if messageLen == 0 {
624 messageLen = 32
625 }
626 testMessage := make([]byte, messageLen)
627 for i := range testMessage {
628 testMessage[i] = 0x42
629 }
Adam Langley95c29f32014-06-20 12:00:00 -0700630 tlsConn.Write(testMessage)
631
632 buf := make([]byte, len(testMessage))
David Benjamin6fd297b2014-08-11 18:43:38 -0400633 if test.protocol == dtls {
634 bufTmp := make([]byte, len(buf)+1)
635 n, err := tlsConn.Read(bufTmp)
636 if err != nil {
637 return err
638 }
639 if n != len(buf) {
640 return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
641 }
642 copy(buf, bufTmp)
643 } else {
644 _, err := io.ReadFull(tlsConn, buf)
645 if err != nil {
646 return err
647 }
Adam Langley95c29f32014-06-20 12:00:00 -0700648 }
649
650 for i, v := range buf {
651 if v != testMessage[i]^0xff {
652 return fmt.Errorf("bad reply contents at byte %d", i)
653 }
654 }
655
656 return nil
657}
658
David Benjamin325b5c32014-07-01 19:40:31 -0400659func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
660 valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
Adam Langley95c29f32014-06-20 12:00:00 -0700661 if dbAttach {
David Benjamin325b5c32014-07-01 19:40:31 -0400662 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
Adam Langley95c29f32014-06-20 12:00:00 -0700663 }
David Benjamin325b5c32014-07-01 19:40:31 -0400664 valgrindArgs = append(valgrindArgs, path)
665 valgrindArgs = append(valgrindArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700666
David Benjamin325b5c32014-07-01 19:40:31 -0400667 return exec.Command("valgrind", valgrindArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700668}
669
David Benjamin325b5c32014-07-01 19:40:31 -0400670func gdbOf(path string, args ...string) *exec.Cmd {
671 xtermArgs := []string{"-e", "gdb", "--args"}
672 xtermArgs = append(xtermArgs, path)
673 xtermArgs = append(xtermArgs, args...)
Adam Langley95c29f32014-06-20 12:00:00 -0700674
David Benjamin325b5c32014-07-01 19:40:31 -0400675 return exec.Command("xterm", xtermArgs...)
Adam Langley95c29f32014-06-20 12:00:00 -0700676}
677
David Benjamin1d5c83e2014-07-22 19:20:02 -0400678func openSocketPair() (shimEnd *os.File, conn net.Conn) {
Adam Langley95c29f32014-06-20 12:00:00 -0700679 socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
680 if err != nil {
681 panic(err)
682 }
683
684 syscall.CloseOnExec(socks[0])
685 syscall.CloseOnExec(socks[1])
David Benjamin1d5c83e2014-07-22 19:20:02 -0400686 shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
Adam Langley95c29f32014-06-20 12:00:00 -0700687 connFile := os.NewFile(uintptr(socks[1]), "our end")
David Benjamin1d5c83e2014-07-22 19:20:02 -0400688 conn, err = net.FileConn(connFile)
689 if err != nil {
690 panic(err)
691 }
Adam Langley95c29f32014-06-20 12:00:00 -0700692 connFile.Close()
693 if err != nil {
694 panic(err)
695 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400696 return shimEnd, conn
697}
698
David Benjamin884fdf12014-08-02 15:28:23 -0400699func runTest(test *testCase, buildDir string) error {
Adam Langley38311732014-10-16 19:04:35 -0700700 if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
701 panic("Error expected without shouldFail in " + test.name)
702 }
703
David Benjamin1d5c83e2014-07-22 19:20:02 -0400704 shimEnd, conn := openSocketPair()
705 shimEndResume, connResume := openSocketPair()
Adam Langley95c29f32014-06-20 12:00:00 -0700706
David Benjamin884fdf12014-08-02 15:28:23 -0400707 shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
David Benjamin5a593af2014-08-11 19:51:50 -0400708 var flags []string
David Benjamin1d5c83e2014-07-22 19:20:02 -0400709 if test.testType == serverTest {
David Benjamin5a593af2014-08-11 19:51:50 -0400710 flags = append(flags, "-server")
711
David Benjamin025b3d32014-07-01 19:53:04 -0400712 flags = append(flags, "-key-file")
713 if test.keyFile == "" {
714 flags = append(flags, rsaKeyFile)
715 } else {
716 flags = append(flags, test.keyFile)
717 }
718
719 flags = append(flags, "-cert-file")
720 if test.certFile == "" {
721 flags = append(flags, rsaCertificateFile)
722 } else {
723 flags = append(flags, test.certFile)
724 }
725 }
David Benjamin5a593af2014-08-11 19:51:50 -0400726
David Benjamin6fd297b2014-08-11 18:43:38 -0400727 if test.protocol == dtls {
728 flags = append(flags, "-dtls")
729 }
730
David Benjamin5a593af2014-08-11 19:51:50 -0400731 if test.resumeSession {
732 flags = append(flags, "-resume")
733 }
734
David Benjamine58c4f52014-08-24 03:47:07 -0400735 if test.shimWritesFirst {
736 flags = append(flags, "-shim-writes-first")
737 }
738
David Benjamin025b3d32014-07-01 19:53:04 -0400739 flags = append(flags, test.flags...)
740
741 var shim *exec.Cmd
742 if *useValgrind {
743 shim = valgrindOf(false, shim_path, flags...)
Adam Langley75712922014-10-10 16:23:43 -0700744 } else if *useGDB {
745 shim = gdbOf(shim_path, flags...)
David Benjamin025b3d32014-07-01 19:53:04 -0400746 } else {
747 shim = exec.Command(shim_path, flags...)
748 }
David Benjamin1d5c83e2014-07-22 19:20:02 -0400749 shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
David Benjamin025b3d32014-07-01 19:53:04 -0400750 shim.Stdin = os.Stdin
751 var stdoutBuf, stderrBuf bytes.Buffer
752 shim.Stdout = &stdoutBuf
753 shim.Stderr = &stderrBuf
754
755 if err := shim.Start(); err != nil {
Adam Langley95c29f32014-06-20 12:00:00 -0700756 panic(err)
757 }
David Benjamin025b3d32014-07-01 19:53:04 -0400758 shimEnd.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400759 shimEndResume.Close()
Adam Langley95c29f32014-06-20 12:00:00 -0700760
761 config := test.config
David Benjamin1d5c83e2014-07-22 19:20:02 -0400762 config.ClientSessionCache = NewLRUClientSessionCache(1)
David Benjamin025b3d32014-07-01 19:53:04 -0400763 if test.testType == clientTest {
764 if len(config.Certificates) == 0 {
765 config.Certificates = []Certificate{getRSACertificate()}
766 }
David Benjamin025b3d32014-07-01 19:53:04 -0400767 }
Adam Langley95c29f32014-06-20 12:00:00 -0700768
Adam Langley75712922014-10-10 16:23:43 -0700769 var connDebug *recordingConn
770 if *flagDebug {
771 connDebug = &recordingConn{Conn: conn}
772 conn = connDebug
773 }
774
David Benjamin01fe8202014-09-24 15:21:44 -0400775 err := doExchange(test, &config, conn, test.messageLen,
776 false /* not a resumption */)
Adam Langley75712922014-10-10 16:23:43 -0700777
778 if *flagDebug {
779 connDebug.WriteTo(os.Stdout)
780 }
781
Adam Langley95c29f32014-06-20 12:00:00 -0700782 conn.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400783 if err == nil && test.resumeSession {
David Benjamin01fe8202014-09-24 15:21:44 -0400784 var resumeConfig Config
785 if test.resumeConfig != nil {
786 resumeConfig = *test.resumeConfig
787 if len(resumeConfig.Certificates) == 0 {
788 resumeConfig.Certificates = []Certificate{getRSACertificate()}
789 }
790 resumeConfig.SessionTicketKey = config.SessionTicketKey
791 resumeConfig.ClientSessionCache = config.ClientSessionCache
792 } else {
793 resumeConfig = config
794 }
795 err = doExchange(test, &resumeConfig, connResume, test.messageLen,
796 true /* resumption */)
David Benjamin1d5c83e2014-07-22 19:20:02 -0400797 }
David Benjamin812152a2014-09-06 12:49:07 -0400798 connResume.Close()
David Benjamin1d5c83e2014-07-22 19:20:02 -0400799
David Benjamin025b3d32014-07-01 19:53:04 -0400800 childErr := shim.Wait()
Adam Langley95c29f32014-06-20 12:00:00 -0700801
802 stdout := string(stdoutBuf.Bytes())
803 stderr := string(stderrBuf.Bytes())
804 failed := err != nil || childErr != nil
805 correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
Adam Langleyac61fa32014-06-23 12:03:11 -0700806 localError := "none"
807 if err != nil {
808 localError = err.Error()
809 }
810 if len(test.expectedLocalError) != 0 {
811 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
812 }
Adam Langley95c29f32014-06-20 12:00:00 -0700813
814 if failed != test.shouldFail || failed && !correctFailure {
Adam Langley95c29f32014-06-20 12:00:00 -0700815 childError := "none"
Adam Langley95c29f32014-06-20 12:00:00 -0700816 if childErr != nil {
817 childError = childErr.Error()
818 }
819
820 var msg string
821 switch {
822 case failed && !test.shouldFail:
823 msg = "unexpected failure"
824 case !failed && test.shouldFail:
825 msg = "unexpected success"
826 case failed && !correctFailure:
Adam Langleyac61fa32014-06-23 12:03:11 -0700827 msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
Adam Langley95c29f32014-06-20 12:00:00 -0700828 default:
829 panic("internal error")
830 }
831
832 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
833 }
834
835 if !*useValgrind && len(stderr) > 0 {
836 println(stderr)
837 }
838
839 return nil
840}
841
842var tlsVersions = []struct {
843 name string
844 version uint16
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400845 flag string
Adam Langley95c29f32014-06-20 12:00:00 -0700846}{
David Benjamin7e2e6cf2014-08-07 17:44:24 -0400847 {"SSL3", VersionSSL30, "-no-ssl3"},
848 {"TLS1", VersionTLS10, "-no-tls1"},
849 {"TLS11", VersionTLS11, "-no-tls11"},
850 {"TLS12", VersionTLS12, "-no-tls12"},
Adam Langley95c29f32014-06-20 12:00:00 -0700851}
852
853var testCipherSuites = []struct {
854 name string
855 id uint16
856}{
857 {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400858 {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700859 {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400860 {"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400861 {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700862 {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400863 {"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400864 {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
865 {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400866 {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400867 {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
868 {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400869 {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700870 {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
871 {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400872 {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
873 {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700874 {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400875 {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700876 {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
David Benjamin2af684f2014-10-27 02:23:15 -0400877 {"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700878 {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Adam Langley95c29f32014-06-20 12:00:00 -0700879 {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400880 {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400881 {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700882 {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
David Benjaminf7768e42014-08-31 02:06:47 -0400883 {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
Adam Langley95c29f32014-06-20 12:00:00 -0700884 {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
David Benjamin48cae082014-10-27 01:06:24 -0400885 {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
886 {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
887 {"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700888 {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
David Benjaminf4e5c4e2014-08-02 17:35:45 -0400889 {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
Adam Langley95c29f32014-06-20 12:00:00 -0700890}
891
David Benjaminf7768e42014-08-31 02:06:47 -0400892func isTLS12Only(suiteName string) bool {
893 return strings.HasSuffix(suiteName, "-GCM") ||
894 strings.HasSuffix(suiteName, "-SHA256") ||
895 strings.HasSuffix(suiteName, "-SHA384")
896}
897
Adam Langley95c29f32014-06-20 12:00:00 -0700898func addCipherSuiteTests() {
899 for _, suite := range testCipherSuites {
David Benjamin48cae082014-10-27 01:06:24 -0400900 const psk = "12345"
901 const pskIdentity = "luggage combo"
902
Adam Langley95c29f32014-06-20 12:00:00 -0700903 var cert Certificate
David Benjamin025b3d32014-07-01 19:53:04 -0400904 var certFile string
905 var keyFile string
Adam Langley95c29f32014-06-20 12:00:00 -0700906 if strings.Contains(suite.name, "ECDSA") {
907 cert = getECDSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400908 certFile = ecdsaCertificateFile
909 keyFile = ecdsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700910 } else {
911 cert = getRSACertificate()
David Benjamin025b3d32014-07-01 19:53:04 -0400912 certFile = rsaCertificateFile
913 keyFile = rsaKeyFile
Adam Langley95c29f32014-06-20 12:00:00 -0700914 }
915
David Benjamin48cae082014-10-27 01:06:24 -0400916 var flags []string
917 if strings.HasPrefix(suite.name, "PSK-") || strings.Contains(suite.name, "-PSK-") {
918 flags = append(flags,
919 "-psk", psk,
920 "-psk-identity", pskIdentity)
921 }
922
Adam Langley95c29f32014-06-20 12:00:00 -0700923 for _, ver := range tlsVersions {
David Benjaminf7768e42014-08-31 02:06:47 -0400924 if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
Adam Langley95c29f32014-06-20 12:00:00 -0700925 continue
926 }
927
David Benjamin1d5c83e2014-07-22 19:20:02 -0400928 // Go's TLS implementation only implements session
929 // resumption with tickets, so SSLv3 cannot resume
930 // sessions.
931 resumeSession := ver.version != VersionSSL30
932
David Benjamin025b3d32014-07-01 19:53:04 -0400933 testCases = append(testCases, testCase{
934 testType: clientTest,
935 name: ver.name + "-" + suite.name + "-client",
Adam Langley95c29f32014-06-20 12:00:00 -0700936 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400937 MinVersion: ver.version,
938 MaxVersion: ver.version,
939 CipherSuites: []uint16{suite.id},
940 Certificates: []Certificate{cert},
941 PreSharedKey: []byte(psk),
942 PreSharedKeyIdentity: pskIdentity,
Adam Langley95c29f32014-06-20 12:00:00 -0700943 },
David Benjamin48cae082014-10-27 01:06:24 -0400944 flags: flags,
David Benjamin1d5c83e2014-07-22 19:20:02 -0400945 resumeSession: resumeSession,
Adam Langley95c29f32014-06-20 12:00:00 -0700946 })
David Benjamin025b3d32014-07-01 19:53:04 -0400947
David Benjamin76d8abe2014-08-14 16:25:34 -0400948 testCases = append(testCases, testCase{
949 testType: serverTest,
950 name: ver.name + "-" + suite.name + "-server",
951 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400952 MinVersion: ver.version,
953 MaxVersion: ver.version,
954 CipherSuites: []uint16{suite.id},
955 Certificates: []Certificate{cert},
956 PreSharedKey: []byte(psk),
957 PreSharedKeyIdentity: pskIdentity,
David Benjamin76d8abe2014-08-14 16:25:34 -0400958 },
959 certFile: certFile,
960 keyFile: keyFile,
David Benjamin48cae082014-10-27 01:06:24 -0400961 flags: flags,
David Benjamin76d8abe2014-08-14 16:25:34 -0400962 resumeSession: resumeSession,
963 })
David Benjamin6fd297b2014-08-11 18:43:38 -0400964
965 // TODO(davidben): Fix DTLS 1.2 support and test that.
966 if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
967 testCases = append(testCases, testCase{
968 testType: clientTest,
969 protocol: dtls,
970 name: "D" + ver.name + "-" + suite.name + "-client",
971 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400972 MinVersion: ver.version,
973 MaxVersion: ver.version,
974 CipherSuites: []uint16{suite.id},
975 Certificates: []Certificate{cert},
976 PreSharedKey: []byte(psk),
977 PreSharedKeyIdentity: pskIdentity,
David Benjamin6fd297b2014-08-11 18:43:38 -0400978 },
David Benjamin48cae082014-10-27 01:06:24 -0400979 flags: flags,
David Benjamin6fd297b2014-08-11 18:43:38 -0400980 resumeSession: resumeSession,
981 })
982 testCases = append(testCases, testCase{
983 testType: serverTest,
984 protocol: dtls,
985 name: "D" + ver.name + "-" + suite.name + "-server",
986 config: Config{
David Benjamin48cae082014-10-27 01:06:24 -0400987 MinVersion: ver.version,
988 MaxVersion: ver.version,
989 CipherSuites: []uint16{suite.id},
990 Certificates: []Certificate{cert},
991 PreSharedKey: []byte(psk),
992 PreSharedKeyIdentity: pskIdentity,
David Benjamin6fd297b2014-08-11 18:43:38 -0400993 },
994 certFile: certFile,
995 keyFile: keyFile,
David Benjamin48cae082014-10-27 01:06:24 -0400996 flags: flags,
David Benjamin6fd297b2014-08-11 18:43:38 -0400997 resumeSession: resumeSession,
998 })
999 }
Adam Langley95c29f32014-06-20 12:00:00 -07001000 }
1001 }
1002}
1003
1004func addBadECDSASignatureTests() {
1005 for badR := BadValue(1); badR < NumBadValues; badR++ {
1006 for badS := BadValue(1); badS < NumBadValues; badS++ {
David Benjamin025b3d32014-07-01 19:53:04 -04001007 testCases = append(testCases, testCase{
Adam Langley95c29f32014-06-20 12:00:00 -07001008 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
1009 config: Config{
1010 CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
1011 Certificates: []Certificate{getECDSACertificate()},
1012 Bugs: ProtocolBugs{
1013 BadECDSAR: badR,
1014 BadECDSAS: badS,
1015 },
1016 },
1017 shouldFail: true,
1018 expectedError: "SIGNATURE",
1019 })
1020 }
1021 }
1022}
1023
Adam Langley80842bd2014-06-20 12:00:00 -07001024func addCBCPaddingTests() {
David Benjamin025b3d32014-07-01 19:53:04 -04001025 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -07001026 name: "MaxCBCPadding",
1027 config: Config{
1028 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1029 Bugs: ProtocolBugs{
1030 MaxPadding: true,
1031 },
1032 },
1033 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
1034 })
David Benjamin025b3d32014-07-01 19:53:04 -04001035 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -07001036 name: "BadCBCPadding",
1037 config: Config{
1038 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1039 Bugs: ProtocolBugs{
1040 PaddingFirstByteBad: true,
1041 },
1042 },
1043 shouldFail: true,
1044 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1045 })
1046 // OpenSSL previously had an issue where the first byte of padding in
1047 // 255 bytes of padding wasn't checked.
David Benjamin025b3d32014-07-01 19:53:04 -04001048 testCases = append(testCases, testCase{
Adam Langley80842bd2014-06-20 12:00:00 -07001049 name: "BadCBCPadding255",
1050 config: Config{
1051 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1052 Bugs: ProtocolBugs{
1053 MaxPadding: true,
1054 PaddingFirstByteBadIf255: true,
1055 },
1056 },
1057 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
1058 shouldFail: true,
1059 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1060 })
1061}
1062
Kenny Root7fdeaf12014-08-05 15:23:37 -07001063func addCBCSplittingTests() {
1064 testCases = append(testCases, testCase{
1065 name: "CBCRecordSplitting",
1066 config: Config{
1067 MaxVersion: VersionTLS10,
1068 MinVersion: VersionTLS10,
1069 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1070 },
1071 messageLen: -1, // read until EOF
1072 flags: []string{
1073 "-async",
1074 "-write-different-record-sizes",
1075 "-cbc-record-splitting",
1076 },
David Benjamina8e3e0e2014-08-06 22:11:10 -04001077 })
1078 testCases = append(testCases, testCase{
Kenny Root7fdeaf12014-08-05 15:23:37 -07001079 name: "CBCRecordSplittingPartialWrite",
1080 config: Config{
1081 MaxVersion: VersionTLS10,
1082 MinVersion: VersionTLS10,
1083 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1084 },
1085 messageLen: -1, // read until EOF
1086 flags: []string{
1087 "-async",
1088 "-write-different-record-sizes",
1089 "-cbc-record-splitting",
1090 "-partial-write",
1091 },
1092 })
1093}
1094
David Benjamin636293b2014-07-08 17:59:18 -04001095func addClientAuthTests() {
David Benjamin407a10c2014-07-16 12:58:59 -04001096 // Add a dummy cert pool to stress certificate authority parsing.
1097 // TODO(davidben): Add tests that those values parse out correctly.
1098 certPool := x509.NewCertPool()
1099 cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
1100 if err != nil {
1101 panic(err)
1102 }
1103 certPool.AddCert(cert)
1104
David Benjamin636293b2014-07-08 17:59:18 -04001105 for _, ver := range tlsVersions {
David Benjamin636293b2014-07-08 17:59:18 -04001106 testCases = append(testCases, testCase{
1107 testType: clientTest,
David Benjamin67666e72014-07-12 15:47:52 -04001108 name: ver.name + "-Client-ClientAuth-RSA",
David Benjamin636293b2014-07-08 17:59:18 -04001109 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001110 MinVersion: ver.version,
1111 MaxVersion: ver.version,
1112 ClientAuth: RequireAnyClientCert,
1113 ClientCAs: certPool,
David Benjamin636293b2014-07-08 17:59:18 -04001114 },
1115 flags: []string{
1116 "-cert-file", rsaCertificateFile,
1117 "-key-file", rsaKeyFile,
1118 },
1119 })
1120 testCases = append(testCases, testCase{
David Benjamin67666e72014-07-12 15:47:52 -04001121 testType: serverTest,
1122 name: ver.name + "-Server-ClientAuth-RSA",
1123 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001124 MinVersion: ver.version,
1125 MaxVersion: ver.version,
David Benjamin67666e72014-07-12 15:47:52 -04001126 Certificates: []Certificate{rsaCertificate},
1127 },
1128 flags: []string{"-require-any-client-certificate"},
1129 })
David Benjamine098ec22014-08-27 23:13:20 -04001130 if ver.version != VersionSSL30 {
1131 testCases = append(testCases, testCase{
1132 testType: serverTest,
1133 name: ver.name + "-Server-ClientAuth-ECDSA",
1134 config: Config{
1135 MinVersion: ver.version,
1136 MaxVersion: ver.version,
1137 Certificates: []Certificate{ecdsaCertificate},
1138 },
1139 flags: []string{"-require-any-client-certificate"},
1140 })
1141 testCases = append(testCases, testCase{
1142 testType: clientTest,
1143 name: ver.name + "-Client-ClientAuth-ECDSA",
1144 config: Config{
1145 MinVersion: ver.version,
1146 MaxVersion: ver.version,
1147 ClientAuth: RequireAnyClientCert,
1148 ClientCAs: certPool,
1149 },
1150 flags: []string{
1151 "-cert-file", ecdsaCertificateFile,
1152 "-key-file", ecdsaKeyFile,
1153 },
1154 })
1155 }
David Benjamin636293b2014-07-08 17:59:18 -04001156 }
1157}
1158
Adam Langley75712922014-10-10 16:23:43 -07001159func addExtendedMasterSecretTests() {
1160 const expectEMSFlag = "-expect-extended-master-secret"
1161
1162 for _, with := range []bool{false, true} {
1163 prefix := "No"
1164 var flags []string
1165 if with {
1166 prefix = ""
1167 flags = []string{expectEMSFlag}
1168 }
1169
1170 for _, isClient := range []bool{false, true} {
1171 suffix := "-Server"
1172 testType := serverTest
1173 if isClient {
1174 suffix = "-Client"
1175 testType = clientTest
1176 }
1177
1178 for _, ver := range tlsVersions {
1179 test := testCase{
1180 testType: testType,
1181 name: prefix + "ExtendedMasterSecret-" + ver.name + suffix,
1182 config: Config{
1183 MinVersion: ver.version,
1184 MaxVersion: ver.version,
1185 Bugs: ProtocolBugs{
1186 NoExtendedMasterSecret: !with,
1187 RequireExtendedMasterSecret: with,
1188 },
1189 },
David Benjamin48cae082014-10-27 01:06:24 -04001190 flags: flags,
1191 shouldFail: ver.version == VersionSSL30 && with,
Adam Langley75712922014-10-10 16:23:43 -07001192 }
1193 if test.shouldFail {
1194 test.expectedLocalError = "extended master secret required but not supported by peer"
1195 }
1196 testCases = append(testCases, test)
1197 }
1198 }
1199 }
1200
1201 // When a session is resumed, it should still be aware that its master
1202 // secret was generated via EMS and thus it's safe to use tls-unique.
1203 testCases = append(testCases, testCase{
1204 name: "ExtendedMasterSecret-Resume",
1205 config: Config{
1206 Bugs: ProtocolBugs{
1207 RequireExtendedMasterSecret: true,
1208 },
1209 },
1210 flags: []string{expectEMSFlag},
1211 resumeSession: true,
1212 })
1213}
1214
David Benjamin43ec06f2014-08-05 02:28:57 -04001215// Adds tests that try to cover the range of the handshake state machine, under
1216// various conditions. Some of these are redundant with other tests, but they
1217// only cover the synchronous case.
David Benjamin6fd297b2014-08-11 18:43:38 -04001218func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
David Benjamin43ec06f2014-08-05 02:28:57 -04001219 var suffix string
1220 var flags []string
1221 var maxHandshakeRecordLength int
David Benjamin6fd297b2014-08-11 18:43:38 -04001222 if protocol == dtls {
1223 suffix = "-DTLS"
1224 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001225 if async {
David Benjamin6fd297b2014-08-11 18:43:38 -04001226 suffix += "-Async"
David Benjamin43ec06f2014-08-05 02:28:57 -04001227 flags = append(flags, "-async")
1228 } else {
David Benjamin6fd297b2014-08-11 18:43:38 -04001229 suffix += "-Sync"
David Benjamin43ec06f2014-08-05 02:28:57 -04001230 }
1231 if splitHandshake {
1232 suffix += "-SplitHandshakeRecords"
David Benjamin98214542014-08-07 18:02:39 -04001233 maxHandshakeRecordLength = 1
David Benjamin43ec06f2014-08-05 02:28:57 -04001234 }
1235
1236 // Basic handshake, with resumption. Client and server.
1237 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001238 protocol: protocol,
1239 name: "Basic-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001240 config: Config{
1241 Bugs: ProtocolBugs{
1242 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1243 },
1244 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001245 flags: flags,
1246 resumeSession: true,
1247 })
1248 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001249 protocol: protocol,
1250 name: "Basic-Client-RenewTicket" + suffix,
David Benjaminbed9aae2014-08-07 19:13:38 -04001251 config: Config{
1252 Bugs: ProtocolBugs{
1253 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1254 RenewTicketOnResume: true,
1255 },
1256 },
1257 flags: flags,
1258 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001259 })
1260 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001261 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001262 testType: serverTest,
1263 name: "Basic-Server" + suffix,
1264 config: Config{
1265 Bugs: ProtocolBugs{
1266 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1267 },
1268 },
David Benjaminbed9aae2014-08-07 19:13:38 -04001269 flags: flags,
1270 resumeSession: true,
David Benjamin43ec06f2014-08-05 02:28:57 -04001271 })
1272
David Benjamin6fd297b2014-08-11 18:43:38 -04001273 // TLS client auth.
1274 testCases = append(testCases, testCase{
1275 protocol: protocol,
1276 testType: clientTest,
1277 name: "ClientAuth-Client" + suffix,
1278 config: Config{
David Benjamine098ec22014-08-27 23:13:20 -04001279 ClientAuth: RequireAnyClientCert,
David Benjamin6fd297b2014-08-11 18:43:38 -04001280 Bugs: ProtocolBugs{
1281 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1282 },
1283 },
1284 flags: append(flags,
1285 "-cert-file", rsaCertificateFile,
1286 "-key-file", rsaKeyFile),
1287 })
1288 testCases = append(testCases, testCase{
1289 protocol: protocol,
1290 testType: serverTest,
1291 name: "ClientAuth-Server" + suffix,
1292 config: Config{
1293 Certificates: []Certificate{rsaCertificate},
1294 },
1295 flags: append(flags, "-require-any-client-certificate"),
1296 })
1297
David Benjamin43ec06f2014-08-05 02:28:57 -04001298 // No session ticket support; server doesn't send NewSessionTicket.
1299 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001300 protocol: protocol,
1301 name: "SessionTicketsDisabled-Client" + suffix,
David Benjamin43ec06f2014-08-05 02:28:57 -04001302 config: Config{
1303 SessionTicketsDisabled: true,
1304 Bugs: ProtocolBugs{
1305 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1306 },
1307 },
1308 flags: flags,
1309 })
1310 testCases = append(testCases, testCase{
David Benjamin6fd297b2014-08-11 18:43:38 -04001311 protocol: protocol,
David Benjamin43ec06f2014-08-05 02:28:57 -04001312 testType: serverTest,
1313 name: "SessionTicketsDisabled-Server" + suffix,
1314 config: Config{
1315 SessionTicketsDisabled: true,
1316 Bugs: ProtocolBugs{
1317 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1318 },
1319 },
1320 flags: flags,
1321 })
1322
David Benjamin48cae082014-10-27 01:06:24 -04001323 // Skip ServerKeyExchange in PSK key exchange if there's no
1324 // identity hint.
1325 testCases = append(testCases, testCase{
1326 protocol: protocol,
1327 name: "EmptyPSKHint-Client" + suffix,
1328 config: Config{
1329 CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1330 PreSharedKey: []byte("secret"),
1331 Bugs: ProtocolBugs{
1332 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1333 },
1334 },
1335 flags: append(flags, "-psk", "secret"),
1336 })
1337 testCases = append(testCases, testCase{
1338 protocol: protocol,
1339 testType: serverTest,
1340 name: "EmptyPSKHint-Server" + suffix,
1341 config: Config{
1342 CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1343 PreSharedKey: []byte("secret"),
1344 Bugs: ProtocolBugs{
1345 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1346 },
1347 },
1348 flags: append(flags, "-psk", "secret"),
1349 })
1350
David Benjamin6fd297b2014-08-11 18:43:38 -04001351 if protocol == tls {
1352 // NPN on client and server; results in post-handshake message.
1353 testCases = append(testCases, testCase{
1354 protocol: protocol,
1355 name: "NPN-Client" + suffix,
1356 config: Config{
David Benjaminae2888f2014-09-06 12:58:58 -04001357 NextProtos: []string{"foo"},
David Benjamin6fd297b2014-08-11 18:43:38 -04001358 Bugs: ProtocolBugs{
1359 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1360 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001361 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001362 flags: append(flags, "-select-next-proto", "foo"),
1363 expectedNextProto: "foo",
1364 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001365 })
1366 testCases = append(testCases, testCase{
1367 protocol: protocol,
1368 testType: serverTest,
1369 name: "NPN-Server" + suffix,
1370 config: Config{
1371 NextProtos: []string{"bar"},
1372 Bugs: ProtocolBugs{
1373 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1374 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001375 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001376 flags: append(flags,
1377 "-advertise-npn", "\x03foo\x03bar\x03baz",
1378 "-expect-next-proto", "bar"),
David Benjaminfc7b0862014-09-06 13:21:53 -04001379 expectedNextProto: "bar",
1380 expectedNextProtoType: npn,
David Benjamin6fd297b2014-08-11 18:43:38 -04001381 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001382
David Benjamin6fd297b2014-08-11 18:43:38 -04001383 // Client does False Start and negotiates NPN.
1384 testCases = append(testCases, testCase{
1385 protocol: protocol,
1386 name: "FalseStart" + suffix,
1387 config: Config{
1388 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1389 NextProtos: []string{"foo"},
1390 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001391 ExpectFalseStart: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001392 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1393 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001394 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001395 flags: append(flags,
1396 "-false-start",
1397 "-select-next-proto", "foo"),
David Benjamine58c4f52014-08-24 03:47:07 -04001398 shimWritesFirst: true,
1399 resumeSession: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001400 })
David Benjamin43ec06f2014-08-05 02:28:57 -04001401
David Benjaminae2888f2014-09-06 12:58:58 -04001402 // Client does False Start and negotiates ALPN.
1403 testCases = append(testCases, testCase{
1404 protocol: protocol,
1405 name: "FalseStart-ALPN" + suffix,
1406 config: Config{
1407 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1408 NextProtos: []string{"foo"},
1409 Bugs: ProtocolBugs{
1410 ExpectFalseStart: true,
1411 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1412 },
1413 },
1414 flags: append(flags,
1415 "-false-start",
1416 "-advertise-alpn", "\x03foo"),
1417 shimWritesFirst: true,
1418 resumeSession: true,
1419 })
1420
David Benjamin6fd297b2014-08-11 18:43:38 -04001421 // False Start without session tickets.
1422 testCases = append(testCases, testCase{
1423 name: "FalseStart-SessionTicketsDisabled",
1424 config: Config{
1425 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1426 NextProtos: []string{"foo"},
1427 SessionTicketsDisabled: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001428 Bugs: ProtocolBugs{
David Benjamine58c4f52014-08-24 03:47:07 -04001429 ExpectFalseStart: true,
David Benjamin4e99c522014-08-24 01:45:30 -04001430 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1431 },
David Benjamin43ec06f2014-08-05 02:28:57 -04001432 },
David Benjamin4e99c522014-08-24 01:45:30 -04001433 flags: append(flags,
David Benjamin6fd297b2014-08-11 18:43:38 -04001434 "-false-start",
1435 "-select-next-proto", "foo",
David Benjamin4e99c522014-08-24 01:45:30 -04001436 ),
David Benjamine58c4f52014-08-24 03:47:07 -04001437 shimWritesFirst: true,
David Benjamin6fd297b2014-08-11 18:43:38 -04001438 })
David Benjamin1e7f8d72014-08-08 12:27:04 -04001439
David Benjamina08e49d2014-08-24 01:46:07 -04001440 // Server parses a V2ClientHello.
David Benjamin6fd297b2014-08-11 18:43:38 -04001441 testCases = append(testCases, testCase{
1442 protocol: protocol,
1443 testType: serverTest,
1444 name: "SendV2ClientHello" + suffix,
1445 config: Config{
1446 // Choose a cipher suite that does not involve
1447 // elliptic curves, so no extensions are
1448 // involved.
1449 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1450 Bugs: ProtocolBugs{
1451 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1452 SendV2ClientHello: true,
1453 },
David Benjamin1e7f8d72014-08-08 12:27:04 -04001454 },
David Benjamin6fd297b2014-08-11 18:43:38 -04001455 flags: flags,
1456 })
David Benjamina08e49d2014-08-24 01:46:07 -04001457
1458 // Client sends a Channel ID.
1459 testCases = append(testCases, testCase{
1460 protocol: protocol,
1461 name: "ChannelID-Client" + suffix,
1462 config: Config{
1463 RequestChannelID: true,
1464 Bugs: ProtocolBugs{
1465 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1466 },
1467 },
1468 flags: append(flags,
1469 "-send-channel-id", channelIDKeyFile,
1470 ),
1471 resumeSession: true,
1472 expectChannelID: true,
1473 })
1474
1475 // Server accepts a Channel ID.
1476 testCases = append(testCases, testCase{
1477 protocol: protocol,
1478 testType: serverTest,
1479 name: "ChannelID-Server" + suffix,
1480 config: Config{
1481 ChannelID: channelIDKey,
1482 Bugs: ProtocolBugs{
1483 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1484 },
1485 },
1486 flags: append(flags,
1487 "-expect-channel-id",
1488 base64.StdEncoding.EncodeToString(channelIDBytes),
1489 ),
1490 resumeSession: true,
1491 expectChannelID: true,
1492 })
David Benjamin6fd297b2014-08-11 18:43:38 -04001493 } else {
1494 testCases = append(testCases, testCase{
1495 protocol: protocol,
1496 name: "SkipHelloVerifyRequest" + suffix,
1497 config: Config{
1498 Bugs: ProtocolBugs{
1499 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1500 SkipHelloVerifyRequest: true,
1501 },
1502 },
1503 flags: flags,
1504 })
1505
1506 testCases = append(testCases, testCase{
1507 testType: serverTest,
1508 protocol: protocol,
1509 name: "CookieExchange" + suffix,
1510 config: Config{
1511 Bugs: ProtocolBugs{
1512 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1513 },
1514 },
1515 flags: append(flags, "-cookie-exchange"),
1516 })
1517 }
David Benjamin43ec06f2014-08-05 02:28:57 -04001518}
1519
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001520func addVersionNegotiationTests() {
1521 for i, shimVers := range tlsVersions {
1522 // Assemble flags to disable all newer versions on the shim.
1523 var flags []string
1524 for _, vers := range tlsVersions[i+1:] {
1525 flags = append(flags, vers.flag)
1526 }
1527
1528 for _, runnerVers := range tlsVersions {
1529 expectedVersion := shimVers.version
1530 if runnerVers.version < shimVers.version {
1531 expectedVersion = runnerVers.version
1532 }
1533 suffix := shimVers.name + "-" + runnerVers.name
1534
1535 testCases = append(testCases, testCase{
1536 testType: clientTest,
1537 name: "VersionNegotiation-Client-" + suffix,
1538 config: Config{
1539 MaxVersion: runnerVers.version,
1540 },
1541 flags: flags,
1542 expectedVersion: expectedVersion,
1543 })
1544
David Benjamin76d8abe2014-08-14 16:25:34 -04001545 testCases = append(testCases, testCase{
1546 testType: serverTest,
1547 name: "VersionNegotiation-Server-" + suffix,
1548 config: Config{
1549 MaxVersion: runnerVers.version,
1550 },
1551 flags: flags,
1552 expectedVersion: expectedVersion,
1553 })
David Benjamin7e2e6cf2014-08-07 17:44:24 -04001554 }
1555 }
1556}
1557
David Benjamin5c24a1d2014-08-31 00:59:27 -04001558func addD5BugTests() {
1559 testCases = append(testCases, testCase{
1560 testType: serverTest,
1561 name: "D5Bug-NoQuirk-Reject",
1562 config: Config{
1563 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1564 Bugs: ProtocolBugs{
1565 SSL3RSAKeyExchange: true,
1566 },
1567 },
1568 shouldFail: true,
1569 expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
1570 })
1571 testCases = append(testCases, testCase{
1572 testType: serverTest,
1573 name: "D5Bug-Quirk-Normal",
1574 config: Config{
1575 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1576 },
1577 flags: []string{"-tls-d5-bug"},
1578 })
1579 testCases = append(testCases, testCase{
1580 testType: serverTest,
1581 name: "D5Bug-Quirk-Bug",
1582 config: Config{
1583 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1584 Bugs: ProtocolBugs{
1585 SSL3RSAKeyExchange: true,
1586 },
1587 },
1588 flags: []string{"-tls-d5-bug"},
1589 })
1590}
1591
David Benjamine78bfde2014-09-06 12:45:15 -04001592func addExtensionTests() {
1593 testCases = append(testCases, testCase{
1594 testType: clientTest,
1595 name: "DuplicateExtensionClient",
1596 config: Config{
1597 Bugs: ProtocolBugs{
1598 DuplicateExtension: true,
1599 },
1600 },
1601 shouldFail: true,
1602 expectedLocalError: "remote error: error decoding message",
1603 })
1604 testCases = append(testCases, testCase{
1605 testType: serverTest,
1606 name: "DuplicateExtensionServer",
1607 config: Config{
1608 Bugs: ProtocolBugs{
1609 DuplicateExtension: true,
1610 },
1611 },
1612 shouldFail: true,
1613 expectedLocalError: "remote error: error decoding message",
1614 })
1615 testCases = append(testCases, testCase{
1616 testType: clientTest,
1617 name: "ServerNameExtensionClient",
1618 config: Config{
1619 Bugs: ProtocolBugs{
1620 ExpectServerName: "example.com",
1621 },
1622 },
1623 flags: []string{"-host-name", "example.com"},
1624 })
1625 testCases = append(testCases, testCase{
1626 testType: clientTest,
1627 name: "ServerNameExtensionClient",
1628 config: Config{
1629 Bugs: ProtocolBugs{
1630 ExpectServerName: "mismatch.com",
1631 },
1632 },
1633 flags: []string{"-host-name", "example.com"},
1634 shouldFail: true,
1635 expectedLocalError: "tls: unexpected server name",
1636 })
1637 testCases = append(testCases, testCase{
1638 testType: clientTest,
1639 name: "ServerNameExtensionClient",
1640 config: Config{
1641 Bugs: ProtocolBugs{
1642 ExpectServerName: "missing.com",
1643 },
1644 },
1645 shouldFail: true,
1646 expectedLocalError: "tls: unexpected server name",
1647 })
1648 testCases = append(testCases, testCase{
1649 testType: serverTest,
1650 name: "ServerNameExtensionServer",
1651 config: Config{
1652 ServerName: "example.com",
1653 },
1654 flags: []string{"-expect-server-name", "example.com"},
1655 resumeSession: true,
1656 })
David Benjaminae2888f2014-09-06 12:58:58 -04001657 testCases = append(testCases, testCase{
1658 testType: clientTest,
1659 name: "ALPNClient",
1660 config: Config{
1661 NextProtos: []string{"foo"},
1662 },
1663 flags: []string{
1664 "-advertise-alpn", "\x03foo\x03bar\x03baz",
1665 "-expect-alpn", "foo",
1666 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001667 expectedNextProto: "foo",
1668 expectedNextProtoType: alpn,
1669 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001670 })
1671 testCases = append(testCases, testCase{
1672 testType: serverTest,
1673 name: "ALPNServer",
1674 config: Config{
1675 NextProtos: []string{"foo", "bar", "baz"},
1676 },
1677 flags: []string{
1678 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1679 "-select-alpn", "foo",
1680 },
David Benjaminfc7b0862014-09-06 13:21:53 -04001681 expectedNextProto: "foo",
1682 expectedNextProtoType: alpn,
1683 resumeSession: true,
1684 })
1685 // Test that the server prefers ALPN over NPN.
1686 testCases = append(testCases, testCase{
1687 testType: serverTest,
1688 name: "ALPNServer-Preferred",
1689 config: Config{
1690 NextProtos: []string{"foo", "bar", "baz"},
1691 },
1692 flags: []string{
1693 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1694 "-select-alpn", "foo",
1695 "-advertise-npn", "\x03foo\x03bar\x03baz",
1696 },
1697 expectedNextProto: "foo",
1698 expectedNextProtoType: alpn,
1699 resumeSession: true,
1700 })
1701 testCases = append(testCases, testCase{
1702 testType: serverTest,
1703 name: "ALPNServer-Preferred-Swapped",
1704 config: Config{
1705 NextProtos: []string{"foo", "bar", "baz"},
1706 Bugs: ProtocolBugs{
1707 SwapNPNAndALPN: true,
1708 },
1709 },
1710 flags: []string{
1711 "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1712 "-select-alpn", "foo",
1713 "-advertise-npn", "\x03foo\x03bar\x03baz",
1714 },
1715 expectedNextProto: "foo",
1716 expectedNextProtoType: alpn,
1717 resumeSession: true,
David Benjaminae2888f2014-09-06 12:58:58 -04001718 })
Adam Langley38311732014-10-16 19:04:35 -07001719 // Resume with a corrupt ticket.
1720 testCases = append(testCases, testCase{
1721 testType: serverTest,
1722 name: "CorruptTicket",
1723 config: Config{
1724 Bugs: ProtocolBugs{
1725 CorruptTicket: true,
1726 },
1727 },
1728 resumeSession: true,
1729 flags: []string{"-expect-session-miss"},
1730 })
1731 // Resume with an oversized session id.
1732 testCases = append(testCases, testCase{
1733 testType: serverTest,
1734 name: "OversizedSessionId",
1735 config: Config{
1736 Bugs: ProtocolBugs{
1737 OversizedSessionId: true,
1738 },
1739 },
1740 resumeSession: true,
Adam Langley75712922014-10-10 16:23:43 -07001741 shouldFail: true,
Adam Langley38311732014-10-16 19:04:35 -07001742 expectedError: ":DECODE_ERROR:",
1743 })
David Benjamine78bfde2014-09-06 12:45:15 -04001744}
1745
David Benjamin01fe8202014-09-24 15:21:44 -04001746func addResumptionVersionTests() {
1747 // TODO(davidben): Once DTLS 1.2 is working, test that as well.
1748 for _, sessionVers := range tlsVersions {
1749 // TODO(davidben): SSLv3 is omitted here because runner does not
1750 // support resumption with session IDs.
1751 if sessionVers.version == VersionSSL30 {
1752 continue
1753 }
1754 for _, resumeVers := range tlsVersions {
1755 if resumeVers.version == VersionSSL30 {
1756 continue
1757 }
1758 suffix := "-" + sessionVers.name + "-" + resumeVers.name
1759
David Benjamin01fe8202014-09-24 15:21:44 -04001760 testCases = append(testCases, testCase{
1761 name: "Resume-Client" + suffix,
1762 resumeSession: true,
1763 config: Config{
1764 MaxVersion: sessionVers.version,
1765 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1766 Bugs: ProtocolBugs{
1767 AllowSessionVersionMismatch: true,
1768 },
1769 },
1770 expectedVersion: sessionVers.version,
1771 resumeConfig: &Config{
1772 MaxVersion: resumeVers.version,
1773 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1774 Bugs: ProtocolBugs{
1775 AllowSessionVersionMismatch: true,
1776 },
1777 },
1778 expectedResumeVersion: resumeVers.version,
1779 })
1780
1781 testCases = append(testCases, testCase{
1782 name: "Resume-Client-NoResume" + suffix,
1783 flags: []string{"-expect-session-miss"},
1784 resumeSession: true,
1785 config: Config{
1786 MaxVersion: sessionVers.version,
1787 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1788 },
1789 expectedVersion: sessionVers.version,
1790 resumeConfig: &Config{
1791 MaxVersion: resumeVers.version,
1792 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1793 SessionTicketsDisabled: true,
1794 },
1795 expectedResumeVersion: resumeVers.version,
1796 })
David Benjaminbdf5e722014-11-11 00:52:15 -05001797
1798 var flags []string
1799 if sessionVers.version != resumeVers.version {
1800 flags = append(flags, "-expect-session-miss")
1801 }
1802 testCases = append(testCases, testCase{
1803 testType: serverTest,
1804 name: "Resume-Server" + suffix,
1805 flags: flags,
1806 resumeSession: true,
1807 config: Config{
1808 MaxVersion: sessionVers.version,
1809 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1810 },
1811 expectedVersion: sessionVers.version,
1812 resumeConfig: &Config{
1813 MaxVersion: resumeVers.version,
1814 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1815 },
1816 expectedResumeVersion: resumeVers.version,
1817 })
David Benjamin01fe8202014-09-24 15:21:44 -04001818 }
1819 }
1820}
1821
Adam Langley2ae77d22014-10-28 17:29:33 -07001822func addRenegotiationTests() {
1823 testCases = append(testCases, testCase{
1824 testType: serverTest,
1825 name: "Renegotiate-Server",
1826 flags: []string{"-renegotiate"},
1827 shimWritesFirst: true,
1828 })
1829 testCases = append(testCases, testCase{
1830 testType: serverTest,
1831 name: "Renegotiate-Server-EmptyExt",
1832 config: Config{
1833 Bugs: ProtocolBugs{
1834 EmptyRenegotiationInfo: true,
1835 },
1836 },
1837 flags: []string{"-renegotiate"},
1838 shimWritesFirst: true,
1839 shouldFail: true,
1840 expectedError: ":RENEGOTIATION_MISMATCH:",
1841 })
1842 testCases = append(testCases, testCase{
1843 testType: serverTest,
1844 name: "Renegotiate-Server-BadExt",
1845 config: Config{
1846 Bugs: ProtocolBugs{
1847 BadRenegotiationInfo: true,
1848 },
1849 },
1850 flags: []string{"-renegotiate"},
1851 shimWritesFirst: true,
1852 shouldFail: true,
1853 expectedError: ":RENEGOTIATION_MISMATCH:",
1854 })
David Benjaminca6554b2014-11-08 12:31:52 -05001855 testCases = append(testCases, testCase{
1856 testType: serverTest,
1857 name: "Renegotiate-Server-ClientInitiated",
1858 renegotiate: true,
1859 })
1860 testCases = append(testCases, testCase{
1861 testType: serverTest,
1862 name: "Renegotiate-Server-ClientInitiated-NoExt",
1863 renegotiate: true,
1864 config: Config{
1865 Bugs: ProtocolBugs{
1866 NoRenegotiationInfo: true,
1867 },
1868 },
1869 shouldFail: true,
1870 expectedError: ":UNSAFE_LEGACY_RENEGOTIATION_DISABLED:",
1871 })
1872 testCases = append(testCases, testCase{
1873 testType: serverTest,
1874 name: "Renegotiate-Server-ClientInitiated-NoExt-Allowed",
1875 renegotiate: true,
1876 config: Config{
1877 Bugs: ProtocolBugs{
1878 NoRenegotiationInfo: true,
1879 },
1880 },
1881 flags: []string{"-allow-unsafe-legacy-renegotiation"},
1882 })
Adam Langley2ae77d22014-10-28 17:29:33 -07001883 // TODO(agl): test the renegotiation info SCSV.
Adam Langleycf2d4f42014-10-28 19:06:14 -07001884 testCases = append(testCases, testCase{
1885 name: "Renegotiate-Client",
1886 renegotiate: true,
1887 })
1888 testCases = append(testCases, testCase{
1889 name: "Renegotiate-Client-EmptyExt",
1890 renegotiate: true,
1891 config: Config{
1892 Bugs: ProtocolBugs{
1893 EmptyRenegotiationInfo: true,
1894 },
1895 },
1896 shouldFail: true,
1897 expectedError: ":RENEGOTIATION_MISMATCH:",
1898 })
1899 testCases = append(testCases, testCase{
1900 name: "Renegotiate-Client-BadExt",
1901 renegotiate: true,
1902 config: Config{
1903 Bugs: ProtocolBugs{
1904 BadRenegotiationInfo: true,
1905 },
1906 },
1907 shouldFail: true,
1908 expectedError: ":RENEGOTIATION_MISMATCH:",
1909 })
1910 testCases = append(testCases, testCase{
1911 name: "Renegotiate-Client-SwitchCiphers",
1912 renegotiate: true,
1913 config: Config{
1914 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1915 },
1916 renegotiateCiphers: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1917 })
1918 testCases = append(testCases, testCase{
1919 name: "Renegotiate-Client-SwitchCiphers2",
1920 renegotiate: true,
1921 config: Config{
1922 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1923 },
1924 renegotiateCiphers: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1925 })
Adam Langley2ae77d22014-10-28 17:29:33 -07001926}
1927
David Benjamin5e961c12014-11-07 01:48:35 -05001928func addDTLSReplayTests() {
1929 // Test that sequence number replays are detected.
1930 testCases = append(testCases, testCase{
1931 protocol: dtls,
1932 name: "DTLS-Replay",
1933 replayWrites: true,
1934 })
1935
1936 // Test the outgoing sequence number skipping by values larger
1937 // than the retransmit window.
1938 testCases = append(testCases, testCase{
1939 protocol: dtls,
1940 name: "DTLS-Replay-LargeGaps",
1941 config: Config{
1942 Bugs: ProtocolBugs{
1943 SequenceNumberIncrement: 127,
1944 },
1945 },
1946 replayWrites: true,
1947 })
1948}
1949
David Benjamin884fdf12014-08-02 15:28:23 -04001950func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
Adam Langley95c29f32014-06-20 12:00:00 -07001951 defer wg.Done()
1952
1953 for test := range c {
1954 statusChan <- statusMsg{test: test, started: true}
David Benjamin884fdf12014-08-02 15:28:23 -04001955 err := runTest(test, buildDir)
Adam Langley95c29f32014-06-20 12:00:00 -07001956 statusChan <- statusMsg{test: test, err: err}
1957 }
1958}
1959
1960type statusMsg struct {
1961 test *testCase
1962 started bool
1963 err error
1964}
1965
1966func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1967 var started, done, failed, lineLen int
1968 defer close(doneChan)
1969
1970 for msg := range statusChan {
1971 if msg.started {
1972 started++
1973 } else {
1974 done++
1975 }
1976
1977 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1978
1979 if msg.err != nil {
1980 fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1981 failed++
1982 }
1983 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1984 lineLen = len(line)
1985 os.Stdout.WriteString(line)
1986 }
1987}
1988
1989func main() {
1990 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 -04001991 var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
David Benjamin884fdf12014-08-02 15:28:23 -04001992 var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
Adam Langley95c29f32014-06-20 12:00:00 -07001993
1994 flag.Parse()
1995
1996 addCipherSuiteTests()
1997 addBadECDSASignatureTests()
Adam Langley80842bd2014-06-20 12:00:00 -07001998 addCBCPaddingTests()
Kenny Root7fdeaf12014-08-05 15:23:37 -07001999 addCBCSplittingTests()
David Benjamin636293b2014-07-08 17:59:18 -04002000 addClientAuthTests()
David Benjamin7e2e6cf2014-08-07 17:44:24 -04002001 addVersionNegotiationTests()
David Benjamin5c24a1d2014-08-31 00:59:27 -04002002 addD5BugTests()
David Benjamine78bfde2014-09-06 12:45:15 -04002003 addExtensionTests()
David Benjamin01fe8202014-09-24 15:21:44 -04002004 addResumptionVersionTests()
Adam Langley75712922014-10-10 16:23:43 -07002005 addExtendedMasterSecretTests()
Adam Langley2ae77d22014-10-28 17:29:33 -07002006 addRenegotiationTests()
David Benjamin5e961c12014-11-07 01:48:35 -05002007 addDTLSReplayTests()
David Benjamin43ec06f2014-08-05 02:28:57 -04002008 for _, async := range []bool{false, true} {
2009 for _, splitHandshake := range []bool{false, true} {
David Benjamin6fd297b2014-08-11 18:43:38 -04002010 for _, protocol := range []protocol{tls, dtls} {
2011 addStateMachineCoverageTests(async, splitHandshake, protocol)
2012 }
David Benjamin43ec06f2014-08-05 02:28:57 -04002013 }
2014 }
Adam Langley95c29f32014-06-20 12:00:00 -07002015
2016 var wg sync.WaitGroup
2017
David Benjamin2bc8e6f2014-08-02 15:22:37 -04002018 numWorkers := *flagNumWorkers
Adam Langley95c29f32014-06-20 12:00:00 -07002019
2020 statusChan := make(chan statusMsg, numWorkers)
2021 testChan := make(chan *testCase, numWorkers)
2022 doneChan := make(chan struct{})
2023
David Benjamin025b3d32014-07-01 19:53:04 -04002024 go statusPrinter(doneChan, statusChan, len(testCases))
Adam Langley95c29f32014-06-20 12:00:00 -07002025
2026 for i := 0; i < numWorkers; i++ {
2027 wg.Add(1)
David Benjamin884fdf12014-08-02 15:28:23 -04002028 go worker(statusChan, testChan, *flagBuildDir, &wg)
Adam Langley95c29f32014-06-20 12:00:00 -07002029 }
2030
David Benjamin025b3d32014-07-01 19:53:04 -04002031 for i := range testCases {
2032 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
2033 testChan <- &testCases[i]
Adam Langley95c29f32014-06-20 12:00:00 -07002034 }
2035 }
2036
2037 close(testChan)
2038 wg.Wait()
2039 close(statusChan)
2040 <-doneChan
2041
2042 fmt.Printf("\n")
2043}