From 5ea72c377dae5266b6a2c2cc4f173edcd2a59347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=95=E5=85=83=E6=BA=90?= Date: Wed, 10 Oct 2018 20:50:45 +0800 Subject: [PATCH] Add -cert-file, -key-file and -p12-file (#77) --- cert.go | 53 +++++++++++++++++++++++++++++--------- cert_test.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 12 +++++++-- 3 files changed, 123 insertions(+), 14 deletions(-) create mode 100644 cert_test.go diff --git a/cert.go b/cert.go index 52068db..951646e 100644 --- a/cert.go +++ b/cert.go @@ -12,6 +12,7 @@ import ( "crypto/x509/pkix" "encoding/asn1" "encoding/pem" + "errors" "io/ioutil" "log" "math/big" @@ -39,6 +40,34 @@ 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") @@ -76,28 +105,28 @@ 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") - - filename := strings.Replace(hosts[0], ":", "_", -1) - filename = strings.Replace(filename, "*", "_wildcard", -1) - if len(hosts) > 1 { - filename += "+" + strconv.Itoa(len(hosts)-1) - } - + var keyname, certname, p12name string if !m.pkcs12 { privDER, err := x509.MarshalPKCS8PrivateKey(priv) fatalIfErr(err, "failed to encode certificate key") - err = ioutil.WriteFile(filename+"-key.pem", pem.EncodeToMemory( + keyname, err = m.getFileName("key", hosts) + fatalIfErr(err, "failed to generate key file name") + err = ioutil.WriteFile(keyname, pem.EncodeToMemory( &pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0600) fatalIfErr(err, "failed to save certificate key") - err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory( + certname, err = m.getFileName("cert", hosts) + fatalIfErr(err, "failed to generate cert file name") + err = ioutil.WriteFile(certname, 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") - err = ioutil.WriteFile(filename+".p12", pfxData, 0644) + p12name, err = m.getFileName("p12", hosts) + fatalIfErr(err, "failed to generate cert PKCS#12 file name") + err = ioutil.WriteFile(p12name, pfxData, 0644) fatalIfErr(err, "failed to save PKCS#12") } @@ -118,9 +147,9 @@ func (m *mkcert) makeCert(hosts []string) { } if !m.pkcs12 { - log.Printf("\nThe certificate is at \"./%s.pem\" and the key at \"./%s-key.pem\" ✅\n\n", filename, filename) + log.Printf("\nThe certificate is at \"./%s\" and the key at \"./%s\" ✅\n\n", certname, keyname) } else { - log.Printf("\nThe PKCS#12 bundle is at \"./%s.p12\" ✅\n", filename) + log.Printf("\nThe PKCS#12 bundle is at \"./%s\" ✅\n", p12name) log.Printf("\nThe legacy PKCS#12 encryption password is the often hardcoded default \"changeit\" ℹ️\n\n") } } diff --git a/cert_test.go b/cert_test.go new file mode 100644 index 0000000..c65c7cf --- /dev/null +++ b/cert_test.go @@ -0,0 +1,72 @@ +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 43ab3fe..af41a6c 100644 --- a/main.go +++ b/main.go @@ -50,6 +50,10 @@ 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") flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), usage) } flag.Parse() if *carootFlag { @@ -64,6 +68,9 @@ func main() { } (&mkcert{ installMode: *installFlag, uninstallMode: *uninstallFlag, pkcs12: *pkcs12Flag, + keyFileFlag: *keyFileFlag, + certFileFlag: *certFileFlag, + p12FileFlag: *p12FileFlag, }).Run(flag.Args()) } @@ -71,8 +78,9 @@ const rootName = "rootCA.pem" const keyName = "rootCA-key.pem" type mkcert struct { - installMode, uninstallMode bool - pkcs12 bool + installMode, uninstallMode bool + pkcs12 bool + keyFileFlag, certFileFlag, p12FileFlag string CAROOT string caCert *x509.Certificate