truststore_windows.go 4.7 KB

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