...

Source file src/pkg/crypto/x509/root_windows.go

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

View as plain text