123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- // 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
- }
|