xref: /openbsd-src/regress/lib/libtls/gotls/tls_test.go (revision 7f9db3f57363babddf052875753bdd857fe7f6b2)
11e88be94Sjsingpackage tls
21e88be94Sjsing
31e88be94Sjsingimport (
40b17b726Sjsing	"crypto/tls"
51e88be94Sjsing	"encoding/pem"
61e88be94Sjsing	"fmt"
71e88be94Sjsing	"io/ioutil"
81e88be94Sjsing	"net/http"
91e88be94Sjsing	"net/http/httptest"
101e88be94Sjsing	"net/url"
111e88be94Sjsing	"os"
121e88be94Sjsing	"strings"
131e88be94Sjsing	"testing"
14c68aa4d5Sjsing	"time"
15c68aa4d5Sjsing)
16c68aa4d5Sjsing
17c68aa4d5Sjsingconst (
18c68aa4d5Sjsing	httpContent = "Hello, TLS!"
19c68aa4d5Sjsing
2099fe86a4Sjsing	certHash = "SHA256:1153aa0230ee0481b36bdd83ddb04b607340dbda35f3a4fff0615e4d9292d687"
21c68aa4d5Sjsing)
22c68aa4d5Sjsing
23c68aa4d5Sjsingvar (
24c68aa4d5Sjsing	certNotBefore = time.Unix(0, 0)
25c68aa4d5Sjsing	certNotAfter  = certNotBefore.Add(1000000 * time.Hour)
2699fe86a4Sjsing
2799fe86a4Sjsing	// Generated with:
2899fe86a4Sjsing	//   go run crypto/tls/generate_cert.go --rsa-bits 2048 \
2999fe86a4Sjsing	//     --host 127.0.0.1,::1,example.com --ca \
3099fe86a4Sjsing	//     --start-date "Jan 1 00:00:00 1970" --duration=1000000h`
3199fe86a4Sjsing	testServerCert = []byte(`-----BEGIN CERTIFICATE-----
3299fe86a4SjsingMIIDGTCCAgGgAwIBAgIRAJHZkrBTk/yTKT3L2Z+dgZcwDQYJKoZIhvcNAQELBQAw
3399fe86a4SjsingEjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2
3499fe86a4SjsingMDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEP
3599fe86a4SjsingADCCAQoCggEBANxPCe2pafj2pWdA+hnN+Ne9Auh2YdoSPbQqIPQMVTT/3j6w9LlW
3699fe86a4SjsingJirXCLWNuoarOA2iCgVa4Y607O/f2FTN7cKY2lvhAkuftCUJzB/lJVH5bWZgSrks
3799fe86a4Sjsing3AaOBlBcyMKBajFoEOIgSMwHGAZO2XsWIvdbuQw3EKY50vfBvxQspjbMruhpZoKd
3899fe86a4Sjsing9tHx6XUBoYSf5t9X+FrG2UjihnfcfBcsKGq7lbujt3+3QvlU6w1ZGOX+f9b+3+yw
3999fe86a4SjsingRQkswxvkzKpfmgvr8GWWUm8w9wkImhAmA2UAhsM8OwnKVltvMih5mb9L2hw5+qBV
4099fe86a4SjsingW1V+CSR0tDI9D8eiL26B3dvOilpZjttp3fsCAwEAAaNoMGYwDgYDVR0PAQH/BAQD
4199fe86a4SjsingAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wLgYDVR0R
4299fe86a4SjsingBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZI
4399fe86a4SjsinghvcNAQELBQADggEBAA+tFyWOZLoUjN2SKcIXnN5zs4VZedybLFVZoJSDakgo8awS
4499fe86a4SjsingHPkD/1ReIOzT41Hmzjs/4CeVw6FSeKnYtEqTPOJoRVrXAIqyHGHJ2cEWpUXvg2b0
4599fe86a4Sjsingu7lkFfElRqcBjsDZYr+rJUxkjlCa11ylCbgdwoDMIbKNldcJoLB0iwQWUE7j19xe
4699fe86a4SjsingCF32aISt/nGxCYcO81tn+ionwzZyf5zh5k/SmAqrPy4O/qxn8oEaox4Z7BfoZlAS
4799fe86a4SjsinggmPA2gedTWORfthamJdT2irz3rdHjV7NWxwTsgOAx9y+P3fqmMCyMwxFJkmP118W
4899fe86a4SjsingyM5xDRR+ldYKoRts5qkPR6LVtCw9kn+dJKQm0Bc=
4999fe86a4Sjsing-----END CERTIFICATE-----`)
5099fe86a4Sjsing	testServerKey = []byte(`-----BEGIN PRIVATE KEY-----
5199fe86a4SjsingMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcTwntqWn49qVn
5299fe86a4SjsingQPoZzfjXvQLodmHaEj20KiD0DFU0/94+sPS5ViYq1wi1jbqGqzgNogoFWuGOtOzv
5399fe86a4Sjsing39hUze3CmNpb4QJLn7QlCcwf5SVR+W1mYEq5LNwGjgZQXMjCgWoxaBDiIEjMBxgG
5499fe86a4SjsingTtl7FiL3W7kMNxCmOdL3wb8ULKY2zK7oaWaCnfbR8el1AaGEn+bfV/haxtlI4oZ3
5599fe86a4Sjsing3HwXLChqu5W7o7d/t0L5VOsNWRjl/n/W/t/ssEUJLMMb5MyqX5oL6/BlllJvMPcJ
5699fe86a4SjsingCJoQJgNlAIbDPDsJylZbbzIoeZm/S9ocOfqgVVtVfgkkdLQyPQ/Hoi9ugd3bzopa
5799fe86a4SjsingWY7bad37AgMBAAECggEAKSmnbD1sLHVBIFK2qB2g8gZBxddgnxMrbj802wR24ykv
5899fe86a4SjsingiD0d7IcZKIX2/Z0WjdTt6zYscyWw4S4S2xrS272CQAq5OdOHz0NusEDtX8Q7vd5B
5999fe86a4Sjsingv5AcRg8IqTzeFyPO6vCtO7/675UipORqa7tNzT6sl9UOdSbQuI4zSdFsd0OEZtZs
6099fe86a4SjsingoqKkv+jdvKaVJQ1vsoQSup23V0bvVCRydBNFZ2mQ3etZcRRYXyu1digJ7/oMyCHf
6199fe86a4Sjsing1F37lJmjPJ8WwsGJMk2ngJiUOQx21bbTZ22c/8sMMLJjhhC2qu984keVRanSsJwC
6299fe86a4SjsingZ80XcCxL/yoLF42A5ReMtutFs83rW7VX7VJGxoOaKQKBgQD91dCs9jGBVxHr4vxy
6399fe86a4SjsingNJC2n92R5/JpqXygXS3L6RDP+we6p/fmSd4/QllwIVeC9kepsFz4//ArmLOy9JHu
6499fe86a4SjsingrkXa7W9G+XbmYXSftmG78roLfAtvdudoytLQJg2bu8J3bzPVibRCUq0OORFyqOHR
6599fe86a4SjsingQGcQtvPxwFHctIkOjajbLpbL7QKBgQDeMAbvjzD8wU1gp2U8Bl5l5ohYgQpcs15R
6699fe86a4SjsingeBPS5DlRzICAeuQWi+BRjW5BPZVmTr3Ml3KiMWcalXMeH1TKoPON8RjmWgY2Fxvh
6799fe86a4SjsingnS7gV+rJm4H0T+bBEXNAraracwGYd6JgcH9BPD9znHRmyFR4pMPqkSa7o/OExH6W
6899fe86a4SjsingO32KqTMkhwKBgQCoX7wb/vK3qNnqbpal6thTS5fdwM276QESHrzSFbdhPlLSLbjy
6999fe86a4SjsinguO0DaS+KgZNa+6JtnN8PDDZztMb+XdyvRkpv/i9iFPgZuWtyxbfuxANEuvOa7HRz
7099fe86a4SjsingvpY4HAXK17EXKFxpuP4pQE4qsRAxznR8KQw0uib2pWunytlfHfhz62N7wQKBgQC+
7199fe86a4Sjsing+TTc74zBkzx42SiwYSD+IRoMSE2pxBpLmBQh7jw+TLIevIITxwJ11kRwGwiwuPl2
7299fe86a4SjsingQq4rLp9aQB6EQ5XT3Ge7FwG57KLuFwrF7x59gdOymdEnNw414FPZwevae4Nhk2Kj
7399fe86a4Sjsing1c3rOmenbVC3j3TbhXNHyJ8sJQ2IjoPniRas+iWVPQKBgQDcZzKh6U+e9efYLAt0
7499fe86a4SjsingqdaKhm5MCAgzD9X/Tx2OvOqgWnSXt2Q2AhK2UsHnrGBn1SDNTNDGlniQy2OM2Ywn
7599fe86a4Sjsingn71nH1QUmgoiwBrFUh0gLxv878vwgUATqfFRTlirmK9XxHuTX9Jh6elmRebjYWyc
7699fe86a4SjsingOo0CJBeMABu71Y+VkCxURT1bzw==
7799fe86a4Sjsing-----END PRIVATE KEY-----`)
781e88be94Sjsing)
791e88be94Sjsing
800b17b726Sjsingtype handshakeError string
810b17b726Sjsing
820b17b726Sjsingfunc (he handshakeError) Error() string {
830b17b726Sjsing	return string(he)
840b17b726Sjsing}
850b17b726Sjsing
861e88be94Sjsing// createCAFile writes a PEM encoded version of the certificate out to a
871e88be94Sjsing// temporary file, for use by libtls.
881e88be94Sjsingfunc createCAFile(cert []byte) (string, error) {
891e88be94Sjsing	f, err := ioutil.TempFile("", "tls")
901e88be94Sjsing	if err != nil {
911e88be94Sjsing		return "", fmt.Errorf("failed to create file: %v", err)
921e88be94Sjsing	}
931e88be94Sjsing	defer f.Close()
941e88be94Sjsing	block := &pem.Block{
951e88be94Sjsing		Type:  "CERTIFICATE",
961e88be94Sjsing		Bytes: cert,
971e88be94Sjsing	}
981e88be94Sjsing	if err := pem.Encode(f, block); err != nil {
991e88be94Sjsing		return "", fmt.Errorf("failed to encode certificate: %v", err)
1001e88be94Sjsing	}
1011e88be94Sjsing	return f.Name(), nil
1021e88be94Sjsing}
1031e88be94Sjsing
1040b17b726Sjsingfunc newTestServer(tlsCfg *tls.Config) (*httptest.Server, *url.URL, string, error) {
1050b17b726Sjsing	ts := httptest.NewUnstartedServer(
1061e88be94Sjsing		http.HandlerFunc(
1071e88be94Sjsing			func(w http.ResponseWriter, r *http.Request) {
1081e88be94Sjsing				fmt.Fprintln(w, httpContent)
1091e88be94Sjsing			},
1101e88be94Sjsing		),
1111e88be94Sjsing	)
11299fe86a4Sjsing	if tlsCfg == nil {
11399fe86a4Sjsing		tlsCfg = &tls.Config{}
11499fe86a4Sjsing	}
11599fe86a4Sjsing	if len(tlsCfg.Certificates) == 0 {
11699fe86a4Sjsing		cert, err := tls.X509KeyPair(testServerCert, testServerKey)
11799fe86a4Sjsing		if err != nil {
11899fe86a4Sjsing			return nil, nil, "", fmt.Errorf("failed to load key pair: %v", err)
11999fe86a4Sjsing		}
12099fe86a4Sjsing		tlsCfg.Certificates = []tls.Certificate{cert}
12199fe86a4Sjsing	}
1220b17b726Sjsing	ts.TLS = tlsCfg
1230b17b726Sjsing	ts.StartTLS()
1241e88be94Sjsing
1251e88be94Sjsing	u, err := url.Parse(ts.URL)
1261e88be94Sjsing	if err != nil {
127c68aa4d5Sjsing		return nil, nil, "", fmt.Errorf("failed to parse URL %q: %v", ts.URL, err)
1281e88be94Sjsing	}
1291e88be94Sjsing
1301e88be94Sjsing	caFile, err := createCAFile(ts.TLS.Certificates[0].Certificate[0])
1311e88be94Sjsing	if err != nil {
132c68aa4d5Sjsing		return nil, nil, "", fmt.Errorf("failed to create CA file: %v", err)
133c68aa4d5Sjsing	}
134c68aa4d5Sjsing
135c68aa4d5Sjsing	return ts, u, caFile, nil
136c68aa4d5Sjsing}
137c68aa4d5Sjsing
1380b17b726Sjsingfunc handshakeVersionTest(tlsCfg *tls.Config) (ProtocolVersion, error) {
1390b17b726Sjsing	ts, u, caFile, err := newTestServer(tlsCfg)
1400b17b726Sjsing	if err != nil {
1410b17b726Sjsing		return 0, fmt.Errorf("failed to start test server: %v", err)
1420b17b726Sjsing	}
1430b17b726Sjsing	defer os.Remove(caFile)
1440b17b726Sjsing	defer ts.Close()
1450b17b726Sjsing
1460b17b726Sjsing	if err := Init(); err != nil {
1470b17b726Sjsing		return 0, err
1480b17b726Sjsing	}
1490b17b726Sjsing
1500b17b726Sjsing	cfg, err := NewConfig()
1510b17b726Sjsing	if err != nil {
1520b17b726Sjsing		return 0, err
1530b17b726Sjsing	}
1540b17b726Sjsing	defer cfg.Free()
1550b17b726Sjsing	if err := cfg.SetCAFile(caFile); err != nil {
1560b17b726Sjsing		return 0, err
1570b17b726Sjsing	}
1580b17b726Sjsing	if err := cfg.SetCiphers("compat"); err != nil {
1590b17b726Sjsing		return 0, err
1600b17b726Sjsing	}
1610b17b726Sjsing	if err := cfg.SetProtocols(ProtocolsAll); err != nil {
1620b17b726Sjsing		return 0, err
1630b17b726Sjsing	}
1640b17b726Sjsing
1650b17b726Sjsing	tls, err := NewClient(cfg)
1660b17b726Sjsing	if err != nil {
1670b17b726Sjsing		return 0, err
1680b17b726Sjsing	}
1690b17b726Sjsing	defer tls.Free()
1700b17b726Sjsing
1710b17b726Sjsing	if err := tls.Connect(u.Host, ""); err != nil {
1720b17b726Sjsing		return 0, err
1730b17b726Sjsing	}
1740b17b726Sjsing	if err := tls.Handshake(); err != nil {
1750b17b726Sjsing		return 0, handshakeError(err.Error())
1760b17b726Sjsing	}
1770b17b726Sjsing	version, err := tls.ConnVersion()
1780b17b726Sjsing	if err != nil {
1790b17b726Sjsing		return 0, err
1800b17b726Sjsing	}
1810b17b726Sjsing	if err := tls.Close(); err != nil {
1820b17b726Sjsing		return 0, err
1830b17b726Sjsing	}
1840b17b726Sjsing	return version, nil
1850b17b726Sjsing}
1860b17b726Sjsing
187c68aa4d5Sjsingfunc TestTLSBasic(t *testing.T) {
1880b17b726Sjsing	ts, u, caFile, err := newTestServer(nil)
189c68aa4d5Sjsing	if err != nil {
190c68aa4d5Sjsing		t.Fatalf("Failed to start test server: %v", err)
1911e88be94Sjsing	}
1921e88be94Sjsing	defer os.Remove(caFile)
193c68aa4d5Sjsing	defer ts.Close()
1941e88be94Sjsing
1951e88be94Sjsing	if err := Init(); err != nil {
1961e88be94Sjsing		t.Fatal(err)
1971e88be94Sjsing	}
1981e88be94Sjsing
1991e88be94Sjsing	cfg, err := NewConfig()
2001e88be94Sjsing	if err != nil {
2011e88be94Sjsing		t.Fatal(err)
2021e88be94Sjsing	}
2031e88be94Sjsing	defer cfg.Free()
2046cbf0df4Sjsing	if err := cfg.SetCAFile(caFile); err != nil {
2056cbf0df4Sjsing		t.Fatal(err)
2066cbf0df4Sjsing	}
2071e88be94Sjsing
2081e88be94Sjsing	tls, err := NewClient(cfg)
2091e88be94Sjsing	if err != nil {
2101e88be94Sjsing		t.Fatal(err)
2111e88be94Sjsing	}
2121e88be94Sjsing	defer tls.Free()
2131e88be94Sjsing
2141e88be94Sjsing	t.Logf("Connecting to %s", u.Host)
2151e88be94Sjsing
2161e88be94Sjsing	if err := tls.Connect(u.Host, ""); err != nil {
2171e88be94Sjsing		t.Fatal(err)
2181e88be94Sjsing	}
2191e88be94Sjsing	defer func() {
2201e88be94Sjsing		if err := tls.Close(); err != nil {
22163818bffSjsing			t.Fatalf("Close failed: %v", err)
2221e88be94Sjsing		}
2231e88be94Sjsing	}()
2241e88be94Sjsing
2251e88be94Sjsing	n, err := tls.Write([]byte("GET / HTTP/1.0\n\n"))
2261e88be94Sjsing	if err != nil {
2271e88be94Sjsing		t.Fatal(err)
2281e88be94Sjsing	}
2291e88be94Sjsing	t.Logf("Wrote %d bytes...", n)
2301e88be94Sjsing
2311e88be94Sjsing	buf := make([]byte, 1024)
2321e88be94Sjsing	n, err = tls.Read(buf)
2331e88be94Sjsing	if err != nil {
2341e88be94Sjsing		t.Fatal(err)
2351e88be94Sjsing	}
2361e88be94Sjsing	t.Logf("Read %d bytes...", n)
2371e88be94Sjsing
2381e88be94Sjsing	if !strings.Contains(string(buf), httpContent) {
2391e88be94Sjsing		t.Errorf("Response does not contain %q", httpContent)
2401e88be94Sjsing	}
2411e88be94Sjsing}
242c68aa4d5Sjsing
2430b17b726Sjsingfunc TestTLSVersions(t *testing.T) {
2440b17b726Sjsing	tests := []struct {
2450b17b726Sjsing		minVersion       uint16
2460b17b726Sjsing		maxVersion       uint16
2470b17b726Sjsing		wantVersion      ProtocolVersion
2480b17b726Sjsing		wantHandshakeErr bool
2490b17b726Sjsing	}{
2504f528881Sjsing		{tls.VersionTLS10, tls.VersionTLS13, ProtocolTLSv13, false},
2510b17b726Sjsing		{tls.VersionSSL30, tls.VersionTLS12, ProtocolTLSv12, false},
2520b17b726Sjsing		{tls.VersionTLS10, tls.VersionTLS12, ProtocolTLSv12, false},
2530b17b726Sjsing		{tls.VersionTLS11, tls.VersionTLS12, ProtocolTLSv12, false},
2545c389b79Sbeck		{tls.VersionSSL30, tls.VersionTLS11, ProtocolTLSv11, true},
2555c389b79Sbeck		{tls.VersionSSL30, tls.VersionTLS10, ProtocolTLSv10, true},
2560b17b726Sjsing		{tls.VersionSSL30, tls.VersionSSL30, 0, true},
2575c389b79Sbeck		{tls.VersionTLS10, tls.VersionTLS10, ProtocolTLSv10, true},
2585c389b79Sbeck		{tls.VersionTLS11, tls.VersionTLS11, ProtocolTLSv11, true},
2590b17b726Sjsing		{tls.VersionTLS12, tls.VersionTLS12, ProtocolTLSv12, false},
2600b17b726Sjsing	}
2610b17b726Sjsing	for i, test := range tests {
2620b17b726Sjsing		t.Logf("Testing handshake with protocols %x:%x", test.minVersion, test.maxVersion)
2630b17b726Sjsing		tlsCfg := &tls.Config{
2640b17b726Sjsing			MinVersion: test.minVersion,
2650b17b726Sjsing			MaxVersion: test.maxVersion,
2660b17b726Sjsing		}
2670b17b726Sjsing		version, err := handshakeVersionTest(tlsCfg)
2680b17b726Sjsing		switch {
2690b17b726Sjsing		case test.wantHandshakeErr && err == nil:
2700b17b726Sjsing			t.Errorf("Test %d - handshake %x:%x succeeded, want handshake error",
2710b17b726Sjsing				i, test.minVersion, test.maxVersion)
2720b17b726Sjsing		case test.wantHandshakeErr && err != nil:
2730b17b726Sjsing			if _, ok := err.(handshakeError); !ok {
2740b17b726Sjsing				t.Errorf("Test %d - handshake %x:%x; got unknown error, want handshake error: %v",
2750b17b726Sjsing					i, test.minVersion, test.maxVersion, err)
2760b17b726Sjsing			}
2770b17b726Sjsing		case !test.wantHandshakeErr && err != nil:
2780b17b726Sjsing			t.Errorf("Test %d - handshake %x:%x failed: %v", i, test.minVersion, test.maxVersion, err)
2790b17b726Sjsing		case !test.wantHandshakeErr && err == nil:
2800b17b726Sjsing			if got, want := version, test.wantVersion; got != want {
2810b17b726Sjsing				t.Errorf("Test %d - handshake %x:%x; got protocol version %v, want %v",
2820b17b726Sjsing					i, test.minVersion, test.maxVersion, got, want)
2830b17b726Sjsing			}
2840b17b726Sjsing		}
2850b17b726Sjsing	}
2860b17b726Sjsing}
2870b17b726Sjsing
2887396c4efSjsingfunc TestTLSSingleByteReadWrite(t *testing.T) {
2890b17b726Sjsing	ts, u, caFile, err := newTestServer(nil)
2907396c4efSjsing	if err != nil {
2917396c4efSjsing		t.Fatalf("Failed to start test server: %v", err)
2927396c4efSjsing	}
2937396c4efSjsing	defer os.Remove(caFile)
2947396c4efSjsing	defer ts.Close()
2957396c4efSjsing
2967396c4efSjsing	if err := Init(); err != nil {
2977396c4efSjsing		t.Fatal(err)
2987396c4efSjsing	}
2997396c4efSjsing
3007396c4efSjsing	cfg, err := NewConfig()
3017396c4efSjsing	if err != nil {
3027396c4efSjsing		t.Fatal(err)
3037396c4efSjsing	}
3047396c4efSjsing	defer cfg.Free()
3056cbf0df4Sjsing	if err := cfg.SetCAFile(caFile); err != nil {
3066cbf0df4Sjsing		t.Fatal(err)
3076cbf0df4Sjsing	}
3087396c4efSjsing
3097396c4efSjsing	tls, err := NewClient(cfg)
3107396c4efSjsing	if err != nil {
3117396c4efSjsing		t.Fatal(err)
3127396c4efSjsing	}
3137396c4efSjsing	defer tls.Free()
3147396c4efSjsing
3157396c4efSjsing	t.Logf("Connecting to %s", u.Host)
3167396c4efSjsing
3177396c4efSjsing	if err := tls.Connect(u.Host, ""); err != nil {
3187396c4efSjsing		t.Fatal(err)
3197396c4efSjsing	}
3207396c4efSjsing	defer func() {
3217396c4efSjsing		if err := tls.Close(); err != nil {
3227396c4efSjsing			t.Fatalf("Close failed: %v", err)
3237396c4efSjsing		}
3247396c4efSjsing	}()
3257396c4efSjsing
3267396c4efSjsing	for _, b := range []byte("GET / HTTP/1.0\n\n") {
3277396c4efSjsing		n, err := tls.Write([]byte{b})
3287396c4efSjsing		if err != nil {
3297396c4efSjsing			t.Fatal(err)
3307396c4efSjsing		}
3317396c4efSjsing		if n != 1 {
3327396c4efSjsing			t.Fatalf("Wrote byte %v, got length %d, want 1", b, n)
3337396c4efSjsing		}
3347396c4efSjsing	}
3357396c4efSjsing
3367396c4efSjsing	var body []byte
3377396c4efSjsing	for {
3387396c4efSjsing		buf := make([]byte, 1)
3397396c4efSjsing		n, err := tls.Read(buf)
3407396c4efSjsing		if err != nil {
3417396c4efSjsing			t.Fatal(err)
3427396c4efSjsing		}
3437396c4efSjsing		if n == 0 {
3447396c4efSjsing			break
3457396c4efSjsing		}
3467396c4efSjsing		if n != 1 {
3477396c4efSjsing			t.Fatalf("Read single byte, got length %d, want 1", n)
3487396c4efSjsing		}
3497396c4efSjsing		body = append(body, buf...)
3507396c4efSjsing	}
3517396c4efSjsing
3527396c4efSjsing	if !strings.Contains(string(body), httpContent) {
3537396c4efSjsing		t.Errorf("Response does not contain %q", httpContent)
3547396c4efSjsing	}
3557396c4efSjsing}
3567396c4efSjsing
357c68aa4d5Sjsingfunc TestTLSInfo(t *testing.T) {
3580b17b726Sjsing	ts, u, caFile, err := newTestServer(nil)
359c68aa4d5Sjsing	if err != nil {
360c68aa4d5Sjsing		t.Fatalf("Failed to start test server: %v", err)
361c68aa4d5Sjsing	}
362c68aa4d5Sjsing	defer os.Remove(caFile)
363c68aa4d5Sjsing	defer ts.Close()
364c68aa4d5Sjsing
365c68aa4d5Sjsing	if err := Init(); err != nil {
366c68aa4d5Sjsing		t.Fatal(err)
367c68aa4d5Sjsing	}
368c68aa4d5Sjsing
369c68aa4d5Sjsing	cfg, err := NewConfig()
370c68aa4d5Sjsing	if err != nil {
371c68aa4d5Sjsing		t.Fatal(err)
372c68aa4d5Sjsing	}
373c68aa4d5Sjsing	defer cfg.Free()
3746cbf0df4Sjsing	if err := cfg.SetCAFile(caFile); err != nil {
3756cbf0df4Sjsing		t.Fatal(err)
3766cbf0df4Sjsing	}
377c68aa4d5Sjsing
378c68aa4d5Sjsing	tls, err := NewClient(cfg)
379c68aa4d5Sjsing	if err != nil {
380c68aa4d5Sjsing		t.Fatal(err)
381c68aa4d5Sjsing	}
382c68aa4d5Sjsing	defer tls.Free()
383c68aa4d5Sjsing
384c68aa4d5Sjsing	t.Logf("Connecting to %s", u.Host)
385c68aa4d5Sjsing
386c68aa4d5Sjsing	if err := tls.Connect(u.Host, ""); err != nil {
387c68aa4d5Sjsing		t.Fatal(err)
388c68aa4d5Sjsing	}
389c68aa4d5Sjsing	defer func() {
390c68aa4d5Sjsing		if err := tls.Close(); err != nil {
391c68aa4d5Sjsing			t.Fatalf("Close failed: %v", err)
392c68aa4d5Sjsing		}
393c68aa4d5Sjsing	}()
394c68aa4d5Sjsing
395c68aa4d5Sjsing	// All of these should fail since the handshake has not completed.
396c68aa4d5Sjsing	if _, err := tls.ConnVersion(); err == nil {
397c68aa4d5Sjsing		t.Error("ConnVersion() return nil error, want error")
398c68aa4d5Sjsing	}
399c68aa4d5Sjsing	if _, err := tls.ConnCipher(); err == nil {
400c68aa4d5Sjsing		t.Error("ConnCipher() return nil error, want error")
401c68aa4d5Sjsing	}
402b97dc7d2Sjsing	if _, err := tls.ConnCipherStrength(); err == nil {
403b97dc7d2Sjsing		t.Error("ConnCipherStrength() return nil error, want error")
404b97dc7d2Sjsing	}
405c68aa4d5Sjsing
406c68aa4d5Sjsing	if got, want := tls.PeerCertProvided(), false; got != want {
407c68aa4d5Sjsing		t.Errorf("PeerCertProvided() = %v, want %v", got, want)
408c68aa4d5Sjsing	}
409c68aa4d5Sjsing	for _, name := range []string{"127.0.0.1", "::1", "example.com"} {
410c68aa4d5Sjsing		if got, want := tls.PeerCertContainsName(name), false; got != want {
411c68aa4d5Sjsing			t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want)
412c68aa4d5Sjsing		}
413c68aa4d5Sjsing	}
414c68aa4d5Sjsing
415c68aa4d5Sjsing	if _, err := tls.PeerCertIssuer(); err == nil {
416c68aa4d5Sjsing		t.Error("PeerCertIssuer() returned nil error, want error")
417c68aa4d5Sjsing	}
418c68aa4d5Sjsing	if _, err := tls.PeerCertSubject(); err == nil {
419c68aa4d5Sjsing		t.Error("PeerCertSubject() returned nil error, want error")
420c68aa4d5Sjsing	}
421*7f9db3f5Stb	if _, err := tls.PeerCertCommonName(); err == nil {
422*7f9db3f5Stb		t.Error("PeerCertCommonName() returned nil error, want error")
423*7f9db3f5Stb	}
424c68aa4d5Sjsing	if _, err := tls.PeerCertHash(); err == nil {
425c68aa4d5Sjsing		t.Error("PeerCertHash() returned nil error, want error")
426c68aa4d5Sjsing	}
427c68aa4d5Sjsing	if _, err := tls.PeerCertNotBefore(); err == nil {
428c68aa4d5Sjsing		t.Error("PeerCertNotBefore() returned nil error, want error")
429c68aa4d5Sjsing	}
430c68aa4d5Sjsing	if _, err := tls.PeerCertNotAfter(); err == nil {
431c68aa4d5Sjsing		t.Error("PeerCertNotAfter() returned nil error, want error")
432c68aa4d5Sjsing	}
433c68aa4d5Sjsing
434c68aa4d5Sjsing	// Complete the handshake...
435c68aa4d5Sjsing	if err := tls.Handshake(); err != nil {
436c68aa4d5Sjsing		t.Fatalf("Handshake failed: %v", err)
437c68aa4d5Sjsing	}
438c68aa4d5Sjsing
439c68aa4d5Sjsing	if version, err := tls.ConnVersion(); err != nil {
440b97dc7d2Sjsing		t.Errorf("ConnVersion() returned error: %v", err)
441c68aa4d5Sjsing	} else {
442c68aa4d5Sjsing		t.Logf("Protocol version: %v", version)
443c68aa4d5Sjsing	}
444c68aa4d5Sjsing	if cipher, err := tls.ConnCipher(); err != nil {
445b97dc7d2Sjsing		t.Errorf("ConnCipher() returned error: %v", err)
446c68aa4d5Sjsing	} else {
447c68aa4d5Sjsing		t.Logf("Cipher: %v", cipher)
448c68aa4d5Sjsing	}
449b97dc7d2Sjsing	if strength, err := tls.ConnCipherStrength(); err != nil {
450b97dc7d2Sjsing		t.Errorf("ConnCipherStrength() return ederror: %v", err)
451b97dc7d2Sjsing	} else {
452b97dc7d2Sjsing		t.Logf("Cipher Strength: %v bits", strength)
453b97dc7d2Sjsing	}
454c68aa4d5Sjsing
455c68aa4d5Sjsing	if got, want := tls.PeerCertProvided(), true; got != want {
456c68aa4d5Sjsing		t.Errorf("PeerCertProvided() = %v, want %v", got, want)
457c68aa4d5Sjsing	}
458c68aa4d5Sjsing	for _, name := range []string{"127.0.0.1", "::1", "example.com"} {
459c68aa4d5Sjsing		if got, want := tls.PeerCertContainsName(name), true; got != want {
460c68aa4d5Sjsing			t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want)
461c68aa4d5Sjsing		}
462c68aa4d5Sjsing	}
463c68aa4d5Sjsing
464c68aa4d5Sjsing	if issuer, err := tls.PeerCertIssuer(); err != nil {
465c68aa4d5Sjsing		t.Errorf("PeerCertIssuer() returned error: %v", err)
466c68aa4d5Sjsing	} else {
467c68aa4d5Sjsing		t.Logf("Issuer: %v", issuer)
468c68aa4d5Sjsing	}
469c68aa4d5Sjsing	if subject, err := tls.PeerCertSubject(); err != nil {
470c68aa4d5Sjsing		t.Errorf("PeerCertSubject() returned error: %v", err)
471c68aa4d5Sjsing	} else {
472c68aa4d5Sjsing		t.Logf("Subject: %v", subject)
473c68aa4d5Sjsing	}
474*7f9db3f5Stb	if commonName, err := tls.PeerCertCommonName(); err != nil {
475*7f9db3f5Stb		t.Errorf("PeerCertCommonName() returned error: %v", err)
476*7f9db3f5Stb	} else {
477*7f9db3f5Stb		t.Logf("Subject: %v", commonName)
478*7f9db3f5Stb	}
479c68aa4d5Sjsing	if hash, err := tls.PeerCertHash(); err != nil {
480c68aa4d5Sjsing		t.Errorf("PeerCertHash() returned error: %v", err)
481c68aa4d5Sjsing	} else if hash != certHash {
482c68aa4d5Sjsing		t.Errorf("Got cert hash %q, want %q", hash, certHash)
483c68aa4d5Sjsing	} else {
484c68aa4d5Sjsing		t.Logf("Hash: %v", hash)
485c68aa4d5Sjsing	}
486c68aa4d5Sjsing	if notBefore, err := tls.PeerCertNotBefore(); err != nil {
487c68aa4d5Sjsing		t.Errorf("PeerCertNotBefore() returned error: %v", err)
488c68aa4d5Sjsing	} else if !certNotBefore.Equal(notBefore) {
489c68aa4d5Sjsing		t.Errorf("Got cert notBefore %v, want %v", notBefore.UTC(), certNotBefore.UTC())
490c68aa4d5Sjsing	} else {
491c68aa4d5Sjsing		t.Logf("NotBefore: %v", notBefore.UTC())
492c68aa4d5Sjsing	}
493c68aa4d5Sjsing	if notAfter, err := tls.PeerCertNotAfter(); err != nil {
494c68aa4d5Sjsing		t.Errorf("PeerCertNotAfter() returned error: %v", err)
495c68aa4d5Sjsing	} else if !certNotAfter.Equal(notAfter) {
496c68aa4d5Sjsing		t.Errorf("Got cert notAfter %v, want %v", notAfter.UTC(), certNotAfter.UTC())
497c68aa4d5Sjsing	} else {
498c68aa4d5Sjsing		t.Logf("NotAfter: %v", notAfter.UTC())
499c68aa4d5Sjsing	}
500c68aa4d5Sjsing}
501