1package main
2
3import (
4	"bytes"
5	"crypto/ecdsa"
6	"crypto/elliptic"
7	"crypto/x509"
8	"encoding/base64"
9	"encoding/pem"
10	"flag"
11	"fmt"
12	"io"
13	"io/ioutil"
14	"math/big"
15	"net"
16	"os"
17	"os/exec"
18	"path"
19	"runtime"
20	"strconv"
21	"strings"
22	"sync"
23	"syscall"
24	"time"
25)
26
27var (
28	useValgrind     = flag.Bool("valgrind", false, "If true, run code under valgrind")
29	useGDB          = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
30	flagDebug       = flag.Bool("debug", false, "Hexdump the contents of the connection")
31	mallocTest      = flag.Int64("malloc-test", -1, "If non-negative, run each test with each malloc in turn failing from the given number onwards.")
32	mallocTestDebug = flag.Bool("malloc-test-debug", false, "If true, ask bssl_shim to abort rather than fail a malloc. This can be used with a specific value for --malloc-test to identity the malloc failing that is causing problems.")
33	jsonOutput      = flag.String("json-output", "", "The file to output JSON results to.")
34	pipe            = flag.Bool("pipe", false, "If true, print status output suitable for piping into another program.")
35)
36
37const (
38	rsaCertificateFile   = "cert.pem"
39	ecdsaCertificateFile = "ecdsa_cert.pem"
40)
41
42const (
43	rsaKeyFile       = "key.pem"
44	ecdsaKeyFile     = "ecdsa_key.pem"
45	channelIDKeyFile = "channel_id_key.pem"
46)
47
48var rsaCertificate, ecdsaCertificate Certificate
49var channelIDKey *ecdsa.PrivateKey
50var channelIDBytes []byte
51
52var testOCSPResponse = []byte{1, 2, 3, 4}
53var testSCTList = []byte{5, 6, 7, 8}
54
55func initCertificates() {
56	var err error
57	rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
58	if err != nil {
59		panic(err)
60	}
61	rsaCertificate.OCSPStaple = testOCSPResponse
62	rsaCertificate.SignedCertificateTimestampList = testSCTList
63
64	ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
65	if err != nil {
66		panic(err)
67	}
68	ecdsaCertificate.OCSPStaple = testOCSPResponse
69	ecdsaCertificate.SignedCertificateTimestampList = testSCTList
70
71	channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile)
72	if err != nil {
73		panic(err)
74	}
75	channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock)
76	if channelIDDERBlock.Type != "EC PRIVATE KEY" {
77		panic("bad key type")
78	}
79	channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes)
80	if err != nil {
81		panic(err)
82	}
83	if channelIDKey.Curve != elliptic.P256() {
84		panic("bad curve")
85	}
86
87	channelIDBytes = make([]byte, 64)
88	writeIntPadded(channelIDBytes[:32], channelIDKey.X)
89	writeIntPadded(channelIDBytes[32:], channelIDKey.Y)
90}
91
92var certificateOnce sync.Once
93
94func getRSACertificate() Certificate {
95	certificateOnce.Do(initCertificates)
96	return rsaCertificate
97}
98
99func getECDSACertificate() Certificate {
100	certificateOnce.Do(initCertificates)
101	return ecdsaCertificate
102}
103
104type testType int
105
106const (
107	clientTest testType = iota
108	serverTest
109)
110
111type protocol int
112
113const (
114	tls protocol = iota
115	dtls
116)
117
118const (
119	alpn = 1
120	npn  = 2
121)
122
123type testCase struct {
124	testType      testType
125	protocol      protocol
126	name          string
127	config        Config
128	shouldFail    bool
129	expectedError string
130	// expectedLocalError, if not empty, contains a substring that must be
131	// found in the local error.
132	expectedLocalError string
133	// expectedVersion, if non-zero, specifies the TLS version that must be
134	// negotiated.
135	expectedVersion uint16
136	// expectedResumeVersion, if non-zero, specifies the TLS version that
137	// must be negotiated on resumption. If zero, expectedVersion is used.
138	expectedResumeVersion uint16
139	// expectedCipher, if non-zero, specifies the TLS cipher suite that
140	// should be negotiated.
141	expectedCipher uint16
142	// expectChannelID controls whether the connection should have
143	// negotiated a Channel ID with channelIDKey.
144	expectChannelID bool
145	// expectedNextProto controls whether the connection should
146	// negotiate a next protocol via NPN or ALPN.
147	expectedNextProto string
148	// expectedNextProtoType, if non-zero, is the expected next
149	// protocol negotiation mechanism.
150	expectedNextProtoType int
151	// expectedSRTPProtectionProfile is the DTLS-SRTP profile that
152	// should be negotiated. If zero, none should be negotiated.
153	expectedSRTPProtectionProfile uint16
154	// messageLen is the length, in bytes, of the test message that will be
155	// sent.
156	messageLen int
157	// certFile is the path to the certificate to use for the server.
158	certFile string
159	// keyFile is the path to the private key to use for the server.
160	keyFile string
161	// resumeSession controls whether a second connection should be tested
162	// which attempts to resume the first session.
163	resumeSession bool
164	// expectResumeRejected, if true, specifies that the attempted
165	// resumption must be rejected by the client. This is only valid for a
166	// serverTest.
167	expectResumeRejected bool
168	// resumeConfig, if not nil, points to a Config to be used on
169	// resumption. Unless newSessionsOnResume is set,
170	// SessionTicketKey, ServerSessionCache, and
171	// ClientSessionCache are copied from the initial connection's
172	// config. If nil, the initial connection's config is used.
173	resumeConfig *Config
174	// newSessionsOnResume, if true, will cause resumeConfig to
175	// use a different session resumption context.
176	newSessionsOnResume bool
177	// sendPrefix sends a prefix on the socket before actually performing a
178	// handshake.
179	sendPrefix string
180	// shimWritesFirst controls whether the shim sends an initial "hello"
181	// message before doing a roundtrip with the runner.
182	shimWritesFirst bool
183	// renegotiate indicates the the connection should be renegotiated
184	// during the exchange.
185	renegotiate bool
186	// renegotiateCiphers is a list of ciphersuite ids that will be
187	// switched in just before renegotiation.
188	renegotiateCiphers []uint16
189	// replayWrites, if true, configures the underlying transport
190	// to replay every write it makes in DTLS tests.
191	replayWrites bool
192	// damageFirstWrite, if true, configures the underlying transport to
193	// damage the final byte of the first application data write.
194	damageFirstWrite bool
195	// exportKeyingMaterial, if non-zero, configures the test to exchange
196	// keying material and verify they match.
197	exportKeyingMaterial int
198	exportLabel          string
199	exportContext        string
200	useExportContext     bool
201	// flags, if not empty, contains a list of command-line flags that will
202	// be passed to the shim program.
203	flags []string
204	// testTLSUnique, if true, causes the shim to send the tls-unique value
205	// which will be compared against the expected value.
206	testTLSUnique bool
207}
208
209var testCases = []testCase{
210	{
211		name: "BadRSASignature",
212		config: Config{
213			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
214			Bugs: ProtocolBugs{
215				InvalidSKXSignature: true,
216			},
217		},
218		shouldFail:    true,
219		expectedError: ":BAD_SIGNATURE:",
220	},
221	{
222		name: "BadECDSASignature",
223		config: Config{
224			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
225			Bugs: ProtocolBugs{
226				InvalidSKXSignature: true,
227			},
228			Certificates: []Certificate{getECDSACertificate()},
229		},
230		shouldFail:    true,
231		expectedError: ":BAD_SIGNATURE:",
232	},
233	{
234		name: "BadECDSACurve",
235		config: Config{
236			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
237			Bugs: ProtocolBugs{
238				InvalidSKXCurve: true,
239			},
240			Certificates: []Certificate{getECDSACertificate()},
241		},
242		shouldFail:    true,
243		expectedError: ":WRONG_CURVE:",
244	},
245	{
246		testType: serverTest,
247		name:     "BadRSAVersion",
248		config: Config{
249			CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
250			Bugs: ProtocolBugs{
251				RsaClientKeyExchangeVersion: VersionTLS11,
252			},
253		},
254		shouldFail:    true,
255		expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
256	},
257	{
258		name: "NoFallbackSCSV",
259		config: Config{
260			Bugs: ProtocolBugs{
261				FailIfNotFallbackSCSV: true,
262			},
263		},
264		shouldFail:         true,
265		expectedLocalError: "no fallback SCSV found",
266	},
267	{
268		name: "SendFallbackSCSV",
269		config: Config{
270			Bugs: ProtocolBugs{
271				FailIfNotFallbackSCSV: true,
272			},
273		},
274		flags: []string{"-fallback-scsv"},
275	},
276	{
277		name: "ClientCertificateTypes",
278		config: Config{
279			ClientAuth: RequestClientCert,
280			ClientCertificateTypes: []byte{
281				CertTypeDSSSign,
282				CertTypeRSASign,
283				CertTypeECDSASign,
284			},
285		},
286		flags: []string{
287			"-expect-certificate-types",
288			base64.StdEncoding.EncodeToString([]byte{
289				CertTypeDSSSign,
290				CertTypeRSASign,
291				CertTypeECDSASign,
292			}),
293		},
294	},
295	{
296		name: "NoClientCertificate",
297		config: Config{
298			ClientAuth: RequireAnyClientCert,
299		},
300		shouldFail:         true,
301		expectedLocalError: "client didn't provide a certificate",
302	},
303	{
304		name: "UnauthenticatedECDH",
305		config: Config{
306			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
307			Bugs: ProtocolBugs{
308				UnauthenticatedECDH: true,
309			},
310		},
311		shouldFail:    true,
312		expectedError: ":UNEXPECTED_MESSAGE:",
313	},
314	{
315		name: "SkipCertificateStatus",
316		config: Config{
317			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
318			Bugs: ProtocolBugs{
319				SkipCertificateStatus: true,
320			},
321		},
322		flags: []string{
323			"-enable-ocsp-stapling",
324		},
325	},
326	{
327		name: "SkipServerKeyExchange",
328		config: Config{
329			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
330			Bugs: ProtocolBugs{
331				SkipServerKeyExchange: true,
332			},
333		},
334		shouldFail:    true,
335		expectedError: ":UNEXPECTED_MESSAGE:",
336	},
337	{
338		name: "SkipChangeCipherSpec-Client",
339		config: Config{
340			Bugs: ProtocolBugs{
341				SkipChangeCipherSpec: true,
342			},
343		},
344		shouldFail:    true,
345		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
346	},
347	{
348		testType: serverTest,
349		name:     "SkipChangeCipherSpec-Server",
350		config: Config{
351			Bugs: ProtocolBugs{
352				SkipChangeCipherSpec: true,
353			},
354		},
355		shouldFail:    true,
356		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
357	},
358	{
359		testType: serverTest,
360		name:     "SkipChangeCipherSpec-Server-NPN",
361		config: Config{
362			NextProtos: []string{"bar"},
363			Bugs: ProtocolBugs{
364				SkipChangeCipherSpec: true,
365			},
366		},
367		flags: []string{
368			"-advertise-npn", "\x03foo\x03bar\x03baz",
369		},
370		shouldFail:    true,
371		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
372	},
373	{
374		name: "FragmentAcrossChangeCipherSpec-Client",
375		config: Config{
376			Bugs: ProtocolBugs{
377				FragmentAcrossChangeCipherSpec: true,
378			},
379		},
380		shouldFail:    true,
381		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
382	},
383	{
384		testType: serverTest,
385		name:     "FragmentAcrossChangeCipherSpec-Server",
386		config: Config{
387			Bugs: ProtocolBugs{
388				FragmentAcrossChangeCipherSpec: true,
389			},
390		},
391		shouldFail:    true,
392		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
393	},
394	{
395		testType: serverTest,
396		name:     "FragmentAcrossChangeCipherSpec-Server-NPN",
397		config: Config{
398			NextProtos: []string{"bar"},
399			Bugs: ProtocolBugs{
400				FragmentAcrossChangeCipherSpec: true,
401			},
402		},
403		flags: []string{
404			"-advertise-npn", "\x03foo\x03bar\x03baz",
405		},
406		shouldFail:    true,
407		expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
408	},
409	{
410		testType: serverTest,
411		name:     "Alert",
412		config: Config{
413			Bugs: ProtocolBugs{
414				SendSpuriousAlert: alertRecordOverflow,
415			},
416		},
417		shouldFail:    true,
418		expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
419	},
420	{
421		protocol: dtls,
422		testType: serverTest,
423		name:     "Alert-DTLS",
424		config: Config{
425			Bugs: ProtocolBugs{
426				SendSpuriousAlert: alertRecordOverflow,
427			},
428		},
429		shouldFail:    true,
430		expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
431	},
432	{
433		testType: serverTest,
434		name:     "FragmentAlert",
435		config: Config{
436			Bugs: ProtocolBugs{
437				FragmentAlert:     true,
438				SendSpuriousAlert: alertRecordOverflow,
439			},
440		},
441		shouldFail:    true,
442		expectedError: ":BAD_ALERT:",
443	},
444	{
445		protocol: dtls,
446		testType: serverTest,
447		name:     "FragmentAlert-DTLS",
448		config: Config{
449			Bugs: ProtocolBugs{
450				FragmentAlert:     true,
451				SendSpuriousAlert: alertRecordOverflow,
452			},
453		},
454		shouldFail:    true,
455		expectedError: ":BAD_ALERT:",
456	},
457	{
458		testType: serverTest,
459		name:     "EarlyChangeCipherSpec-server-1",
460		config: Config{
461			Bugs: ProtocolBugs{
462				EarlyChangeCipherSpec: 1,
463			},
464		},
465		shouldFail:    true,
466		expectedError: ":CCS_RECEIVED_EARLY:",
467	},
468	{
469		testType: serverTest,
470		name:     "EarlyChangeCipherSpec-server-2",
471		config: Config{
472			Bugs: ProtocolBugs{
473				EarlyChangeCipherSpec: 2,
474			},
475		},
476		shouldFail:    true,
477		expectedError: ":CCS_RECEIVED_EARLY:",
478	},
479	{
480		name: "SkipNewSessionTicket",
481		config: Config{
482			Bugs: ProtocolBugs{
483				SkipNewSessionTicket: true,
484			},
485		},
486		shouldFail:    true,
487		expectedError: ":CCS_RECEIVED_EARLY:",
488	},
489	{
490		testType: serverTest,
491		name:     "FallbackSCSV",
492		config: Config{
493			MaxVersion: VersionTLS11,
494			Bugs: ProtocolBugs{
495				SendFallbackSCSV: true,
496			},
497		},
498		shouldFail:    true,
499		expectedError: ":INAPPROPRIATE_FALLBACK:",
500	},
501	{
502		testType: serverTest,
503		name:     "FallbackSCSV-VersionMatch",
504		config: Config{
505			Bugs: ProtocolBugs{
506				SendFallbackSCSV: true,
507			},
508		},
509	},
510	{
511		testType: serverTest,
512		name:     "FragmentedClientVersion",
513		config: Config{
514			Bugs: ProtocolBugs{
515				MaxHandshakeRecordLength: 1,
516				FragmentClientVersion:    true,
517			},
518		},
519		expectedVersion: VersionTLS12,
520	},
521	{
522		testType: serverTest,
523		name:     "MinorVersionTolerance",
524		config: Config{
525			Bugs: ProtocolBugs{
526				SendClientVersion: 0x03ff,
527			},
528		},
529		expectedVersion: VersionTLS12,
530	},
531	{
532		testType: serverTest,
533		name:     "MajorVersionTolerance",
534		config: Config{
535			Bugs: ProtocolBugs{
536				SendClientVersion: 0x0400,
537			},
538		},
539		expectedVersion: VersionTLS12,
540	},
541	{
542		testType: serverTest,
543		name:     "VersionTooLow",
544		config: Config{
545			Bugs: ProtocolBugs{
546				SendClientVersion: 0x0200,
547			},
548		},
549		shouldFail:    true,
550		expectedError: ":UNSUPPORTED_PROTOCOL:",
551	},
552	{
553		testType:      serverTest,
554		name:          "HttpGET",
555		sendPrefix:    "GET / HTTP/1.0\n",
556		shouldFail:    true,
557		expectedError: ":HTTP_REQUEST:",
558	},
559	{
560		testType:      serverTest,
561		name:          "HttpPOST",
562		sendPrefix:    "POST / HTTP/1.0\n",
563		shouldFail:    true,
564		expectedError: ":HTTP_REQUEST:",
565	},
566	{
567		testType:      serverTest,
568		name:          "HttpHEAD",
569		sendPrefix:    "HEAD / HTTP/1.0\n",
570		shouldFail:    true,
571		expectedError: ":HTTP_REQUEST:",
572	},
573	{
574		testType:      serverTest,
575		name:          "HttpPUT",
576		sendPrefix:    "PUT / HTTP/1.0\n",
577		shouldFail:    true,
578		expectedError: ":HTTP_REQUEST:",
579	},
580	{
581		testType:      serverTest,
582		name:          "HttpCONNECT",
583		sendPrefix:    "CONNECT www.google.com:443 HTTP/1.0\n",
584		shouldFail:    true,
585		expectedError: ":HTTPS_PROXY_REQUEST:",
586	},
587	{
588		testType:      serverTest,
589		name:          "Garbage",
590		sendPrefix:    "blah",
591		shouldFail:    true,
592		expectedError: ":UNKNOWN_PROTOCOL:",
593	},
594	{
595		name: "SkipCipherVersionCheck",
596		config: Config{
597			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
598			MaxVersion:   VersionTLS11,
599			Bugs: ProtocolBugs{
600				SkipCipherVersionCheck: true,
601			},
602		},
603		shouldFail:    true,
604		expectedError: ":WRONG_CIPHER_RETURNED:",
605	},
606	{
607		name: "RSAEphemeralKey",
608		config: Config{
609			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
610			Bugs: ProtocolBugs{
611				RSAEphemeralKey: true,
612			},
613		},
614		shouldFail:    true,
615		expectedError: ":UNEXPECTED_MESSAGE:",
616	},
617	{
618		name:          "DisableEverything",
619		flags:         []string{"-no-tls12", "-no-tls11", "-no-tls1", "-no-ssl3"},
620		shouldFail:    true,
621		expectedError: ":WRONG_SSL_VERSION:",
622	},
623	{
624		protocol:      dtls,
625		name:          "DisableEverything-DTLS",
626		flags:         []string{"-no-tls12", "-no-tls1"},
627		shouldFail:    true,
628		expectedError: ":WRONG_SSL_VERSION:",
629	},
630	{
631		name: "NoSharedCipher",
632		config: Config{
633			CipherSuites: []uint16{},
634		},
635		shouldFail:    true,
636		expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:",
637	},
638	{
639		protocol: dtls,
640		testType: serverTest,
641		name:     "MTU",
642		config: Config{
643			Bugs: ProtocolBugs{
644				MaxPacketLength: 256,
645			},
646		},
647		flags: []string{"-mtu", "256"},
648	},
649	{
650		protocol: dtls,
651		testType: serverTest,
652		name:     "MTUExceeded",
653		config: Config{
654			Bugs: ProtocolBugs{
655				MaxPacketLength: 255,
656			},
657		},
658		flags:              []string{"-mtu", "256"},
659		shouldFail:         true,
660		expectedLocalError: "dtls: exceeded maximum packet length",
661	},
662	{
663		name: "CertMismatchRSA",
664		config: Config{
665			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
666			Certificates: []Certificate{getECDSACertificate()},
667			Bugs: ProtocolBugs{
668				SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
669			},
670		},
671		shouldFail:    true,
672		expectedError: ":WRONG_CERTIFICATE_TYPE:",
673	},
674	{
675		name: "CertMismatchECDSA",
676		config: Config{
677			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
678			Certificates: []Certificate{getRSACertificate()},
679			Bugs: ProtocolBugs{
680				SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
681			},
682		},
683		shouldFail:    true,
684		expectedError: ":WRONG_CERTIFICATE_TYPE:",
685	},
686	{
687		name:             "TLSFatalBadPackets",
688		damageFirstWrite: true,
689		shouldFail:       true,
690		expectedError:    ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
691	},
692	{
693		protocol:         dtls,
694		name:             "DTLSIgnoreBadPackets",
695		damageFirstWrite: true,
696	},
697	{
698		protocol:         dtls,
699		name:             "DTLSIgnoreBadPackets-Async",
700		damageFirstWrite: true,
701		flags:            []string{"-async"},
702	},
703	{
704		name: "AppDataAfterChangeCipherSpec",
705		config: Config{
706			Bugs: ProtocolBugs{
707				AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
708			},
709		},
710		shouldFail:    true,
711		expectedError: ":DATA_BETWEEN_CCS_AND_FINISHED:",
712	},
713	{
714		protocol: dtls,
715		name:     "AppDataAfterChangeCipherSpec-DTLS",
716		config: Config{
717			Bugs: ProtocolBugs{
718				AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"),
719			},
720		},
721		// BoringSSL's DTLS implementation will drop the out-of-order
722		// application data.
723	},
724	{
725		name: "AlertAfterChangeCipherSpec",
726		config: Config{
727			Bugs: ProtocolBugs{
728				AlertAfterChangeCipherSpec: alertRecordOverflow,
729			},
730		},
731		shouldFail:    true,
732		expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
733	},
734	{
735		protocol: dtls,
736		name:     "AlertAfterChangeCipherSpec-DTLS",
737		config: Config{
738			Bugs: ProtocolBugs{
739				AlertAfterChangeCipherSpec: alertRecordOverflow,
740			},
741		},
742		shouldFail:    true,
743		expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:",
744	},
745	{
746		protocol: dtls,
747		name:     "ReorderHandshakeFragments-Small-DTLS",
748		config: Config{
749			Bugs: ProtocolBugs{
750				ReorderHandshakeFragments: true,
751				// Small enough that every handshake message is
752				// fragmented.
753				MaxHandshakeRecordLength: 2,
754			},
755		},
756	},
757	{
758		protocol: dtls,
759		name:     "ReorderHandshakeFragments-Large-DTLS",
760		config: Config{
761			Bugs: ProtocolBugs{
762				ReorderHandshakeFragments: true,
763				// Large enough that no handshake message is
764				// fragmented.
765				MaxHandshakeRecordLength: 2048,
766			},
767		},
768	},
769	{
770		protocol: dtls,
771		name:     "MixCompleteMessageWithFragments-DTLS",
772		config: Config{
773			Bugs: ProtocolBugs{
774				ReorderHandshakeFragments:       true,
775				MixCompleteMessageWithFragments: true,
776				MaxHandshakeRecordLength:        2,
777			},
778		},
779	},
780	{
781		name: "SendInvalidRecordType",
782		config: Config{
783			Bugs: ProtocolBugs{
784				SendInvalidRecordType: true,
785			},
786		},
787		shouldFail:    true,
788		expectedError: ":UNEXPECTED_RECORD:",
789	},
790	{
791		protocol: dtls,
792		name:     "SendInvalidRecordType-DTLS",
793		config: Config{
794			Bugs: ProtocolBugs{
795				SendInvalidRecordType: true,
796			},
797		},
798		shouldFail:    true,
799		expectedError: ":UNEXPECTED_RECORD:",
800	},
801	{
802		name: "FalseStart-SkipServerSecondLeg",
803		config: Config{
804			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
805			NextProtos:   []string{"foo"},
806			Bugs: ProtocolBugs{
807				SkipNewSessionTicket: true,
808				SkipChangeCipherSpec: true,
809				SkipFinished:         true,
810				ExpectFalseStart:     true,
811			},
812		},
813		flags: []string{
814			"-false-start",
815			"-handshake-never-done",
816			"-advertise-alpn", "\x03foo",
817		},
818		shimWritesFirst: true,
819		shouldFail:      true,
820		expectedError:   ":UNEXPECTED_RECORD:",
821	},
822	{
823		name: "FalseStart-SkipServerSecondLeg-Implicit",
824		config: Config{
825			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
826			NextProtos:   []string{"foo"},
827			Bugs: ProtocolBugs{
828				SkipNewSessionTicket: true,
829				SkipChangeCipherSpec: true,
830				SkipFinished:         true,
831			},
832		},
833		flags: []string{
834			"-implicit-handshake",
835			"-false-start",
836			"-handshake-never-done",
837			"-advertise-alpn", "\x03foo",
838		},
839		shouldFail:    true,
840		expectedError: ":UNEXPECTED_RECORD:",
841	},
842	{
843		testType:           serverTest,
844		name:               "FailEarlyCallback",
845		flags:              []string{"-fail-early-callback"},
846		shouldFail:         true,
847		expectedError:      ":CONNECTION_REJECTED:",
848		expectedLocalError: "remote error: access denied",
849	},
850	{
851		name: "WrongMessageType",
852		config: Config{
853			Bugs: ProtocolBugs{
854				WrongCertificateMessageType: true,
855			},
856		},
857		shouldFail:         true,
858		expectedError:      ":UNEXPECTED_MESSAGE:",
859		expectedLocalError: "remote error: unexpected message",
860	},
861	{
862		protocol: dtls,
863		name:     "WrongMessageType-DTLS",
864		config: Config{
865			Bugs: ProtocolBugs{
866				WrongCertificateMessageType: true,
867			},
868		},
869		shouldFail:         true,
870		expectedError:      ":UNEXPECTED_MESSAGE:",
871		expectedLocalError: "remote error: unexpected message",
872	},
873	{
874		protocol: dtls,
875		name:     "FragmentMessageTypeMismatch-DTLS",
876		config: Config{
877			Bugs: ProtocolBugs{
878				MaxHandshakeRecordLength:    2,
879				FragmentMessageTypeMismatch: true,
880			},
881		},
882		shouldFail:    true,
883		expectedError: ":FRAGMENT_MISMATCH:",
884	},
885	{
886		protocol: dtls,
887		name:     "FragmentMessageLengthMismatch-DTLS",
888		config: Config{
889			Bugs: ProtocolBugs{
890				MaxHandshakeRecordLength:      2,
891				FragmentMessageLengthMismatch: true,
892			},
893		},
894		shouldFail:    true,
895		expectedError: ":FRAGMENT_MISMATCH:",
896	},
897	{
898		protocol: dtls,
899		name:     "SplitFragmentHeader-DTLS",
900		config: Config{
901			Bugs: ProtocolBugs{
902				SplitFragmentHeader: true,
903			},
904		},
905		shouldFail:    true,
906		expectedError: ":UNEXPECTED_MESSAGE:",
907	},
908	{
909		protocol: dtls,
910		name:     "SplitFragmentBody-DTLS",
911		config: Config{
912			Bugs: ProtocolBugs{
913				SplitFragmentBody: true,
914			},
915		},
916		shouldFail:    true,
917		expectedError: ":UNEXPECTED_MESSAGE:",
918	},
919	{
920		protocol: dtls,
921		name:     "SendEmptyFragments-DTLS",
922		config: Config{
923			Bugs: ProtocolBugs{
924				SendEmptyFragments: true,
925			},
926		},
927	},
928	{
929		name: "UnsupportedCipherSuite",
930		config: Config{
931			CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
932			Bugs: ProtocolBugs{
933				IgnorePeerCipherPreferences: true,
934			},
935		},
936		flags:         []string{"-cipher", "DEFAULT:!RC4"},
937		shouldFail:    true,
938		expectedError: ":WRONG_CIPHER_RETURNED:",
939	},
940	{
941		name: "UnsupportedCurve",
942		config: Config{
943			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
944			// BoringSSL implements P-224 but doesn't enable it by
945			// default.
946			CurvePreferences: []CurveID{CurveP224},
947			Bugs: ProtocolBugs{
948				IgnorePeerCurvePreferences: true,
949			},
950		},
951		shouldFail:    true,
952		expectedError: ":WRONG_CURVE:",
953	},
954	{
955		name: "SendWarningAlerts",
956		config: Config{
957			Bugs: ProtocolBugs{
958				SendWarningAlerts: alertAccessDenied,
959			},
960		},
961	},
962	{
963		protocol: dtls,
964		name:     "SendWarningAlerts-DTLS",
965		config: Config{
966			Bugs: ProtocolBugs{
967				SendWarningAlerts: alertAccessDenied,
968			},
969		},
970	},
971	{
972		name: "BadFinished",
973		config: Config{
974			Bugs: ProtocolBugs{
975				BadFinished: true,
976			},
977		},
978		shouldFail:    true,
979		expectedError: ":DIGEST_CHECK_FAILED:",
980	},
981	{
982		name: "FalseStart-BadFinished",
983		config: Config{
984			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
985			NextProtos:   []string{"foo"},
986			Bugs: ProtocolBugs{
987				BadFinished:      true,
988				ExpectFalseStart: true,
989			},
990		},
991		flags: []string{
992			"-false-start",
993			"-handshake-never-done",
994			"-advertise-alpn", "\x03foo",
995		},
996		shimWritesFirst: true,
997		shouldFail:      true,
998		expectedError:   ":DIGEST_CHECK_FAILED:",
999	},
1000	{
1001		name: "NoFalseStart-NoALPN",
1002		config: Config{
1003			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1004			Bugs: ProtocolBugs{
1005				ExpectFalseStart:          true,
1006				AlertBeforeFalseStartTest: alertAccessDenied,
1007			},
1008		},
1009		flags: []string{
1010			"-false-start",
1011		},
1012		shimWritesFirst:    true,
1013		shouldFail:         true,
1014		expectedError:      ":TLSV1_ALERT_ACCESS_DENIED:",
1015		expectedLocalError: "tls: peer did not false start: EOF",
1016	},
1017	{
1018		name: "NoFalseStart-NoAEAD",
1019		config: Config{
1020			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1021			NextProtos:   []string{"foo"},
1022			Bugs: ProtocolBugs{
1023				ExpectFalseStart:          true,
1024				AlertBeforeFalseStartTest: alertAccessDenied,
1025			},
1026		},
1027		flags: []string{
1028			"-false-start",
1029			"-advertise-alpn", "\x03foo",
1030		},
1031		shimWritesFirst:    true,
1032		shouldFail:         true,
1033		expectedError:      ":TLSV1_ALERT_ACCESS_DENIED:",
1034		expectedLocalError: "tls: peer did not false start: EOF",
1035	},
1036	{
1037		name: "NoFalseStart-RSA",
1038		config: Config{
1039			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1040			NextProtos:   []string{"foo"},
1041			Bugs: ProtocolBugs{
1042				ExpectFalseStart:          true,
1043				AlertBeforeFalseStartTest: alertAccessDenied,
1044			},
1045		},
1046		flags: []string{
1047			"-false-start",
1048			"-advertise-alpn", "\x03foo",
1049		},
1050		shimWritesFirst:    true,
1051		shouldFail:         true,
1052		expectedError:      ":TLSV1_ALERT_ACCESS_DENIED:",
1053		expectedLocalError: "tls: peer did not false start: EOF",
1054	},
1055	{
1056		name: "NoFalseStart-DHE_RSA",
1057		config: Config{
1058			CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
1059			NextProtos:   []string{"foo"},
1060			Bugs: ProtocolBugs{
1061				ExpectFalseStart:          true,
1062				AlertBeforeFalseStartTest: alertAccessDenied,
1063			},
1064		},
1065		flags: []string{
1066			"-false-start",
1067			"-advertise-alpn", "\x03foo",
1068		},
1069		shimWritesFirst:    true,
1070		shouldFail:         true,
1071		expectedError:      ":TLSV1_ALERT_ACCESS_DENIED:",
1072		expectedLocalError: "tls: peer did not false start: EOF",
1073	},
1074	{
1075		testType: serverTest,
1076		name:     "NoSupportedCurves",
1077		config: Config{
1078			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1079			Bugs: ProtocolBugs{
1080				NoSupportedCurves: true,
1081			},
1082		},
1083	},
1084	{
1085		testType: serverTest,
1086		name:     "NoCommonCurves",
1087		config: Config{
1088			CipherSuites: []uint16{
1089				TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
1090				TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
1091			},
1092			CurvePreferences: []CurveID{CurveP224},
1093		},
1094		expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
1095	},
1096	{
1097		protocol: dtls,
1098		name:     "SendSplitAlert-Sync",
1099		config: Config{
1100			Bugs: ProtocolBugs{
1101				SendSplitAlert: true,
1102			},
1103		},
1104	},
1105	{
1106		protocol: dtls,
1107		name:     "SendSplitAlert-Async",
1108		config: Config{
1109			Bugs: ProtocolBugs{
1110				SendSplitAlert: true,
1111			},
1112		},
1113		flags: []string{"-async"},
1114	},
1115	{
1116		protocol: dtls,
1117		name:     "PackDTLSHandshake",
1118		config: Config{
1119			Bugs: ProtocolBugs{
1120				MaxHandshakeRecordLength: 2,
1121				PackHandshakeFragments:   20,
1122				PackHandshakeRecords:     200,
1123			},
1124		},
1125	},
1126	{
1127		testType: serverTest,
1128		protocol: dtls,
1129		name:     "NoRC4-DTLS",
1130		config: Config{
1131			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA},
1132			Bugs: ProtocolBugs{
1133				EnableAllCiphersInDTLS: true,
1134			},
1135		},
1136		shouldFail:    true,
1137		expectedError: ":NO_SHARED_CIPHER:",
1138	},
1139}
1140
1141func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
1142	var connDebug *recordingConn
1143	var connDamage *damageAdaptor
1144	if *flagDebug {
1145		connDebug = &recordingConn{Conn: conn}
1146		conn = connDebug
1147		defer func() {
1148			connDebug.WriteTo(os.Stdout)
1149		}()
1150	}
1151
1152	if test.protocol == dtls {
1153		config.Bugs.PacketAdaptor = newPacketAdaptor(conn)
1154		conn = config.Bugs.PacketAdaptor
1155		if test.replayWrites {
1156			conn = newReplayAdaptor(conn)
1157		}
1158	}
1159
1160	if test.damageFirstWrite {
1161		connDamage = newDamageAdaptor(conn)
1162		conn = connDamage
1163	}
1164
1165	if test.sendPrefix != "" {
1166		if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
1167			return err
1168		}
1169	}
1170
1171	var tlsConn *Conn
1172	if test.testType == clientTest {
1173		if test.protocol == dtls {
1174			tlsConn = DTLSServer(conn, config)
1175		} else {
1176			tlsConn = Server(conn, config)
1177		}
1178	} else {
1179		config.InsecureSkipVerify = true
1180		if test.protocol == dtls {
1181			tlsConn = DTLSClient(conn, config)
1182		} else {
1183			tlsConn = Client(conn, config)
1184		}
1185	}
1186
1187	if err := tlsConn.Handshake(); err != nil {
1188		return err
1189	}
1190
1191	// TODO(davidben): move all per-connection expectations into a dedicated
1192	// expectations struct that can be specified separately for the two
1193	// legs.
1194	expectedVersion := test.expectedVersion
1195	if isResume && test.expectedResumeVersion != 0 {
1196		expectedVersion = test.expectedResumeVersion
1197	}
1198	connState := tlsConn.ConnectionState()
1199	if vers := connState.Version; expectedVersion != 0 && vers != expectedVersion {
1200		return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
1201	}
1202
1203	if cipher := connState.CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher {
1204		return fmt.Errorf("got cipher %x, expected %x", cipher, test.expectedCipher)
1205	}
1206	if didResume := connState.DidResume; isResume && didResume == test.expectResumeRejected {
1207		return fmt.Errorf("didResume is %t, but we expected the opposite", didResume)
1208	}
1209
1210	if test.expectChannelID {
1211		channelID := connState.ChannelID
1212		if channelID == nil {
1213			return fmt.Errorf("no channel ID negotiated")
1214		}
1215		if channelID.Curve != channelIDKey.Curve ||
1216			channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
1217			channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
1218			return fmt.Errorf("incorrect channel ID")
1219		}
1220	}
1221
1222	if expected := test.expectedNextProto; expected != "" {
1223		if actual := connState.NegotiatedProtocol; actual != expected {
1224			return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
1225		}
1226	}
1227
1228	if test.expectedNextProtoType != 0 {
1229		if (test.expectedNextProtoType == alpn) != connState.NegotiatedProtocolFromALPN {
1230			return fmt.Errorf("next proto type mismatch")
1231		}
1232	}
1233
1234	if p := connState.SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile {
1235		return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile)
1236	}
1237
1238	if test.exportKeyingMaterial > 0 {
1239		actual := make([]byte, test.exportKeyingMaterial)
1240		if _, err := io.ReadFull(tlsConn, actual); err != nil {
1241			return err
1242		}
1243		expected, err := tlsConn.ExportKeyingMaterial(test.exportKeyingMaterial, []byte(test.exportLabel), []byte(test.exportContext), test.useExportContext)
1244		if err != nil {
1245			return err
1246		}
1247		if !bytes.Equal(actual, expected) {
1248			return fmt.Errorf("keying material mismatch")
1249		}
1250	}
1251
1252	if test.testTLSUnique {
1253		var peersValue [12]byte
1254		if _, err := io.ReadFull(tlsConn, peersValue[:]); err != nil {
1255			return err
1256		}
1257		expected := tlsConn.ConnectionState().TLSUnique
1258		if !bytes.Equal(peersValue[:], expected) {
1259			return fmt.Errorf("tls-unique mismatch: peer sent %x, but %x was expected", peersValue[:], expected)
1260		}
1261	}
1262
1263	if test.shimWritesFirst {
1264		var buf [5]byte
1265		_, err := io.ReadFull(tlsConn, buf[:])
1266		if err != nil {
1267			return err
1268		}
1269		if string(buf[:]) != "hello" {
1270			return fmt.Errorf("bad initial message")
1271		}
1272	}
1273
1274	if test.renegotiate {
1275		if test.renegotiateCiphers != nil {
1276			config.CipherSuites = test.renegotiateCiphers
1277		}
1278		if err := tlsConn.Renegotiate(); err != nil {
1279			return err
1280		}
1281	} else if test.renegotiateCiphers != nil {
1282		panic("renegotiateCiphers without renegotiate")
1283	}
1284
1285	if test.damageFirstWrite {
1286		connDamage.setDamage(true)
1287		tlsConn.Write([]byte("DAMAGED WRITE"))
1288		connDamage.setDamage(false)
1289	}
1290
1291	if messageLen < 0 {
1292		if test.protocol == dtls {
1293			return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
1294		}
1295		// Read until EOF.
1296		_, err := io.Copy(ioutil.Discard, tlsConn)
1297		return err
1298	}
1299
1300	if messageLen == 0 {
1301		messageLen = 32
1302	}
1303	testMessage := make([]byte, messageLen)
1304	for i := range testMessage {
1305		testMessage[i] = 0x42
1306	}
1307	tlsConn.Write(testMessage)
1308
1309	buf := make([]byte, len(testMessage))
1310	if test.protocol == dtls {
1311		bufTmp := make([]byte, len(buf)+1)
1312		n, err := tlsConn.Read(bufTmp)
1313		if err != nil {
1314			return err
1315		}
1316		if n != len(buf) {
1317			return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
1318		}
1319		copy(buf, bufTmp)
1320	} else {
1321		_, err := io.ReadFull(tlsConn, buf)
1322		if err != nil {
1323			return err
1324		}
1325	}
1326
1327	for i, v := range buf {
1328		if v != testMessage[i]^0xff {
1329			return fmt.Errorf("bad reply contents at byte %d", i)
1330		}
1331	}
1332
1333	return nil
1334}
1335
1336func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
1337	valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
1338	if dbAttach {
1339		valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
1340	}
1341	valgrindArgs = append(valgrindArgs, path)
1342	valgrindArgs = append(valgrindArgs, args...)
1343
1344	return exec.Command("valgrind", valgrindArgs...)
1345}
1346
1347func gdbOf(path string, args ...string) *exec.Cmd {
1348	xtermArgs := []string{"-e", "gdb", "--args"}
1349	xtermArgs = append(xtermArgs, path)
1350	xtermArgs = append(xtermArgs, args...)
1351
1352	return exec.Command("xterm", xtermArgs...)
1353}
1354
1355type moreMallocsError struct{}
1356
1357func (moreMallocsError) Error() string {
1358	return "child process did not exhaust all allocation calls"
1359}
1360
1361var errMoreMallocs = moreMallocsError{}
1362
1363// accept accepts a connection from listener, unless waitChan signals a process
1364// exit first.
1365func acceptOrWait(listener net.Listener, waitChan chan error) (net.Conn, error) {
1366	type connOrError struct {
1367		conn net.Conn
1368		err  error
1369	}
1370	connChan := make(chan connOrError, 1)
1371	go func() {
1372		conn, err := listener.Accept()
1373		connChan <- connOrError{conn, err}
1374		close(connChan)
1375	}()
1376	select {
1377	case result := <-connChan:
1378		return result.conn, result.err
1379	case childErr := <-waitChan:
1380		waitChan <- childErr
1381		return nil, fmt.Errorf("child exited early: %s", childErr)
1382	}
1383}
1384
1385func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
1386	if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
1387		panic("Error expected without shouldFail in " + test.name)
1388	}
1389
1390	if test.expectResumeRejected && !test.resumeSession {
1391		panic("expectResumeRejected without resumeSession in " + test.name)
1392	}
1393
1394	listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}})
1395	if err != nil {
1396		panic(err)
1397	}
1398	defer func() {
1399		if listener != nil {
1400			listener.Close()
1401		}
1402	}()
1403
1404	shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
1405	flags := []string{"-port", strconv.Itoa(listener.Addr().(*net.TCPAddr).Port)}
1406	if test.testType == serverTest {
1407		flags = append(flags, "-server")
1408
1409		flags = append(flags, "-key-file")
1410		if test.keyFile == "" {
1411			flags = append(flags, rsaKeyFile)
1412		} else {
1413			flags = append(flags, test.keyFile)
1414		}
1415
1416		flags = append(flags, "-cert-file")
1417		if test.certFile == "" {
1418			flags = append(flags, rsaCertificateFile)
1419		} else {
1420			flags = append(flags, test.certFile)
1421		}
1422	}
1423
1424	if test.protocol == dtls {
1425		flags = append(flags, "-dtls")
1426	}
1427
1428	if test.resumeSession {
1429		flags = append(flags, "-resume")
1430	}
1431
1432	if test.shimWritesFirst {
1433		flags = append(flags, "-shim-writes-first")
1434	}
1435
1436	if test.exportKeyingMaterial > 0 {
1437		flags = append(flags, "-export-keying-material", strconv.Itoa(test.exportKeyingMaterial))
1438		flags = append(flags, "-export-label", test.exportLabel)
1439		flags = append(flags, "-export-context", test.exportContext)
1440		if test.useExportContext {
1441			flags = append(flags, "-use-export-context")
1442		}
1443	}
1444	if test.expectResumeRejected {
1445		flags = append(flags, "-expect-session-miss")
1446	}
1447
1448	if test.testTLSUnique {
1449		flags = append(flags, "-tls-unique")
1450	}
1451
1452	flags = append(flags, test.flags...)
1453
1454	var shim *exec.Cmd
1455	if *useValgrind {
1456		shim = valgrindOf(false, shim_path, flags...)
1457	} else if *useGDB {
1458		shim = gdbOf(shim_path, flags...)
1459	} else {
1460		shim = exec.Command(shim_path, flags...)
1461	}
1462	shim.Stdin = os.Stdin
1463	var stdoutBuf, stderrBuf bytes.Buffer
1464	shim.Stdout = &stdoutBuf
1465	shim.Stderr = &stderrBuf
1466	if mallocNumToFail >= 0 {
1467		shim.Env = os.Environ()
1468		shim.Env = append(shim.Env, "MALLOC_NUMBER_TO_FAIL="+strconv.FormatInt(mallocNumToFail, 10))
1469		if *mallocTestDebug {
1470			shim.Env = append(shim.Env, "MALLOC_ABORT_ON_FAIL=1")
1471		}
1472		shim.Env = append(shim.Env, "_MALLOC_CHECK=1")
1473	}
1474
1475	if err := shim.Start(); err != nil {
1476		panic(err)
1477	}
1478	waitChan := make(chan error, 1)
1479	go func() { waitChan <- shim.Wait() }()
1480
1481	config := test.config
1482	config.ClientSessionCache = NewLRUClientSessionCache(1)
1483	config.ServerSessionCache = NewLRUServerSessionCache(1)
1484	if test.testType == clientTest {
1485		if len(config.Certificates) == 0 {
1486			config.Certificates = []Certificate{getRSACertificate()}
1487		}
1488	} else {
1489		// Supply a ServerName to ensure a constant session cache key,
1490		// rather than falling back to net.Conn.RemoteAddr.
1491		if len(config.ServerName) == 0 {
1492			config.ServerName = "test"
1493		}
1494	}
1495
1496	conn, err := acceptOrWait(listener, waitChan)
1497	if err == nil {
1498		err = doExchange(test, &config, conn, test.messageLen, false /* not a resumption */)
1499		conn.Close()
1500	}
1501
1502	if err == nil && test.resumeSession {
1503		var resumeConfig Config
1504		if test.resumeConfig != nil {
1505			resumeConfig = *test.resumeConfig
1506			if len(resumeConfig.ServerName) == 0 {
1507				resumeConfig.ServerName = config.ServerName
1508			}
1509			if len(resumeConfig.Certificates) == 0 {
1510				resumeConfig.Certificates = []Certificate{getRSACertificate()}
1511			}
1512			if !test.newSessionsOnResume {
1513				resumeConfig.SessionTicketKey = config.SessionTicketKey
1514				resumeConfig.ClientSessionCache = config.ClientSessionCache
1515				resumeConfig.ServerSessionCache = config.ServerSessionCache
1516			}
1517		} else {
1518			resumeConfig = config
1519		}
1520		var connResume net.Conn
1521		connResume, err = acceptOrWait(listener, waitChan)
1522		if err == nil {
1523			err = doExchange(test, &resumeConfig, connResume, test.messageLen, true /* resumption */)
1524			connResume.Close()
1525		}
1526	}
1527
1528	// Close the listener now. This is to avoid hangs should the shim try to
1529	// open more connections than expected.
1530	listener.Close()
1531	listener = nil
1532
1533	childErr := <-waitChan
1534	if exitError, ok := childErr.(*exec.ExitError); ok {
1535		if exitError.Sys().(syscall.WaitStatus).ExitStatus() == 88 {
1536			return errMoreMallocs
1537		}
1538	}
1539
1540	stdout := string(stdoutBuf.Bytes())
1541	stderr := string(stderrBuf.Bytes())
1542	failed := err != nil || childErr != nil
1543	correctFailure := len(test.expectedError) == 0 || strings.Contains(stderr, test.expectedError)
1544	localError := "none"
1545	if err != nil {
1546		localError = err.Error()
1547	}
1548	if len(test.expectedLocalError) != 0 {
1549		correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
1550	}
1551
1552	if failed != test.shouldFail || failed && !correctFailure {
1553		childError := "none"
1554		if childErr != nil {
1555			childError = childErr.Error()
1556		}
1557
1558		var msg string
1559		switch {
1560		case failed && !test.shouldFail:
1561			msg = "unexpected failure"
1562		case !failed && test.shouldFail:
1563			msg = "unexpected success"
1564		case failed && !correctFailure:
1565			msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
1566		default:
1567			panic("internal error")
1568		}
1569
1570		return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, stdout, stderr)
1571	}
1572
1573	if !*useValgrind && !failed && len(stderr) > 0 {
1574		println(stderr)
1575	}
1576
1577	return nil
1578}
1579
1580var tlsVersions = []struct {
1581	name    string
1582	version uint16
1583	flag    string
1584	hasDTLS bool
1585}{
1586	{"SSL3", VersionSSL30, "-no-ssl3", false},
1587	{"TLS1", VersionTLS10, "-no-tls1", true},
1588	{"TLS11", VersionTLS11, "-no-tls11", false},
1589	{"TLS12", VersionTLS12, "-no-tls12", true},
1590}
1591
1592var testCipherSuites = []struct {
1593	name string
1594	id   uint16
1595}{
1596	{"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
1597	{"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
1598	{"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
1599	{"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
1600	{"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
1601	{"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
1602	{"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
1603	{"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
1604	{"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
1605	{"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
1606	{"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
1607	{"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
1608	{"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
1609	{"DHE-RSA-CHACHA20-POLY1305", TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
1610	{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
1611	{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
1612	{"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
1613	{"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
1614	{"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
1615	{"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
1616	{"ECDHE-ECDSA-CHACHA20-POLY1305", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
1617	{"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
1618	{"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1619	{"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1620	{"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
1621	{"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
1622	{"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
1623	{"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
1624	{"ECDHE-RSA-CHACHA20-POLY1305", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
1625	{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
1626	{"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
1627	{"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
1628	{"ECDHE-PSK-AES128-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA},
1629	{"ECDHE-PSK-AES256-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA},
1630	{"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
1631	{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
1632	{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
1633}
1634
1635func hasComponent(suiteName, component string) bool {
1636	return strings.Contains("-"+suiteName+"-", "-"+component+"-")
1637}
1638
1639func isTLS12Only(suiteName string) bool {
1640	return hasComponent(suiteName, "GCM") ||
1641		hasComponent(suiteName, "SHA256") ||
1642		hasComponent(suiteName, "SHA384") ||
1643		hasComponent(suiteName, "POLY1305")
1644}
1645
1646func isDTLSCipher(suiteName string) bool {
1647	return !hasComponent(suiteName, "RC4")
1648}
1649
1650func bigFromHex(hex string) *big.Int {
1651	ret, ok := new(big.Int).SetString(hex, 16)
1652	if !ok {
1653		panic("failed to parse hex number 0x" + hex)
1654	}
1655	return ret
1656}
1657
1658func addCipherSuiteTests() {
1659	for _, suite := range testCipherSuites {
1660		const psk = "12345"
1661		const pskIdentity = "luggage combo"
1662
1663		var cert Certificate
1664		var certFile string
1665		var keyFile string
1666		if hasComponent(suite.name, "ECDSA") {
1667			cert = getECDSACertificate()
1668			certFile = ecdsaCertificateFile
1669			keyFile = ecdsaKeyFile
1670		} else {
1671			cert = getRSACertificate()
1672			certFile = rsaCertificateFile
1673			keyFile = rsaKeyFile
1674		}
1675
1676		var flags []string
1677		if hasComponent(suite.name, "PSK") {
1678			flags = append(flags,
1679				"-psk", psk,
1680				"-psk-identity", pskIdentity)
1681		}
1682
1683		for _, ver := range tlsVersions {
1684			if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
1685				continue
1686			}
1687
1688			testCases = append(testCases, testCase{
1689				testType: clientTest,
1690				name:     ver.name + "-" + suite.name + "-client",
1691				config: Config{
1692					MinVersion:           ver.version,
1693					MaxVersion:           ver.version,
1694					CipherSuites:         []uint16{suite.id},
1695					Certificates:         []Certificate{cert},
1696					PreSharedKey:         []byte(psk),
1697					PreSharedKeyIdentity: pskIdentity,
1698				},
1699				flags:         flags,
1700				resumeSession: true,
1701			})
1702
1703			testCases = append(testCases, testCase{
1704				testType: serverTest,
1705				name:     ver.name + "-" + suite.name + "-server",
1706				config: Config{
1707					MinVersion:           ver.version,
1708					MaxVersion:           ver.version,
1709					CipherSuites:         []uint16{suite.id},
1710					Certificates:         []Certificate{cert},
1711					PreSharedKey:         []byte(psk),
1712					PreSharedKeyIdentity: pskIdentity,
1713				},
1714				certFile:      certFile,
1715				keyFile:       keyFile,
1716				flags:         flags,
1717				resumeSession: true,
1718			})
1719
1720			if ver.hasDTLS && isDTLSCipher(suite.name) {
1721				testCases = append(testCases, testCase{
1722					testType: clientTest,
1723					protocol: dtls,
1724					name:     "D" + ver.name + "-" + suite.name + "-client",
1725					config: Config{
1726						MinVersion:           ver.version,
1727						MaxVersion:           ver.version,
1728						CipherSuites:         []uint16{suite.id},
1729						Certificates:         []Certificate{cert},
1730						PreSharedKey:         []byte(psk),
1731						PreSharedKeyIdentity: pskIdentity,
1732					},
1733					flags:         flags,
1734					resumeSession: true,
1735				})
1736				testCases = append(testCases, testCase{
1737					testType: serverTest,
1738					protocol: dtls,
1739					name:     "D" + ver.name + "-" + suite.name + "-server",
1740					config: Config{
1741						MinVersion:           ver.version,
1742						MaxVersion:           ver.version,
1743						CipherSuites:         []uint16{suite.id},
1744						Certificates:         []Certificate{cert},
1745						PreSharedKey:         []byte(psk),
1746						PreSharedKeyIdentity: pskIdentity,
1747					},
1748					certFile:      certFile,
1749					keyFile:       keyFile,
1750					flags:         flags,
1751					resumeSession: true,
1752				})
1753			}
1754		}
1755	}
1756
1757	testCases = append(testCases, testCase{
1758		name: "WeakDH",
1759		config: Config{
1760			CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
1761			Bugs: ProtocolBugs{
1762				// This is a 1023-bit prime number, generated
1763				// with:
1764				// openssl gendh 1023 | openssl asn1parse -i
1765				DHGroupPrime: bigFromHex("518E9B7930CE61C6E445C8360584E5FC78D9137C0FFDC880B495D5338ADF7689951A6821C17A76B3ACB8E0156AEA607B7EC406EBEDBB84D8376EB8FE8F8BA1433488BEE0C3EDDFD3A32DBB9481980A7AF6C96BFCF490A094CFFB2B8192C1BB5510B77B658436E27C2D4D023FE3718222AB0CA1273995B51F6D625A4944D0DD4B"),
1766			},
1767		},
1768		shouldFail:    true,
1769		expectedError: "BAD_DH_P_LENGTH",
1770	})
1771}
1772
1773func addBadECDSASignatureTests() {
1774	for badR := BadValue(1); badR < NumBadValues; badR++ {
1775		for badS := BadValue(1); badS < NumBadValues; badS++ {
1776			testCases = append(testCases, testCase{
1777				name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
1778				config: Config{
1779					CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
1780					Certificates: []Certificate{getECDSACertificate()},
1781					Bugs: ProtocolBugs{
1782						BadECDSAR: badR,
1783						BadECDSAS: badS,
1784					},
1785				},
1786				shouldFail:    true,
1787				expectedError: "SIGNATURE",
1788			})
1789		}
1790	}
1791}
1792
1793func addCBCPaddingTests() {
1794	testCases = append(testCases, testCase{
1795		name: "MaxCBCPadding",
1796		config: Config{
1797			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1798			Bugs: ProtocolBugs{
1799				MaxPadding: true,
1800			},
1801		},
1802		messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
1803	})
1804	testCases = append(testCases, testCase{
1805		name: "BadCBCPadding",
1806		config: Config{
1807			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1808			Bugs: ProtocolBugs{
1809				PaddingFirstByteBad: true,
1810			},
1811		},
1812		shouldFail:    true,
1813		expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1814	})
1815	// OpenSSL previously had an issue where the first byte of padding in
1816	// 255 bytes of padding wasn't checked.
1817	testCases = append(testCases, testCase{
1818		name: "BadCBCPadding255",
1819		config: Config{
1820			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1821			Bugs: ProtocolBugs{
1822				MaxPadding:               true,
1823				PaddingFirstByteBadIf255: true,
1824			},
1825		},
1826		messageLen:    12, // 20 bytes of SHA-1 + 12 == 0 % block size
1827		shouldFail:    true,
1828		expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1829	})
1830}
1831
1832func addCBCSplittingTests() {
1833	testCases = append(testCases, testCase{
1834		name: "CBCRecordSplitting",
1835		config: Config{
1836			MaxVersion:   VersionTLS10,
1837			MinVersion:   VersionTLS10,
1838			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1839		},
1840		messageLen: -1, // read until EOF
1841		flags: []string{
1842			"-async",
1843			"-write-different-record-sizes",
1844			"-cbc-record-splitting",
1845		},
1846	})
1847	testCases = append(testCases, testCase{
1848		name: "CBCRecordSplittingPartialWrite",
1849		config: Config{
1850			MaxVersion:   VersionTLS10,
1851			MinVersion:   VersionTLS10,
1852			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1853		},
1854		messageLen: -1, // read until EOF
1855		flags: []string{
1856			"-async",
1857			"-write-different-record-sizes",
1858			"-cbc-record-splitting",
1859			"-partial-write",
1860		},
1861	})
1862}
1863
1864func addClientAuthTests() {
1865	// Add a dummy cert pool to stress certificate authority parsing.
1866	// TODO(davidben): Add tests that those values parse out correctly.
1867	certPool := x509.NewCertPool()
1868	cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
1869	if err != nil {
1870		panic(err)
1871	}
1872	certPool.AddCert(cert)
1873
1874	for _, ver := range tlsVersions {
1875		testCases = append(testCases, testCase{
1876			testType: clientTest,
1877			name:     ver.name + "-Client-ClientAuth-RSA",
1878			config: Config{
1879				MinVersion: ver.version,
1880				MaxVersion: ver.version,
1881				ClientAuth: RequireAnyClientCert,
1882				ClientCAs:  certPool,
1883			},
1884			flags: []string{
1885				"-cert-file", rsaCertificateFile,
1886				"-key-file", rsaKeyFile,
1887			},
1888		})
1889		testCases = append(testCases, testCase{
1890			testType: serverTest,
1891			name:     ver.name + "-Server-ClientAuth-RSA",
1892			config: Config{
1893				MinVersion:   ver.version,
1894				MaxVersion:   ver.version,
1895				Certificates: []Certificate{rsaCertificate},
1896			},
1897			flags: []string{"-require-any-client-certificate"},
1898		})
1899		if ver.version != VersionSSL30 {
1900			testCases = append(testCases, testCase{
1901				testType: serverTest,
1902				name:     ver.name + "-Server-ClientAuth-ECDSA",
1903				config: Config{
1904					MinVersion:   ver.version,
1905					MaxVersion:   ver.version,
1906					Certificates: []Certificate{ecdsaCertificate},
1907				},
1908				flags: []string{"-require-any-client-certificate"},
1909			})
1910			testCases = append(testCases, testCase{
1911				testType: clientTest,
1912				name:     ver.name + "-Client-ClientAuth-ECDSA",
1913				config: Config{
1914					MinVersion: ver.version,
1915					MaxVersion: ver.version,
1916					ClientAuth: RequireAnyClientCert,
1917					ClientCAs:  certPool,
1918				},
1919				flags: []string{
1920					"-cert-file", ecdsaCertificateFile,
1921					"-key-file", ecdsaKeyFile,
1922				},
1923			})
1924		}
1925	}
1926}
1927
1928func addExtendedMasterSecretTests() {
1929	const expectEMSFlag = "-expect-extended-master-secret"
1930
1931	for _, with := range []bool{false, true} {
1932		prefix := "No"
1933		var flags []string
1934		if with {
1935			prefix = ""
1936			flags = []string{expectEMSFlag}
1937		}
1938
1939		for _, isClient := range []bool{false, true} {
1940			suffix := "-Server"
1941			testType := serverTest
1942			if isClient {
1943				suffix = "-Client"
1944				testType = clientTest
1945			}
1946
1947			for _, ver := range tlsVersions {
1948				test := testCase{
1949					testType: testType,
1950					name:     prefix + "ExtendedMasterSecret-" + ver.name + suffix,
1951					config: Config{
1952						MinVersion: ver.version,
1953						MaxVersion: ver.version,
1954						Bugs: ProtocolBugs{
1955							NoExtendedMasterSecret:      !with,
1956							RequireExtendedMasterSecret: with,
1957						},
1958					},
1959					flags:      flags,
1960					shouldFail: ver.version == VersionSSL30 && with,
1961				}
1962				if test.shouldFail {
1963					test.expectedLocalError = "extended master secret required but not supported by peer"
1964				}
1965				testCases = append(testCases, test)
1966			}
1967		}
1968	}
1969
1970	for _, isClient := range []bool{false, true} {
1971		for _, supportedInFirstConnection := range []bool{false, true} {
1972			for _, supportedInResumeConnection := range []bool{false, true} {
1973				boolToWord := func(b bool) string {
1974					if b {
1975						return "Yes"
1976					}
1977					return "No"
1978				}
1979				suffix := boolToWord(supportedInFirstConnection) + "To" + boolToWord(supportedInResumeConnection) + "-"
1980				if isClient {
1981					suffix += "Client"
1982				} else {
1983					suffix += "Server"
1984				}
1985
1986				supportedConfig := Config{
1987					Bugs: ProtocolBugs{
1988						RequireExtendedMasterSecret: true,
1989					},
1990				}
1991
1992				noSupportConfig := Config{
1993					Bugs: ProtocolBugs{
1994						NoExtendedMasterSecret: true,
1995					},
1996				}
1997
1998				test := testCase{
1999					name:          "ExtendedMasterSecret-" + suffix,
2000					resumeSession: true,
2001				}
2002
2003				if !isClient {
2004					test.testType = serverTest
2005				}
2006
2007				if supportedInFirstConnection {
2008					test.config = supportedConfig
2009				} else {
2010					test.config = noSupportConfig
2011				}
2012
2013				if supportedInResumeConnection {
2014					test.resumeConfig = &supportedConfig
2015				} else {
2016					test.resumeConfig = &noSupportConfig
2017				}
2018
2019				switch suffix {
2020				case "YesToYes-Client", "YesToYes-Server":
2021					// When a session is resumed, it should
2022					// still be aware that its master
2023					// secret was generated via EMS and
2024					// thus it's safe to use tls-unique.
2025					test.flags = []string{expectEMSFlag}
2026				case "NoToYes-Server":
2027					// If an original connection did not
2028					// contain EMS, but a resumption
2029					// handshake does, then a server should
2030					// not resume the session.
2031					test.expectResumeRejected = true
2032				case "YesToNo-Server":
2033					// Resuming an EMS session without the
2034					// EMS extension should cause the
2035					// server to abort the connection.
2036					test.shouldFail = true
2037					test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:"
2038				case "NoToYes-Client":
2039					// A client should abort a connection
2040					// where the server resumed a non-EMS
2041					// session but echoed the EMS
2042					// extension.
2043					test.shouldFail = true
2044					test.expectedError = ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:"
2045				case "YesToNo-Client":
2046					// A client should abort a connection
2047					// where the server didn't echo EMS
2048					// when the session used it.
2049					test.shouldFail = true
2050					test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:"
2051				}
2052
2053				testCases = append(testCases, test)
2054			}
2055		}
2056	}
2057}
2058
2059// Adds tests that try to cover the range of the handshake state machine, under
2060// various conditions. Some of these are redundant with other tests, but they
2061// only cover the synchronous case.
2062func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
2063	var tests []testCase
2064
2065	// Basic handshake, with resumption. Client and server,
2066	// session ID and session ticket.
2067	tests = append(tests, testCase{
2068		name:          "Basic-Client",
2069		resumeSession: true,
2070	})
2071	tests = append(tests, testCase{
2072		name: "Basic-Client-RenewTicket",
2073		config: Config{
2074			Bugs: ProtocolBugs{
2075				RenewTicketOnResume: true,
2076			},
2077		},
2078		resumeSession: true,
2079	})
2080	tests = append(tests, testCase{
2081		name: "Basic-Client-NoTicket",
2082		config: Config{
2083			SessionTicketsDisabled: true,
2084		},
2085		resumeSession: true,
2086	})
2087	tests = append(tests, testCase{
2088		name:          "Basic-Client-Implicit",
2089		flags:         []string{"-implicit-handshake"},
2090		resumeSession: true,
2091	})
2092	tests = append(tests, testCase{
2093		testType:      serverTest,
2094		name:          "Basic-Server",
2095		resumeSession: true,
2096	})
2097	tests = append(tests, testCase{
2098		testType: serverTest,
2099		name:     "Basic-Server-NoTickets",
2100		config: Config{
2101			SessionTicketsDisabled: true,
2102		},
2103		resumeSession: true,
2104	})
2105	tests = append(tests, testCase{
2106		testType:      serverTest,
2107		name:          "Basic-Server-Implicit",
2108		flags:         []string{"-implicit-handshake"},
2109		resumeSession: true,
2110	})
2111	tests = append(tests, testCase{
2112		testType:      serverTest,
2113		name:          "Basic-Server-EarlyCallback",
2114		flags:         []string{"-use-early-callback"},
2115		resumeSession: true,
2116	})
2117
2118	// TLS client auth.
2119	tests = append(tests, testCase{
2120		testType: clientTest,
2121		name:     "ClientAuth-Client",
2122		config: Config{
2123			ClientAuth: RequireAnyClientCert,
2124		},
2125		flags: []string{
2126			"-cert-file", rsaCertificateFile,
2127			"-key-file", rsaKeyFile,
2128		},
2129	})
2130	tests = append(tests, testCase{
2131		testType: serverTest,
2132		name:     "ClientAuth-Server",
2133		config: Config{
2134			Certificates: []Certificate{rsaCertificate},
2135		},
2136		flags: []string{"-require-any-client-certificate"},
2137	})
2138
2139	// No session ticket support; server doesn't send NewSessionTicket.
2140	tests = append(tests, testCase{
2141		name: "SessionTicketsDisabled-Client",
2142		config: Config{
2143			SessionTicketsDisabled: true,
2144		},
2145	})
2146	tests = append(tests, testCase{
2147		testType: serverTest,
2148		name:     "SessionTicketsDisabled-Server",
2149		config: Config{
2150			SessionTicketsDisabled: true,
2151		},
2152	})
2153
2154	// Skip ServerKeyExchange in PSK key exchange if there's no
2155	// identity hint.
2156	tests = append(tests, testCase{
2157		name: "EmptyPSKHint-Client",
2158		config: Config{
2159			CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
2160			PreSharedKey: []byte("secret"),
2161		},
2162		flags: []string{"-psk", "secret"},
2163	})
2164	tests = append(tests, testCase{
2165		testType: serverTest,
2166		name:     "EmptyPSKHint-Server",
2167		config: Config{
2168			CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
2169			PreSharedKey: []byte("secret"),
2170		},
2171		flags: []string{"-psk", "secret"},
2172	})
2173
2174	if protocol == tls {
2175		tests = append(tests, testCase{
2176			name:        "Renegotiate-Client",
2177			renegotiate: true,
2178		})
2179		// NPN on client and server; results in post-handshake message.
2180		tests = append(tests, testCase{
2181			name: "NPN-Client",
2182			config: Config{
2183				NextProtos: []string{"foo"},
2184			},
2185			flags:                 []string{"-select-next-proto", "foo"},
2186			expectedNextProto:     "foo",
2187			expectedNextProtoType: npn,
2188		})
2189		tests = append(tests, testCase{
2190			testType: serverTest,
2191			name:     "NPN-Server",
2192			config: Config{
2193				NextProtos: []string{"bar"},
2194			},
2195			flags: []string{
2196				"-advertise-npn", "\x03foo\x03bar\x03baz",
2197				"-expect-next-proto", "bar",
2198			},
2199			expectedNextProto:     "bar",
2200			expectedNextProtoType: npn,
2201		})
2202
2203		// TODO(davidben): Add tests for when False Start doesn't trigger.
2204
2205		// Client does False Start and negotiates NPN.
2206		tests = append(tests, testCase{
2207			name: "FalseStart",
2208			config: Config{
2209				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2210				NextProtos:   []string{"foo"},
2211				Bugs: ProtocolBugs{
2212					ExpectFalseStart: true,
2213				},
2214			},
2215			flags: []string{
2216				"-false-start",
2217				"-select-next-proto", "foo",
2218			},
2219			shimWritesFirst: true,
2220			resumeSession:   true,
2221		})
2222
2223		// Client does False Start and negotiates ALPN.
2224		tests = append(tests, testCase{
2225			name: "FalseStart-ALPN",
2226			config: Config{
2227				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2228				NextProtos:   []string{"foo"},
2229				Bugs: ProtocolBugs{
2230					ExpectFalseStart: true,
2231				},
2232			},
2233			flags: []string{
2234				"-false-start",
2235				"-advertise-alpn", "\x03foo",
2236			},
2237			shimWritesFirst: true,
2238			resumeSession:   true,
2239		})
2240
2241		// Client does False Start but doesn't explicitly call
2242		// SSL_connect.
2243		tests = append(tests, testCase{
2244			name: "FalseStart-Implicit",
2245			config: Config{
2246				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2247				NextProtos:   []string{"foo"},
2248			},
2249			flags: []string{
2250				"-implicit-handshake",
2251				"-false-start",
2252				"-advertise-alpn", "\x03foo",
2253			},
2254		})
2255
2256		// False Start without session tickets.
2257		tests = append(tests, testCase{
2258			name: "FalseStart-SessionTicketsDisabled",
2259			config: Config{
2260				CipherSuites:           []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
2261				NextProtos:             []string{"foo"},
2262				SessionTicketsDisabled: true,
2263				Bugs: ProtocolBugs{
2264					ExpectFalseStart: true,
2265				},
2266			},
2267			flags: []string{
2268				"-false-start",
2269				"-select-next-proto", "foo",
2270			},
2271			shimWritesFirst: true,
2272		})
2273
2274		// Server parses a V2ClientHello.
2275		tests = append(tests, testCase{
2276			testType: serverTest,
2277			name:     "SendV2ClientHello",
2278			config: Config{
2279				// Choose a cipher suite that does not involve
2280				// elliptic curves, so no extensions are
2281				// involved.
2282				CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
2283				Bugs: ProtocolBugs{
2284					SendV2ClientHello: true,
2285				},
2286			},
2287		})
2288
2289		// Client sends a Channel ID.
2290		tests = append(tests, testCase{
2291			name: "ChannelID-Client",
2292			config: Config{
2293				RequestChannelID: true,
2294			},
2295			flags:           []string{"-send-channel-id", channelIDKeyFile},
2296			resumeSession:   true,
2297			expectChannelID: true,
2298		})
2299
2300		// Server accepts a Channel ID.
2301		tests = append(tests, testCase{
2302			testType: serverTest,
2303			name:     "ChannelID-Server",
2304			config: Config{
2305				ChannelID: channelIDKey,
2306			},
2307			flags: []string{
2308				"-expect-channel-id",
2309				base64.StdEncoding.EncodeToString(channelIDBytes),
2310			},
2311			resumeSession:   true,
2312			expectChannelID: true,
2313		})
2314	} else {
2315		tests = append(tests, testCase{
2316			name: "SkipHelloVerifyRequest",
2317			config: Config{
2318				Bugs: ProtocolBugs{
2319					SkipHelloVerifyRequest: true,
2320				},
2321			},
2322		})
2323	}
2324
2325	var suffix string
2326	var flags []string
2327	var maxHandshakeRecordLength int
2328	if protocol == dtls {
2329		suffix = "-DTLS"
2330	}
2331	if async {
2332		suffix += "-Async"
2333		flags = append(flags, "-async")
2334	} else {
2335		suffix += "-Sync"
2336	}
2337	if splitHandshake {
2338		suffix += "-SplitHandshakeRecords"
2339		maxHandshakeRecordLength = 1
2340	}
2341	for _, test := range tests {
2342		test.protocol = protocol
2343		test.name += suffix
2344		test.config.Bugs.MaxHandshakeRecordLength = maxHandshakeRecordLength
2345		test.flags = append(test.flags, flags...)
2346		testCases = append(testCases, test)
2347	}
2348}
2349
2350func addDDoSCallbackTests() {
2351	// DDoS callback.
2352
2353	for _, resume := range []bool{false, true} {
2354		suffix := "Resume"
2355		if resume {
2356			suffix = "No" + suffix
2357		}
2358
2359		testCases = append(testCases, testCase{
2360			testType:      serverTest,
2361			name:          "Server-DDoS-OK-" + suffix,
2362			flags:         []string{"-install-ddos-callback"},
2363			resumeSession: resume,
2364		})
2365
2366		failFlag := "-fail-ddos-callback"
2367		if resume {
2368			failFlag = "-fail-second-ddos-callback"
2369		}
2370		testCases = append(testCases, testCase{
2371			testType:      serverTest,
2372			name:          "Server-DDoS-Reject-" + suffix,
2373			flags:         []string{"-install-ddos-callback", failFlag},
2374			resumeSession: resume,
2375			shouldFail:    true,
2376			expectedError: ":CONNECTION_REJECTED:",
2377		})
2378	}
2379}
2380
2381func addVersionNegotiationTests() {
2382	for i, shimVers := range tlsVersions {
2383		// Assemble flags to disable all newer versions on the shim.
2384		var flags []string
2385		for _, vers := range tlsVersions[i+1:] {
2386			flags = append(flags, vers.flag)
2387		}
2388
2389		for _, runnerVers := range tlsVersions {
2390			protocols := []protocol{tls}
2391			if runnerVers.hasDTLS && shimVers.hasDTLS {
2392				protocols = append(protocols, dtls)
2393			}
2394			for _, protocol := range protocols {
2395				expectedVersion := shimVers.version
2396				if runnerVers.version < shimVers.version {
2397					expectedVersion = runnerVers.version
2398				}
2399
2400				suffix := shimVers.name + "-" + runnerVers.name
2401				if protocol == dtls {
2402					suffix += "-DTLS"
2403				}
2404
2405				shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls)))
2406
2407				clientVers := shimVers.version
2408				if clientVers > VersionTLS10 {
2409					clientVers = VersionTLS10
2410				}
2411				testCases = append(testCases, testCase{
2412					protocol: protocol,
2413					testType: clientTest,
2414					name:     "VersionNegotiation-Client-" + suffix,
2415					config: Config{
2416						MaxVersion: runnerVers.version,
2417						Bugs: ProtocolBugs{
2418							ExpectInitialRecordVersion: clientVers,
2419						},
2420					},
2421					flags:           flags,
2422					expectedVersion: expectedVersion,
2423				})
2424				testCases = append(testCases, testCase{
2425					protocol: protocol,
2426					testType: clientTest,
2427					name:     "VersionNegotiation-Client2-" + suffix,
2428					config: Config{
2429						MaxVersion: runnerVers.version,
2430						Bugs: ProtocolBugs{
2431							ExpectInitialRecordVersion: clientVers,
2432						},
2433					},
2434					flags:           []string{"-max-version", shimVersFlag},
2435					expectedVersion: expectedVersion,
2436				})
2437
2438				testCases = append(testCases, testCase{
2439					protocol: protocol,
2440					testType: serverTest,
2441					name:     "VersionNegotiation-Server-" + suffix,
2442					config: Config{
2443						MaxVersion: runnerVers.version,
2444						Bugs: ProtocolBugs{
2445							ExpectInitialRecordVersion: expectedVersion,
2446						},
2447					},
2448					flags:           flags,
2449					expectedVersion: expectedVersion,
2450				})
2451				testCases = append(testCases, testCase{
2452					protocol: protocol,
2453					testType: serverTest,
2454					name:     "VersionNegotiation-Server2-" + suffix,
2455					config: Config{
2456						MaxVersion: runnerVers.version,
2457						Bugs: ProtocolBugs{
2458							ExpectInitialRecordVersion: expectedVersion,
2459						},
2460					},
2461					flags:           []string{"-max-version", shimVersFlag},
2462					expectedVersion: expectedVersion,
2463				})
2464			}
2465		}
2466	}
2467}
2468
2469func addMinimumVersionTests() {
2470	for i, shimVers := range tlsVersions {
2471		// Assemble flags to disable all older versions on the shim.
2472		var flags []string
2473		for _, vers := range tlsVersions[:i] {
2474			flags = append(flags, vers.flag)
2475		}
2476
2477		for _, runnerVers := range tlsVersions {
2478			protocols := []protocol{tls}
2479			if runnerVers.hasDTLS && shimVers.hasDTLS {
2480				protocols = append(protocols, dtls)
2481			}
2482			for _, protocol := range protocols {
2483				suffix := shimVers.name + "-" + runnerVers.name
2484				if protocol == dtls {
2485					suffix += "-DTLS"
2486				}
2487				shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls)))
2488
2489				var expectedVersion uint16
2490				var shouldFail bool
2491				var expectedError string
2492				var expectedLocalError string
2493				if runnerVers.version >= shimVers.version {
2494					expectedVersion = runnerVers.version
2495				} else {
2496					shouldFail = true
2497					expectedError = ":UNSUPPORTED_PROTOCOL:"
2498					if runnerVers.version > VersionSSL30 {
2499						expectedLocalError = "remote error: protocol version not supported"
2500					} else {
2501						expectedLocalError = "remote error: handshake failure"
2502					}
2503				}
2504
2505				testCases = append(testCases, testCase{
2506					protocol: protocol,
2507					testType: clientTest,
2508					name:     "MinimumVersion-Client-" + suffix,
2509					config: Config{
2510						MaxVersion: runnerVers.version,
2511					},
2512					flags:              flags,
2513					expectedVersion:    expectedVersion,
2514					shouldFail:         shouldFail,
2515					expectedError:      expectedError,
2516					expectedLocalError: expectedLocalError,
2517				})
2518				testCases = append(testCases, testCase{
2519					protocol: protocol,
2520					testType: clientTest,
2521					name:     "MinimumVersion-Client2-" + suffix,
2522					config: Config{
2523						MaxVersion: runnerVers.version,
2524					},
2525					flags:              []string{"-min-version", shimVersFlag},
2526					expectedVersion:    expectedVersion,
2527					shouldFail:         shouldFail,
2528					expectedError:      expectedError,
2529					expectedLocalError: expectedLocalError,
2530				})
2531
2532				testCases = append(testCases, testCase{
2533					protocol: protocol,
2534					testType: serverTest,
2535					name:     "MinimumVersion-Server-" + suffix,
2536					config: Config{
2537						MaxVersion: runnerVers.version,
2538					},
2539					flags:              flags,
2540					expectedVersion:    expectedVersion,
2541					shouldFail:         shouldFail,
2542					expectedError:      expectedError,
2543					expectedLocalError: expectedLocalError,
2544				})
2545				testCases = append(testCases, testCase{
2546					protocol: protocol,
2547					testType: serverTest,
2548					name:     "MinimumVersion-Server2-" + suffix,
2549					config: Config{
2550						MaxVersion: runnerVers.version,
2551					},
2552					flags:              []string{"-min-version", shimVersFlag},
2553					expectedVersion:    expectedVersion,
2554					shouldFail:         shouldFail,
2555					expectedError:      expectedError,
2556					expectedLocalError: expectedLocalError,
2557				})
2558			}
2559		}
2560	}
2561}
2562
2563func addD5BugTests() {
2564	testCases = append(testCases, testCase{
2565		testType: serverTest,
2566		name:     "D5Bug-NoQuirk-Reject",
2567		config: Config{
2568			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
2569			Bugs: ProtocolBugs{
2570				SSL3RSAKeyExchange: true,
2571			},
2572		},
2573		shouldFail:    true,
2574		expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
2575	})
2576	testCases = append(testCases, testCase{
2577		testType: serverTest,
2578		name:     "D5Bug-Quirk-Normal",
2579		config: Config{
2580			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
2581		},
2582		flags: []string{"-tls-d5-bug"},
2583	})
2584	testCases = append(testCases, testCase{
2585		testType: serverTest,
2586		name:     "D5Bug-Quirk-Bug",
2587		config: Config{
2588			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
2589			Bugs: ProtocolBugs{
2590				SSL3RSAKeyExchange: true,
2591			},
2592		},
2593		flags: []string{"-tls-d5-bug"},
2594	})
2595}
2596
2597func addExtensionTests() {
2598	testCases = append(testCases, testCase{
2599		testType: clientTest,
2600		name:     "DuplicateExtensionClient",
2601		config: Config{
2602			Bugs: ProtocolBugs{
2603				DuplicateExtension: true,
2604			},
2605		},
2606		shouldFail:         true,
2607		expectedLocalError: "remote error: error decoding message",
2608	})
2609	testCases = append(testCases, testCase{
2610		testType: serverTest,
2611		name:     "DuplicateExtensionServer",
2612		config: Config{
2613			Bugs: ProtocolBugs{
2614				DuplicateExtension: true,
2615			},
2616		},
2617		shouldFail:         true,
2618		expectedLocalError: "remote error: error decoding message",
2619	})
2620	testCases = append(testCases, testCase{
2621		testType: clientTest,
2622		name:     "ServerNameExtensionClient",
2623		config: Config{
2624			Bugs: ProtocolBugs{
2625				ExpectServerName: "example.com",
2626			},
2627		},
2628		flags: []string{"-host-name", "example.com"},
2629	})
2630	testCases = append(testCases, testCase{
2631		testType: clientTest,
2632		name:     "ServerNameExtensionClientMismatch",
2633		config: Config{
2634			Bugs: ProtocolBugs{
2635				ExpectServerName: "mismatch.com",
2636			},
2637		},
2638		flags:              []string{"-host-name", "example.com"},
2639		shouldFail:         true,
2640		expectedLocalError: "tls: unexpected server name",
2641	})
2642	testCases = append(testCases, testCase{
2643		testType: clientTest,
2644		name:     "ServerNameExtensionClientMissing",
2645		config: Config{
2646			Bugs: ProtocolBugs{
2647				ExpectServerName: "missing.com",
2648			},
2649		},
2650		shouldFail:         true,
2651		expectedLocalError: "tls: unexpected server name",
2652	})
2653	testCases = append(testCases, testCase{
2654		testType: serverTest,
2655		name:     "ServerNameExtensionServer",
2656		config: Config{
2657			ServerName: "example.com",
2658		},
2659		flags:         []string{"-expect-server-name", "example.com"},
2660		resumeSession: true,
2661	})
2662	testCases = append(testCases, testCase{
2663		testType: clientTest,
2664		name:     "ALPNClient",
2665		config: Config{
2666			NextProtos: []string{"foo"},
2667		},
2668		flags: []string{
2669			"-advertise-alpn", "\x03foo\x03bar\x03baz",
2670			"-expect-alpn", "foo",
2671		},
2672		expectedNextProto:     "foo",
2673		expectedNextProtoType: alpn,
2674		resumeSession:         true,
2675	})
2676	testCases = append(testCases, testCase{
2677		testType: serverTest,
2678		name:     "ALPNServer",
2679		config: Config{
2680			NextProtos: []string{"foo", "bar", "baz"},
2681		},
2682		flags: []string{
2683			"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
2684			"-select-alpn", "foo",
2685		},
2686		expectedNextProto:     "foo",
2687		expectedNextProtoType: alpn,
2688		resumeSession:         true,
2689	})
2690	// Test that the server prefers ALPN over NPN.
2691	testCases = append(testCases, testCase{
2692		testType: serverTest,
2693		name:     "ALPNServer-Preferred",
2694		config: Config{
2695			NextProtos: []string{"foo", "bar", "baz"},
2696		},
2697		flags: []string{
2698			"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
2699			"-select-alpn", "foo",
2700			"-advertise-npn", "\x03foo\x03bar\x03baz",
2701		},
2702		expectedNextProto:     "foo",
2703		expectedNextProtoType: alpn,
2704		resumeSession:         true,
2705	})
2706	testCases = append(testCases, testCase{
2707		testType: serverTest,
2708		name:     "ALPNServer-Preferred-Swapped",
2709		config: Config{
2710			NextProtos: []string{"foo", "bar", "baz"},
2711			Bugs: ProtocolBugs{
2712				SwapNPNAndALPN: true,
2713			},
2714		},
2715		flags: []string{
2716			"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
2717			"-select-alpn", "foo",
2718			"-advertise-npn", "\x03foo\x03bar\x03baz",
2719		},
2720		expectedNextProto:     "foo",
2721		expectedNextProtoType: alpn,
2722		resumeSession:         true,
2723	})
2724	// Resume with a corrupt ticket.
2725	testCases = append(testCases, testCase{
2726		testType: serverTest,
2727		name:     "CorruptTicket",
2728		config: Config{
2729			Bugs: ProtocolBugs{
2730				CorruptTicket: true,
2731			},
2732		},
2733		resumeSession:        true,
2734		expectResumeRejected: true,
2735	})
2736	// Resume with an oversized session id.
2737	testCases = append(testCases, testCase{
2738		testType: serverTest,
2739		name:     "OversizedSessionId",
2740		config: Config{
2741			Bugs: ProtocolBugs{
2742				OversizedSessionId: true,
2743			},
2744		},
2745		resumeSession: true,
2746		shouldFail:    true,
2747		expectedError: ":DECODE_ERROR:",
2748	})
2749	// Basic DTLS-SRTP tests. Include fake profiles to ensure they
2750	// are ignored.
2751	testCases = append(testCases, testCase{
2752		protocol: dtls,
2753		name:     "SRTP-Client",
2754		config: Config{
2755			SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
2756		},
2757		flags: []string{
2758			"-srtp-profiles",
2759			"SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
2760		},
2761		expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
2762	})
2763	testCases = append(testCases, testCase{
2764		protocol: dtls,
2765		testType: serverTest,
2766		name:     "SRTP-Server",
2767		config: Config{
2768			SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
2769		},
2770		flags: []string{
2771			"-srtp-profiles",
2772			"SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
2773		},
2774		expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
2775	})
2776	// Test that the MKI is ignored.
2777	testCases = append(testCases, testCase{
2778		protocol: dtls,
2779		testType: serverTest,
2780		name:     "SRTP-Server-IgnoreMKI",
2781		config: Config{
2782			SRTPProtectionProfiles: []uint16{SRTP_AES128_CM_HMAC_SHA1_80},
2783			Bugs: ProtocolBugs{
2784				SRTPMasterKeyIdentifer: "bogus",
2785			},
2786		},
2787		flags: []string{
2788			"-srtp-profiles",
2789			"SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
2790		},
2791		expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
2792	})
2793	// Test that SRTP isn't negotiated on the server if there were
2794	// no matching profiles.
2795	testCases = append(testCases, testCase{
2796		protocol: dtls,
2797		testType: serverTest,
2798		name:     "SRTP-Server-NoMatch",
2799		config: Config{
2800			SRTPProtectionProfiles: []uint16{100, 101, 102},
2801		},
2802		flags: []string{
2803			"-srtp-profiles",
2804			"SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
2805		},
2806		expectedSRTPProtectionProfile: 0,
2807	})
2808	// Test that the server returning an invalid SRTP profile is
2809	// flagged as an error by the client.
2810	testCases = append(testCases, testCase{
2811		protocol: dtls,
2812		name:     "SRTP-Client-NoMatch",
2813		config: Config{
2814			Bugs: ProtocolBugs{
2815				SendSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_32,
2816			},
2817		},
2818		flags: []string{
2819			"-srtp-profiles",
2820			"SRTP_AES128_CM_SHA1_80",
2821		},
2822		shouldFail:    true,
2823		expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:",
2824	})
2825	// Test OCSP stapling and SCT list.
2826	testCases = append(testCases, testCase{
2827		name: "OCSPStapling",
2828		flags: []string{
2829			"-enable-ocsp-stapling",
2830			"-expect-ocsp-response",
2831			base64.StdEncoding.EncodeToString(testOCSPResponse),
2832		},
2833	})
2834	testCases = append(testCases, testCase{
2835		name: "SignedCertificateTimestampList",
2836		flags: []string{
2837			"-enable-signed-cert-timestamps",
2838			"-expect-signed-cert-timestamps",
2839			base64.StdEncoding.EncodeToString(testSCTList),
2840		},
2841	})
2842}
2843
2844func addResumptionVersionTests() {
2845	for _, sessionVers := range tlsVersions {
2846		for _, resumeVers := range tlsVersions {
2847			protocols := []protocol{tls}
2848			if sessionVers.hasDTLS && resumeVers.hasDTLS {
2849				protocols = append(protocols, dtls)
2850			}
2851			for _, protocol := range protocols {
2852				suffix := "-" + sessionVers.name + "-" + resumeVers.name
2853				if protocol == dtls {
2854					suffix += "-DTLS"
2855				}
2856
2857				if sessionVers.version == resumeVers.version {
2858					testCases = append(testCases, testCase{
2859						protocol:      protocol,
2860						name:          "Resume-Client" + suffix,
2861						resumeSession: true,
2862						config: Config{
2863							MaxVersion:   sessionVers.version,
2864							CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
2865						},
2866						expectedVersion:       sessionVers.version,
2867						expectedResumeVersion: resumeVers.version,
2868					})
2869				} else {
2870					testCases = append(testCases, testCase{
2871						protocol:      protocol,
2872						name:          "Resume-Client-Mismatch" + suffix,
2873						resumeSession: true,
2874						config: Config{
2875							MaxVersion:   sessionVers.version,
2876							CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
2877						},
2878						expectedVersion: sessionVers.version,
2879						resumeConfig: &Config{
2880							MaxVersion:   resumeVers.version,
2881							CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
2882							Bugs: ProtocolBugs{
2883								AllowSessionVersionMismatch: true,
2884							},
2885						},
2886						expectedResumeVersion: resumeVers.version,
2887						shouldFail:            true,
2888						expectedError:         ":OLD_SESSION_VERSION_NOT_RETURNED:",
2889					})
2890				}
2891
2892				testCases = append(testCases, testCase{
2893					protocol:      protocol,
2894					name:          "Resume-Client-NoResume" + suffix,
2895					resumeSession: true,
2896					config: Config{
2897						MaxVersion:   sessionVers.version,
2898						CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
2899					},
2900					expectedVersion: sessionVers.version,
2901					resumeConfig: &Config{
2902						MaxVersion:   resumeVers.version,
2903						CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
2904					},
2905					newSessionsOnResume:   true,
2906					expectResumeRejected:  true,
2907					expectedResumeVersion: resumeVers.version,
2908				})
2909
2910				testCases = append(testCases, testCase{
2911					protocol:      protocol,
2912					testType:      serverTest,
2913					name:          "Resume-Server" + suffix,
2914					resumeSession: true,
2915					config: Config{
2916						MaxVersion:   sessionVers.version,
2917						CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
2918					},
2919					expectedVersion:      sessionVers.version,
2920					expectResumeRejected: sessionVers.version != resumeVers.version,
2921					resumeConfig: &Config{
2922						MaxVersion:   resumeVers.version,
2923						CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
2924					},
2925					expectedResumeVersion: resumeVers.version,
2926				})
2927			}
2928		}
2929	}
2930
2931	testCases = append(testCases, testCase{
2932		name:          "Resume-Client-CipherMismatch",
2933		resumeSession: true,
2934		config: Config{
2935			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
2936		},
2937		resumeConfig: &Config{
2938			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
2939			Bugs: ProtocolBugs{
2940				SendCipherSuite: TLS_RSA_WITH_AES_128_CBC_SHA,
2941			},
2942		},
2943		shouldFail:    true,
2944		expectedError: ":OLD_SESSION_CIPHER_NOT_RETURNED:",
2945	})
2946}
2947
2948func addRenegotiationTests() {
2949	// Servers cannot renegotiate.
2950	testCases = append(testCases, testCase{
2951		testType:           serverTest,
2952		name:               "Renegotiate-Server-Forbidden",
2953		renegotiate:        true,
2954		flags:              []string{"-reject-peer-renegotiations"},
2955		shouldFail:         true,
2956		expectedError:      ":NO_RENEGOTIATION:",
2957		expectedLocalError: "remote error: no renegotiation",
2958	})
2959	// TODO(agl): test the renegotiation info SCSV.
2960	testCases = append(testCases, testCase{
2961		name: "Renegotiate-Client",
2962		config: Config{
2963			Bugs: ProtocolBugs{
2964				FailIfResumeOnRenego: true,
2965			},
2966		},
2967		renegotiate: true,
2968	})
2969	testCases = append(testCases, testCase{
2970		name:        "Renegotiate-Client-EmptyExt",
2971		renegotiate: true,
2972		config: Config{
2973			Bugs: ProtocolBugs{
2974				EmptyRenegotiationInfo: true,
2975			},
2976		},
2977		shouldFail:    true,
2978		expectedError: ":RENEGOTIATION_MISMATCH:",
2979	})
2980	testCases = append(testCases, testCase{
2981		name:        "Renegotiate-Client-BadExt",
2982		renegotiate: true,
2983		config: Config{
2984			Bugs: ProtocolBugs{
2985				BadRenegotiationInfo: true,
2986			},
2987		},
2988		shouldFail:    true,
2989		expectedError: ":RENEGOTIATION_MISMATCH:",
2990	})
2991	testCases = append(testCases, testCase{
2992		name:        "Renegotiate-Client-NoExt",
2993		renegotiate: true,
2994		config: Config{
2995			Bugs: ProtocolBugs{
2996				NoRenegotiationInfo: true,
2997			},
2998		},
2999		shouldFail:    true,
3000		expectedError: ":UNSAFE_LEGACY_RENEGOTIATION_DISABLED:",
3001		flags:         []string{"-no-legacy-server-connect"},
3002	})
3003	testCases = append(testCases, testCase{
3004		name:        "Renegotiate-Client-NoExt-Allowed",
3005		renegotiate: true,
3006		config: Config{
3007			Bugs: ProtocolBugs{
3008				NoRenegotiationInfo: true,
3009			},
3010		},
3011	})
3012	testCases = append(testCases, testCase{
3013		name:        "Renegotiate-Client-SwitchCiphers",
3014		renegotiate: true,
3015		config: Config{
3016			CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
3017		},
3018		renegotiateCiphers: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
3019	})
3020	testCases = append(testCases, testCase{
3021		name:        "Renegotiate-Client-SwitchCiphers2",
3022		renegotiate: true,
3023		config: Config{
3024			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
3025		},
3026		renegotiateCiphers: []uint16{TLS_RSA_WITH_RC4_128_SHA},
3027	})
3028	testCases = append(testCases, testCase{
3029		name:               "Renegotiate-Client-Forbidden",
3030		renegotiate:        true,
3031		flags:              []string{"-reject-peer-renegotiations"},
3032		shouldFail:         true,
3033		expectedError:      ":NO_RENEGOTIATION:",
3034		expectedLocalError: "remote error: no renegotiation",
3035	})
3036	testCases = append(testCases, testCase{
3037		name:        "Renegotiate-SameClientVersion",
3038		renegotiate: true,
3039		config: Config{
3040			MaxVersion: VersionTLS10,
3041			Bugs: ProtocolBugs{
3042				RequireSameRenegoClientVersion: true,
3043			},
3044		},
3045	})
3046}
3047
3048func addDTLSReplayTests() {
3049	// Test that sequence number replays are detected.
3050	testCases = append(testCases, testCase{
3051		protocol:     dtls,
3052		name:         "DTLS-Replay",
3053		replayWrites: true,
3054	})
3055
3056	// Test the outgoing sequence number skipping by values larger
3057	// than the retransmit window.
3058	testCases = append(testCases, testCase{
3059		protocol: dtls,
3060		name:     "DTLS-Replay-LargeGaps",
3061		config: Config{
3062			Bugs: ProtocolBugs{
3063				SequenceNumberIncrement: 127,
3064			},
3065		},
3066		replayWrites: true,
3067	})
3068}
3069
3070func addFastRadioPaddingTests() {
3071	testCases = append(testCases, testCase{
3072		protocol: tls,
3073		name:     "FastRadio-Padding",
3074		config: Config{
3075			Bugs: ProtocolBugs{
3076				RequireFastradioPadding: true,
3077			},
3078		},
3079		flags: []string{"-fastradio-padding"},
3080	})
3081	testCases = append(testCases, testCase{
3082		protocol: dtls,
3083		name:     "FastRadio-Padding-DTLS",
3084		config: Config{
3085			Bugs: ProtocolBugs{
3086				RequireFastradioPadding: true,
3087			},
3088		},
3089		flags: []string{"-fastradio-padding"},
3090	})
3091}
3092
3093var testHashes = []struct {
3094	name string
3095	id   uint8
3096}{
3097	{"SHA1", hashSHA1},
3098	{"SHA224", hashSHA224},
3099	{"SHA256", hashSHA256},
3100	{"SHA384", hashSHA384},
3101	{"SHA512", hashSHA512},
3102}
3103
3104func addSigningHashTests() {
3105	// Make sure each hash works. Include some fake hashes in the list and
3106	// ensure they're ignored.
3107	for _, hash := range testHashes {
3108		testCases = append(testCases, testCase{
3109			name: "SigningHash-ClientAuth-" + hash.name,
3110			config: Config{
3111				ClientAuth: RequireAnyClientCert,
3112				SignatureAndHashes: []signatureAndHash{
3113					{signatureRSA, 42},
3114					{signatureRSA, hash.id},
3115					{signatureRSA, 255},
3116				},
3117			},
3118			flags: []string{
3119				"-cert-file", rsaCertificateFile,
3120				"-key-file", rsaKeyFile,
3121			},
3122		})
3123
3124		testCases = append(testCases, testCase{
3125			testType: serverTest,
3126			name:     "SigningHash-ServerKeyExchange-Sign-" + hash.name,
3127			config: Config{
3128				CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
3129				SignatureAndHashes: []signatureAndHash{
3130					{signatureRSA, 42},
3131					{signatureRSA, hash.id},
3132					{signatureRSA, 255},
3133				},
3134			},
3135		})
3136	}
3137
3138	// Test that hash resolution takes the signature type into account.
3139	testCases = append(testCases, testCase{
3140		name: "SigningHash-ClientAuth-SignatureType",
3141		config: Config{
3142			ClientAuth: RequireAnyClientCert,
3143			SignatureAndHashes: []signatureAndHash{
3144				{signatureECDSA, hashSHA512},
3145				{signatureRSA, hashSHA384},
3146				{signatureECDSA, hashSHA1},
3147			},
3148		},
3149		flags: []string{
3150			"-cert-file", rsaCertificateFile,
3151			"-key-file", rsaKeyFile,
3152		},
3153	})
3154
3155	testCases = append(testCases, testCase{
3156		testType: serverTest,
3157		name:     "SigningHash-ServerKeyExchange-SignatureType",
3158		config: Config{
3159			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
3160			SignatureAndHashes: []signatureAndHash{
3161				{signatureECDSA, hashSHA512},
3162				{signatureRSA, hashSHA384},
3163				{signatureECDSA, hashSHA1},
3164			},
3165		},
3166	})
3167
3168	// Test that, if the list is missing, the peer falls back to SHA-1.
3169	testCases = append(testCases, testCase{
3170		name: "SigningHash-ClientAuth-Fallback",
3171		config: Config{
3172			ClientAuth: RequireAnyClientCert,
3173			SignatureAndHashes: []signatureAndHash{
3174				{signatureRSA, hashSHA1},
3175			},
3176			Bugs: ProtocolBugs{
3177				NoSignatureAndHashes: true,
3178			},
3179		},
3180		flags: []string{
3181			"-cert-file", rsaCertificateFile,
3182			"-key-file", rsaKeyFile,
3183		},
3184	})
3185
3186	testCases = append(testCases, testCase{
3187		testType: serverTest,
3188		name:     "SigningHash-ServerKeyExchange-Fallback",
3189		config: Config{
3190			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
3191			SignatureAndHashes: []signatureAndHash{
3192				{signatureRSA, hashSHA1},
3193			},
3194			Bugs: ProtocolBugs{
3195				NoSignatureAndHashes: true,
3196			},
3197		},
3198	})
3199
3200	// Test that hash preferences are enforced. BoringSSL defaults to
3201	// rejecting MD5 signatures.
3202	testCases = append(testCases, testCase{
3203		testType: serverTest,
3204		name:     "SigningHash-ClientAuth-Enforced",
3205		config: Config{
3206			Certificates: []Certificate{rsaCertificate},
3207			SignatureAndHashes: []signatureAndHash{
3208				{signatureRSA, hashMD5},
3209				// Advertise SHA-1 so the handshake will
3210				// proceed, but the shim's preferences will be
3211				// ignored in CertificateVerify generation, so
3212				// MD5 will be chosen.
3213				{signatureRSA, hashSHA1},
3214			},
3215			Bugs: ProtocolBugs{
3216				IgnorePeerSignatureAlgorithmPreferences: true,
3217			},
3218		},
3219		flags:         []string{"-require-any-client-certificate"},
3220		shouldFail:    true,
3221		expectedError: ":WRONG_SIGNATURE_TYPE:",
3222	})
3223
3224	testCases = append(testCases, testCase{
3225		name: "SigningHash-ServerKeyExchange-Enforced",
3226		config: Config{
3227			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
3228			SignatureAndHashes: []signatureAndHash{
3229				{signatureRSA, hashMD5},
3230			},
3231			Bugs: ProtocolBugs{
3232				IgnorePeerSignatureAlgorithmPreferences: true,
3233			},
3234		},
3235		shouldFail:    true,
3236		expectedError: ":WRONG_SIGNATURE_TYPE:",
3237	})
3238}
3239
3240// timeouts is the retransmit schedule for BoringSSL. It doubles and
3241// caps at 60 seconds. On the 13th timeout, it gives up.
3242var timeouts = []time.Duration{
3243	1 * time.Second,
3244	2 * time.Second,
3245	4 * time.Second,
3246	8 * time.Second,
3247	16 * time.Second,
3248	32 * time.Second,
3249	60 * time.Second,
3250	60 * time.Second,
3251	60 * time.Second,
3252	60 * time.Second,
3253	60 * time.Second,
3254	60 * time.Second,
3255	60 * time.Second,
3256}
3257
3258func addDTLSRetransmitTests() {
3259	// Test that this is indeed the timeout schedule. Stress all
3260	// four patterns of handshake.
3261	for i := 1; i < len(timeouts); i++ {
3262		number := strconv.Itoa(i)
3263		testCases = append(testCases, testCase{
3264			protocol: dtls,
3265			name:     "DTLS-Retransmit-Client-" + number,
3266			config: Config{
3267				Bugs: ProtocolBugs{
3268					TimeoutSchedule: timeouts[:i],
3269				},
3270			},
3271			resumeSession: true,
3272			flags:         []string{"-async"},
3273		})
3274		testCases = append(testCases, testCase{
3275			protocol: dtls,
3276			testType: serverTest,
3277			name:     "DTLS-Retransmit-Server-" + number,
3278			config: Config{
3279				Bugs: ProtocolBugs{
3280					TimeoutSchedule: timeouts[:i],
3281				},
3282			},
3283			resumeSession: true,
3284			flags:         []string{"-async"},
3285		})
3286	}
3287
3288	// Test that exceeding the timeout schedule hits a read
3289	// timeout.
3290	testCases = append(testCases, testCase{
3291		protocol: dtls,
3292		name:     "DTLS-Retransmit-Timeout",
3293		config: Config{
3294			Bugs: ProtocolBugs{
3295				TimeoutSchedule: timeouts,
3296			},
3297		},
3298		resumeSession: true,
3299		flags:         []string{"-async"},
3300		shouldFail:    true,
3301		expectedError: ":READ_TIMEOUT_EXPIRED:",
3302	})
3303
3304	// Test that timeout handling has a fudge factor, due to API
3305	// problems.
3306	testCases = append(testCases, testCase{
3307		protocol: dtls,
3308		name:     "DTLS-Retransmit-Fudge",
3309		config: Config{
3310			Bugs: ProtocolBugs{
3311				TimeoutSchedule: []time.Duration{
3312					timeouts[0] - 10*time.Millisecond,
3313				},
3314			},
3315		},
3316		resumeSession: true,
3317		flags:         []string{"-async"},
3318	})
3319
3320	// Test that the final Finished retransmitting isn't
3321	// duplicated if the peer badly fragments everything.
3322	testCases = append(testCases, testCase{
3323		testType: serverTest,
3324		protocol: dtls,
3325		name:     "DTLS-Retransmit-Fragmented",
3326		config: Config{
3327			Bugs: ProtocolBugs{
3328				TimeoutSchedule:          []time.Duration{timeouts[0]},
3329				MaxHandshakeRecordLength: 2,
3330			},
3331		},
3332		flags: []string{"-async"},
3333	})
3334}
3335
3336func addExportKeyingMaterialTests() {
3337	for _, vers := range tlsVersions {
3338		if vers.version == VersionSSL30 {
3339			continue
3340		}
3341		testCases = append(testCases, testCase{
3342			name: "ExportKeyingMaterial-" + vers.name,
3343			config: Config{
3344				MaxVersion: vers.version,
3345			},
3346			exportKeyingMaterial: 1024,
3347			exportLabel:          "label",
3348			exportContext:        "context",
3349			useExportContext:     true,
3350		})
3351		testCases = append(testCases, testCase{
3352			name: "ExportKeyingMaterial-NoContext-" + vers.name,
3353			config: Config{
3354				MaxVersion: vers.version,
3355			},
3356			exportKeyingMaterial: 1024,
3357		})
3358		testCases = append(testCases, testCase{
3359			name: "ExportKeyingMaterial-EmptyContext-" + vers.name,
3360			config: Config{
3361				MaxVersion: vers.version,
3362			},
3363			exportKeyingMaterial: 1024,
3364			useExportContext:     true,
3365		})
3366		testCases = append(testCases, testCase{
3367			name: "ExportKeyingMaterial-Small-" + vers.name,
3368			config: Config{
3369				MaxVersion: vers.version,
3370			},
3371			exportKeyingMaterial: 1,
3372			exportLabel:          "label",
3373			exportContext:        "context",
3374			useExportContext:     true,
3375		})
3376	}
3377	testCases = append(testCases, testCase{
3378		name: "ExportKeyingMaterial-SSL3",
3379		config: Config{
3380			MaxVersion: VersionSSL30,
3381		},
3382		exportKeyingMaterial: 1024,
3383		exportLabel:          "label",
3384		exportContext:        "context",
3385		useExportContext:     true,
3386		shouldFail:           true,
3387		expectedError:        "failed to export keying material",
3388	})
3389}
3390
3391func addTLSUniqueTests() {
3392	for _, isClient := range []bool{false, true} {
3393		for _, isResumption := range []bool{false, true} {
3394			for _, hasEMS := range []bool{false, true} {
3395				var suffix string
3396				if isResumption {
3397					suffix = "Resume-"
3398				} else {
3399					suffix = "Full-"
3400				}
3401
3402				if hasEMS {
3403					suffix += "EMS-"
3404				} else {
3405					suffix += "NoEMS-"
3406				}
3407
3408				if isClient {
3409					suffix += "Client"
3410				} else {
3411					suffix += "Server"
3412				}
3413
3414				test := testCase{
3415					name:          "TLSUnique-" + suffix,
3416					testTLSUnique: true,
3417					config: Config{
3418						Bugs: ProtocolBugs{
3419							NoExtendedMasterSecret: !hasEMS,
3420						},
3421					},
3422				}
3423
3424				if isResumption {
3425					test.resumeSession = true
3426					test.resumeConfig = &Config{
3427						Bugs: ProtocolBugs{
3428							NoExtendedMasterSecret: !hasEMS,
3429						},
3430					}
3431				}
3432
3433				if isResumption && !hasEMS {
3434					test.shouldFail = true
3435					test.expectedError = "failed to get tls-unique"
3436				}
3437
3438				testCases = append(testCases, test)
3439			}
3440		}
3441	}
3442}
3443
3444func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
3445	defer wg.Done()
3446
3447	for test := range c {
3448		var err error
3449
3450		if *mallocTest < 0 {
3451			statusChan <- statusMsg{test: test, started: true}
3452			err = runTest(test, buildDir, -1)
3453		} else {
3454			for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ {
3455				statusChan <- statusMsg{test: test, started: true}
3456				if err = runTest(test, buildDir, mallocNumToFail); err != errMoreMallocs {
3457					if err != nil {
3458						fmt.Printf("\n\nmalloc test failed at %d: %s\n", mallocNumToFail, err)
3459					}
3460					break
3461				}
3462			}
3463		}
3464		statusChan <- statusMsg{test: test, err: err}
3465	}
3466}
3467
3468type statusMsg struct {
3469	test    *testCase
3470	started bool
3471	err     error
3472}
3473
3474func statusPrinter(doneChan chan *testOutput, statusChan chan statusMsg, total int) {
3475	var started, done, failed, lineLen int
3476
3477	testOutput := newTestOutput()
3478	for msg := range statusChan {
3479		if !*pipe {
3480			// Erase the previous status line.
3481			var erase string
3482			for i := 0; i < lineLen; i++ {
3483				erase += "\b \b"
3484			}
3485			fmt.Print(erase)
3486		}
3487
3488		if msg.started {
3489			started++
3490		} else {
3491			done++
3492
3493			if msg.err != nil {
3494				fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
3495				failed++
3496				testOutput.addResult(msg.test.name, "FAIL")
3497			} else {
3498				if *pipe {
3499					// Print each test instead of a status line.
3500					fmt.Printf("PASSED (%s)\n", msg.test.name)
3501				}
3502				testOutput.addResult(msg.test.name, "PASS")
3503			}
3504		}
3505
3506		if !*pipe {
3507			// Print a new status line.
3508			line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
3509			lineLen = len(line)
3510			os.Stdout.WriteString(line)
3511		}
3512	}
3513
3514	doneChan <- testOutput
3515}
3516
3517func main() {
3518	var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
3519	var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
3520	var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
3521
3522	flag.Parse()
3523
3524	addCipherSuiteTests()
3525	addBadECDSASignatureTests()
3526	addCBCPaddingTests()
3527	addCBCSplittingTests()
3528	addClientAuthTests()
3529	addDDoSCallbackTests()
3530	addVersionNegotiationTests()
3531	addMinimumVersionTests()
3532	addD5BugTests()
3533	addExtensionTests()
3534	addResumptionVersionTests()
3535	addExtendedMasterSecretTests()
3536	addRenegotiationTests()
3537	addDTLSReplayTests()
3538	addSigningHashTests()
3539	addFastRadioPaddingTests()
3540	addDTLSRetransmitTests()
3541	addExportKeyingMaterialTests()
3542	addTLSUniqueTests()
3543	for _, async := range []bool{false, true} {
3544		for _, splitHandshake := range []bool{false, true} {
3545			for _, protocol := range []protocol{tls, dtls} {
3546				addStateMachineCoverageTests(async, splitHandshake, protocol)
3547			}
3548		}
3549	}
3550
3551	var wg sync.WaitGroup
3552
3553	numWorkers := *flagNumWorkers
3554
3555	statusChan := make(chan statusMsg, numWorkers)
3556	testChan := make(chan *testCase, numWorkers)
3557	doneChan := make(chan *testOutput)
3558
3559	go statusPrinter(doneChan, statusChan, len(testCases))
3560
3561	for i := 0; i < numWorkers; i++ {
3562		wg.Add(1)
3563		go worker(statusChan, testChan, *flagBuildDir, &wg)
3564	}
3565
3566	for i := range testCases {
3567		if len(*flagTest) == 0 || *flagTest == testCases[i].name {
3568			testChan <- &testCases[i]
3569		}
3570	}
3571
3572	close(testChan)
3573	wg.Wait()
3574	close(statusChan)
3575	testOutput := <-doneChan
3576
3577	fmt.Printf("\n")
3578
3579	if *jsonOutput != "" {
3580		if err := testOutput.writeTo(*jsonOutput); err != nil {
3581			fmt.Fprintf(os.Stderr, "Error: %s\n", err)
3582		}
3583	}
3584
3585	if !testOutput.allPassed {
3586		os.Exit(1)
3587	}
3588}
3589