Inital import.

Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).

(This change contains substantial changes from the original and
effectively starts a new history.)
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
new file mode 100644
index 0000000..1edd00b
--- /dev/null
+++ b/ssl/test/runner/runner.go
@@ -0,0 +1,365 @@
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io"
+	"net"
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+	"syscall"
+)
+
+var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
+
+var rsaCertificate, ecdsaCertificate Certificate
+
+func initCertificates() {
+	var err error
+	rsaCertificate, err = LoadX509KeyPair("cert.pem", "key.pem")
+	if err != nil {
+		panic(err)
+	}
+
+	ecdsaCertificate, err = LoadX509KeyPair("ecdsa_cert.pem", "ecdsa_key.pem")
+	if err != nil {
+		panic(err)
+	}
+}
+
+var certificateOnce sync.Once
+
+func getRSACertificate() Certificate {
+	certificateOnce.Do(initCertificates)
+	return rsaCertificate
+}
+
+func getECDSACertificate() Certificate {
+	certificateOnce.Do(initCertificates)
+	return ecdsaCertificate
+}
+
+type testCase struct {
+	name          string
+	config        Config
+	shouldFail    bool
+	expectedError string
+}
+
+var clientTests = []testCase{
+	{
+		name: "BadRSASignature",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				InvalidSKXSignature: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":BAD_SIGNATURE:",
+	},
+	{
+		name: "BadECDSASignature",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				InvalidSKXSignature: true,
+			},
+			Certificates: []Certificate{getECDSACertificate()},
+		},
+		shouldFail:    true,
+		expectedError: ":BAD_SIGNATURE:",
+	},
+	{
+		name: "BadECDSACurve",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				InvalidSKXCurve: true,
+			},
+			Certificates: []Certificate{getECDSACertificate()},
+		},
+		shouldFail:    true,
+		expectedError: ":WRONG_CURVE:",
+	},
+}
+
+var testMessage = []byte("testing")
+
+func doExchange(tlsConn *Conn) error {
+	if err := tlsConn.Handshake(); err != nil {
+		return err
+	}
+	tlsConn.Write(testMessage)
+
+	buf := make([]byte, len(testMessage))
+	_, err := io.ReadFull(tlsConn, buf)
+	if err != nil {
+		return err
+	}
+
+	for i, v := range buf {
+		if v != testMessage[i]^0xff {
+			return fmt.Errorf("bad reply contents at byte %d", i)
+		}
+	}
+
+	return nil
+}
+
+func valgrindOf(dbAttach bool, baseArgs ...string) *exec.Cmd {
+	args := []string{"--error-exitcode=99", "--track-origins=yes", "--leak-check=full"}
+	if dbAttach {
+		args = append(args, "--db-attach=yes", "--db-command=xterm -e gdb -nw %f %p")
+	}
+	args = append(args, baseArgs...)
+
+	return exec.Command("valgrind", args...)
+}
+
+func gdbOf(baseArgs ...string) *exec.Cmd {
+	args := []string{"-e", "gdb", "--args"}
+	args = append(args, baseArgs...)
+
+	return exec.Command("xterm", args...)
+}
+
+func runTest(test *testCase) error {
+	socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
+	if err != nil {
+		panic(err)
+	}
+
+	syscall.CloseOnExec(socks[0])
+	syscall.CloseOnExec(socks[1])
+	clientEnd := os.NewFile(uintptr(socks[0]), "client end")
+	connFile := os.NewFile(uintptr(socks[1]), "our end")
+	conn, err := net.FileConn(connFile)
+	connFile.Close()
+	if err != nil {
+		panic(err)
+	}
+
+	const shim_path = "../../../build/ssl/test/client_shim"
+	var client *exec.Cmd
+	if *useValgrind {
+		client = valgrindOf(false, shim_path)
+	} else {
+		client = exec.Command(shim_path)
+	}
+	//client := gdbOf(shim_path)
+	client.ExtraFiles = []*os.File{clientEnd}
+	client.Stdin = os.Stdin
+	var stdoutBuf, stderrBuf bytes.Buffer
+	client.Stdout = &stdoutBuf
+	client.Stderr = &stderrBuf
+
+	if err := client.Start(); err != nil {
+		panic(err)
+	}
+	clientEnd.Close()
+
+	config := test.config
+	if len(config.Certificates) == 0 {
+		config.Certificates = []Certificate{getRSACertificate()}
+	}
+
+	tlsConn := Server(conn, &config)
+	err = doExchange(tlsConn)
+
+	conn.Close()
+	childErr := client.Wait()
+
+	stdout := string(stdoutBuf.Bytes())
+	stderr := string(stderrBuf.Bytes())
+	failed := err != nil || childErr != nil
+	correctFailure := len(test.expectedError) == 0 || strings.Contains(stdout, test.expectedError)
+
+	if failed != test.shouldFail || failed && !correctFailure {
+		localError := "none"
+		childError := "none"
+		if err != nil {
+			localError = err.Error()
+		}
+		if childErr != nil {
+			childError = childErr.Error()
+		}
+
+		var msg string
+		switch {
+		case failed && !test.shouldFail:
+			msg = "unexpected failure"
+		case !failed && test.shouldFail:
+			msg = "unexpected success"
+		case failed && !correctFailure:
+			msg = "bad error (wanted '" + test.expectedError + "')"
+		default:
+			panic("internal error")
+		}
+
+		return fmt.Errorf("%s: local error '%s', child error '%s', stdout:\n%s\nstderr:\n%s", msg, localError, childError, string(stdoutBuf.Bytes()), stderr)
+	}
+
+	if !*useValgrind && len(stderr) > 0 {
+		println(stderr)
+	}
+
+	return nil
+}
+
+var tlsVersions = []struct {
+	name    string
+	version uint16
+}{
+	{"SSL3", VersionSSL30},
+	{"TLS1", VersionTLS10},
+	{"TLS11", VersionTLS11},
+	{"TLS12", VersionTLS12},
+}
+
+var testCipherSuites = []struct {
+	name string
+	id   uint16
+}{
+	{"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+	{"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
+	{"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
+	{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+	{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
+	{"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+	{"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
+	{"ECDHE-RSA-3DES-SHA", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
+	{"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+	{"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
+	{"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+	{"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+	{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+	{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
+	{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
+}
+
+func addCipherSuiteTests() {
+	for _, suite := range testCipherSuites {
+		var cert Certificate
+		if strings.Contains(suite.name, "ECDSA") {
+			cert = getECDSACertificate()
+		} else {
+			cert = getRSACertificate()
+		}
+
+		for _, ver := range tlsVersions {
+			if ver.version != VersionTLS12 && strings.HasSuffix(suite.name, "-GCM") {
+				continue
+			}
+
+			clientTests = append(clientTests, testCase{
+				name: ver.name + "-" + suite.name,
+				config: Config{
+					MinVersion:   ver.version,
+					MaxVersion:   ver.version,
+					CipherSuites: []uint16{suite.id},
+					Certificates: []Certificate{cert},
+				},
+			})
+		}
+	}
+}
+
+func addBadECDSASignatureTests() {
+	for badR := BadValue(1); badR < NumBadValues; badR++ {
+		for badS := BadValue(1); badS < NumBadValues; badS++ {
+			clientTests = append(clientTests, testCase{
+				name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
+				config: Config{
+					CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+					Certificates: []Certificate{getECDSACertificate()},
+					Bugs: ProtocolBugs{
+						BadECDSAR: badR,
+						BadECDSAS: badS,
+					},
+				},
+				shouldFail:    true,
+				expectedError: "SIGNATURE",
+			})
+		}
+	}
+}
+
+func worker(statusChan chan statusMsg, c chan *testCase, wg *sync.WaitGroup) {
+	defer wg.Done()
+
+	for test := range c {
+		statusChan <- statusMsg{test: test, started: true}
+		err := runTest(test)
+		statusChan <- statusMsg{test: test, err: err}
+	}
+}
+
+type statusMsg struct {
+	test    *testCase
+	started bool
+	err     error
+}
+
+func statusPrinter(doneChan chan struct{}, statusChan chan statusMsg, total int) {
+	var started, done, failed, lineLen int
+	defer close(doneChan)
+
+	for msg := range statusChan {
+		if msg.started {
+			started++
+		} else {
+			done++
+		}
+
+		fmt.Printf("\x1b[%dD\x1b[K", lineLen)
+
+		if msg.err != nil {
+			fmt.Printf("FAILED (%s)\n%s\n", msg.test.name, msg.err)
+			failed++
+		}
+		line := fmt.Sprintf("%d/%d/%d/%d", failed, done, started, total)
+		lineLen = len(line)
+		os.Stdout.WriteString(line)
+	}
+}
+
+func main() {
+	var flagTest *string = flag.String("test", "", "The name of a test to run, or empty to run all tests")
+
+	flag.Parse()
+
+	addCipherSuiteTests()
+	addBadECDSASignatureTests()
+
+	var wg sync.WaitGroup
+
+	const numWorkers = 64
+
+	statusChan := make(chan statusMsg, numWorkers)
+	testChan := make(chan *testCase, numWorkers)
+	doneChan := make(chan struct{})
+
+	go statusPrinter(doneChan, statusChan, len(clientTests))
+
+	for i := 0; i < numWorkers; i++ {
+		wg.Add(1)
+		go worker(statusChan, testChan, &wg)
+	}
+
+	for i := range clientTests {
+		if len(*flagTest) == 0 || *flagTest == clientTests[i].name {
+			testChan <- &clientTests[i]
+		}
+	}
+
+	close(testChan)
+	wg.Wait()
+	close(statusChan)
+	<-doneChan
+
+	fmt.Printf("\n")
+}