[tor-commits] [meek/master] Tests for certContext.

dcf at torproject.org dcf at torproject.org
Wed Mar 22 06:49:31 UTC 2017


commit fe142d4ee313772a7713dbe1fc994880d6a1fdf6
Author: David Fifield <david at bamsoftware.com>
Date:   Tue Mar 21 23:48:31 2017 -0700

    Tests for certContext.
---
 meek-server/certificate_test.go | 312 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 312 insertions(+)

diff --git a/meek-server/certificate_test.go b/meek-server/certificate_test.go
new file mode 100644
index 0000000..94e18f0
--- /dev/null
+++ b/meek-server/certificate_test.go
@@ -0,0 +1,312 @@
+package main
+
+import (
+	"bytes"
+	"crypto/rand"
+	"crypto/tls"
+	"encoding/hex"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+	"time"
+)
+
+// openssl genpkey -out key1.pem -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve
+const key1PEM = `-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwBuadiHWuhiCwUHK
+pvzM0MYVySH8FE5T/76qoDBozzChRANCAAQao88iJDj284z5YsSOwynblbNfhRHL
+dhInn3bl8dYUr0s88q7yaOHW0riAYAX8Q/G5zoP/P1MgNPFMYV76eSY4
+-----END PRIVATE KEY-----`
+
+// openssl req -out cert1.pem -x509 -new -nodes -key key1.pem -days 1 -subj "/CN=meek-server.example.com"
+const cert1PEM = `-----BEGIN CERTIFICATE-----
+MIIBjjCCATSgAwIBAgIJAKpvM1Hu/AeyMAoGCCqGSM49BAMCMCIxIDAeBgNVBAMM
+F21lZWstc2VydmVyLmV4YW1wbGUuY29tMB4XDTE3MDMyMTIyNTM0N1oXDTE3MDMy
+MjIyNTM0N1owIjEgMB4GA1UEAwwXbWVlay1zZXJ2ZXIuZXhhbXBsZS5jb20wWTAT
+BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQao88iJDj284z5YsSOwynblbNfhRHLdhIn
+n3bl8dYUr0s88q7yaOHW0riAYAX8Q/G5zoP/P1MgNPFMYV76eSY4o1MwUTAdBgNV
+HQ4EFgQU/FIFX5DX58BFhNBSWV0ulWmS+XIwHwYDVR0jBBgwFoAU/FIFX5DX58BF
+hNBSWV0ulWmS+XIwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEA
+mylhVbnAd0KEQoaIEH1whj9oUxlk2kWU5G8daG5uUjMCIBW6fwv0cbYmyzspCMqJ
+eib1vgFnhGTI44K05cunpXJ+
+-----END CERTIFICATE-----`
+
+// openssl genpkey -out key2.pem -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -pkeyopt ec_param_enc:named_curve
+const key2PEM = `-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUbNm7exkEPKMv/DT
+B3UMv6XevnD2E99W3Rp8L/a1v12hRANCAATqnza9H9uNa8EvoKm2GOLvw25kR7OA
+oVHZiyaXdBeB480FBUtRmWUukLZFxp/QStd4OCwaOwWGtXGlspM2LEum
+-----END PRIVATE KEY-----`
+
+// openssl req -out cert2.pem -x509 -new -nodes -key key2.pem -days 1 -subj "/CN=meek-server.example.com"
+const cert2PEM = `-----BEGIN CERTIFICATE-----
+MIIBjzCCATSgAwIBAgIJAKvKZ4vqwpySMAoGCCqGSM49BAMCMCIxIDAeBgNVBAMM
+F21lZWstc2VydmVyLmV4YW1wbGUuY29tMB4XDTE3MDMyMTIyNTQzN1oXDTE3MDMy
+MjIyNTQzN1owIjEgMB4GA1UEAwwXbWVlay1zZXJ2ZXIuZXhhbXBsZS5jb20wWTAT
+BgcqhkjOPQIBBggqhkjOPQMBBwNCAATqnza9H9uNa8EvoKm2GOLvw25kR7OAoVHZ
+iyaXdBeB480FBUtRmWUukLZFxp/QStd4OCwaOwWGtXGlspM2LEumo1MwUTAdBgNV
+HQ4EFgQUdqTMumWa7f965k/SLgWJT0tIlcswHwYDVR0jBBgwFoAUdqTMumWa7f96
+5k/SLgWJT0tIlcswDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA
+yOhMqBPZLpqnjTGD1OgOc1N1SkS53bdWAazAZgLgwvICIQC7hFOK1j74Frh+1l3h
+kLn8Jbjpp6jzNBhQhVHF/nj3CQ==
+-----END CERTIFICATE-----`
+
+const badSyntax = "hello world\n"
+
+// Backdate file times so any modifications will make them appear different;
+// otherwise immediately overwriting the files may happen quickly enough that
+// the times don't change.
+func backdateFile(filename string) error {
+	info, err := os.Stat(filename)
+	if err != nil {
+		return err
+	}
+	timestamp := info.ModTime().Add(-10 * time.Second)
+	return os.Chtimes(filename, timestamp, timestamp)
+}
+
+func mustBackdateFile(filename string) {
+	err := backdateFile(filename)
+	if err != nil {
+		panic(err)
+	}
+}
+
+// Return the path to a newly created temporary file with the given contents.
+func makeTempFileFromContents(contents []byte) (string, error) {
+	f, err := ioutil.TempFile("", "meek-server-certificate-test-")
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	_, err = f.Write(contents)
+	if err != nil {
+		return f.Name(), err
+	}
+
+	err = backdateFile(f.Name())
+
+	return f.Name(), err
+}
+
+func mustMakeTempFileFromContents(contents []byte) string {
+	f, err := makeTempFileFromContents(contents)
+	if err != nil {
+		panic(err)
+	}
+	return f
+}
+
+// Return a random filename that is unlikely to exist.
+func makeNonexistentFilename() string {
+	bytes := make([]byte, 8)
+	_, err := rand.Read(bytes)
+	if err != nil {
+		panic(err)
+	}
+	return filepath.Join(os.TempDir(), hex.EncodeToString(bytes))
+}
+
+// Call tls.X509KeyPair and panic if it fails.
+func mustLoadCertificate(certPEM, keyPEM []byte) *tls.Certificate {
+	cert, err := tls.X509KeyPair(certPEM, keyPEM)
+	if err != nil {
+		panic(err)
+	}
+	return &cert
+}
+
+func mustWriteFile(filename string, data []byte) {
+	err := ioutil.WriteFile(filename, data, 0600)
+	if err != nil {
+		panic(err)
+	}
+}
+
+// A bunch of temporary certificate filenames and the like.
+type testFiles struct {
+	cert1 *tls.Certificate
+	cert2 *tls.Certificate
+
+	key1Filename        string
+	key2Filename        string
+	cert1Filename       string
+	cert2Filename       string
+	badSyntaxFilename   string
+	nonexistentFilename string
+}
+
+func loadTestFiles() *testFiles {
+	var files testFiles
+
+	files.cert1 = mustLoadCertificate([]byte(cert1PEM), []byte(key1PEM))
+	files.cert2 = mustLoadCertificate([]byte(cert2PEM), []byte(key2PEM))
+
+	files.key1Filename = mustMakeTempFileFromContents([]byte(key1PEM))
+	files.key2Filename = mustMakeTempFileFromContents([]byte(key2PEM))
+	files.cert1Filename = mustMakeTempFileFromContents([]byte(cert1PEM))
+	files.cert2Filename = mustMakeTempFileFromContents([]byte(cert2PEM))
+	files.badSyntaxFilename = mustMakeTempFileFromContents([]byte(badSyntax))
+	files.nonexistentFilename = makeNonexistentFilename()
+
+	return &files
+}
+
+// Delete temporary files created by loadTestFiles (to be called in a defer
+// handler).
+func (files *testFiles) Cleanup() {
+	os.Remove(files.key1Filename)
+	os.Remove(files.key2Filename)
+	os.Remove(files.cert1Filename)
+	os.Remove(files.cert2Filename)
+	os.Remove(files.badSyntaxFilename)
+}
+
+// Check if two certificate chains are equal.
+func certificatesEqual(cert1, cert2 *tls.Certificate) bool {
+	if len(cert1.Certificate) != len(cert2.Certificate) {
+		return false
+	}
+	for i := range cert1.Certificate {
+		if !bytes.Equal(cert1.Certificate[i], cert2.Certificate[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// Call ctx.reloadCertificate and check if the certificate and error status are
+// as expected.
+func checkCertificate(t *testing.T, ctx *certContext, expectedCert *tls.Certificate, expectedError bool) {
+	cert, err := ctx.reloadCertificate()
+	if expectedError && err == nil {
+		t.Errorf("expected error, got %v\n", err)
+	} else if !expectedError && err != nil {
+		t.Errorf("expected no error, got %v\n", err)
+	}
+	if !certificatesEqual(cert, expectedCert) {
+		t.Errorf("certificate was other than expected")
+	}
+}
+
+func TestNewCertContext(t *testing.T) {
+	files := loadTestFiles()
+	defer files.Cleanup()
+
+	var ctx *certContext
+	var err error
+
+	// Test with one or both files nonexistent.
+	ctx, err = newCertContext(files.nonexistentFilename, files.nonexistentFilename)
+	if err == nil {
+		t.Errorf("did not raise error on nonexistent cert and key")
+	}
+	ctx, err = newCertContext(files.cert1Filename, files.nonexistentFilename)
+	if err == nil {
+		t.Errorf("did not raise error on nonexistent cert")
+	}
+	ctx, err = newCertContext(files.nonexistentFilename, files.key1Filename)
+	if err == nil {
+		t.Errorf("did not raise error on nonexistent key")
+	}
+
+	// Test with bad syntax.
+	ctx, err = newCertContext(files.badSyntaxFilename, files.badSyntaxFilename)
+	if err == nil {
+		t.Errorf("did not raise error on bad-syntax cert and key")
+	}
+	ctx, err = newCertContext(files.cert1Filename, files.badSyntaxFilename)
+	if err == nil {
+		t.Errorf("did not raise error on bad-syntax cert")
+	}
+	ctx, err = newCertContext(files.badSyntaxFilename, files.key1Filename)
+	if err == nil {
+		t.Errorf("did not raise error on bad-syntax key")
+	}
+
+	// Test with certificate and key that don't match.
+	ctx, err = newCertContext(files.cert1Filename, files.key2Filename)
+	if err == nil {
+		t.Errorf("did not raise error on mismatched cert and key")
+	}
+	ctx, err = newCertContext(files.cert2Filename, files.key1Filename)
+	if err == nil {
+		t.Errorf("did not raise error on mismatched cert and key")
+	}
+
+	// Test with everything good.
+	ctx, err = newCertContext(files.cert1Filename, files.key1Filename)
+	if ctx == nil || err != nil {
+		t.Fatalf("raised an error: %s", err)
+	}
+}
+
+// Test that reloadCertificate continues returning the old certificate if files
+// are deleted.
+func TestDelete(t *testing.T) {
+	files := loadTestFiles()
+	defer files.Cleanup()
+
+	var ctx *certContext
+	var err error
+
+	ctx, err = newCertContext(files.cert1Filename, files.key1Filename)
+	if ctx == nil || err != nil {
+		t.Fatalf("raised an error: %s", err)
+	}
+	checkCertificate(t, ctx, files.cert1, false)
+	// Try removing the cert file; cert should be the same but now raise an error.
+	os.Remove(files.cert1Filename)
+	checkCertificate(t, ctx, files.cert1, true)
+
+	ctx, err = newCertContext(files.cert2Filename, files.key2Filename)
+	if ctx == nil || err != nil {
+		t.Fatalf("raised an error: %s", err)
+	}
+	checkCertificate(t, ctx, files.cert2, false)
+	// Try removing the key file; cert should be the same but now raise an error.
+	os.Remove(files.key2Filename)
+	checkCertificate(t, ctx, files.cert2, true)
+}
+
+// Test replacing the contents of cert and key files.
+func TestReplace(t *testing.T) {
+	files := loadTestFiles()
+	defer files.Cleanup()
+
+	var ctx *certContext
+	var err error
+
+	ctx, err = newCertContext(files.cert1Filename, files.key1Filename)
+	if ctx == nil || err != nil {
+		t.Fatalf("raised an error: %s", err)
+	}
+	checkCertificate(t, ctx, files.cert1, false)
+
+	// Replace cert file with junk.
+	mustWriteFile(files.cert1Filename, []byte(badSyntax))
+	checkCertificate(t, ctx, files.cert1, true)
+	// Put it back to normal.
+	mustWriteFile(files.cert1Filename, []byte(cert1PEM))
+	checkCertificate(t, ctx, files.cert1, false)
+
+	// Replace key file with junk.
+	mustWriteFile(files.key1Filename, []byte(badSyntax))
+	checkCertificate(t, ctx, files.cert1, true)
+	// Put it back to normal.
+	mustWriteFile(files.key1Filename, []byte(key1PEM))
+	checkCertificate(t, ctx, files.cert1, false)
+
+	mustBackdateFile(files.cert1Filename)
+	mustBackdateFile(files.key1Filename)
+	checkCertificate(t, ctx, files.cert1, false)
+
+	// Replace cert1 with cert2 contents; expect to still get cert1, with an error.
+	mustWriteFile(files.cert1Filename, []byte(cert2PEM))
+	checkCertificate(t, ctx, files.cert1, true)
+	// Replace key1 with key2 contents; now we expect to be using cert2.
+	mustWriteFile(files.key1Filename, []byte(key2PEM))
+	checkCertificate(t, ctx, files.cert2, false)
+}



More information about the tor-commits mailing list