git » chasquid » commit 90d3855

testlib: Add GenerateCert function

author Alberto Bertogli
2021-10-15 10:16:46 UTC
committer Alberto Bertogli
2021-10-25 11:41:24 UTC
parent ed38945fca3305544f3997cbbef81ee4450f8799

testlib: Add GenerateCert function

This patch moves the GenerateCert function from the smtpsrv tests to the
common testlib, so it can be used by other tests in the future.

internal/smtpsrv/server_test.go +1 -76
internal/testlib/testlib.go +80 -0
internal/testlib/testlib_test.go +22 -0

diff --git a/internal/smtpsrv/server_test.go b/internal/smtpsrv/server_test.go
index 891ee2e..9915973 100644
--- a/internal/smtpsrv/server_test.go
+++ b/internal/smtpsrv/server_test.go
@@ -1,16 +1,10 @@
 package smtpsrv
 
 import (
-	"crypto/rand"
-	"crypto/rsa"
 	"crypto/tls"
-	"crypto/x509"
-	"crypto/x509/pkix"
-	"encoding/pem"
 	"flag"
 	"fmt"
 	"io/ioutil"
-	"math/big"
 	"net"
 	"net/smtp"
 	"os"
@@ -516,75 +510,6 @@ func BenchmarkManyEmailsParallel(b *testing.B) {
 // === Test environment ===
 //
 
-// generateCert generates a new, INSECURE self-signed certificate and writes
-// it to a pair of (cert.pem, key.pem) files to the given path.
-// Note the certificate is only useful for testing purposes.
-func generateCert(path string) error {
-	tmpl := x509.Certificate{
-		SerialNumber: big.NewInt(1234),
-		Subject: pkix.Name{
-			Organization: []string{"chasquid_test.go"},
-		},
-
-		DNSNames:    []string{"localhost"},
-		IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
-
-		NotBefore: time.Now(),
-		NotAfter:  time.Now().Add(30 * time.Minute),
-
-		KeyUsage: x509.KeyUsageKeyEncipherment |
-			x509.KeyUsageDigitalSignature |
-			x509.KeyUsageCertSign,
-
-		BasicConstraintsValid: true,
-		IsCA:                  true,
-	}
-
-	priv, err := rsa.GenerateKey(rand.Reader, 1024)
-	if err != nil {
-		return err
-	}
-
-	derBytes, err := x509.CreateCertificate(
-		rand.Reader, &tmpl, &tmpl, &priv.PublicKey, priv)
-	if err != nil {
-		return err
-	}
-
-	// Create a global config for convenience.
-	srvCert, err := x509.ParseCertificate(derBytes)
-	if err != nil {
-		return err
-	}
-	rootCAs := x509.NewCertPool()
-	rootCAs.AddCert(srvCert)
-	tlsConfig = &tls.Config{
-		ServerName: "localhost",
-		RootCAs:    rootCAs,
-	}
-
-	certOut, err := os.Create(path + "/cert.pem")
-	if err != nil {
-		return err
-	}
-	defer certOut.Close()
-	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
-
-	keyOut, err := os.OpenFile(
-		path+"/key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
-	if err != nil {
-		return err
-	}
-	defer keyOut.Close()
-
-	block := &pem.Block{
-		Type:  "RSA PRIVATE KEY",
-		Bytes: x509.MarshalPKCS1PrivateKey(priv),
-	}
-	pem.Encode(keyOut, block)
-	return nil
-}
-
 // waitForServer waits 5 seconds for the server to start, and returns an error
 // if it fails to do so.
 // It does this by repeatedly connecting to the address until it either
@@ -650,7 +575,7 @@ func realMain(m *testing.M) int {
 		}
 		defer os.RemoveAll(tmpDir)
 
-		err = generateCert(tmpDir)
+		tlsConfig, err = testlib.GenerateCert(tmpDir)
 		if err != nil {
 			fmt.Printf("Failed to generate cert for testing: %v\n", err)
 			return 1
diff --git a/internal/testlib/testlib.go b/internal/testlib/testlib.go
index 162f4f8..461764d 100644
--- a/internal/testlib/testlib.go
+++ b/internal/testlib/testlib.go
@@ -2,7 +2,14 @@
 package testlib
 
 import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/tls"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
 	"io/ioutil"
+	"math/big"
 	"net"
 	"os"
 	"strings"
@@ -129,3 +136,76 @@ func (c dumbCourier) Deliver(from string, to string, data []byte) (error, bool)
 
 // DumbCourier always succeeds delivery, and ignores everything.
 var DumbCourier = dumbCourier{}
+
+// generateCert generates a new, INSECURE self-signed certificate and writes
+// it to a pair of (cert.pem, key.pem) files to the given path.
+// Note the certificate is only useful for testing purposes.
+func GenerateCert(path string) (*tls.Config, error) {
+	tmpl := x509.Certificate{
+		SerialNumber: big.NewInt(1234),
+		Subject: pkix.Name{
+			Organization: []string{"chasquid_test.go"},
+		},
+
+		DNSNames:    []string{"localhost"},
+		IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
+
+		NotBefore: time.Now(),
+		NotAfter:  time.Now().Add(30 * time.Minute),
+
+		KeyUsage: x509.KeyUsageKeyEncipherment |
+			x509.KeyUsageDigitalSignature |
+			x509.KeyUsageCertSign,
+
+		BasicConstraintsValid: true,
+		IsCA:                  true,
+	}
+
+	priv, err := rsa.GenerateKey(rand.Reader, 1024)
+	if err != nil {
+		return nil, err
+	}
+
+	derBytes, err := x509.CreateCertificate(
+		rand.Reader, &tmpl, &tmpl, &priv.PublicKey, priv)
+	if err != nil {
+		return nil, err
+	}
+
+	// Create a global config for convenience.
+	srvCert, err := x509.ParseCertificate(derBytes)
+	if err != nil {
+		return nil, err
+	}
+	rootCAs := x509.NewCertPool()
+	rootCAs.AddCert(srvCert)
+	tlsConfig := &tls.Config{
+		ServerName: "localhost",
+		RootCAs:    rootCAs,
+	}
+
+	certOut, err := os.Create(path + "/cert.pem")
+	if err != nil {
+		return nil, err
+	}
+	defer certOut.Close()
+	err = pem.Encode(certOut,
+		&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+	if err != nil {
+		return nil, err
+	}
+
+	keyOut, err := os.OpenFile(
+		path+"/key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+	if err != nil {
+		return nil, err
+	}
+	defer keyOut.Close()
+
+	block := &pem.Block{
+		Type:  "RSA PRIVATE KEY",
+		Bytes: x509.MarshalPKCS1PrivateKey(priv),
+	}
+	err = pem.Encode(keyOut, block)
+	return tlsConfig, err
+}
diff --git a/internal/testlib/testlib_test.go b/internal/testlib/testlib_test.go
index b2da661..f514dc4 100644
--- a/internal/testlib/testlib_test.go
+++ b/internal/testlib/testlib_test.go
@@ -96,3 +96,25 @@ func TestWaitFor(t *testing.T) {
 		t.Errorf("WaitFor(false) worked")
 	}
 }
+
+func TestGenerateCert(t *testing.T) {
+	dir := MustTempDir(t)
+	defer os.RemoveAll(dir)
+	conf, err := GenerateCert(dir)
+	if err != nil {
+		t.Errorf("GenerateCert returned error: %v", err)
+	}
+	if conf.ServerName != "localhost" {
+		t.Errorf("Config server name %q != localhost", conf.ServerName)
+	}
+	if conf.RootCAs == nil {
+		t.Errorf("Config had an empty RootCAs pool")
+	}
+}
+
+func TestGenerateCertBadDir(t *testing.T) {
+	conf, err := GenerateCert("/doesnotexist/")
+	if err == nil || conf != nil {
+		t.Fatalf("GenerateCert returned non-error: %v / %v", conf, err)
+	}
+}