diff --git a/truststore_nss.go b/truststore_nss.go index d288eb837ad9fac0d6fbda70bd57f5def80602d7..b77133acebd117a875b111b87b123b50c130b08a 100644 --- a/truststore_nss.go +++ b/truststore_nss.go @@ -1,12 +1,11 @@ -// +build ignore -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. +// Copyright (c) 2018 The truststore Authors. All rights reserved. +// Copyright (c) 2018 The mkcert Authors. All rights reserved. package truststore import ( - "log" + "crypto/x509" + "fmt" "os" "os/exec" "path/filepath" @@ -15,52 +14,72 @@ import ( ) var ( - hasNSS bool - hasCertutil bool certutilPath string nssDB = filepath.Join(os.Getenv("HOME"), ".pki/nssdb") ) -func init() { +func hasNSS() bool { for _, path := range []string{ "/usr/bin/firefox", nssDB, "/Applications/Firefox.app", "/Applications/Firefox Developer Edition.app", "/Applications/Firefox Nightly.app", "C:\\Program Files\\Mozilla Firefox", } { - _, err := os.Stat(path) - hasNSS = hasNSS || err == nil + if _, err := os.Stat(path); err == nil { + return true + } + } + // Try with user defined path + if path := os.Getenv("TRUSTSTORE_NSS_LOCATION"); path != "" { + if _, err := os.Stat(path); err == nil { + fmt.Println() + return true + } else { + println(err.Error()) + } } + debug("%s not found. Try to define the environment variable TRUSTSTORE_NSS_LOCATION", NSSBrowsers) + return false +} + +func hasCertUtil() bool { + var err error switch runtime.GOOS { case "darwin": - var err error certutilPath, err = exec.LookPath("certutil") if err != nil { - var out []byte - out, err = exec.Command("brew", "--prefix", "nss").Output() - if err != nil { - return + out, err1 := exec.Command("brew", "--prefix", "nss").Output() + if err1 != nil { + return false } certutilPath = filepath.Join(strings.TrimSpace(string(out)), "bin", "certutil") _, err = os.Stat(certutilPath) } - hasCertutil = err == nil - + return err == nil case "linux": - var err error certutilPath, err = exec.LookPath("certutil") - hasCertutil = err == nil + return err == nil + default: + return false } } -func (m *mkcert) checkNSS() bool { - if !hasCertutil { +func checkNSS(cert *x509.Certificate) bool { + if !hasCertUtil() { + if CertutilInstallHelp == "" { + debug("Note: %s support is not available on your platform. ℹï¸", NSSBrowsers) + } else { + debug(`Warning: "certutil" is not available, so the certificate can't be automatically installed in %s!`, NSSBrowsers) + debug(`Install "certutil" with "%s" and try again`, CertutilInstallHelp) + } return false } + + // Check if the certificate is already installed success := true - if m.forEachNSSProfile(func(profile string) { - err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run() + if forEachNSSProfile(func(profile string) { + err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", uniqueName(cert)).Run() if err != nil { success = false } @@ -70,36 +89,45 @@ func (m *mkcert) checkNSS() bool { return success } -func (m *mkcert) installNSS() bool { - if m.forEachNSSProfile(func(profile string) { - cmd := exec.Command(certutilPath, "-A", "-d", profile, "-t", "C,,", "-n", m.caUniqueName(), "-i", filepath.Join(m.CAROOT, rootName)) +func installNSS(filename string, cert *x509.Certificate) error { + // install certificate in all profiles + if forEachNSSProfile(func(profile string) { + cmd := exec.Command(certutilPath, "-A", "-d", profile, "-t", "C,,", "-n", uniqueName(cert), "-i", filename) out, err := cmd.CombinedOutput() - fatalIfCmdErr(err, "certutil -A", out) + if err != nil { + debug("failed to execute \"certutil -A\": %s\n\n%s", err, out) + } }) == 0 { - log.Printf("ERROR: no %s security databases found", NSSBrowsers) - return false + return fmt.Errorf("not %s security databases found", NSSBrowsers) } - if !m.checkNSS() { - log.Printf("Installing in %s failed. Please report the issue with details about your environment at https://github.com/FiloSottile/mkcert/issues/new 👎", NSSBrowsers) - log.Printf("Note that if you never started %s, you need to do that at least once.", NSSBrowsers) - return false + // check for the cert in all profiles + if !checkNSS(cert) { + return fmt.Errorf("certificate cannot be installed in %s", NSSBrowsers) } - return true + debug("certificate installed properly in %s", NSSBrowsers) + return nil } -func (m *mkcert) uninstallNSS() { - m.forEachNSSProfile(func(profile string) { - err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", m.caUniqueName()).Run() +func uninstallNSS(filname string, cert *x509.Certificate) (err error) { + forEachNSSProfile(func(profile string) { if err != nil { return } - cmd := exec.Command(certutilPath, "-D", "-d", profile, "-n", m.caUniqueName()) - out, err := cmd.CombinedOutput() - fatalIfCmdErr(err, "certutil -D", out) + // skip if not found + if err := exec.Command(certutilPath, "-V", "-d", profile, "-u", "L", "-n", uniqueName(cert)).Run(); err != nil { + return + } + // delete certificate + cmd := exec.Command(certutilPath, "-D", "-d", profile, "-n", uniqueName(cert)) + out, err1 := cmd.CombinedOutput() + if err1 != nil { + err = cmdError(err1, "certutil -D", out) + } }) + return } -func (m *mkcert) forEachNSSProfile(f func(profile string)) (found int) { +func forEachNSSProfile(f func(profile string)) (found int) { profiles, _ := filepath.Glob(FirefoxProfile) if _, err := os.Stat(nssDB); err == nil { profiles = append(profiles, nssDB)