truststore_java.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package main
  5. import (
  6. "bytes"
  7. "crypto/sha1"
  8. "crypto/sha256"
  9. "crypto/x509"
  10. "encoding/hex"
  11. "hash"
  12. "os"
  13. "os/exec"
  14. "path/filepath"
  15. "runtime"
  16. "strings"
  17. )
  18. var (
  19. hasJava bool
  20. hasKeytool bool
  21. javaHome string
  22. cacertsPath string
  23. keytoolPath string
  24. storePass string = "changeit"
  25. )
  26. func init() {
  27. if runtime.GOOS == "windows" {
  28. keytoolPath = filepath.Join("bin", "keytool.exe")
  29. } else {
  30. keytoolPath = filepath.Join("bin", "keytool")
  31. }
  32. if v := os.Getenv("JAVA_HOME"); v != "" {
  33. hasJava = true
  34. javaHome = v
  35. _, err := os.Stat(filepath.Join(v, keytoolPath))
  36. if err == nil {
  37. hasKeytool = true
  38. keytoolPath = filepath.Join(v, keytoolPath)
  39. }
  40. _, err = os.Stat(filepath.Join(v, "lib", "security", "cacerts"))
  41. if err == nil {
  42. cacertsPath = filepath.Join(v, "lib", "security", "cacerts")
  43. }
  44. _, err = os.Stat(filepath.Join(v, "jre", "lib", "security", "cacerts"))
  45. if err == nil {
  46. cacertsPath = filepath.Join(v, "jre", "lib", "security", "cacerts")
  47. }
  48. }
  49. }
  50. func (m *mkcert) checkJava() bool {
  51. if !hasKeytool {
  52. return false
  53. }
  54. // exists returns true if the given x509.Certificate's fingerprint
  55. // is in the keytool -list output
  56. exists := func(c *x509.Certificate, h hash.Hash, keytoolOutput []byte) bool {
  57. h.Write(c.Raw)
  58. fp := strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  59. return bytes.Contains(keytoolOutput, []byte(fp))
  60. }
  61. keytoolOutput, err := exec.Command(keytoolPath, "-list", "-keystore", cacertsPath, "-storepass", storePass).CombinedOutput()
  62. fatalIfCmdErr(err, "keytool -list", keytoolOutput)
  63. // keytool outputs SHA1 and SHA256 (Java 9+) certificates in uppercase hex
  64. // with each octet pair delimitated by ":". Drop them from the keytool output
  65. keytoolOutput = bytes.Replace(keytoolOutput, []byte(":"), nil, -1)
  66. // pre-Java 9 uses SHA1 fingerprints
  67. s1, s256 := sha1.New(), sha256.New()
  68. return exists(m.caCert, s1, keytoolOutput) || exists(m.caCert, s256, keytoolOutput)
  69. }
  70. func (m *mkcert) installJava() {
  71. args := []string{
  72. "-importcert", "-noprompt",
  73. "-keystore", cacertsPath,
  74. "-storepass", storePass,
  75. "-file", filepath.Join(m.CAROOT, rootName),
  76. "-alias", m.caUniqueName(),
  77. }
  78. out, err := m.execKeytool(exec.Command(keytoolPath, args...))
  79. fatalIfCmdErr(err, "keytool -importcert", out)
  80. }
  81. func (m *mkcert) uninstallJava() {
  82. args := []string{
  83. "-delete",
  84. "-alias", m.caUniqueName(),
  85. "-keystore", cacertsPath,
  86. "-storepass", storePass,
  87. }
  88. out, err := m.execKeytool(exec.Command(keytoolPath, args...))
  89. if bytes.Contains(out, []byte("does not exist")) {
  90. return // cert didn't exist
  91. }
  92. fatalIfCmdErr(err, "keytool -delete", out)
  93. }
  94. // execKeytool will execute a "keytool" command and if needed re-execute
  95. // the command wrapped in 'sudo' to work around file permissions.
  96. func (m *mkcert) execKeytool(cmd *exec.Cmd) ([]byte, error) {
  97. out, err := cmd.CombinedOutput()
  98. if err != nil && bytes.Contains(out, []byte("java.io.FileNotFoundException")) && runtime.GOOS != "windows" {
  99. origArgs := cmd.Args[1:]
  100. cmd = exec.Command("sudo", keytoolPath)
  101. cmd.Args = append(cmd.Args, origArgs...)
  102. cmd.Env = []string{
  103. "JAVA_HOME=" + javaHome,
  104. }
  105. out, err = cmd.CombinedOutput()
  106. }
  107. return out, err
  108. }