Add certificate generation and -uninstall
This commit is contained in:
parent
c3ffec658a
commit
314622cbb3
110
main.go
110
main.go
@ -16,18 +16,27 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var installFlag = flag.Bool("install", false, "install the local root CA in the system trust store")
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
var installFlag = flag.Bool("install", false, "install the local root CA in the system trust store")
|
||||
var uninstallFlag = flag.Bool("uninstall", false, "uninstall the local root CA from the system trust store")
|
||||
flag.Parse()
|
||||
(&mkcert{}).Run()
|
||||
if *installFlag && *uninstallFlag {
|
||||
log.Fatalln("ERROR: you can't set -install and -uninstall at the same time")
|
||||
}
|
||||
(&mkcert{
|
||||
installMode: *installFlag, uninstallMode: *uninstallFlag,
|
||||
}).Run(flag.Args())
|
||||
}
|
||||
|
||||
const rootName = "rootCA.pem"
|
||||
@ -38,6 +47,8 @@ var rootSubject = pkix.Name{
|
||||
}
|
||||
|
||||
type mkcert struct {
|
||||
installMode, uninstallMode bool
|
||||
|
||||
CAROOT string
|
||||
caCert *x509.Certificate
|
||||
caKey crypto.PrivateKey
|
||||
@ -48,19 +59,99 @@ type mkcert struct {
|
||||
ignoreCheckFailure bool
|
||||
}
|
||||
|
||||
func (m *mkcert) Run() {
|
||||
func (m *mkcert) Run(args []string) {
|
||||
m.CAROOT = getCAROOT()
|
||||
if m.CAROOT == "" {
|
||||
log.Fatalln("ERROR: failed to find the default CA location, set one as the CAROOT env var")
|
||||
}
|
||||
fatalIfErr(os.MkdirAll(m.CAROOT, 0755), "failed to create the CAROOT")
|
||||
m.loadCA()
|
||||
if *installFlag {
|
||||
|
||||
if m.installMode {
|
||||
m.install()
|
||||
if len(args) == 0 {
|
||||
return
|
||||
}
|
||||
} else if m.uninstallMode {
|
||||
m.uninstall()
|
||||
return
|
||||
} else if !m.check() {
|
||||
log.Println("Warning: the local CA is not installed in the system trust store! ⚠️")
|
||||
log.Println("Run \"mkcert -install\" to avoid verification errors ‼️")
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
log.Println("Usage: TODO")
|
||||
return
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`^[0-9A-Za-z._-]+$`)
|
||||
for _, name := range args {
|
||||
if ip := net.ParseIP(name); ip != nil {
|
||||
continue
|
||||
}
|
||||
if re.MatchString(name) {
|
||||
continue
|
||||
}
|
||||
log.Fatalf("ERROR: %q is not a valid hostname or IP", name)
|
||||
}
|
||||
|
||||
m.makeCert(args)
|
||||
}
|
||||
|
||||
func (m *mkcert) makeCert(hosts []string) {
|
||||
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)
|
||||
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}), 0644)
|
||||
fatalIfErr(err, "failed to save certificate key")
|
||||
|
||||
err = ioutil.WriteFile(filename+".pem", pem.EncodeToMemory(
|
||||
&pem.Block{Type: "CERTIFICATE", Bytes: cert}), 0600)
|
||||
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.
|
||||
@ -176,12 +267,17 @@ func (m *mkcert) install() {
|
||||
*/
|
||||
|
||||
if m.check() { // useless, see comment on ignoreCheckFailure
|
||||
log.Println("The local CA is now installed in the system trust store! ⚡️")
|
||||
log.Print("The local CA is now installed in the system trust store! ⚡️\n\n")
|
||||
} else {
|
||||
log.Fatalln("Installing failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎")
|
||||
log.Fatal("Installing failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mkcert) uninstall() {
|
||||
m.uninstallPlatform()
|
||||
log.Print("The local CA is now uninstalled from the system trust store! 👋\n\n")
|
||||
}
|
||||
|
||||
func (m *mkcert) check() bool {
|
||||
if m.ignoreCheckFailure {
|
||||
return true
|
||||
|
@ -95,6 +95,12 @@ func (m *mkcert) installPlatform() {
|
||||
fatalIfCmdErr(err, "security trust-settings-import", out)
|
||||
}
|
||||
|
||||
func (m *mkcert) uninstallPlatform() {
|
||||
cmd := exec.Command("sudo", "security", "remove-trusted-cert", "-d", filepath.Join(m.CAROOT, rootName))
|
||||
out, err := cmd.CombinedOutput()
|
||||
fatalIfCmdErr(err, "security remove-trusted-cert", out)
|
||||
}
|
||||
|
||||
func fatalIfCmdErr(err error, cmd string, out []byte) {
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR: failed to execute \"%s\": %s\n\n%s\n", cmd, err, out)
|
||||
|
Loading…
Reference in New Issue
Block a user