From da4da8a4bc86e0dff9c338c547bb1298220d5433 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sun, 6 Jan 2019 18:55:49 -0500 Subject: [PATCH] Refactor output path flags --- cert.go | 78 +++++++++++++++++++++++----------------------------- cert_test.go | 72 ------------------------------------------------ main.go | 21 +++++++------- 3 files changed, 44 insertions(+), 127 deletions(-) delete mode 100644 cert_test.go diff --git a/cert.go b/cert.go index 951646ec..79d59753 100644 --- a/cert.go +++ b/cert.go @@ -12,7 +12,6 @@ import ( "crypto/x509/pkix" "encoding/asn1" "encoding/pem" - "errors" "io/ioutil" "log" "math/big" @@ -40,34 +39,6 @@ func init() { userAndHostname += strings.TrimSpace(string(out)) } -// getFileName generate file name according to flags -func (m *mkcert) getFileName(w string, args []string) (name string, err error) { - filename := strings.Replace(args[0], ":", "_", -1) - filename = strings.Replace(filename, "*", "_wildcard", -1) - if len(args) > 1 { - filename += "+" + strconv.Itoa(len(args)-1) - } - switch w { - case "key": - if m.keyFileFlag != "" { - return m.keyFileFlag, nil - } - return filename + "-key.pem", nil - case "cert": - if m.certFileFlag != "" { - return m.certFileFlag, nil - } - return filename + ".pem", nil - case "p12": - if m.p12FileFlag != "" { - return m.p12FileFlag, nil - } - return filename + ".p12", nil - default: - return "", errors.New("failed to generate file name") - } -} - 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") @@ -105,28 +76,24 @@ func (m *mkcert) makeCert(hosts []string) { pub := priv.PublicKey cert, err := x509.CreateCertificate(rand.Reader, tpl, m.caCert, &pub, m.caKey) fatalIfErr(err, "failed to generate certificate") - var keyname, certname, p12name string + + certFile, keyFile, p12File := m.fileNames(hosts) + if !m.pkcs12 { privDER, err := x509.MarshalPKCS8PrivateKey(priv) fatalIfErr(err, "failed to encode certificate key") - keyname, err = m.getFileName("key", hosts) - fatalIfErr(err, "failed to generate key file name") - err = ioutil.WriteFile(keyname, pem.EncodeToMemory( + err = ioutil.WriteFile(keyFile, pem.EncodeToMemory( &pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0600) fatalIfErr(err, "failed to save certificate key") - certname, err = m.getFileName("cert", hosts) - fatalIfErr(err, "failed to generate cert file name") - err = ioutil.WriteFile(certname, pem.EncodeToMemory( + err = ioutil.WriteFile(certFile, pem.EncodeToMemory( &pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644) fatalIfErr(err, "failed to save certificate key") } else { domainCert, _ := x509.ParseCertificate(cert) pfxData, err := pkcs12.Encode(rand.Reader, priv, domainCert, []*x509.Certificate{m.caCert}, "changeit") fatalIfErr(err, "failed to generate PKCS#12") - p12name, err = m.getFileName("p12", hosts) - fatalIfErr(err, "failed to generate cert PKCS#12 file name") - err = ioutil.WriteFile(p12name, pfxData, 0644) + err = ioutil.WriteFile(p12File, pfxData, 0644) fatalIfErr(err, "failed to save PKCS#12") } @@ -147,13 +114,36 @@ func (m *mkcert) makeCert(hosts []string) { } if !m.pkcs12 { - log.Printf("\nThe certificate is at \"./%s\" and the key at \"./%s\" ✅\n\n", certname, keyname) + log.Printf("\nThe certificate is at \"%s\" and the key at \"%s\" ✅\n\n", certFile, keyFile) } else { - log.Printf("\nThe PKCS#12 bundle is at \"./%s\" ✅\n", p12name) + log.Printf("\nThe PKCS#12 bundle is at \"%s\" ✅\n", p12File) log.Printf("\nThe legacy PKCS#12 encryption password is the often hardcoded default \"changeit\" ℹ️\n\n") } } +func (m *mkcert) fileNames(hosts []string) (certFile, keyFile, p12File string) { + defaultName := strings.Replace(hosts[0], ":", "_", -1) + defaultName = strings.Replace(defaultName, "*", "_wildcard", -1) + if len(hosts) > 1 { + defaultName += "+" + strconv.Itoa(len(hosts)-1) + } + + certFile = "./" + defaultName + ".pem" + if m.certFile != "" { + certFile = m.certFile + } + keyFile = "./" + defaultName + "-key.pem" + if m.keyFile != "" { + keyFile = m.keyFile + } + p12File = "./" + defaultName + ".p12" + if m.p12File != "" { + p12File = m.p12File + } + + return +} + // 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) { @@ -171,11 +161,11 @@ func (m *mkcert) loadCA() { 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) { + if _, err := os.Stat(filepath.Join(m.CAROOT, rootKeyName)); os.IsNotExist(err) { return // keyless mode, where only -install works } - keyPEMBlock, err := ioutil.ReadFile(filepath.Join(m.CAROOT, keyName)) + keyPEMBlock, err := ioutil.ReadFile(filepath.Join(m.CAROOT, rootKeyName)) fatalIfErr(err, "failed to read the CA key") keyDERBlock, _ := pem.Decode(keyPEMBlock) if keyDERBlock == nil || keyDERBlock.Type != "PRIVATE KEY" { @@ -234,7 +224,7 @@ func (m *mkcert) newCA() { privDER, err := x509.MarshalPKCS8PrivateKey(priv) fatalIfErr(err, "failed to encode CA key") - err = ioutil.WriteFile(filepath.Join(m.CAROOT, keyName), pem.EncodeToMemory( + err = ioutil.WriteFile(filepath.Join(m.CAROOT, rootKeyName), pem.EncodeToMemory( &pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0400) fatalIfErr(err, "failed to save CA key") diff --git a/cert_test.go b/cert_test.go deleted file mode 100644 index c65c7cfe..00000000 --- a/cert_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package main - -import ( - "testing" -) - -// TestGetFileName test func getFileName -func TestGetFileName(t *testing.T) { - // all flags are added - mk := &mkcert{ - keyFileFlag: "test-key-name.pem", - certFileFlag: "test-cert-name.pem", - p12FileFlag: "test.p12", - } - // check keyname, the result should be customized - keyname, err := mk.getFileName("key", []string{"example.com"}) - if err != nil { - t.Error("failed to get customized key file name") - } - if keyname != "test-key-name.pem" { - t.Error("keyname check failed") - } - - // check certname, the result should be customized - certname, err := mk.getFileName("cert", []string{"example.com"}) - if err != nil { - t.Error("failed to get customized cert file name") - } - if certname != "test-cert-name.pem" { - t.Error("certname check failed") - } - - // check p12name, the result should be customized - p12name, err := mk.getFileName("p12", []string{"example.com"}) - if err != nil { - t.Error("failed to get customized p12 file name") - } - if p12name != "test.p12" { - t.Error("p12 check failed") - } - - // default name will be generated if no flags passed - mk = &mkcert{ - keyFileFlag: "test-key-name.pem", - } - // check keyname again, the result should be custoomized due to keyFileFlag - keyname, err = mk.getFileName("key", []string{"example.com", "localhost"}) - if err != nil { - t.Error("failed to get customized key file name") - } - if keyname != "test-key-name.pem" { - t.Error("keyname check failed") - } - - // check default certname, the result should be default file name generated by original principle - certname, err = mk.getFileName("cert", []string{"*.example.com", "localhost"}) - if err != nil { - t.Error("failed to get default cert file name") - } - if certname != "_wildcard.example.com+1.pem" { - t.Error("certname check failed") - } - - // check default p12name, the result should be default file name generated by original principle - p12name, err = mk.getFileName("p12", []string{"x.co:y.com"}) - if err != nil { - t.Error("failed to get default p12 file name") - } - if p12name != "x.co_y.com.p12" { - t.Error("p12 check failed") - } -} diff --git a/main.go b/main.go index af41a6c1..3fc5823c 100644 --- a/main.go +++ b/main.go @@ -40,6 +40,8 @@ const usage = `Usage of mkcert: $ mkcert -uninstall Uninstall the local CA (but do not delete it). +Use -cert-file, -key-file and -p12-file to customize the output paths. + Change the CA certificate and key storage location by setting $CAROOT, print it with "mkcert -CAROOT". ` @@ -50,10 +52,9 @@ func main() { var uninstallFlag = flag.Bool("uninstall", false, "uninstall the local root CA from the system trust store") var pkcs12Flag = flag.Bool("pkcs12", false, "generate PKCS#12 instead of PEM") var carootFlag = flag.Bool("CAROOT", false, "print the CAROOT path") - // customize file name according to issue#72 - var keyFileFlag = flag.String("key-file", "", "customlize your key file name") - var certFileFlag = flag.String("cert-file", "", "customlize your cert file name") - var p12FileFlag = flag.String("p12-file", "", "customlize your p12 file name") + var certFileFlag = flag.String("cert-file", "", "output certificate file path") + var keyFileFlag = flag.String("key-file", "", "output key file path") + var p12FileFlag = flag.String("p12-file", "", "output PKCS#12 file path") flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), usage) } flag.Parse() if *carootFlag { @@ -68,19 +69,17 @@ func main() { } (&mkcert{ installMode: *installFlag, uninstallMode: *uninstallFlag, pkcs12: *pkcs12Flag, - keyFileFlag: *keyFileFlag, - certFileFlag: *certFileFlag, - p12FileFlag: *p12FileFlag, + certFile: *certFileFlag, keyFile: *keyFileFlag, p12File: *p12FileFlag, }).Run(flag.Args()) } const rootName = "rootCA.pem" -const keyName = "rootCA-key.pem" +const rootKeyName = "rootCA-key.pem" type mkcert struct { - installMode, uninstallMode bool - pkcs12 bool - keyFileFlag, certFileFlag, p12FileFlag string + installMode, uninstallMode bool + pkcs12 bool + keyFile, certFile, p12File string CAROOT string caCert *x509.Certificate