Browse Source

Split off certificate generation code

Filippo Valsorda 6 years ago
parent
commit
d6aab07a4c
2 changed files with 152 additions and 143 deletions
  1. 152 0
      cert.go
  2. 0 143
      main.go

+ 152 - 0
cert.go

@@ -0,0 +1,152 @@
+package main
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"io/ioutil"
+	"log"
+	"math/big"
+	"net"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+)
+
+var rootSubject = pkix.Name{
+	Organization: []string{"mkcert development CA"},
+}
+
+func (m *mkcert) makeCert(hosts []string) {
+	if m.caKey == nil {
+		log.Fatalln("ERROR: can't create new certificates because the CA key (rootCA-key.pem) is missing")
+	}
+
+	priv, err := rsa.GenerateKey(rand.Reader, 2048)
+	fatalIfErr(err, "failed to generate certificate key")
+
+	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+	fatalIfErr(err, "failed to generate serial number")
+
+	tpl := &x509.Certificate{
+		SerialNumber: serialNumber,
+		Subject: pkix.Name{
+			Organization: []string{"mkcert development certificate"},
+		},
+
+		NotAfter:  time.Now().AddDate(10, 0, 0),
+		NotBefore: time.Now().AddDate(0, 0, -1),
+
+		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+		BasicConstraintsValid: true,
+	}
+	for _, h := range hosts {
+		if ip := net.ParseIP(h); ip != nil {
+			tpl.IPAddresses = append(tpl.IPAddresses, ip)
+		} else {
+			tpl.DNSNames = append(tpl.DNSNames, h)
+		}
+	}
+
+	pub := priv.PublicKey
+	cert, err := x509.CreateCertificate(rand.Reader, tpl, m.caCert, &pub, m.caKey)
+	fatalIfErr(err, "failed to generate certificate")
+
+	filename := strings.Replace(hosts[0], ":", "_", -1)
+	filename = strings.Replace(filename, "*", "_wildcard", -1)
+	if len(hosts) > 1 {
+		filename += "+" + strconv.Itoa(len(hosts)-1)
+	}
+
+	privDER, err := x509.MarshalPKCS8PrivateKey(priv)
+	fatalIfErr(err, "failed to encode certificate key")
+	err = ioutil.WriteFile(filename+"-key.pem", pem.EncodeToMemory(
+		&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0400)
+	fatalIfErr(err, "failed to save certificate key")
+
+	err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory(
+		&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
+	fatalIfErr(err, "failed to save certificate key")
+
+	log.Printf("\nCreated a new certificate valid for the following names 📜")
+	for _, h := range hosts {
+		log.Printf(" - %q", h)
+	}
+	log.Printf("\nThe certificate is at \"./%s.pem\" and the key at \"./%s-key.pem\" ✅\n\n", filename, filename)
+}
+
+// loadCA will load or create the CA at CAROOT.
+func (m *mkcert) loadCA() {
+	if _, err := os.Stat(filepath.Join(m.CAROOT, rootName)); os.IsNotExist(err) {
+		m.newCA()
+	} else {
+		log.Printf("Using the local CA at \"%s\" ✨\n", m.CAROOT)
+	}
+
+	certPEMBlock, err := ioutil.ReadFile(filepath.Join(m.CAROOT, rootName))
+	fatalIfErr(err, "failed to read the CA certificate")
+	certDERBlock, _ := pem.Decode(certPEMBlock)
+	if certDERBlock == nil || certDERBlock.Type != "CERTIFICATE" {
+		log.Fatalln("ERROR: failed to read the CA certificate: unexpected content")
+	}
+	m.caCert, err = x509.ParseCertificate(certDERBlock.Bytes)
+	fatalIfErr(err, "failed to parse the CA certificate")
+
+	if _, err := os.Stat(filepath.Join(m.CAROOT, keyName)); os.IsNotExist(err) {
+		return // keyless mode, where only -install works
+	}
+
+	keyPEMBlock, err := ioutil.ReadFile(filepath.Join(m.CAROOT, keyName))
+	fatalIfErr(err, "failed to read the CA key")
+	keyDERBlock, _ := pem.Decode(keyPEMBlock)
+	if keyDERBlock == nil || keyDERBlock.Type != "PRIVATE KEY" {
+		log.Fatalln("ERROR: failed to read the CA key: unexpected content")
+	}
+	m.caKey, err = x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes)
+	fatalIfErr(err, "failed to parse the CA key")
+}
+
+func (m *mkcert) newCA() {
+	priv, err := rsa.GenerateKey(rand.Reader, 3072)
+	fatalIfErr(err, "failed to generate the CA key")
+
+	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+	fatalIfErr(err, "failed to generate serial number")
+
+	tpl := &x509.Certificate{
+		SerialNumber: serialNumber,
+		Subject:      rootSubject,
+
+		NotAfter:  time.Now().AddDate(10, 0, 0),
+		NotBefore: time.Now().AddDate(0, 0, -1),
+
+		KeyUsage: x509.KeyUsageCertSign,
+
+		BasicConstraintsValid: true,
+		IsCA:           true,
+		MaxPathLenZero: true,
+	}
+
+	pub := priv.PublicKey
+	cert, err := x509.CreateCertificate(rand.Reader, tpl, tpl, &pub, priv)
+	fatalIfErr(err, "failed to generate CA certificate")
+
+	privDER, err := x509.MarshalPKCS8PrivateKey(priv)
+	fatalIfErr(err, "failed to encode CA key")
+	err = ioutil.WriteFile(filepath.Join(m.CAROOT, keyName), pem.EncodeToMemory(
+		&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0400)
+	fatalIfErr(err, "failed to save CA key")
+
+	err = ioutil.WriteFile(filepath.Join(m.CAROOT, rootName), pem.EncodeToMemory(
+		&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
+	fatalIfErr(err, "failed to save CA key")
+
+	log.Printf("Created a new local CA at \"%s\" 💥\n", m.CAROOT)
+}

+ 0 - 143
main.go

@@ -7,23 +7,14 @@ package main
 
 import (
 	"crypto"
-	"crypto/rand"
-	"crypto/rsa"
 	"crypto/x509"
-	"crypto/x509/pkix"
-	"encoding/pem"
 	"flag"
-	"io/ioutil"
 	"log"
-	"math/big"
 	"net"
 	"os"
 	"path/filepath"
 	"regexp"
 	"runtime"
-	"strconv"
-	"strings"
-	"time"
 )
 
 func main() {
@@ -42,10 +33,6 @@ func main() {
 const rootName = "rootCA.pem"
 const keyName = "rootCA-key.pem"
 
-var rootSubject = pkix.Name{
-	Organization: []string{"mkcert development CA"},
-}
-
 type mkcert struct {
 	installMode, uninstallMode bool
 
@@ -118,136 +105,6 @@ Change the CA certificate and key storage location by setting $CAROOT.
 	m.makeCert(args)
 }
 
-func (m *mkcert) makeCert(hosts []string) {
-	if m.caKey == nil {
-		log.Fatalln("ERROR: can't create new certificates because the CA key (rootCA-key.pem) is missing")
-	}
-
-	priv, err := rsa.GenerateKey(rand.Reader, 2048)
-	fatalIfErr(err, "failed to generate certificate key")
-
-	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
-	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
-	fatalIfErr(err, "failed to generate serial number")
-
-	tpl := &x509.Certificate{
-		SerialNumber: serialNumber,
-		Subject: pkix.Name{
-			Organization: []string{"mkcert development certificate"},
-		},
-
-		NotAfter:  time.Now().AddDate(10, 0, 0),
-		NotBefore: time.Now().AddDate(0, 0, -1),
-
-		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
-		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
-		BasicConstraintsValid: true,
-	}
-	for _, h := range hosts {
-		if ip := net.ParseIP(h); ip != nil {
-			tpl.IPAddresses = append(tpl.IPAddresses, ip)
-		} else {
-			tpl.DNSNames = append(tpl.DNSNames, h)
-		}
-	}
-
-	pub := priv.PublicKey
-	cert, err := x509.CreateCertificate(rand.Reader, tpl, m.caCert, &pub, m.caKey)
-	fatalIfErr(err, "failed to generate certificate")
-
-	filename := strings.Replace(hosts[0], ":", "_", -1)
-	filename = strings.Replace(filename, "*", "_wildcard", -1)
-	if len(hosts) > 1 {
-		filename += "+" + strconv.Itoa(len(hosts)-1)
-	}
-
-	privDER, err := x509.MarshalPKCS8PrivateKey(priv)
-	fatalIfErr(err, "failed to encode certificate key")
-	err = ioutil.WriteFile(filename+"-key.pem", pem.EncodeToMemory(
-		&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0400)
-	fatalIfErr(err, "failed to save certificate key")
-
-	err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory(
-		&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
-	fatalIfErr(err, "failed to save certificate key")
-
-	log.Printf("\nCreated a new certificate valid for the following names 📜")
-	for _, h := range hosts {
-		log.Printf(" - %q", h)
-	}
-	log.Printf("\nThe certificate is at \"./%s.pem\" and the key at \"./%s-key.pem\" ✅\n\n", filename, filename)
-}
-
-// loadCA will load or create the CA at CAROOT.
-func (m *mkcert) loadCA() {
-	if _, err := os.Stat(filepath.Join(m.CAROOT, rootName)); os.IsNotExist(err) {
-		m.newCA()
-	} else {
-		log.Printf("Using the local CA at \"%s\" ✨\n", m.CAROOT)
-	}
-
-	certPEMBlock, err := ioutil.ReadFile(filepath.Join(m.CAROOT, rootName))
-	fatalIfErr(err, "failed to read the CA certificate")
-	certDERBlock, _ := pem.Decode(certPEMBlock)
-	if certDERBlock == nil || certDERBlock.Type != "CERTIFICATE" {
-		log.Fatalln("ERROR: failed to read the CA certificate: unexpected content")
-	}
-	m.caCert, err = x509.ParseCertificate(certDERBlock.Bytes)
-	fatalIfErr(err, "failed to parse the CA certificate")
-
-	if _, err := os.Stat(filepath.Join(m.CAROOT, keyName)); os.IsNotExist(err) {
-		return // keyless mode, where only -install works
-	}
-
-	keyPEMBlock, err := ioutil.ReadFile(filepath.Join(m.CAROOT, keyName))
-	fatalIfErr(err, "failed to read the CA key")
-	keyDERBlock, _ := pem.Decode(keyPEMBlock)
-	if keyDERBlock == nil || keyDERBlock.Type != "PRIVATE KEY" {
-		log.Fatalln("ERROR: failed to read the CA key: unexpected content")
-	}
-	m.caKey, err = x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes)
-	fatalIfErr(err, "failed to parse the CA key")
-}
-
-func (m *mkcert) newCA() {
-	priv, err := rsa.GenerateKey(rand.Reader, 3072)
-	fatalIfErr(err, "failed to generate the CA key")
-
-	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
-	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
-	fatalIfErr(err, "failed to generate serial number")
-
-	tpl := &x509.Certificate{
-		SerialNumber: serialNumber,
-		Subject:      rootSubject,
-
-		NotAfter:  time.Now().AddDate(10, 0, 0),
-		NotBefore: time.Now().AddDate(0, 0, -1),
-
-		KeyUsage: x509.KeyUsageCertSign,
-
-		BasicConstraintsValid: true,
-		IsCA:           true,
-		MaxPathLenZero: true,
-	}
-
-	pub := priv.PublicKey
-	cert, err := x509.CreateCertificate(rand.Reader, tpl, tpl, &pub, priv)
-	fatalIfErr(err, "failed to generate CA certificate")
-
-	privDER, err := x509.MarshalPKCS8PrivateKey(priv)
-	fatalIfErr(err, "failed to encode CA key")
-	err = ioutil.WriteFile(filepath.Join(m.CAROOT, keyName), pem.EncodeToMemory(
-		&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0400)
-	fatalIfErr(err, "failed to save CA key")
-
-	err = ioutil.WriteFile(filepath.Join(m.CAROOT, rootName), pem.EncodeToMemory(
-		&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
-	fatalIfErr(err, "failed to save CA key")
-
-	log.Printf("Created a new local CA at \"%s\" 💥\n", m.CAROOT)
-}
-
 func getCAROOT() string {
 	if env := os.Getenv("CAROOT"); env != "" {
 		return env