Support installing into Java's root store (#38)
This commit is contained in:
parent
fd504a1868
commit
ae768be874
22
main.go
22
main.go
@ -105,6 +105,10 @@ func (m *mkcert) Run(args []string) {
|
||||
warning = true
|
||||
log.Printf("Warning: the local CA is not installed in the %s trust store! ⚠️", NSSBrowsers)
|
||||
}
|
||||
if hasJava && !m.checkJava() {
|
||||
warning = true
|
||||
log.Println("Warning: the local CA is not installed in the Java trust store! ⚠️")
|
||||
}
|
||||
if warning {
|
||||
log.Println("Run \"mkcert -install\" to avoid verification errors ‼️")
|
||||
}
|
||||
@ -179,6 +183,15 @@ func (m *mkcert) install() {
|
||||
}
|
||||
printed = true
|
||||
}
|
||||
if hasJava && !m.checkJava() {
|
||||
if hasKeytool {
|
||||
m.installJava()
|
||||
log.Println("The local CA is now installed in Java's trust store! ☕️")
|
||||
} else {
|
||||
log.Println(`Warning: "keytool" is not available, so the CA can't be automatically installed in Java's trust store! ⚠️`)
|
||||
}
|
||||
printed = true
|
||||
}
|
||||
if printed {
|
||||
log.Print("")
|
||||
}
|
||||
@ -195,6 +208,15 @@ func (m *mkcert) uninstall() {
|
||||
log.Print("")
|
||||
}
|
||||
}
|
||||
if hasJava {
|
||||
if hasKeytool {
|
||||
m.uninstallJava()
|
||||
} else {
|
||||
log.Print("")
|
||||
log.Println(`Warning: "keytool" is not available, so the CA can't be automatically uninstalled from Java's trust store (if it was ever installed)! ⚠️`)
|
||||
log.Print("")
|
||||
}
|
||||
}
|
||||
if m.uninstallPlatform() {
|
||||
log.Print("The local CA is now uninstalled from the system trust store(s)! 👋")
|
||||
log.Print("")
|
||||
|
107
truststore_java.go
Normal file
107
truststore_java.go
Normal file
@ -0,0 +1,107 @@
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
hasJava bool
|
||||
hasKeytool bool
|
||||
|
||||
javaHome string
|
||||
cacertsPath string
|
||||
keytoolPath string
|
||||
storePass string = "changeit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if v := os.Getenv("JAVA_HOME"); v != "" {
|
||||
hasJava = true
|
||||
javaHome = v
|
||||
|
||||
_, err := os.Stat(path.Join(v, "bin/keytool"))
|
||||
if err == nil {
|
||||
hasKeytool = true
|
||||
keytoolPath = path.Join(v, "bin/keytool")
|
||||
}
|
||||
|
||||
cacertsPath = path.Join(v, "jre/lib/security/cacerts")
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mkcert) checkJava() bool {
|
||||
// exists returns true if the given x509.Certificate's fingerprint
|
||||
// is in the keytool -list output
|
||||
exists := func(c *x509.Certificate, h hash.Hash, keytoolOutput []byte) bool {
|
||||
h.Write(c.Raw)
|
||||
fp := strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
|
||||
return bytes.Contains(keytoolOutput, []byte(fp))
|
||||
}
|
||||
|
||||
keytoolOutput, err := exec.Command(keytoolPath, "-list", "-keystore", cacertsPath, "-storepass", storePass).CombinedOutput()
|
||||
fatalIfCmdErr(err, "keytool -list", keytoolOutput)
|
||||
// keytool outputs SHA1 and SHA256 (Java 9+) certificates in uppercase hex
|
||||
// with each octet pair delimitated by ":". Drop them from the keytool output
|
||||
keytoolOutput = bytes.Replace(keytoolOutput, []byte(":"), nil, -1)
|
||||
|
||||
// pre-Java 9 uses SHA1 fingerprints
|
||||
s1, s256 := sha1.New(), sha256.New()
|
||||
return exists(m.caCert, s1, keytoolOutput) || exists(m.caCert, s256, keytoolOutput)
|
||||
}
|
||||
|
||||
func (m *mkcert) installJava() {
|
||||
args := []string{
|
||||
"-importcert", "-noprompt",
|
||||
"-keystore", cacertsPath,
|
||||
"-storepass", storePass,
|
||||
"-file", filepath.Join(m.CAROOT, rootName),
|
||||
"-alias", m.caUniqueName(),
|
||||
}
|
||||
|
||||
out, err := m.execKeytool(exec.Command(keytoolPath, args...))
|
||||
fatalIfCmdErr(err, "keytool -importcert", out)
|
||||
}
|
||||
|
||||
func (m *mkcert) uninstallJava() {
|
||||
args := []string{
|
||||
"-delete",
|
||||
"-alias", m.caUniqueName(),
|
||||
"-keystore", cacertsPath,
|
||||
"-storepass", storePass,
|
||||
}
|
||||
out, err := m.execKeytool(exec.Command(keytoolPath, args...))
|
||||
if bytes.Contains(out, []byte("does not exist")) {
|
||||
return // cert didn't exist
|
||||
}
|
||||
fatalIfCmdErr(err, "keytool -delete", out)
|
||||
}
|
||||
|
||||
// execKeytool will execute a "keytool" command and if needed re-execute
|
||||
// the command wrapped in 'sudo' to work around file permissions.
|
||||
func (m *mkcert) execKeytool(cmd *exec.Cmd) ([]byte, error) {
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil && bytes.Contains(out, []byte("java.io.FileNotFoundException")) {
|
||||
origArgs := cmd.Args[1:]
|
||||
cmd = exec.Command("sudo", keytoolPath)
|
||||
cmd.Args = append(cmd.Args, origArgs...)
|
||||
cmd.Env = []string{
|
||||
"JAVA_HOME=" + javaHome,
|
||||
}
|
||||
out, err = cmd.CombinedOutput()
|
||||
}
|
||||
return out, err
|
||||
}
|
Loading…
Reference in New Issue
Block a user