root_windows.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // Copyright 2012 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 x509
  5. import (
  6. "errors"
  7. "syscall"
  8. "unsafe"
  9. )
  10. // Creates a new *syscall.CertContext representing the leaf certificate in an in-memory
  11. // certificate store containing itself and all of the intermediate certificates specified
  12. // in the opts.Intermediates CertPool.
  13. //
  14. // A pointer to the in-memory store is available in the returned CertContext's Store field.
  15. // The store is automatically freed when the CertContext is freed using
  16. // syscall.CertFreeCertificateContext.
  17. func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
  18. var storeCtx *syscall.CertContext
  19. leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
  20. if err != nil {
  21. return nil, err
  22. }
  23. defer syscall.CertFreeCertificateContext(leafCtx)
  24. handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
  25. if err != nil {
  26. return nil, err
  27. }
  28. defer syscall.CertCloseStore(handle, 0)
  29. err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
  30. if err != nil {
  31. return nil, err
  32. }
  33. if opts.Intermediates != nil {
  34. for _, intermediate := range opts.Intermediates.certs {
  35. ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
  36. if err != nil {
  37. return nil, err
  38. }
  39. err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
  40. syscall.CertFreeCertificateContext(ctx)
  41. if err != nil {
  42. return nil, err
  43. }
  44. }
  45. }
  46. return storeCtx, nil
  47. }
  48. // extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
  49. func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
  50. if simpleChain == nil || count == 0 {
  51. return nil, errors.New("x509: invalid simple chain")
  52. }
  53. simpleChains := (*[1 << 20]*syscall.CertSimpleChain)(unsafe.Pointer(simpleChain))[:]
  54. lastChain := simpleChains[count-1]
  55. elements := (*[1 << 20]*syscall.CertChainElement)(unsafe.Pointer(lastChain.Elements))[:]
  56. for i := 0; i < int(lastChain.NumElements); i++ {
  57. // Copy the buf, since ParseCertificate does not create its own copy.
  58. cert := elements[i].CertContext
  59. encodedCert := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
  60. buf := make([]byte, cert.Length)
  61. copy(buf, encodedCert[:])
  62. parsedCert, err := ParseCertificate(buf)
  63. if err != nil {
  64. return nil, err
  65. }
  66. chain = append(chain, parsedCert)
  67. }
  68. return chain, nil
  69. }
  70. // checkChainTrustStatus checks the trust status of the certificate chain, translating
  71. // any errors it finds into Go errors in the process.
  72. func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
  73. if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
  74. status := chainCtx.TrustStatus.ErrorStatus
  75. switch status {
  76. case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
  77. return CertificateInvalidError{c, Expired, ""}
  78. default:
  79. return UnknownAuthorityError{c, nil, nil}
  80. }
  81. }
  82. return nil
  83. }
  84. // checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
  85. // use as a certificate chain for a SSL/TLS server.
  86. func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
  87. servernamep, err := syscall.UTF16PtrFromString(opts.DNSName)
  88. if err != nil {
  89. return err
  90. }
  91. sslPara := &syscall.SSLExtraCertChainPolicyPara{
  92. AuthType: syscall.AUTHTYPE_SERVER,
  93. ServerName: servernamep,
  94. }
  95. sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
  96. para := &syscall.CertChainPolicyPara{
  97. ExtraPolicyPara: convertToPolicyParaType(unsafe.Pointer(sslPara)),
  98. }
  99. para.Size = uint32(unsafe.Sizeof(*para))
  100. status := syscall.CertChainPolicyStatus{}
  101. err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
  102. if err != nil {
  103. return err
  104. }
  105. // TODO(mkrautz): use the lChainIndex and lElementIndex fields
  106. // of the CertChainPolicyStatus to provide proper context, instead
  107. // using c.
  108. if status.Error != 0 {
  109. switch status.Error {
  110. case syscall.CERT_E_EXPIRED:
  111. return CertificateInvalidError{c, Expired, ""}
  112. case syscall.CERT_E_CN_NO_MATCH:
  113. return HostnameError{c, opts.DNSName}
  114. case syscall.CERT_E_UNTRUSTEDROOT:
  115. return UnknownAuthorityError{c, nil, nil}
  116. default:
  117. return UnknownAuthorityError{c, nil, nil}
  118. }
  119. }
  120. return nil
  121. }
  122. // systemVerify is like Verify, except that it uses CryptoAPI calls
  123. // to build certificate chains and verify them.
  124. func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
  125. hasDNSName := opts != nil && len(opts.DNSName) > 0
  126. storeCtx, err := createStoreContext(c, opts)
  127. if err != nil {
  128. return nil, err
  129. }
  130. defer syscall.CertFreeCertificateContext(storeCtx)
  131. para := new(syscall.CertChainPara)
  132. para.Size = uint32(unsafe.Sizeof(*para))
  133. // If there's a DNSName set in opts, assume we're verifying
  134. // a certificate from a TLS server.
  135. if hasDNSName {
  136. oids := []*byte{
  137. &syscall.OID_PKIX_KP_SERVER_AUTH[0],
  138. // Both IE and Chrome allow certificates with
  139. // Server Gated Crypto as well. Some certificates
  140. // in the wild require them.
  141. &syscall.OID_SERVER_GATED_CRYPTO[0],
  142. &syscall.OID_SGC_NETSCAPE[0],
  143. }
  144. para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
  145. para.RequestedUsage.Usage.Length = uint32(len(oids))
  146. para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
  147. } else {
  148. para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
  149. para.RequestedUsage.Usage.Length = 0
  150. para.RequestedUsage.Usage.UsageIdentifiers = nil
  151. }
  152. var verifyTime *syscall.Filetime
  153. if opts != nil && !opts.CurrentTime.IsZero() {
  154. ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
  155. verifyTime = &ft
  156. }
  157. // CertGetCertificateChain will traverse Windows's root stores
  158. // in an attempt to build a verified certificate chain. Once
  159. // it has found a verified chain, it stops. MSDN docs on
  160. // CERT_CHAIN_CONTEXT:
  161. //
  162. // When a CERT_CHAIN_CONTEXT is built, the first simple chain
  163. // begins with an end certificate and ends with a self-signed
  164. // certificate. If that self-signed certificate is not a root
  165. // or otherwise trusted certificate, an attempt is made to
  166. // build a new chain. CTLs are used to create the new chain
  167. // beginning with the self-signed certificate from the original
  168. // chain as the end certificate of the new chain. This process
  169. // continues building additional simple chains until the first
  170. // self-signed certificate is a trusted certificate or until
  171. // an additional simple chain cannot be built.
  172. //
  173. // The result is that we'll only get a single trusted chain to
  174. // return to our caller.
  175. var chainCtx *syscall.CertChainContext
  176. err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, 0, 0, &chainCtx)
  177. if err != nil {
  178. return nil, err
  179. }
  180. defer syscall.CertFreeCertificateChain(chainCtx)
  181. err = checkChainTrustStatus(c, chainCtx)
  182. if err != nil {
  183. return nil, err
  184. }
  185. if hasDNSName {
  186. err = checkChainSSLServerPolicy(c, chainCtx, opts)
  187. if err != nil {
  188. return nil, err
  189. }
  190. }
  191. chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
  192. if err != nil {
  193. return nil, err
  194. }
  195. chains = append(chains, chain)
  196. return chains, nil
  197. }
  198. func loadSystemRoots() (*CertPool, error) {
  199. // TODO: restore this functionality on Windows. We tried to do
  200. // it in Go 1.8 but had to revert it. See Issue 18609.
  201. // Returning (nil, nil) was the old behavior, prior to CL 30578.
  202. return nil, nil
  203. const CRYPT_E_NOT_FOUND = 0x80092004
  204. store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
  205. if err != nil {
  206. return nil, err
  207. }
  208. defer syscall.CertCloseStore(store, 0)
  209. roots := NewCertPool()
  210. var cert *syscall.CertContext
  211. for {
  212. cert, err = syscall.CertEnumCertificatesInStore(store, cert)
  213. if err != nil {
  214. if errno, ok := err.(syscall.Errno); ok {
  215. if errno == CRYPT_E_NOT_FOUND {
  216. break
  217. }
  218. }
  219. return nil, err
  220. }
  221. if cert == nil {
  222. break
  223. }
  224. // Copy the buf, since ParseCertificate does not create its own copy.
  225. buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
  226. buf2 := make([]byte, cert.Length)
  227. copy(buf2, buf)
  228. if c, err := ParseCertificate(buf2); err == nil {
  229. roots.AddCert(c)
  230. }
  231. }
  232. return roots, nil
  233. }