mirror of
https://github.com/FiloSottile/mkcert.git
synced 2024-11-25 16:51:09 +08:00
1b4ad6c774
Based on @rfay's investigation and fix. Fixes #192 Closes #193
123 lines
3.2 KiB
Go
123 lines
3.2 KiB
Go
// Copyright 2018 The mkcert 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/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
hasJava bool
|
|
hasKeytool bool
|
|
|
|
javaHome string
|
|
cacertsPath string
|
|
keytoolPath string
|
|
storePass string = "changeit"
|
|
)
|
|
|
|
func init() {
|
|
if runtime.GOOS == "windows" {
|
|
keytoolPath = filepath.Join("bin", "keytool.exe")
|
|
} else {
|
|
keytoolPath = filepath.Join("bin", "keytool")
|
|
}
|
|
|
|
if v := os.Getenv("JAVA_HOME"); v != "" {
|
|
hasJava = true
|
|
javaHome = v
|
|
|
|
if pathExists(filepath.Join(v, keytoolPath)) {
|
|
hasKeytool = true
|
|
keytoolPath = filepath.Join(v, keytoolPath)
|
|
}
|
|
|
|
if pathExists(filepath.Join(v, "lib", "security", "cacerts")) {
|
|
cacertsPath = filepath.Join(v, "lib", "security", "cacerts")
|
|
}
|
|
|
|
if pathExists(filepath.Join(v, "jre", "lib", "security", "cacerts")) {
|
|
cacertsPath = filepath.Join(v, "jre", "lib", "security", "cacerts")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *mkcert) checkJava() bool {
|
|
if !hasKeytool {
|
|
return false
|
|
}
|
|
|
|
// 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 := 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 := 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 with commandWithSudo to work around file permissions.
|
|
func execKeytool(cmd *exec.Cmd) ([]byte, error) {
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil && bytes.Contains(out, []byte("java.io.FileNotFoundException")) && runtime.GOOS != "windows" {
|
|
origArgs := cmd.Args[1:]
|
|
cmd = commandWithSudo(cmd.Path)
|
|
cmd.Args = append(cmd.Args, origArgs...)
|
|
cmd.Env = []string{
|
|
"JAVA_HOME=" + javaHome,
|
|
}
|
|
out, err = cmd.CombinedOutput()
|
|
}
|
|
return out, err
|
|
}
|