truststore_windows.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package main
  2. import (
  3. "crypto/x509"
  4. "encoding/pem"
  5. "fmt"
  6. "io/ioutil"
  7. "math/big"
  8. "os"
  9. "path/filepath"
  10. "syscall"
  11. "unsafe"
  12. )
  13. var (
  14. FirefoxPath = "C:\\Program Files\\Mozilla Firefox"
  15. FirefoxProfile = os.Getenv("USERPROFILE") + "\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles"
  16. CertutilInstallHelp = "<certutil unsupported on Windows>"
  17. NSSBrowsers = "Firefox"
  18. )
  19. var (
  20. modcrypt32 = syscall.NewLazyDLL("crypt32.dll")
  21. procCertAddEncodedCertificateToStore = modcrypt32.NewProc("CertAddEncodedCertificateToStore")
  22. procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
  23. procCertDeleteCertificateFromStore = modcrypt32.NewProc("CertDeleteCertificateFromStore")
  24. procCertDuplicateCertificateContext = modcrypt32.NewProc("CertDuplicateCertificateContext")
  25. procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
  26. procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
  27. )
  28. func (m *mkcert) installPlatform() bool {
  29. // Load cert
  30. cert, err := ioutil.ReadFile(filepath.Join(m.CAROOT, rootName))
  31. fatalIfErr(err, "failed to read root certificate")
  32. // Decode PEM
  33. if certBlock, _ := pem.Decode(cert); certBlock == nil || certBlock.Type != "CERTIFICATE" {
  34. fatalIfErr(fmt.Errorf("Invalid PEM data"), "decode pem")
  35. } else {
  36. cert = certBlock.Bytes
  37. }
  38. // Open root store
  39. store, err := openWindowsRootStore()
  40. fatalIfErr(err, "open root store")
  41. defer store.close()
  42. // Add cert
  43. fatalIfErr(store.addCert(cert), "add cert")
  44. return true
  45. }
  46. func (m *mkcert) uninstallPlatform() bool {
  47. // We'll just remove all certs with the same serial number
  48. // Open root store
  49. store, err := openWindowsRootStore()
  50. fatalIfErr(err, "open root store")
  51. defer store.close()
  52. // Do the deletion
  53. deletedAny, err := store.deleteCertsWithSerial(m.caCert.SerialNumber)
  54. if err == nil && !deletedAny {
  55. err = fmt.Errorf("No certs found")
  56. }
  57. fatalIfErr(err, "delete cert")
  58. return true
  59. }
  60. type windowsRootStore uintptr
  61. func openWindowsRootStore() (windowsRootStore, error) {
  62. store, _, err := procCertOpenSystemStoreW.Call(0, uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("ROOT"))))
  63. if store != 0 {
  64. return windowsRootStore(store), nil
  65. }
  66. return 0, fmt.Errorf("Failed to open windows root store: %v", err)
  67. }
  68. func (w windowsRootStore) close() error {
  69. ret, _, err := procCertCloseStore.Call(uintptr(w), 0)
  70. if ret != 0 {
  71. return nil
  72. }
  73. return fmt.Errorf("Failed to close windows root store: %v", err)
  74. }
  75. func (w windowsRootStore) addCert(cert []byte) error {
  76. // TODO: ok to always overwrite?
  77. ret, _, err := procCertAddEncodedCertificateToStore.Call(
  78. uintptr(w), // HCERTSTORE hCertStore
  79. uintptr(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING), // DWORD dwCertEncodingType
  80. uintptr(unsafe.Pointer(&cert[0])), // const BYTE *pbCertEncoded
  81. uintptr(len(cert)), // DWORD cbCertEncoded
  82. 3, // DWORD dwAddDisposition (CERT_STORE_ADD_REPLACE_EXISTING is 3)
  83. 0, // PCCERT_CONTEXT *ppCertContext
  84. )
  85. if ret != 0 {
  86. return nil
  87. }
  88. return fmt.Errorf("Failed adding cert: %v", err)
  89. }
  90. func (w windowsRootStore) deleteCertsWithSerial(serial *big.Int) (bool, error) {
  91. // Go over each, deleting the ones we find
  92. var cert *syscall.CertContext
  93. deletedAny := false
  94. for {
  95. // Next enum
  96. certPtr, _, err := procCertEnumCertificatesInStore.Call(uintptr(w), uintptr(unsafe.Pointer(cert)))
  97. if cert = (*syscall.CertContext)(unsafe.Pointer(certPtr)); cert == nil {
  98. if errno, ok := err.(syscall.Errno); ok && errno == 0x80092004 {
  99. break
  100. }
  101. return deletedAny, fmt.Errorf("Failed enumerating certs: %v", err)
  102. }
  103. // Parse cert
  104. certBytes := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:cert.Length]
  105. parsedCert, err := x509.ParseCertificate(certBytes)
  106. // We'll just ignore parse failures for now
  107. if err == nil && parsedCert.SerialNumber != nil && parsedCert.SerialNumber.Cmp(serial) == 0 {
  108. // Duplicate the context so it doesn't stop the enum when we delete it
  109. dupCertPtr, _, err := procCertDuplicateCertificateContext.Call(uintptr(unsafe.Pointer(cert)))
  110. if dupCertPtr == 0 {
  111. return deletedAny, fmt.Errorf("Failed duplicating context: %v", err)
  112. }
  113. if ret, _, err := procCertDeleteCertificateFromStore.Call(dupCertPtr); ret == 0 {
  114. return deletedAny, fmt.Errorf("Failed deleting certificate: %v", err)
  115. }
  116. deletedAny = true
  117. }
  118. }
  119. return deletedAny, nil
  120. }