truststore_java.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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"
  15. "path/filepath"
  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 v := os.Getenv("JAVA_HOME"); v != "" {
  28. hasJava = true
  29. javaHome = v
  30. _, err := os.Stat(path.Join(v, "bin/keytool"))
  31. if err == nil {
  32. hasKeytool = true
  33. keytoolPath = path.Join(v, "bin/keytool")
  34. }
  35. cacertsPath = path.Join(v, "jre/lib/security/cacerts")
  36. }
  37. }
  38. func (m *mkcert) checkJava() bool {
  39. // exists returns true if the given x509.Certificate's fingerprint
  40. // is in the keytool -list output
  41. exists := func(c *x509.Certificate, h hash.Hash, keytoolOutput []byte) bool {
  42. h.Write(c.Raw)
  43. fp := strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
  44. return bytes.Contains(keytoolOutput, []byte(fp))
  45. }
  46. keytoolOutput, err := exec.Command(keytoolPath, "-list", "-keystore", cacertsPath, "-storepass", storePass).CombinedOutput()
  47. fatalIfCmdErr(err, "keytool -list", keytoolOutput)
  48. // keytool outputs SHA1 and SHA256 (Java 9+) certificates in uppercase hex
  49. // with each octet pair delimitated by ":". Drop them from the keytool output
  50. keytoolOutput = bytes.Replace(keytoolOutput, []byte(":"), nil, -1)
  51. // pre-Java 9 uses SHA1 fingerprints
  52. s1, s256 := sha1.New(), sha256.New()
  53. return exists(m.caCert, s1, keytoolOutput) || exists(m.caCert, s256, keytoolOutput)
  54. }
  55. func (m *mkcert) installJava() {
  56. args := []string{
  57. "-importcert", "-noprompt",
  58. "-keystore", cacertsPath,
  59. "-storepass", storePass,
  60. "-file", filepath.Join(m.CAROOT, rootName),
  61. "-alias", m.caUniqueName(),
  62. }
  63. out, err := m.execKeytool(exec.Command(keytoolPath, args...))
  64. fatalIfCmdErr(err, "keytool -importcert", out)
  65. }
  66. func (m *mkcert) uninstallJava() {
  67. args := []string{
  68. "-delete",
  69. "-alias", m.caUniqueName(),
  70. "-keystore", cacertsPath,
  71. "-storepass", storePass,
  72. }
  73. out, err := m.execKeytool(exec.Command(keytoolPath, args...))
  74. if bytes.Contains(out, []byte("does not exist")) {
  75. return // cert didn't exist
  76. }
  77. fatalIfCmdErr(err, "keytool -delete", out)
  78. }
  79. // execKeytool will execute a "keytool" command and if needed re-execute
  80. // the command wrapped in 'sudo' to work around file permissions.
  81. func (m *mkcert) execKeytool(cmd *exec.Cmd) ([]byte, error) {
  82. out, err := cmd.CombinedOutput()
  83. if err != nil && bytes.Contains(out, []byte("java.io.FileNotFoundException")) {
  84. origArgs := cmd.Args[1:]
  85. cmd = exec.Command("sudo", keytoolPath)
  86. cmd.Args = append(cmd.Args, origArgs...)
  87. cmd.Env = []string{
  88. "JAVA_HOME=" + javaHome,
  89. }
  90. out, err = cmd.CombinedOutput()
  91. }
  92. return out, err
  93. }