xref: /openbsd/regress/lib/libtls/gotls/tls_test.go (revision 73471bf0)
1package tls
2
3import (
4	"crypto/tls"
5	"encoding/pem"
6	"fmt"
7	"io/ioutil"
8	"net/http"
9	"net/http/httptest"
10	"net/url"
11	"os"
12	"strings"
13	"testing"
14	"time"
15)
16
17const (
18	httpContent = "Hello, TLS!"
19
20	certHash = "SHA256:1153aa0230ee0481b36bdd83ddb04b607340dbda35f3a4fff0615e4d9292d687"
21)
22
23var (
24	certNotBefore = time.Unix(0, 0)
25	certNotAfter  = certNotBefore.Add(1000000 * time.Hour)
26
27	// Generated with:
28	//   go run crypto/tls/generate_cert.go --rsa-bits 2048 \
29	//     --host 127.0.0.1,::1,example.com --ca \
30	//     --start-date "Jan 1 00:00:00 1970" --duration=1000000h`
31	testServerCert = []byte(`-----BEGIN CERTIFICATE-----
32MIIDGTCCAgGgAwIBAgIRAJHZkrBTk/yTKT3L2Z+dgZcwDQYJKoZIhvcNAQELBQAw
33EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2
34MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEP
35ADCCAQoCggEBANxPCe2pafj2pWdA+hnN+Ne9Auh2YdoSPbQqIPQMVTT/3j6w9LlW
36JirXCLWNuoarOA2iCgVa4Y607O/f2FTN7cKY2lvhAkuftCUJzB/lJVH5bWZgSrks
373AaOBlBcyMKBajFoEOIgSMwHGAZO2XsWIvdbuQw3EKY50vfBvxQspjbMruhpZoKd
389tHx6XUBoYSf5t9X+FrG2UjihnfcfBcsKGq7lbujt3+3QvlU6w1ZGOX+f9b+3+yw
39RQkswxvkzKpfmgvr8GWWUm8w9wkImhAmA2UAhsM8OwnKVltvMih5mb9L2hw5+qBV
40W1V+CSR0tDI9D8eiL26B3dvOilpZjttp3fsCAwEAAaNoMGYwDgYDVR0PAQH/BAQD
41AgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wLgYDVR0R
42BCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZI
43hvcNAQELBQADggEBAA+tFyWOZLoUjN2SKcIXnN5zs4VZedybLFVZoJSDakgo8awS
44HPkD/1ReIOzT41Hmzjs/4CeVw6FSeKnYtEqTPOJoRVrXAIqyHGHJ2cEWpUXvg2b0
45u7lkFfElRqcBjsDZYr+rJUxkjlCa11ylCbgdwoDMIbKNldcJoLB0iwQWUE7j19xe
46CF32aISt/nGxCYcO81tn+ionwzZyf5zh5k/SmAqrPy4O/qxn8oEaox4Z7BfoZlAS
47gmPA2gedTWORfthamJdT2irz3rdHjV7NWxwTsgOAx9y+P3fqmMCyMwxFJkmP118W
48yM5xDRR+ldYKoRts5qkPR6LVtCw9kn+dJKQm0Bc=
49-----END CERTIFICATE-----`)
50	testServerKey = []byte(`-----BEGIN PRIVATE KEY-----
51MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcTwntqWn49qVn
52QPoZzfjXvQLodmHaEj20KiD0DFU0/94+sPS5ViYq1wi1jbqGqzgNogoFWuGOtOzv
5339hUze3CmNpb4QJLn7QlCcwf5SVR+W1mYEq5LNwGjgZQXMjCgWoxaBDiIEjMBxgG
54Ttl7FiL3W7kMNxCmOdL3wb8ULKY2zK7oaWaCnfbR8el1AaGEn+bfV/haxtlI4oZ3
553HwXLChqu5W7o7d/t0L5VOsNWRjl/n/W/t/ssEUJLMMb5MyqX5oL6/BlllJvMPcJ
56CJoQJgNlAIbDPDsJylZbbzIoeZm/S9ocOfqgVVtVfgkkdLQyPQ/Hoi9ugd3bzopa
57WY7bad37AgMBAAECggEAKSmnbD1sLHVBIFK2qB2g8gZBxddgnxMrbj802wR24ykv
58iD0d7IcZKIX2/Z0WjdTt6zYscyWw4S4S2xrS272CQAq5OdOHz0NusEDtX8Q7vd5B
59v5AcRg8IqTzeFyPO6vCtO7/675UipORqa7tNzT6sl9UOdSbQuI4zSdFsd0OEZtZs
60oqKkv+jdvKaVJQ1vsoQSup23V0bvVCRydBNFZ2mQ3etZcRRYXyu1digJ7/oMyCHf
611F37lJmjPJ8WwsGJMk2ngJiUOQx21bbTZ22c/8sMMLJjhhC2qu984keVRanSsJwC
62Z80XcCxL/yoLF42A5ReMtutFs83rW7VX7VJGxoOaKQKBgQD91dCs9jGBVxHr4vxy
63NJC2n92R5/JpqXygXS3L6RDP+we6p/fmSd4/QllwIVeC9kepsFz4//ArmLOy9JHu
64rkXa7W9G+XbmYXSftmG78roLfAtvdudoytLQJg2bu8J3bzPVibRCUq0OORFyqOHR
65QGcQtvPxwFHctIkOjajbLpbL7QKBgQDeMAbvjzD8wU1gp2U8Bl5l5ohYgQpcs15R
66eBPS5DlRzICAeuQWi+BRjW5BPZVmTr3Ml3KiMWcalXMeH1TKoPON8RjmWgY2Fxvh
67nS7gV+rJm4H0T+bBEXNAraracwGYd6JgcH9BPD9znHRmyFR4pMPqkSa7o/OExH6W
68O32KqTMkhwKBgQCoX7wb/vK3qNnqbpal6thTS5fdwM276QESHrzSFbdhPlLSLbjy
69uO0DaS+KgZNa+6JtnN8PDDZztMb+XdyvRkpv/i9iFPgZuWtyxbfuxANEuvOa7HRz
70vpY4HAXK17EXKFxpuP4pQE4qsRAxznR8KQw0uib2pWunytlfHfhz62N7wQKBgQC+
71+TTc74zBkzx42SiwYSD+IRoMSE2pxBpLmBQh7jw+TLIevIITxwJ11kRwGwiwuPl2
72Qq4rLp9aQB6EQ5XT3Ge7FwG57KLuFwrF7x59gdOymdEnNw414FPZwevae4Nhk2Kj
731c3rOmenbVC3j3TbhXNHyJ8sJQ2IjoPniRas+iWVPQKBgQDcZzKh6U+e9efYLAt0
74qdaKhm5MCAgzD9X/Tx2OvOqgWnSXt2Q2AhK2UsHnrGBn1SDNTNDGlniQy2OM2Ywn
75n71nH1QUmgoiwBrFUh0gLxv878vwgUATqfFRTlirmK9XxHuTX9Jh6elmRebjYWyc
76Oo0CJBeMABu71Y+VkCxURT1bzw==
77-----END PRIVATE KEY-----`)
78)
79
80type handshakeError string
81
82func (he handshakeError) Error() string {
83	return string(he)
84}
85
86// createCAFile writes a PEM encoded version of the certificate out to a
87// temporary file, for use by libtls.
88func createCAFile(cert []byte) (string, error) {
89	f, err := ioutil.TempFile("", "tls")
90	if err != nil {
91		return "", fmt.Errorf("failed to create file: %v", err)
92	}
93	defer f.Close()
94	block := &pem.Block{
95		Type:  "CERTIFICATE",
96		Bytes: cert,
97	}
98	if err := pem.Encode(f, block); err != nil {
99		return "", fmt.Errorf("failed to encode certificate: %v", err)
100	}
101	return f.Name(), nil
102}
103
104func newTestServer(tlsCfg *tls.Config) (*httptest.Server, *url.URL, string, error) {
105	ts := httptest.NewUnstartedServer(
106		http.HandlerFunc(
107			func(w http.ResponseWriter, r *http.Request) {
108				fmt.Fprintln(w, httpContent)
109			},
110		),
111	)
112	if tlsCfg == nil {
113		tlsCfg = &tls.Config{}
114	}
115	if len(tlsCfg.Certificates) == 0 {
116		cert, err := tls.X509KeyPair(testServerCert, testServerKey)
117		if err != nil {
118			return nil, nil, "", fmt.Errorf("failed to load key pair: %v", err)
119		}
120		tlsCfg.Certificates = []tls.Certificate{cert}
121	}
122	ts.TLS = tlsCfg
123	ts.StartTLS()
124
125	u, err := url.Parse(ts.URL)
126	if err != nil {
127		return nil, nil, "", fmt.Errorf("failed to parse URL %q: %v", ts.URL, err)
128	}
129
130	caFile, err := createCAFile(ts.TLS.Certificates[0].Certificate[0])
131	if err != nil {
132		return nil, nil, "", fmt.Errorf("failed to create CA file: %v", err)
133	}
134
135	return ts, u, caFile, nil
136}
137
138func handshakeVersionTest(tlsCfg *tls.Config) (ProtocolVersion, error) {
139	ts, u, caFile, err := newTestServer(tlsCfg)
140	if err != nil {
141		return 0, fmt.Errorf("failed to start test server: %v", err)
142	}
143	defer os.Remove(caFile)
144	defer ts.Close()
145
146	if err := Init(); err != nil {
147		return 0, err
148	}
149
150	cfg, err := NewConfig()
151	if err != nil {
152		return 0, err
153	}
154	defer cfg.Free()
155	if err := cfg.SetCAFile(caFile); err != nil {
156		return 0, err
157	}
158	if err := cfg.SetCiphers("compat"); err != nil {
159		return 0, err
160	}
161	if err := cfg.SetProtocols(ProtocolsAll); err != nil {
162		return 0, err
163	}
164
165	tls, err := NewClient(cfg)
166	if err != nil {
167		return 0, err
168	}
169	defer tls.Free()
170
171	if err := tls.Connect(u.Host, ""); err != nil {
172		return 0, err
173	}
174	if err := tls.Handshake(); err != nil {
175		return 0, handshakeError(err.Error())
176	}
177	version, err := tls.ConnVersion()
178	if err != nil {
179		return 0, err
180	}
181	if err := tls.Close(); err != nil {
182		return 0, err
183	}
184	return version, nil
185}
186
187func TestTLSBasic(t *testing.T) {
188	ts, u, caFile, err := newTestServer(nil)
189	if err != nil {
190		t.Fatalf("Failed to start test server: %v", err)
191	}
192	defer os.Remove(caFile)
193	defer ts.Close()
194
195	if err := Init(); err != nil {
196		t.Fatal(err)
197	}
198
199	cfg, err := NewConfig()
200	if err != nil {
201		t.Fatal(err)
202	}
203	defer cfg.Free()
204	if err := cfg.SetCAFile(caFile); err != nil {
205		t.Fatal(err)
206	}
207
208	tls, err := NewClient(cfg)
209	if err != nil {
210		t.Fatal(err)
211	}
212	defer tls.Free()
213
214	t.Logf("Connecting to %s", u.Host)
215
216	if err := tls.Connect(u.Host, ""); err != nil {
217		t.Fatal(err)
218	}
219	defer func() {
220		if err := tls.Close(); err != nil {
221			t.Fatalf("Close failed: %v", err)
222		}
223	}()
224
225	n, err := tls.Write([]byte("GET / HTTP/1.0\n\n"))
226	if err != nil {
227		t.Fatal(err)
228	}
229	t.Logf("Wrote %d bytes...", n)
230
231	buf := make([]byte, 1024)
232	n, err = tls.Read(buf)
233	if err != nil {
234		t.Fatal(err)
235	}
236	t.Logf("Read %d bytes...", n)
237
238	if !strings.Contains(string(buf), httpContent) {
239		t.Errorf("Response does not contain %q", httpContent)
240	}
241}
242
243func TestTLSVersions(t *testing.T) {
244	tests := []struct {
245		minVersion       uint16
246		maxVersion       uint16
247		wantVersion      ProtocolVersion
248		wantHandshakeErr bool
249	}{
250		{tls.VersionTLS10, tls.VersionTLS13, ProtocolTLSv13, false},
251		{tls.VersionSSL30, tls.VersionTLS12, ProtocolTLSv12, false},
252		{tls.VersionTLS10, tls.VersionTLS12, ProtocolTLSv12, false},
253		{tls.VersionTLS11, tls.VersionTLS12, ProtocolTLSv12, false},
254		{tls.VersionSSL30, tls.VersionTLS11, ProtocolTLSv11, false},
255		{tls.VersionSSL30, tls.VersionTLS10, ProtocolTLSv10, false},
256		{tls.VersionSSL30, tls.VersionSSL30, 0, true},
257		{tls.VersionTLS10, tls.VersionTLS10, ProtocolTLSv10, false},
258		{tls.VersionTLS11, tls.VersionTLS11, ProtocolTLSv11, false},
259		{tls.VersionTLS12, tls.VersionTLS12, ProtocolTLSv12, false},
260	}
261	for i, test := range tests {
262		t.Logf("Testing handshake with protocols %x:%x", test.minVersion, test.maxVersion)
263		tlsCfg := &tls.Config{
264			MinVersion: test.minVersion,
265			MaxVersion: test.maxVersion,
266		}
267		version, err := handshakeVersionTest(tlsCfg)
268		switch {
269		case test.wantHandshakeErr && err == nil:
270			t.Errorf("Test %d - handshake %x:%x succeeded, want handshake error",
271				i, test.minVersion, test.maxVersion)
272		case test.wantHandshakeErr && err != nil:
273			if _, ok := err.(handshakeError); !ok {
274				t.Errorf("Test %d - handshake %x:%x; got unknown error, want handshake error: %v",
275					i, test.minVersion, test.maxVersion, err)
276			}
277		case !test.wantHandshakeErr && err != nil:
278			t.Errorf("Test %d - handshake %x:%x failed: %v", i, test.minVersion, test.maxVersion, err)
279		case !test.wantHandshakeErr && err == nil:
280			if got, want := version, test.wantVersion; got != want {
281				t.Errorf("Test %d - handshake %x:%x; got protocol version %v, want %v",
282					i, test.minVersion, test.maxVersion, got, want)
283			}
284		}
285	}
286}
287
288func TestTLSSingleByteReadWrite(t *testing.T) {
289	ts, u, caFile, err := newTestServer(nil)
290	if err != nil {
291		t.Fatalf("Failed to start test server: %v", err)
292	}
293	defer os.Remove(caFile)
294	defer ts.Close()
295
296	if err := Init(); err != nil {
297		t.Fatal(err)
298	}
299
300	cfg, err := NewConfig()
301	if err != nil {
302		t.Fatal(err)
303	}
304	defer cfg.Free()
305	if err := cfg.SetCAFile(caFile); err != nil {
306		t.Fatal(err)
307	}
308
309	tls, err := NewClient(cfg)
310	if err != nil {
311		t.Fatal(err)
312	}
313	defer tls.Free()
314
315	t.Logf("Connecting to %s", u.Host)
316
317	if err := tls.Connect(u.Host, ""); err != nil {
318		t.Fatal(err)
319	}
320	defer func() {
321		if err := tls.Close(); err != nil {
322			t.Fatalf("Close failed: %v", err)
323		}
324	}()
325
326	for _, b := range []byte("GET / HTTP/1.0\n\n") {
327		n, err := tls.Write([]byte{b})
328		if err != nil {
329			t.Fatal(err)
330		}
331		if n != 1 {
332			t.Fatalf("Wrote byte %v, got length %d, want 1", b, n)
333		}
334	}
335
336	var body []byte
337	for {
338		buf := make([]byte, 1)
339		n, err := tls.Read(buf)
340		if err != nil {
341			t.Fatal(err)
342		}
343		if n == 0 {
344			break
345		}
346		if n != 1 {
347			t.Fatalf("Read single byte, got length %d, want 1", n)
348		}
349		body = append(body, buf...)
350	}
351
352	if !strings.Contains(string(body), httpContent) {
353		t.Errorf("Response does not contain %q", httpContent)
354	}
355}
356
357func TestTLSInfo(t *testing.T) {
358	ts, u, caFile, err := newTestServer(nil)
359	if err != nil {
360		t.Fatalf("Failed to start test server: %v", err)
361	}
362	defer os.Remove(caFile)
363	defer ts.Close()
364
365	if err := Init(); err != nil {
366		t.Fatal(err)
367	}
368
369	cfg, err := NewConfig()
370	if err != nil {
371		t.Fatal(err)
372	}
373	defer cfg.Free()
374	if err := cfg.SetCAFile(caFile); err != nil {
375		t.Fatal(err)
376	}
377
378	tls, err := NewClient(cfg)
379	if err != nil {
380		t.Fatal(err)
381	}
382	defer tls.Free()
383
384	t.Logf("Connecting to %s", u.Host)
385
386	if err := tls.Connect(u.Host, ""); err != nil {
387		t.Fatal(err)
388	}
389	defer func() {
390		if err := tls.Close(); err != nil {
391			t.Fatalf("Close failed: %v", err)
392		}
393	}()
394
395	// All of these should fail since the handshake has not completed.
396	if _, err := tls.ConnVersion(); err == nil {
397		t.Error("ConnVersion() return nil error, want error")
398	}
399	if _, err := tls.ConnCipher(); err == nil {
400		t.Error("ConnCipher() return nil error, want error")
401	}
402	if _, err := tls.ConnCipherStrength(); err == nil {
403		t.Error("ConnCipherStrength() return nil error, want error")
404	}
405
406	if got, want := tls.PeerCertProvided(), false; got != want {
407		t.Errorf("PeerCertProvided() = %v, want %v", got, want)
408	}
409	for _, name := range []string{"127.0.0.1", "::1", "example.com"} {
410		if got, want := tls.PeerCertContainsName(name), false; got != want {
411			t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want)
412		}
413	}
414
415	if _, err := tls.PeerCertIssuer(); err == nil {
416		t.Error("PeerCertIssuer() returned nil error, want error")
417	}
418	if _, err := tls.PeerCertSubject(); err == nil {
419		t.Error("PeerCertSubject() returned nil error, want error")
420	}
421	if _, err := tls.PeerCertHash(); err == nil {
422		t.Error("PeerCertHash() returned nil error, want error")
423	}
424	if _, err := tls.PeerCertNotBefore(); err == nil {
425		t.Error("PeerCertNotBefore() returned nil error, want error")
426	}
427	if _, err := tls.PeerCertNotAfter(); err == nil {
428		t.Error("PeerCertNotAfter() returned nil error, want error")
429	}
430
431	// Complete the handshake...
432	if err := tls.Handshake(); err != nil {
433		t.Fatalf("Handshake failed: %v", err)
434	}
435
436	if version, err := tls.ConnVersion(); err != nil {
437		t.Errorf("ConnVersion() returned error: %v", err)
438	} else {
439		t.Logf("Protocol version: %v", version)
440	}
441	if cipher, err := tls.ConnCipher(); err != nil {
442		t.Errorf("ConnCipher() returned error: %v", err)
443	} else {
444		t.Logf("Cipher: %v", cipher)
445	}
446	if strength, err := tls.ConnCipherStrength(); err != nil {
447		t.Errorf("ConnCipherStrength() return ederror: %v", err)
448	} else {
449		t.Logf("Cipher Strength: %v bits", strength)
450	}
451
452	if got, want := tls.PeerCertProvided(), true; got != want {
453		t.Errorf("PeerCertProvided() = %v, want %v", got, want)
454	}
455	for _, name := range []string{"127.0.0.1", "::1", "example.com"} {
456		if got, want := tls.PeerCertContainsName(name), true; got != want {
457			t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want)
458		}
459	}
460
461	if issuer, err := tls.PeerCertIssuer(); err != nil {
462		t.Errorf("PeerCertIssuer() returned error: %v", err)
463	} else {
464		t.Logf("Issuer: %v", issuer)
465	}
466	if subject, err := tls.PeerCertSubject(); err != nil {
467		t.Errorf("PeerCertSubject() returned error: %v", err)
468	} else {
469		t.Logf("Subject: %v", subject)
470	}
471	if hash, err := tls.PeerCertHash(); err != nil {
472		t.Errorf("PeerCertHash() returned error: %v", err)
473	} else if hash != certHash {
474		t.Errorf("Got cert hash %q, want %q", hash, certHash)
475	} else {
476		t.Logf("Hash: %v", hash)
477	}
478	if notBefore, err := tls.PeerCertNotBefore(); err != nil {
479		t.Errorf("PeerCertNotBefore() returned error: %v", err)
480	} else if !certNotBefore.Equal(notBefore) {
481		t.Errorf("Got cert notBefore %v, want %v", notBefore.UTC(), certNotBefore.UTC())
482	} else {
483		t.Logf("NotBefore: %v", notBefore.UTC())
484	}
485	if notAfter, err := tls.PeerCertNotAfter(); err != nil {
486		t.Errorf("PeerCertNotAfter() returned error: %v", err)
487	} else if !certNotAfter.Equal(notAfter) {
488		t.Errorf("Got cert notAfter %v, want %v", notAfter.UTC(), certNotAfter.UTC())
489	} else {
490		t.Logf("NotAfter: %v", notAfter.UTC())
491	}
492}
493