Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / ssl / test / runner / runner.go
1 package main
2
3 import (
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         "net"
15         "os"
16         "os/exec"
17         "path"
18         "runtime"
19         "strings"
20         "sync"
21         "syscall"
22 )
23
24 var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
25 var useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
26 var flagDebug *bool = flag.Bool("debug", false, "Hexdump the contents of the connection")
27
28 const (
29         rsaCertificateFile   = "cert.pem"
30         ecdsaCertificateFile = "ecdsa_cert.pem"
31 )
32
33 const (
34         rsaKeyFile       = "key.pem"
35         ecdsaKeyFile     = "ecdsa_key.pem"
36         channelIDKeyFile = "channel_id_key.pem"
37 )
38
39 var rsaCertificate, ecdsaCertificate Certificate
40 var channelIDKey *ecdsa.PrivateKey
41 var channelIDBytes []byte
42
43 func initCertificates() {
44         var err error
45         rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
46         if err != nil {
47                 panic(err)
48         }
49
50         ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
51         if err != nil {
52                 panic(err)
53         }
54
55         channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile)
56         if err != nil {
57                 panic(err)
58         }
59         channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock)
60         if channelIDDERBlock.Type != "EC PRIVATE KEY" {
61                 panic("bad key type")
62         }
63         channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes)
64         if err != nil {
65                 panic(err)
66         }
67         if channelIDKey.Curve != elliptic.P256() {
68                 panic("bad curve")
69         }
70
71         channelIDBytes = make([]byte, 64)
72         writeIntPadded(channelIDBytes[:32], channelIDKey.X)
73         writeIntPadded(channelIDBytes[32:], channelIDKey.Y)
74 }
75
76 var certificateOnce sync.Once
77
78 func getRSACertificate() Certificate {
79         certificateOnce.Do(initCertificates)
80         return rsaCertificate
81 }
82
83 func getECDSACertificate() Certificate {
84         certificateOnce.Do(initCertificates)
85         return ecdsaCertificate
86 }
87
88 type testType int
89
90 const (
91         clientTest testType = iota
92         serverTest
93 )
94
95 type protocol int
96
97 const (
98         tls protocol = iota
99         dtls
100 )
101
102 const (
103         alpn = 1
104         npn  = 2
105 )
106
107 type testCase struct {
108         testType      testType
109         protocol      protocol
110         name          string
111         config        Config
112         shouldFail    bool
113         expectedError string
114         // expectedLocalError, if not empty, contains a substring that must be
115         // found in the local error.
116         expectedLocalError string
117         // expectedVersion, if non-zero, specifies the TLS version that must be
118         // negotiated.
119         expectedVersion uint16
120         // expectedResumeVersion, if non-zero, specifies the TLS version that
121         // must be negotiated on resumption. If zero, expectedVersion is used.
122         expectedResumeVersion uint16
123         // expectChannelID controls whether the connection should have
124         // negotiated a Channel ID with channelIDKey.
125         expectChannelID bool
126         // expectedNextProto controls whether the connection should
127         // negotiate a next protocol via NPN or ALPN.
128         expectedNextProto string
129         // expectedNextProtoType, if non-zero, is the expected next
130         // protocol negotiation mechanism.
131         expectedNextProtoType int
132         // messageLen is the length, in bytes, of the test message that will be
133         // sent.
134         messageLen int
135         // certFile is the path to the certificate to use for the server.
136         certFile string
137         // keyFile is the path to the private key to use for the server.
138         keyFile string
139         // resumeSession controls whether a second connection should be tested
140         // which attempts to resume the first session.
141         resumeSession bool
142         // resumeConfig, if not nil, points to a Config to be used on
143         // resumption. SessionTicketKey and ClientSessionCache are copied from
144         // the initial connection's config. If nil, the initial connection's
145         // config is used.
146         resumeConfig *Config
147         // sendPrefix sends a prefix on the socket before actually performing a
148         // handshake.
149         sendPrefix string
150         // shimWritesFirst controls whether the shim sends an initial "hello"
151         // message before doing a roundtrip with the runner.
152         shimWritesFirst bool
153         // renegotiate indicates the the connection should be renegotiated
154         // during the exchange.
155         renegotiate bool
156         // renegotiateCiphers is a list of ciphersuite ids that will be
157         // switched in just before renegotiation.
158         renegotiateCiphers []uint16
159         // flags, if not empty, contains a list of command-line flags that will
160         // be passed to the shim program.
161         flags []string
162 }
163
164 var testCases = []testCase{
165         {
166                 name: "BadRSASignature",
167                 config: Config{
168                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
169                         Bugs: ProtocolBugs{
170                                 InvalidSKXSignature: true,
171                         },
172                 },
173                 shouldFail:    true,
174                 expectedError: ":BAD_SIGNATURE:",
175         },
176         {
177                 name: "BadECDSASignature",
178                 config: Config{
179                         CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
180                         Bugs: ProtocolBugs{
181                                 InvalidSKXSignature: true,
182                         },
183                         Certificates: []Certificate{getECDSACertificate()},
184                 },
185                 shouldFail:    true,
186                 expectedError: ":BAD_SIGNATURE:",
187         },
188         {
189                 name: "BadECDSACurve",
190                 config: Config{
191                         CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
192                         Bugs: ProtocolBugs{
193                                 InvalidSKXCurve: true,
194                         },
195                         Certificates: []Certificate{getECDSACertificate()},
196                 },
197                 shouldFail:    true,
198                 expectedError: ":WRONG_CURVE:",
199         },
200         {
201                 testType: serverTest,
202                 name:     "BadRSAVersion",
203                 config: Config{
204                         CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
205                         Bugs: ProtocolBugs{
206                                 RsaClientKeyExchangeVersion: VersionTLS11,
207                         },
208                 },
209                 shouldFail:    true,
210                 expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
211         },
212         {
213                 name: "NoFallbackSCSV",
214                 config: Config{
215                         Bugs: ProtocolBugs{
216                                 FailIfNotFallbackSCSV: true,
217                         },
218                 },
219                 shouldFail:         true,
220                 expectedLocalError: "no fallback SCSV found",
221         },
222         {
223                 name: "SendFallbackSCSV",
224                 config: Config{
225                         Bugs: ProtocolBugs{
226                                 FailIfNotFallbackSCSV: true,
227                         },
228                 },
229                 flags: []string{"-fallback-scsv"},
230         },
231         {
232                 name: "ClientCertificateTypes",
233                 config: Config{
234                         ClientAuth: RequestClientCert,
235                         ClientCertificateTypes: []byte{
236                                 CertTypeDSSSign,
237                                 CertTypeRSASign,
238                                 CertTypeECDSASign,
239                         },
240                 },
241                 flags: []string{
242                         "-expect-certificate-types",
243                         base64.StdEncoding.EncodeToString([]byte{
244                                 CertTypeDSSSign,
245                                 CertTypeRSASign,
246                                 CertTypeECDSASign,
247                         }),
248                 },
249         },
250         {
251                 name: "NoClientCertificate",
252                 config: Config{
253                         ClientAuth: RequireAnyClientCert,
254                 },
255                 shouldFail:         true,
256                 expectedLocalError: "client didn't provide a certificate",
257         },
258         {
259                 name: "UnauthenticatedECDH",
260                 config: Config{
261                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
262                         Bugs: ProtocolBugs{
263                                 UnauthenticatedECDH: true,
264                         },
265                 },
266                 shouldFail:    true,
267                 expectedError: ":UNEXPECTED_MESSAGE:",
268         },
269         {
270                 name: "SkipServerKeyExchange",
271                 config: Config{
272                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
273                         Bugs: ProtocolBugs{
274                                 SkipServerKeyExchange: true,
275                         },
276                 },
277                 shouldFail:    true,
278                 expectedError: ":UNEXPECTED_MESSAGE:",
279         },
280         {
281                 name: "SkipChangeCipherSpec-Client",
282                 config: Config{
283                         Bugs: ProtocolBugs{
284                                 SkipChangeCipherSpec: true,
285                         },
286                 },
287                 shouldFail:    true,
288                 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
289         },
290         {
291                 testType: serverTest,
292                 name:     "SkipChangeCipherSpec-Server",
293                 config: Config{
294                         Bugs: ProtocolBugs{
295                                 SkipChangeCipherSpec: true,
296                         },
297                 },
298                 shouldFail:    true,
299                 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
300         },
301         {
302                 testType: serverTest,
303                 name:     "SkipChangeCipherSpec-Server-NPN",
304                 config: Config{
305                         NextProtos: []string{"bar"},
306                         Bugs: ProtocolBugs{
307                                 SkipChangeCipherSpec: true,
308                         },
309                 },
310                 flags: []string{
311                         "-advertise-npn", "\x03foo\x03bar\x03baz",
312                 },
313                 shouldFail:    true,
314                 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
315         },
316         {
317                 name: "FragmentAcrossChangeCipherSpec-Client",
318                 config: Config{
319                         Bugs: ProtocolBugs{
320                                 FragmentAcrossChangeCipherSpec: true,
321                         },
322                 },
323                 shouldFail:    true,
324                 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
325         },
326         {
327                 testType: serverTest,
328                 name:     "FragmentAcrossChangeCipherSpec-Server",
329                 config: Config{
330                         Bugs: ProtocolBugs{
331                                 FragmentAcrossChangeCipherSpec: true,
332                         },
333                 },
334                 shouldFail:    true,
335                 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
336         },
337         {
338                 testType: serverTest,
339                 name:     "FragmentAcrossChangeCipherSpec-Server-NPN",
340                 config: Config{
341                         NextProtos: []string{"bar"},
342                         Bugs: ProtocolBugs{
343                                 FragmentAcrossChangeCipherSpec: true,
344                         },
345                 },
346                 flags: []string{
347                         "-advertise-npn", "\x03foo\x03bar\x03baz",
348                 },
349                 shouldFail:    true,
350                 expectedError: ":HANDSHAKE_RECORD_BEFORE_CCS:",
351         },
352         {
353                 testType: serverTest,
354                 name:     "EarlyChangeCipherSpec-server-1",
355                 config: Config{
356                         Bugs: ProtocolBugs{
357                                 EarlyChangeCipherSpec: 1,
358                         },
359                 },
360                 shouldFail:    true,
361                 expectedError: ":CCS_RECEIVED_EARLY:",
362         },
363         {
364                 testType: serverTest,
365                 name:     "EarlyChangeCipherSpec-server-2",
366                 config: Config{
367                         Bugs: ProtocolBugs{
368                                 EarlyChangeCipherSpec: 2,
369                         },
370                 },
371                 shouldFail:    true,
372                 expectedError: ":CCS_RECEIVED_EARLY:",
373         },
374         {
375                 name: "SkipNewSessionTicket",
376                 config: Config{
377                         Bugs: ProtocolBugs{
378                                 SkipNewSessionTicket: true,
379                         },
380                 },
381                 shouldFail:    true,
382                 expectedError: ":CCS_RECEIVED_EARLY:",
383         },
384         {
385                 testType: serverTest,
386                 name:     "FallbackSCSV",
387                 config: Config{
388                         MaxVersion: VersionTLS11,
389                         Bugs: ProtocolBugs{
390                                 SendFallbackSCSV: true,
391                         },
392                 },
393                 shouldFail:    true,
394                 expectedError: ":INAPPROPRIATE_FALLBACK:",
395         },
396         {
397                 testType: serverTest,
398                 name:     "FallbackSCSV-VersionMatch",
399                 config: Config{
400                         Bugs: ProtocolBugs{
401                                 SendFallbackSCSV: true,
402                         },
403                 },
404         },
405         {
406                 testType: serverTest,
407                 name:     "FragmentedClientVersion",
408                 config: Config{
409                         Bugs: ProtocolBugs{
410                                 MaxHandshakeRecordLength: 1,
411                                 FragmentClientVersion:    true,
412                         },
413                 },
414                 shouldFail:    true,
415                 expectedError: ":RECORD_TOO_SMALL:",
416         },
417         {
418                 testType: serverTest,
419                 name:     "MinorVersionTolerance",
420                 config: Config{
421                         Bugs: ProtocolBugs{
422                                 SendClientVersion: 0x03ff,
423                         },
424                 },
425                 expectedVersion: VersionTLS12,
426         },
427         {
428                 testType: serverTest,
429                 name:     "MajorVersionTolerance",
430                 config: Config{
431                         Bugs: ProtocolBugs{
432                                 SendClientVersion: 0x0400,
433                         },
434                 },
435                 expectedVersion: VersionTLS12,
436         },
437         {
438                 testType: serverTest,
439                 name:     "VersionTooLow",
440                 config: Config{
441                         Bugs: ProtocolBugs{
442                                 SendClientVersion: 0x0200,
443                         },
444                 },
445                 shouldFail:    true,
446                 expectedError: ":UNSUPPORTED_PROTOCOL:",
447         },
448         {
449                 testType:      serverTest,
450                 name:          "HttpGET",
451                 sendPrefix:    "GET / HTTP/1.0\n",
452                 shouldFail:    true,
453                 expectedError: ":HTTP_REQUEST:",
454         },
455         {
456                 testType:      serverTest,
457                 name:          "HttpPOST",
458                 sendPrefix:    "POST / HTTP/1.0\n",
459                 shouldFail:    true,
460                 expectedError: ":HTTP_REQUEST:",
461         },
462         {
463                 testType:      serverTest,
464                 name:          "HttpHEAD",
465                 sendPrefix:    "HEAD / HTTP/1.0\n",
466                 shouldFail:    true,
467                 expectedError: ":HTTP_REQUEST:",
468         },
469         {
470                 testType:      serverTest,
471                 name:          "HttpPUT",
472                 sendPrefix:    "PUT / HTTP/1.0\n",
473                 shouldFail:    true,
474                 expectedError: ":HTTP_REQUEST:",
475         },
476         {
477                 testType:      serverTest,
478                 name:          "HttpCONNECT",
479                 sendPrefix:    "CONNECT www.google.com:443 HTTP/1.0\n",
480                 shouldFail:    true,
481                 expectedError: ":HTTPS_PROXY_REQUEST:",
482         },
483         {
484                 name: "SkipCipherVersionCheck",
485                 config: Config{
486                         CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
487                         MaxVersion:   VersionTLS11,
488                         Bugs: ProtocolBugs{
489                                 SkipCipherVersionCheck: true,
490                         },
491                 },
492                 shouldFail:    true,
493                 expectedError: ":WRONG_CIPHER_RETURNED:",
494         },
495 }
496
497 func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
498         if test.protocol == dtls {
499                 conn = newPacketAdaptor(conn)
500         }
501
502         if test.sendPrefix != "" {
503                 if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
504                         return err
505                 }
506         }
507
508         var tlsConn *Conn
509         if test.testType == clientTest {
510                 if test.protocol == dtls {
511                         tlsConn = DTLSServer(conn, config)
512                 } else {
513                         tlsConn = Server(conn, config)
514                 }
515         } else {
516                 config.InsecureSkipVerify = true
517                 if test.protocol == dtls {
518                         tlsConn = DTLSClient(conn, config)
519                 } else {
520                         tlsConn = Client(conn, config)
521                 }
522         }
523
524         if err := tlsConn.Handshake(); err != nil {
525                 return err
526         }
527
528         // TODO(davidben): move all per-connection expectations into a dedicated
529         // expectations struct that can be specified separately for the two
530         // legs.
531         expectedVersion := test.expectedVersion
532         if isResume && test.expectedResumeVersion != 0 {
533                 expectedVersion = test.expectedResumeVersion
534         }
535         if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
536                 return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
537         }
538
539         if test.expectChannelID {
540                 channelID := tlsConn.ConnectionState().ChannelID
541                 if channelID == nil {
542                         return fmt.Errorf("no channel ID negotiated")
543                 }
544                 if channelID.Curve != channelIDKey.Curve ||
545                         channelIDKey.X.Cmp(channelIDKey.X) != 0 ||
546                         channelIDKey.Y.Cmp(channelIDKey.Y) != 0 {
547                         return fmt.Errorf("incorrect channel ID")
548                 }
549         }
550
551         if expected := test.expectedNextProto; expected != "" {
552                 if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
553                         return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
554                 }
555         }
556
557         if test.expectedNextProtoType != 0 {
558                 if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN {
559                         return fmt.Errorf("next proto type mismatch")
560                 }
561         }
562
563         if test.shimWritesFirst {
564                 var buf [5]byte
565                 _, err := io.ReadFull(tlsConn, buf[:])
566                 if err != nil {
567                         return err
568                 }
569                 if string(buf[:]) != "hello" {
570                         return fmt.Errorf("bad initial message")
571                 }
572         }
573
574         if test.renegotiate {
575                 if test.renegotiateCiphers != nil {
576                         config.CipherSuites = test.renegotiateCiphers
577                 }
578                 if err := tlsConn.Renegotiate(); err != nil {
579                         return err
580                 }
581         } else if test.renegotiateCiphers != nil {
582                 panic("renegotiateCiphers without renegotiate")
583         }
584
585         if messageLen < 0 {
586                 if test.protocol == dtls {
587                         return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
588                 }
589                 // Read until EOF.
590                 _, err := io.Copy(ioutil.Discard, tlsConn)
591                 return err
592         }
593
594         if messageLen == 0 {
595                 messageLen = 32
596         }
597         testMessage := make([]byte, messageLen)
598         for i := range testMessage {
599                 testMessage[i] = 0x42
600         }
601         tlsConn.Write(testMessage)
602
603         buf := make([]byte, len(testMessage))
604         if test.protocol == dtls {
605                 bufTmp := make([]byte, len(buf)+1)
606                 n, err := tlsConn.Read(bufTmp)
607                 if err != nil {
608                         return err
609                 }
610                 if n != len(buf) {
611                         return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
612                 }
613                 copy(buf, bufTmp)
614         } else {
615                 _, err := io.ReadFull(tlsConn, buf)
616                 if err != nil {
617                         return err
618                 }
619         }
620
621         for i, v := range buf {
622                 if v != testMessage[i]^0xff {
623                         return fmt.Errorf("bad reply contents at byte %d", i)
624                 }
625         }
626
627         return nil
628 }
629
630 func valgrindOf(dbAttach bool, path string, args ...string) *exec.Cmd {
631         valgrindArgs := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
632         if dbAttach {
633                 valgrindArgs = append(valgrindArgs, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
634         }
635         valgrindArgs = append(valgrindArgs, path)
636         valgrindArgs = append(valgrindArgs, args...)
637
638         return exec.Command("valgrind", valgrindArgs...)
639 }
640
641 func gdbOf(path string, args ...string) *exec.Cmd {
642         xtermArgs := []string{"-e", "gdb", "--args"}
643         xtermArgs = append(xtermArgs, path)
644         xtermArgs = append(xtermArgs, args...)
645
646         return exec.Command("xterm", xtermArgs...)
647 }
648
649 func openSocketPair() (shimEnd *os.File, conn net.Conn) {
650         socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
651         if err != nil {
652                 panic(err)
653         }
654
655         syscall.CloseOnExec(socks[0])
656         syscall.CloseOnExec(socks[1])
657         shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
658         connFile := os.NewFile(uintptr(socks[1]), "our end")
659         conn, err = net.FileConn(connFile)
660         if err != nil {
661                 panic(err)
662         }
663         connFile.Close()
664         if err != nil {
665                 panic(err)
666         }
667         return shimEnd, conn
668 }
669
670 func runTest(test *testCase, buildDir string) error {
671         if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
672                 panic("Error expected without shouldFail in " + test.name)
673         }
674
675         shimEnd, conn := openSocketPair()
676         shimEndResume, connResume := openSocketPair()
677
678         shim_path := path.Join(buildDir, "ssl/test/bssl_shim")
679         var flags []string
680         if test.testType == serverTest {
681                 flags = append(flags, "-server")
682
683                 flags = append(flags, "-key-file")
684                 if test.keyFile == "" {
685                         flags = append(flags, rsaKeyFile)
686                 } else {
687                         flags = append(flags, test.keyFile)
688                 }
689
690                 flags = append(flags, "-cert-file")
691                 if test.certFile == "" {
692                         flags = append(flags, rsaCertificateFile)
693                 } else {
694                         flags = append(flags, test.certFile)
695                 }
696         }
697
698         if test.protocol == dtls {
699                 flags = append(flags, "-dtls")
700         }
701
702         if test.resumeSession {
703                 flags = append(flags, "-resume")
704         }
705
706         if test.shimWritesFirst {
707                 flags = append(flags, "-shim-writes-first")
708         }
709
710         flags = append(flags, test.flags...)
711
712         var shim *exec.Cmd
713         if *useValgrind {
714                 shim = valgrindOf(false, shim_path, flags...)
715         } else if *useGDB {
716                 shim = gdbOf(shim_path, flags...)
717         } else {
718                 shim = exec.Command(shim_path, flags...)
719         }
720         shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
721         shim.Stdin = os.Stdin
722         var stdoutBuf, stderrBuf bytes.Buffer
723         shim.Stdout = &stdoutBuf
724         shim.Stderr = &stderrBuf
725
726         if err := shim.Start(); err != nil {
727                 panic(err)
728         }
729         shimEnd.Close()
730         shimEndResume.Close()
731
732         config := test.config
733         config.ClientSessionCache = NewLRUClientSessionCache(1)
734         if test.testType == clientTest {
735                 if len(config.Certificates) == 0 {
736                         config.Certificates = []Certificate{getRSACertificate()}
737                 }
738         }
739
740         var connDebug *recordingConn
741         if *flagDebug {
742                 connDebug = &recordingConn{Conn: conn}
743                 conn = connDebug
744         }
745
746         err := doExchange(test, &config, conn, test.messageLen,
747                 false /* not a resumption */)
748
749         if *flagDebug {
750                 connDebug.WriteTo(os.Stdout)
751         }
752
753         conn.Close()
754         if err == nil && test.resumeSession {
755                 var resumeConfig Config
756                 if test.resumeConfig != nil {
757                         resumeConfig = *test.resumeConfig
758                         if len(resumeConfig.Certificates) == 0 {
759                                 resumeConfig.Certificates = []Certificate{getRSACertificate()}
760                         }
761                         resumeConfig.SessionTicketKey = config.SessionTicketKey
762                         resumeConfig.ClientSessionCache = config.ClientSessionCache
763                 } else {
764                         resumeConfig = config
765                 }
766                 err = doExchange(test, &resumeConfig, connResume, test.messageLen,
767                         true /* resumption */)
768         }
769         connResume.Close()
770
771         childErr := shim.Wait()
772
773         stdout := string(stdoutBuf.Bytes())
774         stderr := string(stderrBuf.Bytes())
775         failed := err != nil || childErr != nil
776         correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
777         localError := "none"
778         if err != nil {
779                 localError = err.Error()
780         }
781         if len(test.expectedLocalError) != 0 {
782                 correctFailure = correctFailure && strings.Contains(localError, test.expectedLocalError)
783         }
784
785         if failed != test.shouldFail || failed && !correctFailure {
786                 childError := "none"
787                 if childErr != nil {
788                         childError = childErr.Error()
789                 }
790
791                 var msg string
792                 switch {
793                 case failed && !test.shouldFail:
794                         msg = "unexpected failure"
795                 case !failed && test.shouldFail:
796                         msg = "unexpected success"
797                 case failed && !correctFailure:
798                         msg = "bad error (wanted '" + test.expectedError + "' / '" + test.expectedLocalError + "')"
799                 default:
800                         panic("internal error")
801                 }
802
803                 return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
804         }
805
806         if !*useValgrind && len(stderr) > 0 {
807                 println(stderr)
808         }
809
810         return nil
811 }
812
813 var tlsVersions = []struct {
814         name    string
815         version uint16
816         flag    string
817 }{
818         {"SSL3", VersionSSL30, "-no-ssl3"},
819         {"TLS1", VersionTLS10, "-no-tls1"},
820         {"TLS11", VersionTLS11, "-no-tls11"},
821         {"TLS12", VersionTLS12, "-no-tls12"},
822 }
823
824 var testCipherSuites = []struct {
825         name string
826         id   uint16
827 }{
828         {"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
829         {"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
830         {"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
831         {"AES128-SHA256", TLS_RSA_WITH_AES_128_CBC_SHA256},
832         {"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
833         {"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
834         {"AES256-SHA256", TLS_RSA_WITH_AES_256_CBC_SHA256},
835         {"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
836         {"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
837         {"DHE-RSA-AES128-SHA256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
838         {"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
839         {"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
840         {"DHE-RSA-AES256-SHA256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
841         {"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
842         {"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
843         {"ECDHE-ECDSA-AES128-SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
844         {"ECDHE-ECDSA-AES256-GCM", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
845         {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
846         {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
847         {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
848         {"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256},
849         {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
850         {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
851         {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
852         {"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
853         {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
854         {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
855         {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
856         {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA},
857         {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA},
858         {"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA},
859         {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
860         {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
861 }
862
863 func isTLS12Only(suiteName string) bool {
864         return strings.HasSuffix(suiteName, "-GCM") ||
865                 strings.HasSuffix(suiteName, "-SHA256") ||
866                 strings.HasSuffix(suiteName, "-SHA384")
867 }
868
869 func addCipherSuiteTests() {
870         for _, suite := range testCipherSuites {
871                 const psk = "12345"
872                 const pskIdentity = "luggage combo"
873
874                 var cert Certificate
875                 var certFile string
876                 var keyFile string
877                 if strings.Contains(suite.name, "ECDSA") {
878                         cert = getECDSACertificate()
879                         certFile = ecdsaCertificateFile
880                         keyFile = ecdsaKeyFile
881                 } else {
882                         cert = getRSACertificate()
883                         certFile = rsaCertificateFile
884                         keyFile = rsaKeyFile
885                 }
886
887                 var flags []string
888                 if strings.HasPrefix(suite.name, "PSK-") || strings.Contains(suite.name, "-PSK-") {
889                         flags = append(flags,
890                                 "-psk", psk,
891                                 "-psk-identity", pskIdentity)
892                 }
893
894                 for _, ver := range tlsVersions {
895                         if ver.version < VersionTLS12 && isTLS12Only(suite.name) {
896                                 continue
897                         }
898
899                         // Go's TLS implementation only implements session
900                         // resumption with tickets, so SSLv3 cannot resume
901                         // sessions.
902                         resumeSession := ver.version != VersionSSL30
903
904                         testCases = append(testCases, testCase{
905                                 testType: clientTest,
906                                 name:     ver.name + "-" + suite.name + "-client",
907                                 config: Config{
908                                         MinVersion:           ver.version,
909                                         MaxVersion:           ver.version,
910                                         CipherSuites:         []uint16{suite.id},
911                                         Certificates:         []Certificate{cert},
912                                         PreSharedKey:         []byte(psk),
913                                         PreSharedKeyIdentity: pskIdentity,
914                                 },
915                                 flags:         flags,
916                                 resumeSession: resumeSession,
917                         })
918
919                         testCases = append(testCases, testCase{
920                                 testType: serverTest,
921                                 name:     ver.name + "-" + suite.name + "-server",
922                                 config: Config{
923                                         MinVersion:           ver.version,
924                                         MaxVersion:           ver.version,
925                                         CipherSuites:         []uint16{suite.id},
926                                         Certificates:         []Certificate{cert},
927                                         PreSharedKey:         []byte(psk),
928                                         PreSharedKeyIdentity: pskIdentity,
929                                 },
930                                 certFile:      certFile,
931                                 keyFile:       keyFile,
932                                 flags:         flags,
933                                 resumeSession: resumeSession,
934                         })
935
936                         // TODO(davidben): Fix DTLS 1.2 support and test that.
937                         if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
938                                 testCases = append(testCases, testCase{
939                                         testType: clientTest,
940                                         protocol: dtls,
941                                         name:     "D" + ver.name + "-" + suite.name + "-client",
942                                         config: Config{
943                                                 MinVersion:           ver.version,
944                                                 MaxVersion:           ver.version,
945                                                 CipherSuites:         []uint16{suite.id},
946                                                 Certificates:         []Certificate{cert},
947                                                 PreSharedKey:         []byte(psk),
948                                                 PreSharedKeyIdentity: pskIdentity,
949                                         },
950                                         flags:         flags,
951                                         resumeSession: resumeSession,
952                                 })
953                                 testCases = append(testCases, testCase{
954                                         testType: serverTest,
955                                         protocol: dtls,
956                                         name:     "D" + ver.name + "-" + suite.name + "-server",
957                                         config: Config{
958                                                 MinVersion:           ver.version,
959                                                 MaxVersion:           ver.version,
960                                                 CipherSuites:         []uint16{suite.id},
961                                                 Certificates:         []Certificate{cert},
962                                                 PreSharedKey:         []byte(psk),
963                                                 PreSharedKeyIdentity: pskIdentity,
964                                         },
965                                         certFile:      certFile,
966                                         keyFile:       keyFile,
967                                         flags:         flags,
968                                         resumeSession: resumeSession,
969                                 })
970                         }
971                 }
972         }
973 }
974
975 func addBadECDSASignatureTests() {
976         for badR := BadValue(1); badR < NumBadValues; badR++ {
977                 for badS := BadValue(1); badS < NumBadValues; badS++ {
978                         testCases = append(testCases, testCase{
979                                 name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
980                                 config: Config{
981                                         CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
982                                         Certificates: []Certificate{getECDSACertificate()},
983                                         Bugs: ProtocolBugs{
984                                                 BadECDSAR: badR,
985                                                 BadECDSAS: badS,
986                                         },
987                                 },
988                                 shouldFail:    true,
989                                 expectedError: "SIGNATURE",
990                         })
991                 }
992         }
993 }
994
995 func addCBCPaddingTests() {
996         testCases = append(testCases, testCase{
997                 name: "MaxCBCPadding",
998                 config: Config{
999                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1000                         Bugs: ProtocolBugs{
1001                                 MaxPadding: true,
1002                         },
1003                 },
1004                 messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
1005         })
1006         testCases = append(testCases, testCase{
1007                 name: "BadCBCPadding",
1008                 config: Config{
1009                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1010                         Bugs: ProtocolBugs{
1011                                 PaddingFirstByteBad: true,
1012                         },
1013                 },
1014                 shouldFail:    true,
1015                 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1016         })
1017         // OpenSSL previously had an issue where the first byte of padding in
1018         // 255 bytes of padding wasn't checked.
1019         testCases = append(testCases, testCase{
1020                 name: "BadCBCPadding255",
1021                 config: Config{
1022                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1023                         Bugs: ProtocolBugs{
1024                                 MaxPadding:               true,
1025                                 PaddingFirstByteBadIf255: true,
1026                         },
1027                 },
1028                 messageLen:    12, // 20 bytes of SHA-1 + 12 == 0 % block size
1029                 shouldFail:    true,
1030                 expectedError: "DECRYPTION_FAILED_OR_BAD_RECORD_MAC",
1031         })
1032 }
1033
1034 func addCBCSplittingTests() {
1035         testCases = append(testCases, testCase{
1036                 name: "CBCRecordSplitting",
1037                 config: Config{
1038                         MaxVersion:   VersionTLS10,
1039                         MinVersion:   VersionTLS10,
1040                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1041                 },
1042                 messageLen: -1, // read until EOF
1043                 flags: []string{
1044                         "-async",
1045                         "-write-different-record-sizes",
1046                         "-cbc-record-splitting",
1047                 },
1048         })
1049         testCases = append(testCases, testCase{
1050                 name: "CBCRecordSplittingPartialWrite",
1051                 config: Config{
1052                         MaxVersion:   VersionTLS10,
1053                         MinVersion:   VersionTLS10,
1054                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
1055                 },
1056                 messageLen: -1, // read until EOF
1057                 flags: []string{
1058                         "-async",
1059                         "-write-different-record-sizes",
1060                         "-cbc-record-splitting",
1061                         "-partial-write",
1062                 },
1063         })
1064 }
1065
1066 func addClientAuthTests() {
1067         // Add a dummy cert pool to stress certificate authority parsing.
1068         // TODO(davidben): Add tests that those values parse out correctly.
1069         certPool := x509.NewCertPool()
1070         cert, err := x509.ParseCertificate(rsaCertificate.Certificate[0])
1071         if err != nil {
1072                 panic(err)
1073         }
1074         certPool.AddCert(cert)
1075
1076         for _, ver := range tlsVersions {
1077                 testCases = append(testCases, testCase{
1078                         testType: clientTest,
1079                         name:     ver.name + "-Client-ClientAuth-RSA",
1080                         config: Config{
1081                                 MinVersion: ver.version,
1082                                 MaxVersion: ver.version,
1083                                 ClientAuth: RequireAnyClientCert,
1084                                 ClientCAs:  certPool,
1085                         },
1086                         flags: []string{
1087                                 "-cert-file", rsaCertificateFile,
1088                                 "-key-file", rsaKeyFile,
1089                         },
1090                 })
1091                 testCases = append(testCases, testCase{
1092                         testType: serverTest,
1093                         name:     ver.name + "-Server-ClientAuth-RSA",
1094                         config: Config{
1095                                 MinVersion:   ver.version,
1096                                 MaxVersion:   ver.version,
1097                                 Certificates: []Certificate{rsaCertificate},
1098                         },
1099                         flags: []string{"-require-any-client-certificate"},
1100                 })
1101                 if ver.version != VersionSSL30 {
1102                         testCases = append(testCases, testCase{
1103                                 testType: serverTest,
1104                                 name:     ver.name + "-Server-ClientAuth-ECDSA",
1105                                 config: Config{
1106                                         MinVersion:   ver.version,
1107                                         MaxVersion:   ver.version,
1108                                         Certificates: []Certificate{ecdsaCertificate},
1109                                 },
1110                                 flags: []string{"-require-any-client-certificate"},
1111                         })
1112                         testCases = append(testCases, testCase{
1113                                 testType: clientTest,
1114                                 name:     ver.name + "-Client-ClientAuth-ECDSA",
1115                                 config: Config{
1116                                         MinVersion: ver.version,
1117                                         MaxVersion: ver.version,
1118                                         ClientAuth: RequireAnyClientCert,
1119                                         ClientCAs:  certPool,
1120                                 },
1121                                 flags: []string{
1122                                         "-cert-file", ecdsaCertificateFile,
1123                                         "-key-file", ecdsaKeyFile,
1124                                 },
1125                         })
1126                 }
1127         }
1128 }
1129
1130 func addExtendedMasterSecretTests() {
1131         const expectEMSFlag = "-expect-extended-master-secret"
1132
1133         for _, with := range []bool{false, true} {
1134                 prefix := "No"
1135                 var flags []string
1136                 if with {
1137                         prefix = ""
1138                         flags = []string{expectEMSFlag}
1139                 }
1140
1141                 for _, isClient := range []bool{false, true} {
1142                         suffix := "-Server"
1143                         testType := serverTest
1144                         if isClient {
1145                                 suffix = "-Client"
1146                                 testType = clientTest
1147                         }
1148
1149                         for _, ver := range tlsVersions {
1150                                 test := testCase{
1151                                         testType: testType,
1152                                         name:     prefix + "ExtendedMasterSecret-" + ver.name + suffix,
1153                                         config: Config{
1154                                                 MinVersion: ver.version,
1155                                                 MaxVersion: ver.version,
1156                                                 Bugs: ProtocolBugs{
1157                                                         NoExtendedMasterSecret:      !with,
1158                                                         RequireExtendedMasterSecret: with,
1159                                                 },
1160                                         },
1161                                         flags:      flags,
1162                                         shouldFail: ver.version == VersionSSL30 && with,
1163                                 }
1164                                 if test.shouldFail {
1165                                         test.expectedLocalError = "extended master secret required but not supported by peer"
1166                                 }
1167                                 testCases = append(testCases, test)
1168                         }
1169                 }
1170         }
1171
1172         // When a session is resumed, it should still be aware that its master
1173         // secret was generated via EMS and thus it's safe to use tls-unique.
1174         testCases = append(testCases, testCase{
1175                 name: "ExtendedMasterSecret-Resume",
1176                 config: Config{
1177                         Bugs: ProtocolBugs{
1178                                 RequireExtendedMasterSecret: true,
1179                         },
1180                 },
1181                 flags:         []string{expectEMSFlag},
1182                 resumeSession: true,
1183         })
1184 }
1185
1186 // Adds tests that try to cover the range of the handshake state machine, under
1187 // various conditions. Some of these are redundant with other tests, but they
1188 // only cover the synchronous case.
1189 func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
1190         var suffix string
1191         var flags []string
1192         var maxHandshakeRecordLength int
1193         if protocol == dtls {
1194                 suffix = "-DTLS"
1195         }
1196         if async {
1197                 suffix += "-Async"
1198                 flags = append(flags, "-async")
1199         } else {
1200                 suffix += "-Sync"
1201         }
1202         if splitHandshake {
1203                 suffix += "-SplitHandshakeRecords"
1204                 maxHandshakeRecordLength = 1
1205         }
1206
1207         // Basic handshake, with resumption. Client and server.
1208         testCases = append(testCases, testCase{
1209                 protocol: protocol,
1210                 name:     "Basic-Client" + suffix,
1211                 config: Config{
1212                         Bugs: ProtocolBugs{
1213                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1214                         },
1215                 },
1216                 flags:         flags,
1217                 resumeSession: true,
1218         })
1219         testCases = append(testCases, testCase{
1220                 protocol: protocol,
1221                 name:     "Basic-Client-RenewTicket" + suffix,
1222                 config: Config{
1223                         Bugs: ProtocolBugs{
1224                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1225                                 RenewTicketOnResume:      true,
1226                         },
1227                 },
1228                 flags:         flags,
1229                 resumeSession: true,
1230         })
1231         testCases = append(testCases, testCase{
1232                 protocol: protocol,
1233                 testType: serverTest,
1234                 name:     "Basic-Server" + suffix,
1235                 config: Config{
1236                         Bugs: ProtocolBugs{
1237                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1238                         },
1239                 },
1240                 flags:         flags,
1241                 resumeSession: true,
1242         })
1243
1244         // TLS client auth.
1245         testCases = append(testCases, testCase{
1246                 protocol: protocol,
1247                 testType: clientTest,
1248                 name:     "ClientAuth-Client" + suffix,
1249                 config: Config{
1250                         ClientAuth: RequireAnyClientCert,
1251                         Bugs: ProtocolBugs{
1252                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1253                         },
1254                 },
1255                 flags: append(flags,
1256                         "-cert-file", rsaCertificateFile,
1257                         "-key-file", rsaKeyFile),
1258         })
1259         testCases = append(testCases, testCase{
1260                 protocol: protocol,
1261                 testType: serverTest,
1262                 name:     "ClientAuth-Server" + suffix,
1263                 config: Config{
1264                         Certificates: []Certificate{rsaCertificate},
1265                 },
1266                 flags: append(flags, "-require-any-client-certificate"),
1267         })
1268
1269         // No session ticket support; server doesn't send NewSessionTicket.
1270         testCases = append(testCases, testCase{
1271                 protocol: protocol,
1272                 name:     "SessionTicketsDisabled-Client" + suffix,
1273                 config: Config{
1274                         SessionTicketsDisabled: true,
1275                         Bugs: ProtocolBugs{
1276                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1277                         },
1278                 },
1279                 flags: flags,
1280         })
1281         testCases = append(testCases, testCase{
1282                 protocol: protocol,
1283                 testType: serverTest,
1284                 name:     "SessionTicketsDisabled-Server" + suffix,
1285                 config: Config{
1286                         SessionTicketsDisabled: true,
1287                         Bugs: ProtocolBugs{
1288                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1289                         },
1290                 },
1291                 flags: flags,
1292         })
1293
1294         // Skip ServerKeyExchange in PSK key exchange if there's no
1295         // identity hint.
1296         testCases = append(testCases, testCase{
1297                 protocol: protocol,
1298                 name:     "EmptyPSKHint-Client" + suffix,
1299                 config: Config{
1300                         CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1301                         PreSharedKey: []byte("secret"),
1302                         Bugs: ProtocolBugs{
1303                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1304                         },
1305                 },
1306                 flags: append(flags, "-psk", "secret"),
1307         })
1308         testCases = append(testCases, testCase{
1309                 protocol: protocol,
1310                 testType: serverTest,
1311                 name:     "EmptyPSKHint-Server" + suffix,
1312                 config: Config{
1313                         CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
1314                         PreSharedKey: []byte("secret"),
1315                         Bugs: ProtocolBugs{
1316                                 MaxHandshakeRecordLength: maxHandshakeRecordLength,
1317                         },
1318                 },
1319                 flags: append(flags, "-psk", "secret"),
1320         })
1321
1322         if protocol == tls {
1323                 // NPN on client and server; results in post-handshake message.
1324                 testCases = append(testCases, testCase{
1325                         protocol: protocol,
1326                         name:     "NPN-Client" + suffix,
1327                         config: Config{
1328                                 NextProtos: []string{"foo"},
1329                                 Bugs: ProtocolBugs{
1330                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1331                                 },
1332                         },
1333                         flags:                 append(flags, "-select-next-proto", "foo"),
1334                         expectedNextProto:     "foo",
1335                         expectedNextProtoType: npn,
1336                 })
1337                 testCases = append(testCases, testCase{
1338                         protocol: protocol,
1339                         testType: serverTest,
1340                         name:     "NPN-Server" + suffix,
1341                         config: Config{
1342                                 NextProtos: []string{"bar"},
1343                                 Bugs: ProtocolBugs{
1344                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1345                                 },
1346                         },
1347                         flags: append(flags,
1348                                 "-advertise-npn", "\x03foo\x03bar\x03baz",
1349                                 "-expect-next-proto", "bar"),
1350                         expectedNextProto:     "bar",
1351                         expectedNextProtoType: npn,
1352                 })
1353
1354                 // Client does False Start and negotiates NPN.
1355                 testCases = append(testCases, testCase{
1356                         protocol: protocol,
1357                         name:     "FalseStart" + suffix,
1358                         config: Config{
1359                                 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1360                                 NextProtos:   []string{"foo"},
1361                                 Bugs: ProtocolBugs{
1362                                         ExpectFalseStart:         true,
1363                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1364                                 },
1365                         },
1366                         flags: append(flags,
1367                                 "-false-start",
1368                                 "-select-next-proto", "foo"),
1369                         shimWritesFirst: true,
1370                         resumeSession:   true,
1371                 })
1372
1373                 // Client does False Start and negotiates ALPN.
1374                 testCases = append(testCases, testCase{
1375                         protocol: protocol,
1376                         name:     "FalseStart-ALPN" + suffix,
1377                         config: Config{
1378                                 CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1379                                 NextProtos:   []string{"foo"},
1380                                 Bugs: ProtocolBugs{
1381                                         ExpectFalseStart:         true,
1382                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1383                                 },
1384                         },
1385                         flags: append(flags,
1386                                 "-false-start",
1387                                 "-advertise-alpn", "\x03foo"),
1388                         shimWritesFirst: true,
1389                         resumeSession:   true,
1390                 })
1391
1392                 // False Start without session tickets.
1393                 testCases = append(testCases, testCase{
1394                         name: "FalseStart-SessionTicketsDisabled",
1395                         config: Config{
1396                                 CipherSuites:           []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1397                                 NextProtos:             []string{"foo"},
1398                                 SessionTicketsDisabled: true,
1399                                 Bugs: ProtocolBugs{
1400                                         ExpectFalseStart:         true,
1401                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1402                                 },
1403                         },
1404                         flags: append(flags,
1405                                 "-false-start",
1406                                 "-select-next-proto", "foo",
1407                         ),
1408                         shimWritesFirst: true,
1409                 })
1410
1411                 // Server parses a V2ClientHello.
1412                 testCases = append(testCases, testCase{
1413                         protocol: protocol,
1414                         testType: serverTest,
1415                         name:     "SendV2ClientHello" + suffix,
1416                         config: Config{
1417                                 // Choose a cipher suite that does not involve
1418                                 // elliptic curves, so no extensions are
1419                                 // involved.
1420                                 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1421                                 Bugs: ProtocolBugs{
1422                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1423                                         SendV2ClientHello:        true,
1424                                 },
1425                         },
1426                         flags: flags,
1427                 })
1428
1429                 // Client sends a Channel ID.
1430                 testCases = append(testCases, testCase{
1431                         protocol: protocol,
1432                         name:     "ChannelID-Client" + suffix,
1433                         config: Config{
1434                                 RequestChannelID: true,
1435                                 Bugs: ProtocolBugs{
1436                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1437                                 },
1438                         },
1439                         flags: append(flags,
1440                                 "-send-channel-id", channelIDKeyFile,
1441                         ),
1442                         resumeSession:   true,
1443                         expectChannelID: true,
1444                 })
1445
1446                 // Server accepts a Channel ID.
1447                 testCases = append(testCases, testCase{
1448                         protocol: protocol,
1449                         testType: serverTest,
1450                         name:     "ChannelID-Server" + suffix,
1451                         config: Config{
1452                                 ChannelID: channelIDKey,
1453                                 Bugs: ProtocolBugs{
1454                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1455                                 },
1456                         },
1457                         flags: append(flags,
1458                                 "-expect-channel-id",
1459                                 base64.StdEncoding.EncodeToString(channelIDBytes),
1460                         ),
1461                         resumeSession:   true,
1462                         expectChannelID: true,
1463                 })
1464         } else {
1465                 testCases = append(testCases, testCase{
1466                         protocol: protocol,
1467                         name:     "SkipHelloVerifyRequest" + suffix,
1468                         config: Config{
1469                                 Bugs: ProtocolBugs{
1470                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1471                                         SkipHelloVerifyRequest:   true,
1472                                 },
1473                         },
1474                         flags: flags,
1475                 })
1476
1477                 testCases = append(testCases, testCase{
1478                         testType: serverTest,
1479                         protocol: protocol,
1480                         name:     "CookieExchange" + suffix,
1481                         config: Config{
1482                                 Bugs: ProtocolBugs{
1483                                         MaxHandshakeRecordLength: maxHandshakeRecordLength,
1484                                 },
1485                         },
1486                         flags: append(flags, "-cookie-exchange"),
1487                 })
1488         }
1489 }
1490
1491 func addVersionNegotiationTests() {
1492         for i, shimVers := range tlsVersions {
1493                 // Assemble flags to disable all newer versions on the shim.
1494                 var flags []string
1495                 for _, vers := range tlsVersions[i+1:] {
1496                         flags = append(flags, vers.flag)
1497                 }
1498
1499                 for _, runnerVers := range tlsVersions {
1500                         expectedVersion := shimVers.version
1501                         if runnerVers.version < shimVers.version {
1502                                 expectedVersion = runnerVers.version
1503                         }
1504                         suffix := shimVers.name + "-" + runnerVers.name
1505
1506                         testCases = append(testCases, testCase{
1507                                 testType: clientTest,
1508                                 name:     "VersionNegotiation-Client-" + suffix,
1509                                 config: Config{
1510                                         MaxVersion: runnerVers.version,
1511                                 },
1512                                 flags:           flags,
1513                                 expectedVersion: expectedVersion,
1514                         })
1515
1516                         testCases = append(testCases, testCase{
1517                                 testType: serverTest,
1518                                 name:     "VersionNegotiation-Server-" + suffix,
1519                                 config: Config{
1520                                         MaxVersion: runnerVers.version,
1521                                 },
1522                                 flags:           flags,
1523                                 expectedVersion: expectedVersion,
1524                         })
1525                 }
1526         }
1527 }
1528
1529 func addD5BugTests() {
1530         testCases = append(testCases, testCase{
1531                 testType: serverTest,
1532                 name:     "D5Bug-NoQuirk-Reject",
1533                 config: Config{
1534                         CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1535                         Bugs: ProtocolBugs{
1536                                 SSL3RSAKeyExchange: true,
1537                         },
1538                 },
1539                 shouldFail:    true,
1540                 expectedError: ":TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG:",
1541         })
1542         testCases = append(testCases, testCase{
1543                 testType: serverTest,
1544                 name:     "D5Bug-Quirk-Normal",
1545                 config: Config{
1546                         CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1547                 },
1548                 flags: []string{"-tls-d5-bug"},
1549         })
1550         testCases = append(testCases, testCase{
1551                 testType: serverTest,
1552                 name:     "D5Bug-Quirk-Bug",
1553                 config: Config{
1554                         CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
1555                         Bugs: ProtocolBugs{
1556                                 SSL3RSAKeyExchange: true,
1557                         },
1558                 },
1559                 flags: []string{"-tls-d5-bug"},
1560         })
1561 }
1562
1563 func addExtensionTests() {
1564         testCases = append(testCases, testCase{
1565                 testType: clientTest,
1566                 name:     "DuplicateExtensionClient",
1567                 config: Config{
1568                         Bugs: ProtocolBugs{
1569                                 DuplicateExtension: true,
1570                         },
1571                 },
1572                 shouldFail:         true,
1573                 expectedLocalError: "remote error: error decoding message",
1574         })
1575         testCases = append(testCases, testCase{
1576                 testType: serverTest,
1577                 name:     "DuplicateExtensionServer",
1578                 config: Config{
1579                         Bugs: ProtocolBugs{
1580                                 DuplicateExtension: true,
1581                         },
1582                 },
1583                 shouldFail:         true,
1584                 expectedLocalError: "remote error: error decoding message",
1585         })
1586         testCases = append(testCases, testCase{
1587                 testType: clientTest,
1588                 name:     "ServerNameExtensionClient",
1589                 config: Config{
1590                         Bugs: ProtocolBugs{
1591                                 ExpectServerName: "example.com",
1592                         },
1593                 },
1594                 flags: []string{"-host-name", "example.com"},
1595         })
1596         testCases = append(testCases, testCase{
1597                 testType: clientTest,
1598                 name:     "ServerNameExtensionClient",
1599                 config: Config{
1600                         Bugs: ProtocolBugs{
1601                                 ExpectServerName: "mismatch.com",
1602                         },
1603                 },
1604                 flags:              []string{"-host-name", "example.com"},
1605                 shouldFail:         true,
1606                 expectedLocalError: "tls: unexpected server name",
1607         })
1608         testCases = append(testCases, testCase{
1609                 testType: clientTest,
1610                 name:     "ServerNameExtensionClient",
1611                 config: Config{
1612                         Bugs: ProtocolBugs{
1613                                 ExpectServerName: "missing.com",
1614                         },
1615                 },
1616                 shouldFail:         true,
1617                 expectedLocalError: "tls: unexpected server name",
1618         })
1619         testCases = append(testCases, testCase{
1620                 testType: serverTest,
1621                 name:     "ServerNameExtensionServer",
1622                 config: Config{
1623                         ServerName: "example.com",
1624                 },
1625                 flags:         []string{"-expect-server-name", "example.com"},
1626                 resumeSession: true,
1627         })
1628         testCases = append(testCases, testCase{
1629                 testType: clientTest,
1630                 name:     "ALPNClient",
1631                 config: Config{
1632                         NextProtos: []string{"foo"},
1633                 },
1634                 flags: []string{
1635                         "-advertise-alpn", "\x03foo\x03bar\x03baz",
1636                         "-expect-alpn", "foo",
1637                 },
1638                 expectedNextProto:     "foo",
1639                 expectedNextProtoType: alpn,
1640                 resumeSession:         true,
1641         })
1642         testCases = append(testCases, testCase{
1643                 testType: serverTest,
1644                 name:     "ALPNServer",
1645                 config: Config{
1646                         NextProtos: []string{"foo", "bar", "baz"},
1647                 },
1648                 flags: []string{
1649                         "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1650                         "-select-alpn", "foo",
1651                 },
1652                 expectedNextProto:     "foo",
1653                 expectedNextProtoType: alpn,
1654                 resumeSession:         true,
1655         })
1656         // Test that the server prefers ALPN over NPN.
1657         testCases = append(testCases, testCase{
1658                 testType: serverTest,
1659                 name:     "ALPNServer-Preferred",
1660                 config: Config{
1661                         NextProtos: []string{"foo", "bar", "baz"},
1662                 },
1663                 flags: []string{
1664                         "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1665                         "-select-alpn", "foo",
1666                         "-advertise-npn", "\x03foo\x03bar\x03baz",
1667                 },
1668                 expectedNextProto:     "foo",
1669                 expectedNextProtoType: alpn,
1670                 resumeSession:         true,
1671         })
1672         testCases = append(testCases, testCase{
1673                 testType: serverTest,
1674                 name:     "ALPNServer-Preferred-Swapped",
1675                 config: Config{
1676                         NextProtos: []string{"foo", "bar", "baz"},
1677                         Bugs: ProtocolBugs{
1678                                 SwapNPNAndALPN: true,
1679                         },
1680                 },
1681                 flags: []string{
1682                         "-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
1683                         "-select-alpn", "foo",
1684                         "-advertise-npn", "\x03foo\x03bar\x03baz",
1685                 },
1686                 expectedNextProto:     "foo",
1687                 expectedNextProtoType: alpn,
1688                 resumeSession:         true,
1689         })
1690         // Resume with a corrupt ticket.
1691         testCases = append(testCases, testCase{
1692                 testType: serverTest,
1693                 name:     "CorruptTicket",
1694                 config: Config{
1695                         Bugs: ProtocolBugs{
1696                                 CorruptTicket: true,
1697                         },
1698                 },
1699                 resumeSession: true,
1700                 flags:         []string{"-expect-session-miss"},
1701         })
1702         // Resume with an oversized session id.
1703         testCases = append(testCases, testCase{
1704                 testType: serverTest,
1705                 name:     "OversizedSessionId",
1706                 config: Config{
1707                         Bugs: ProtocolBugs{
1708                                 OversizedSessionId: true,
1709                         },
1710                 },
1711                 resumeSession: true,
1712                 shouldFail:    true,
1713                 expectedError: ":DECODE_ERROR:",
1714         })
1715 }
1716
1717 func addResumptionVersionTests() {
1718         // TODO(davidben): Once DTLS 1.2 is working, test that as well.
1719         for _, sessionVers := range tlsVersions {
1720                 // TODO(davidben): SSLv3 is omitted here because runner does not
1721                 // support resumption with session IDs.
1722                 if sessionVers.version == VersionSSL30 {
1723                         continue
1724                 }
1725                 for _, resumeVers := range tlsVersions {
1726                         if resumeVers.version == VersionSSL30 {
1727                                 continue
1728                         }
1729                         suffix := "-" + sessionVers.name + "-" + resumeVers.name
1730
1731                         // TODO(davidben): Write equivalent tests for the server
1732                         // and clean up the server's logic. This requires being
1733                         // able to give the shim a different set of SSL_OP_NO_*
1734                         // flags between the initial connection and the
1735                         // resume. Perhaps resumption should be tested by
1736                         // serializing the SSL_SESSION and starting a second
1737                         // shim.
1738                         testCases = append(testCases, testCase{
1739                                 name:          "Resume-Client" + suffix,
1740                                 resumeSession: true,
1741                                 config: Config{
1742                                         MaxVersion:   sessionVers.version,
1743                                         CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1744                                         Bugs: ProtocolBugs{
1745                                                 AllowSessionVersionMismatch: true,
1746                                         },
1747                                 },
1748                                 expectedVersion: sessionVers.version,
1749                                 resumeConfig: &Config{
1750                                         MaxVersion:   resumeVers.version,
1751                                         CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1752                                         Bugs: ProtocolBugs{
1753                                                 AllowSessionVersionMismatch: true,
1754                                         },
1755                                 },
1756                                 expectedResumeVersion: resumeVers.version,
1757                         })
1758
1759                         testCases = append(testCases, testCase{
1760                                 name:          "Resume-Client-NoResume" + suffix,
1761                                 flags:         []string{"-expect-session-miss"},
1762                                 resumeSession: true,
1763                                 config: Config{
1764                                         MaxVersion:   sessionVers.version,
1765                                         CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1766                                 },
1767                                 expectedVersion: sessionVers.version,
1768                                 resumeConfig: &Config{
1769                                         MaxVersion:             resumeVers.version,
1770                                         CipherSuites:           []uint16{TLS_RSA_WITH_RC4_128_SHA},
1771                                         SessionTicketsDisabled: true,
1772                                 },
1773                                 expectedResumeVersion: resumeVers.version,
1774                         })
1775                 }
1776         }
1777 }
1778
1779 func addRenegotiationTests() {
1780         testCases = append(testCases, testCase{
1781                 testType:        serverTest,
1782                 name:            "Renegotiate-Server",
1783                 flags:           []string{"-renegotiate"},
1784                 shimWritesFirst: true,
1785         })
1786         testCases = append(testCases, testCase{
1787                 testType: serverTest,
1788                 name:     "Renegotiate-Server-EmptyExt",
1789                 config: Config{
1790                         Bugs: ProtocolBugs{
1791                                 EmptyRenegotiationInfo: true,
1792                         },
1793                 },
1794                 flags:           []string{"-renegotiate"},
1795                 shimWritesFirst: true,
1796                 shouldFail:      true,
1797                 expectedError:   ":RENEGOTIATION_MISMATCH:",
1798         })
1799         testCases = append(testCases, testCase{
1800                 testType: serverTest,
1801                 name:     "Renegotiate-Server-BadExt",
1802                 config: Config{
1803                         Bugs: ProtocolBugs{
1804                                 BadRenegotiationInfo: true,
1805                         },
1806                 },
1807                 flags:           []string{"-renegotiate"},
1808                 shimWritesFirst: true,
1809                 shouldFail:      true,
1810                 expectedError:   ":RENEGOTIATION_MISMATCH:",
1811         })
1812         // TODO(agl): test the renegotiation info SCSV.
1813         testCases = append(testCases, testCase{
1814                 name:        "Renegotiate-Client",
1815                 renegotiate: true,
1816         })
1817         testCases = append(testCases, testCase{
1818                 name:        "Renegotiate-Client-EmptyExt",
1819                 renegotiate: true,
1820                 config: Config{
1821                         Bugs: ProtocolBugs{
1822                                 EmptyRenegotiationInfo: true,
1823                         },
1824                 },
1825                 shouldFail:    true,
1826                 expectedError: ":RENEGOTIATION_MISMATCH:",
1827         })
1828         testCases = append(testCases, testCase{
1829                 name:        "Renegotiate-Client-BadExt",
1830                 renegotiate: true,
1831                 config: Config{
1832                         Bugs: ProtocolBugs{
1833                                 BadRenegotiationInfo: true,
1834                         },
1835                 },
1836                 shouldFail:    true,
1837                 expectedError: ":RENEGOTIATION_MISMATCH:",
1838         })
1839         testCases = append(testCases, testCase{
1840                 name:        "Renegotiate-Client-SwitchCiphers",
1841                 renegotiate: true,
1842                 config: Config{
1843                         CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1844                 },
1845                 renegotiateCiphers: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1846         })
1847         testCases = append(testCases, testCase{
1848                 name:        "Renegotiate-Client-SwitchCiphers2",
1849                 renegotiate: true,
1850                 config: Config{
1851                         CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
1852                 },
1853                 renegotiateCiphers: []uint16{TLS_RSA_WITH_RC4_128_SHA},
1854         })
1855 }
1856
1857 func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
1858         defer wg.Done()
1859
1860         for test := range c {
1861                 statusChan <- statusMsg{test: test, started: true}
1862                 err := runTest(test, buildDir)
1863                 statusChan <- statusMsg{test: test, err: err}
1864         }
1865 }
1866
1867 type statusMsg struct {
1868         test    *testCase
1869         started bool
1870         err     error
1871 }
1872
1873 func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
1874         var started, done, failed, lineLen int
1875         defer close(doneChan)
1876
1877         for msg := range statusChan {
1878                 if msg.started {
1879                         started++
1880                 } else {
1881                         done++
1882                 }
1883
1884                 fmt.Printf("\x1b[%dD\x1b[K", lineLen)
1885
1886                 if msg.err != nil {
1887                         fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
1888                         failed++
1889                 }
1890                 line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
1891                 lineLen = len(line)
1892                 os.Stdout.WriteString(line)
1893         }
1894 }
1895
1896 func main() {
1897         var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
1898         var flagNumWorkers *int = flag.Int("num-workers", runtime.NumCPU(), "The number of workers to run in parallel.")
1899         var flagBuildDir *string = flag.String("build-dir", "../../../build", "The build directory to run the shim from.")
1900
1901         flag.Parse()
1902
1903         addCipherSuiteTests()
1904         addBadECDSASignatureTests()
1905         addCBCPaddingTests()
1906         addCBCSplittingTests()
1907         addClientAuthTests()
1908         addVersionNegotiationTests()
1909         addD5BugTests()
1910         addExtensionTests()
1911         addResumptionVersionTests()
1912         addExtendedMasterSecretTests()
1913         addRenegotiationTests()
1914         for _, async := range []bool{false, true} {
1915                 for _, splitHandshake := range []bool{false, true} {
1916                         for _, protocol := range []protocol{tls, dtls} {
1917                                 addStateMachineCoverageTests(async, splitHandshake, protocol)
1918                         }
1919                 }
1920         }
1921
1922         var wg sync.WaitGroup
1923
1924         numWorkers := *flagNumWorkers
1925
1926         statusChan := make(chan statusMsg, numWorkers)
1927         testChan := make(chan *testCase, numWorkers)
1928         doneChan := make(chan struct{})
1929
1930         go statusPrinter(doneChan, statusChan, len(testCases))
1931
1932         for i := 0; i < numWorkers; i++ {
1933                 wg.Add(1)
1934                 go worker(statusChan, testChan, *flagBuildDir, &wg)
1935         }
1936
1937         for i := range testCases {
1938                 if len(*flagTest) == 0 || *flagTest == testCases[i].name {
1939                         testChan <- &testCases[i]
1940                 }
1941         }
1942
1943         close(testChan)
1944         wg.Wait()
1945         close(statusChan)
1946         <-doneChan
1947
1948         fmt.Printf("\n")
1949 }