git » gofer » commit 7b8885a

test: Use our own generate_cert helper

author Alberto Bertogli
2022-08-28 01:05:42 UTC
committer Alberto Bertogli
2022-08-28 01:05:42 UTC
parent ba839c42483a91f4d405ecf489cac36e93a5256f

test: Use our own generate_cert helper

The current generate_cert helper was originally taken from Go's source,
and is more complex than we need it to be.

This patch replaces it with our own version, rewritten from scratch
independently.

test/util/generate_cert.go +72 -67
test/util/lib.sh +1 -1

diff --git a/test/util/generate_cert.go b/test/util/generate_cert.go
index 07daed7..99c5e0d 100644
--- a/test/util/generate_cert.go
+++ b/test/util/generate_cert.go
@@ -1,24 +1,21 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
 //go:build ignore
 // +build ignore
 
-// Generate a self-signed X.509 certificate for a TLS server. Outputs to
-// 'cert.pem' and 'key.pem' and will overwrite existing files.
-
+// Utility to generate self-signed certificates.
+// It generates a self-signed x509 certificate and key pair, and writes them
+// to "fullchain.pem" and "privkey.pem".
+//
+// Intended for use in tests, not for production use.
 package main
 
 import (
-	"crypto/rand"
+	crand "crypto/rand"
 	"crypto/rsa"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"encoding/pem"
 	"flag"
 	"fmt"
-	"log"
 	"math/big"
 	"net"
 	"os"
@@ -27,90 +24,98 @@ import (
 )
 
 var (
-	host      = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
-	validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
-	validFor  = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
-	isCA      = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
+	host = flag.String("host", "",
+		"Hostnames/IPs to generate the certificate for (comma separated)")
+	validFor = flag.Duration("validfor", 4*time.Hour,
+		"How long will the certificate be valid for")
+	isCA = flag.Bool("ca", false,
+		"Should this cert be its own CA?")
 )
 
+func fatalf(f string, a ...interface{}) {
+	fmt.Printf(f, a...)
+	os.Exit(1)
+}
+
 func main() {
 	flag.Parse()
-
-	if len(*host) == 0 {
-		log.Fatalf("Missing required --host parameter")
+	if *host == "" {
+		fatalf("Required flag: --host")
 	}
 
-	priv, err := rsa.GenerateKey(rand.Reader, 2048)
+	// Build the certificate template.
+	serial, err := crand.Int(crand.Reader, big.NewInt(1<<62))
 	if err != nil {
-		log.Fatalf("failed to generate private key: %s", err)
+		fatalf("Error generating serial number: %v\n", err)
 	}
+	tmpl := x509.Certificate{
+		SerialNumber: serial,
+		Subject:      pkix.Name{Organization: []string{"Test Cert Org"}},
 
-	var notBefore time.Time
-	if len(*validFrom) == 0 {
-		notBefore = time.Now()
-	} else {
-		notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom)
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err)
-			os.Exit(1)
-		}
-	}
+		// Valid from now until `--validfor` in the future.
+		// Extended certs can be useful for manual troubleshooting.
+		NotBefore: time.Now(),
+		NotAfter:  time.Now().Add(*validFor),
 
-	notAfter := notBefore.Add(*validFor)
+		KeyUsage: x509.KeyUsageKeyEncipherment |
+			x509.KeyUsageDigitalSignature |
+			x509.KeyUsageCertSign,
+		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
 
-	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
-	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
-	if err != nil {
-		log.Fatalf("failed to generate serial number: %s", err)
+		BasicConstraintsValid: true,
 	}
 
-	template := x509.Certificate{
-		SerialNumber: serialNumber,
-		Subject: pkix.Name{
-			Organization: []string{"Acme Co"},
-		},
-		NotBefore: notBefore,
-		NotAfter:  notAfter,
-
-		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
-		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
-		BasicConstraintsValid: true,
+	if *isCA {
+		tmpl.IsCA = true
 	}
 
 	hosts := strings.Split(*host, ",")
 	for _, h := range hosts {
 		if ip := net.ParseIP(h); ip != nil {
-			template.IPAddresses = append(template.IPAddresses, ip)
+			tmpl.IPAddresses = append(tmpl.IPAddresses, ip)
 		} else {
-			template.DNSNames = append(template.DNSNames, h)
+			tmpl.DNSNames = append(tmpl.DNSNames, h)
 		}
 	}
 
-	if *isCA {
-		template.IsCA = true
-		template.KeyUsage |= x509.KeyUsageCertSign
-	}
-
-	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+	// Generate a private key (RSA 2048).
+	privK, err := rsa.GenerateKey(crand.Reader, 2048)
 	if err != nil {
-		log.Fatalf("Failed to create certificate: %s", err)
+		fatalf("Error generating key: %v\n", err)
 	}
 
-	certOut, err := os.Create("fullchain.pem")
-	if err != nil {
-		log.Fatalf("failed to open fullchain.pem for writing: %s", err)
-	}
-	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
-	certOut.Close()
+	// Write the certificate.
+	{
+		derBytes, err := x509.CreateCertificate(
+			crand.Reader, &tmpl, &tmpl, &privK.PublicKey, privK)
+		if err != nil {
+			fatalf("Failed to create certificate: %v\n", err)
+		}
 
-	keyOut, err := os.OpenFile("privkey.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
-	if err != nil {
-		log.Fatalf("failed to open privkey.pem for writing: %s", err)
-		return
+		fullchain, err := os.Create("fullchain.pem")
+		if err != nil {
+			fatalf("Failed to open fullchain.pem: %v\n", err)
+		}
+		err = pem.Encode(fullchain,
+			&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+		if err != nil {
+			fatalf("Error encoding certificate: %v\n", err)
+		}
+		fullchain.Close()
 	}
 
-	block := &pem.Block{Type: "RSA PRIVATE KEY",
-		Bytes: x509.MarshalPKCS1PrivateKey(priv)}
-	pem.Encode(keyOut, block)
-	keyOut.Close()
+	// Write the private key.
+	{
+		privkey, err := os.Create("privkey.pem")
+		if err != nil {
+			fatalf("failed to open privkey.pem: %v\n", err)
+		}
+		block := &pem.Block{Type: "RSA PRIVATE KEY",
+			Bytes: x509.MarshalPKCS1PrivateKey(privK)}
+		err = pem.Encode(privkey, block)
+		if err != nil {
+			fatalf("Error encoding private key: %v\n", err)
+		}
+		privkey.Close()
+	}
 }
diff --git a/test/util/lib.sh b/test/util/lib.sh
index 6ba248c..4a0adb5 100644
--- a/test/util/lib.sh
+++ b/test/util/lib.sh
@@ -65,7 +65,7 @@ function generate_certs() {
 	(
 		cd .certs/localhost
 		go run ${UTILDIR}/generate_cert.go \
-			-ca -duration=1h --host=localhost
+			-ca -validfor=1h --host=localhost
 	)
 }