mirror of
https://github.com/FiloSottile/mkcert.git
synced 2025-10-14 00:41:40 +08:00
Refactor output path flags
This commit is contained in:

committed by
Filippo Valsorda

parent
5ea72c377d
commit
da4da8a4bc
78
cert.go
78
cert.go
@@ -12,7 +12,6 @@ import (
|
|||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
@@ -40,34 +39,6 @@ func init() {
|
|||||||
userAndHostname += strings.TrimSpace(string(out))
|
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) {
|
func (m *mkcert) makeCert(hosts []string) {
|
||||||
if m.caKey == nil {
|
if m.caKey == nil {
|
||||||
log.Fatalln("ERROR: can't create new certificates because the CA key (rootCA-key.pem) is missing")
|
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
|
pub := priv.PublicKey
|
||||||
cert, err := x509.CreateCertificate(rand.Reader, tpl, m.caCert, &pub, m.caKey)
|
cert, err := x509.CreateCertificate(rand.Reader, tpl, m.caCert, &pub, m.caKey)
|
||||||
fatalIfErr(err, "failed to generate certificate")
|
fatalIfErr(err, "failed to generate certificate")
|
||||||
var keyname, certname, p12name string
|
|
||||||
|
certFile, keyFile, p12File := m.fileNames(hosts)
|
||||||
|
|
||||||
if !m.pkcs12 {
|
if !m.pkcs12 {
|
||||||
privDER, err := x509.MarshalPKCS8PrivateKey(priv)
|
privDER, err := x509.MarshalPKCS8PrivateKey(priv)
|
||||||
fatalIfErr(err, "failed to encode certificate key")
|
fatalIfErr(err, "failed to encode certificate key")
|
||||||
keyname, err = m.getFileName("key", hosts)
|
err = ioutil.WriteFile(keyFile, pem.EncodeToMemory(
|
||||||
fatalIfErr(err, "failed to generate key file name")
|
|
||||||
err = ioutil.WriteFile(keyname, pem.EncodeToMemory(
|
|
||||||
&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0600)
|
&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0600)
|
||||||
fatalIfErr(err, "failed to save certificate key")
|
fatalIfErr(err, "failed to save certificate key")
|
||||||
|
|
||||||
certname, err = m.getFileName("cert", hosts)
|
err = ioutil.WriteFile(certFile, pem.EncodeToMemory(
|
||||||
fatalIfErr(err, "failed to generate cert file name")
|
|
||||||
err = ioutil.WriteFile(certname, pem.EncodeToMemory(
|
|
||||||
&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
|
&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0644)
|
||||||
fatalIfErr(err, "failed to save certificate key")
|
fatalIfErr(err, "failed to save certificate key")
|
||||||
} else {
|
} else {
|
||||||
domainCert, _ := x509.ParseCertificate(cert)
|
domainCert, _ := x509.ParseCertificate(cert)
|
||||||
pfxData, err := pkcs12.Encode(rand.Reader, priv, domainCert, []*x509.Certificate{m.caCert}, "changeit")
|
pfxData, err := pkcs12.Encode(rand.Reader, priv, domainCert, []*x509.Certificate{m.caCert}, "changeit")
|
||||||
fatalIfErr(err, "failed to generate PKCS#12")
|
fatalIfErr(err, "failed to generate PKCS#12")
|
||||||
p12name, err = m.getFileName("p12", hosts)
|
err = ioutil.WriteFile(p12File, pfxData, 0644)
|
||||||
fatalIfErr(err, "failed to generate cert PKCS#12 file name")
|
|
||||||
err = ioutil.WriteFile(p12name, pfxData, 0644)
|
|
||||||
fatalIfErr(err, "failed to save PKCS#12")
|
fatalIfErr(err, "failed to save PKCS#12")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,13 +114,36 @@ func (m *mkcert) makeCert(hosts []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !m.pkcs12 {
|
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 {
|
} 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")
|
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.
|
// loadCA will load or create the CA at CAROOT.
|
||||||
func (m *mkcert) loadCA() {
|
func (m *mkcert) loadCA() {
|
||||||
if _, err := os.Stat(filepath.Join(m.CAROOT, rootName)); os.IsNotExist(err) {
|
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)
|
m.caCert, err = x509.ParseCertificate(certDERBlock.Bytes)
|
||||||
fatalIfErr(err, "failed to parse the CA certificate")
|
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
|
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")
|
fatalIfErr(err, "failed to read the CA key")
|
||||||
keyDERBlock, _ := pem.Decode(keyPEMBlock)
|
keyDERBlock, _ := pem.Decode(keyPEMBlock)
|
||||||
if keyDERBlock == nil || keyDERBlock.Type != "PRIVATE KEY" {
|
if keyDERBlock == nil || keyDERBlock.Type != "PRIVATE KEY" {
|
||||||
@@ -234,7 +224,7 @@ func (m *mkcert) newCA() {
|
|||||||
|
|
||||||
privDER, err := x509.MarshalPKCS8PrivateKey(priv)
|
privDER, err := x509.MarshalPKCS8PrivateKey(priv)
|
||||||
fatalIfErr(err, "failed to encode CA key")
|
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)
|
&pem.Block{Type: "PRIVATE KEY", Bytes: privDER}), 0400)
|
||||||
fatalIfErr(err, "failed to save CA key")
|
fatalIfErr(err, "failed to save CA key")
|
||||||
|
|
||||||
|
72
cert_test.go
72
cert_test.go
@@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
21
main.go
21
main.go
@@ -40,6 +40,8 @@ const usage = `Usage of mkcert:
|
|||||||
$ mkcert -uninstall
|
$ mkcert -uninstall
|
||||||
Uninstall the local CA (but do not delete it).
|
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,
|
Change the CA certificate and key storage location by setting $CAROOT,
|
||||||
print it with "mkcert -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 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 pkcs12Flag = flag.Bool("pkcs12", false, "generate PKCS#12 instead of PEM")
|
||||||
var carootFlag = flag.Bool("CAROOT", false, "print the CAROOT path")
|
var carootFlag = flag.Bool("CAROOT", false, "print the CAROOT path")
|
||||||
// customize file name according to issue#72
|
var certFileFlag = flag.String("cert-file", "", "output certificate file path")
|
||||||
var keyFileFlag = flag.String("key-file", "", "customlize your key file name")
|
var keyFileFlag = flag.String("key-file", "", "output key file path")
|
||||||
var certFileFlag = flag.String("cert-file", "", "customlize your cert file name")
|
var p12FileFlag = flag.String("p12-file", "", "output PKCS#12 file path")
|
||||||
var p12FileFlag = flag.String("p12-file", "", "customlize your p12 file name")
|
|
||||||
flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), usage) }
|
flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), usage) }
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *carootFlag {
|
if *carootFlag {
|
||||||
@@ -68,19 +69,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
(&mkcert{
|
(&mkcert{
|
||||||
installMode: *installFlag, uninstallMode: *uninstallFlag, pkcs12: *pkcs12Flag,
|
installMode: *installFlag, uninstallMode: *uninstallFlag, pkcs12: *pkcs12Flag,
|
||||||
keyFileFlag: *keyFileFlag,
|
certFile: *certFileFlag, keyFile: *keyFileFlag, p12File: *p12FileFlag,
|
||||||
certFileFlag: *certFileFlag,
|
|
||||||
p12FileFlag: *p12FileFlag,
|
|
||||||
}).Run(flag.Args())
|
}).Run(flag.Args())
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootName = "rootCA.pem"
|
const rootName = "rootCA.pem"
|
||||||
const keyName = "rootCA-key.pem"
|
const rootKeyName = "rootCA-key.pem"
|
||||||
|
|
||||||
type mkcert struct {
|
type mkcert struct {
|
||||||
installMode, uninstallMode bool
|
installMode, uninstallMode bool
|
||||||
pkcs12 bool
|
pkcs12 bool
|
||||||
keyFileFlag, certFileFlag, p12FileFlag string
|
keyFile, certFile, p12File string
|
||||||
|
|
||||||
CAROOT string
|
CAROOT string
|
||||||
caCert *x509.Certificate
|
caCert *x509.Certificate
|
||||||
|
Reference in New Issue
Block a user