github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/certstore/certstore_windows.go (about)

     1  // Copyright 2022-2024 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  //
    14  // Adapted, updated, and enhanced from CertToStore, https://github.com/google/certtostore/releases/tag/v1.0.2
    15  // Apache License, Version 2.0, Copyright 2017 Google Inc.
    16  
    17  package certstore
    18  
    19  import (
    20  	"bytes"
    21  	"crypto"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"crypto/rsa"
    25  	"crypto/tls"
    26  	"crypto/x509"
    27  	"encoding/binary"
    28  	"fmt"
    29  	"io"
    30  	"math/big"
    31  	"reflect"
    32  	"sync"
    33  	"syscall"
    34  	"unicode/utf16"
    35  	"unsafe"
    36  
    37  	"golang.org/x/crypto/cryptobyte"
    38  	"golang.org/x/crypto/cryptobyte/asn1"
    39  	"golang.org/x/sys/windows"
    40  )
    41  
    42  const (
    43  	// wincrypt.h constants
    44  	winAcquireCached           = 0x1                                                   // CRYPT_ACQUIRE_CACHE_FLAG
    45  	winAcquireSilent           = 0x40                                                  // CRYPT_ACQUIRE_SILENT_FLAG
    46  	winAcquireOnlyNCryptKey    = 0x40000                                               // CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG
    47  	winEncodingX509ASN         = 1                                                     // X509_ASN_ENCODING
    48  	winEncodingPKCS7           = 65536                                                 // PKCS_7_ASN_ENCODING
    49  	winCertStoreProvSystem     = 10                                                    // CERT_STORE_PROV_SYSTEM
    50  	winCertStoreCurrentUser    = uint32(winCertStoreCurrentUserID << winCompareShift)  // CERT_SYSTEM_STORE_CURRENT_USER
    51  	winCertStoreLocalMachine   = uint32(winCertStoreLocalMachineID << winCompareShift) // CERT_SYSTEM_STORE_LOCAL_MACHINE
    52  	winCertStoreCurrentUserID  = 1                                                     // CERT_SYSTEM_STORE_CURRENT_USER_ID
    53  	winCertStoreLocalMachineID = 2                                                     // CERT_SYSTEM_STORE_LOCAL_MACHINE_ID
    54  	winInfoIssuerFlag          = 4                                                     // CERT_INFO_ISSUER_FLAG
    55  	winInfoSubjectFlag         = 7                                                     // CERT_INFO_SUBJECT_FLAG
    56  	winCompareNameStrW         = 8                                                     // CERT_COMPARE_NAME_STR_A
    57  	winCompareShift            = 16                                                    // CERT_COMPARE_SHIFT
    58  
    59  	// Reference https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindcertificateinstore
    60  	winFindIssuerStr  = winCompareNameStrW<<winCompareShift | winInfoIssuerFlag  // CERT_FIND_ISSUER_STR_W
    61  	winFindSubjectStr = winCompareNameStrW<<winCompareShift | winInfoSubjectFlag // CERT_FIND_SUBJECT_STR_W
    62  
    63  	winNcryptKeySpec = 0xFFFFFFFF // CERT_NCRYPT_KEY_SPEC
    64  
    65  	winBCryptPadPKCS1   uintptr = 0x2
    66  	winBCryptPadPSS     uintptr = 0x8 // Modern TLS 1.2+
    67  	winBCryptPadPSSSalt uint32  = 32  // default 20, 32 optimal for typical SHA256 hash
    68  
    69  	winRSA1Magic = 0x31415352 // "RSA1" BCRYPT_RSAPUBLIC_MAGIC
    70  
    71  	winECS1Magic = 0x31534345 // "ECS1" BCRYPT_ECDSA_PUBLIC_P256_MAGIC
    72  	winECS3Magic = 0x33534345 // "ECS3" BCRYPT_ECDSA_PUBLIC_P384_MAGIC
    73  	winECS5Magic = 0x35534345 // "ECS5" BCRYPT_ECDSA_PUBLIC_P521_MAGIC
    74  
    75  	winECK1Magic = 0x314B4345 // "ECK1" BCRYPT_ECDH_PUBLIC_P256_MAGIC
    76  	winECK3Magic = 0x334B4345 // "ECK3" BCRYPT_ECDH_PUBLIC_P384_MAGIC
    77  	winECK5Magic = 0x354B4345 // "ECK5" BCRYPT_ECDH_PUBLIC_P521_MAGIC
    78  
    79  	winCryptENotFound = 0x80092004 // CRYPT_E_NOT_FOUND
    80  
    81  	providerMSSoftware = "Microsoft Software Key Storage Provider"
    82  )
    83  
    84  var (
    85  	winBCryptRSAPublicBlob = winWide("RSAPUBLICBLOB")
    86  	winBCryptECCPublicBlob = winWide("ECCPUBLICBLOB")
    87  
    88  	winNCryptAlgorithmGroupProperty = winWide("Algorithm Group") // NCRYPT_ALGORITHM_GROUP_PROPERTY
    89  	winNCryptUniqueNameProperty     = winWide("Unique Name")     // NCRYPT_UNIQUE_NAME_PROPERTY
    90  	winNCryptECCCurveNameProperty   = winWide("ECCCurveName")    // NCRYPT_ECC_CURVE_NAME_PROPERTY
    91  
    92  	winCurveIDs = map[uint32]elliptic.Curve{
    93  		winECS1Magic: elliptic.P256(), // BCRYPT_ECDSA_PUBLIC_P256_MAGIC
    94  		winECS3Magic: elliptic.P384(), // BCRYPT_ECDSA_PUBLIC_P384_MAGIC
    95  		winECS5Magic: elliptic.P521(), // BCRYPT_ECDSA_PUBLIC_P521_MAGIC
    96  		winECK1Magic: elliptic.P256(), // BCRYPT_ECDH_PUBLIC_P256_MAGIC
    97  		winECK3Magic: elliptic.P384(), // BCRYPT_ECDH_PUBLIC_P384_MAGIC
    98  		winECK5Magic: elliptic.P521(), // BCRYPT_ECDH_PUBLIC_P521_MAGIC
    99  	}
   100  
   101  	winCurveNames = map[string]elliptic.Curve{
   102  		"nistP256": elliptic.P256(), // BCRYPT_ECC_CURVE_NISTP256
   103  		"nistP384": elliptic.P384(), // BCRYPT_ECC_CURVE_NISTP384
   104  		"nistP521": elliptic.P521(), // BCRYPT_ECC_CURVE_NISTP521
   105  	}
   106  
   107  	winAlgIDs = map[crypto.Hash]*uint16{
   108  		crypto.SHA1:   winWide("SHA1"),   // BCRYPT_SHA1_ALGORITHM
   109  		crypto.SHA256: winWide("SHA256"), // BCRYPT_SHA256_ALGORITHM
   110  		crypto.SHA384: winWide("SHA384"), // BCRYPT_SHA384_ALGORITHM
   111  		crypto.SHA512: winWide("SHA512"), // BCRYPT_SHA512_ALGORITHM
   112  	}
   113  
   114  	// MY is well-known system store on Windows that holds personal certificates. Read
   115  	// More about the CA locations here:
   116  	// https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/certificate-of-clientcertificate-element?redirectedfrom=MSDN
   117  	// https://superuser.com/questions/217719/what-are-the-windows-system-certificate-stores
   118  	// https://docs.microsoft.com/en-us/windows/win32/seccrypto/certificate-stores
   119  	// https://learn.microsoft.com/en-us/windows/win32/seccrypto/system-store-locations
   120  	// https://stackoverflow.com/questions/63286085/which-x509-storename-refers-to-the-certificates-stored-beneath-trusted-root-cert#:~:text=4-,StoreName.,is%20%22Intermediate%20Certification%20Authorities%22.
   121  	winMyStore             = winWide("MY")
   122  	winIntermediateCAStore = winWide("CA")
   123  	winRootStore           = winWide("Root")
   124  	winAuthRootStore       = winWide("AuthRoot")
   125  
   126  	// These DLLs must be available on all Windows hosts
   127  	winCrypt32 = windows.MustLoadDLL("crypt32.dll")
   128  	winNCrypt  = windows.MustLoadDLL("ncrypt.dll")
   129  
   130  	winCertFindCertificateInStore        = winCrypt32.MustFindProc("CertFindCertificateInStore")
   131  	winCryptAcquireCertificatePrivateKey = winCrypt32.MustFindProc("CryptAcquireCertificatePrivateKey")
   132  	winNCryptExportKey                   = winNCrypt.MustFindProc("NCryptExportKey")
   133  	winNCryptOpenStorageProvider         = winNCrypt.MustFindProc("NCryptOpenStorageProvider")
   134  	winNCryptGetProperty                 = winNCrypt.MustFindProc("NCryptGetProperty")
   135  	winNCryptSignHash                    = winNCrypt.MustFindProc("NCryptSignHash")
   136  
   137  	winFnGetProperty = winGetProperty
   138  )
   139  
   140  type winPKCS1PaddingInfo struct {
   141  	pszAlgID *uint16
   142  }
   143  
   144  type winPSSPaddingInfo struct {
   145  	pszAlgID *uint16
   146  	cbSalt   uint32
   147  }
   148  
   149  // createCACertsPool generates a CertPool from the Windows certificate store,
   150  // adding all matching certificates from the caCertsMatch array to the pool.
   151  // All matching certificates (vs first) are added to the pool based on a user
   152  // request. If no certificates are found an error is returned.
   153  func createCACertsPool(cs *winCertStore, storeType uint32, caCertsMatch []string) (*x509.CertPool, error) {
   154  	var errs []error
   155  	caPool := x509.NewCertPool()
   156  	for _, s := range caCertsMatch {
   157  		lfs, err := cs.caCertsBySubjectMatch(s, storeType)
   158  		if err != nil {
   159  			errs = append(errs, err)
   160  		} else {
   161  			for _, lf := range lfs {
   162  				caPool.AddCert(lf)
   163  			}
   164  		}
   165  	}
   166  	// If every lookup failed return the errors.
   167  	if len(errs) == len(caCertsMatch) {
   168  		return nil, fmt.Errorf("unable to match any CA certificate: %v", errs)
   169  	}
   170  	return caPool, nil
   171  }
   172  
   173  // TLSConfig fulfills the same function as reading cert and key pair from
   174  // pem files but sources the Windows certificate store instead. The
   175  // certMatchBy and certMatch fields search the "MY" certificate location
   176  // for the first certificate that matches the certMatch field. The
   177  // caCertsMatch field is used to search the Trusted Root, Third Party Root,
   178  // and Intermediate Certificate Authority locations for certificates with
   179  // Subjects matching the provided strings. If a match is found, the
   180  // certificate is added to the pool that is used to verify the certificate
   181  // chain.
   182  func TLSConfig(certStore StoreType, certMatchBy MatchByType, certMatch string, caCertsMatch []string, config *tls.Config) error {
   183  	var (
   184  		leaf     *x509.Certificate
   185  		leafCtx  *windows.CertContext
   186  		pk       *winKey
   187  		vOpts    = x509.VerifyOptions{}
   188  		chains   [][]*x509.Certificate
   189  		chain    []*x509.Certificate
   190  		rawChain [][]byte
   191  	)
   192  
   193  	// By StoreType, open a store
   194  	if certStore == windowsCurrentUser || certStore == windowsLocalMachine {
   195  		var scope uint32
   196  		cs, err := winOpenCertStore(providerMSSoftware)
   197  		if err != nil || cs == nil {
   198  			return err
   199  		}
   200  		if certStore == windowsCurrentUser {
   201  			scope = winCertStoreCurrentUser
   202  		}
   203  		if certStore == windowsLocalMachine {
   204  			scope = winCertStoreLocalMachine
   205  		}
   206  
   207  		// certByIssuer or certBySubject
   208  		if certMatchBy == matchBySubject || certMatchBy == MATCHBYEMPTY {
   209  			leaf, leafCtx, err = cs.certBySubject(certMatch, scope)
   210  		} else if certMatchBy == matchByIssuer {
   211  			leaf, leafCtx, err = cs.certByIssuer(certMatch, scope)
   212  		} else {
   213  			return ErrBadMatchByType
   214  		}
   215  		if err != nil {
   216  			// pass through error from cert search
   217  			return err
   218  		}
   219  		if leaf == nil || leafCtx == nil {
   220  			return ErrFailedCertSearch
   221  		}
   222  		pk, err = cs.certKey(leafCtx)
   223  		if err != nil {
   224  			return err
   225  		}
   226  		if pk == nil {
   227  			return ErrNoPrivateKeyStoreRef
   228  		}
   229  		// Look for CA Certificates
   230  		if len(caCertsMatch) != 0 {
   231  			caPool, err := createCACertsPool(cs, scope, caCertsMatch)
   232  			if err != nil {
   233  				return err
   234  			}
   235  			config.ClientCAs = caPool
   236  		}
   237  	} else {
   238  		return ErrBadCertStore
   239  	}
   240  
   241  	// Get intermediates in the cert store for the found leaf IFF there is a full chain of trust in the store
   242  	// otherwise just use leaf as the final chain.
   243  	//
   244  	// Using std lib Verify as a reliable way to get valid chains out of the win store for the leaf; however,
   245  	// using empty options since server TLS stanza could be TLS role as server identity or client identity.
   246  	chains, err := leaf.Verify(vOpts)
   247  	if err != nil || len(chains) == 0 {
   248  		chains = append(chains, []*x509.Certificate{leaf})
   249  	}
   250  
   251  	// We have at least one verified chain so pop the first chain and remove the self-signed CA cert (if present)
   252  	// from the end of the chain
   253  	chain = chains[0]
   254  	if len(chain) > 1 {
   255  		chain = chain[:len(chain)-1]
   256  	}
   257  
   258  	// For tls.Certificate.Certificate need a [][]byte from []*x509.Certificate
   259  	// Approximate capacity for efficiency
   260  	rawChain = make([][]byte, 0, len(chain))
   261  	for _, link := range chain {
   262  		rawChain = append(rawChain, link.Raw)
   263  	}
   264  
   265  	tlsCert := tls.Certificate{
   266  		Certificate: rawChain,
   267  		PrivateKey:  pk,
   268  		Leaf:        leaf,
   269  	}
   270  	config.Certificates = []tls.Certificate{tlsCert}
   271  
   272  	// note: pk is a windows pointer (not freed by Go) but needs to live the life of the server for Signing.
   273  	// The cert context (leafCtx) windows pointer must not be freed underneath the pk so also life of the server.
   274  	return nil
   275  }
   276  
   277  // winWide returns a pointer to uint16 representing the equivalent
   278  // to a Windows LPCWSTR.
   279  func winWide(s string) *uint16 {
   280  	w := utf16.Encode([]rune(s))
   281  	w = append(w, 0)
   282  	return &w[0]
   283  }
   284  
   285  // winOpenProvider gets a provider handle for subsequent calls
   286  func winOpenProvider(provider string) (uintptr, error) {
   287  	var hProv uintptr
   288  	pname := winWide(provider)
   289  	// Open the provider, the last parameter is not used
   290  	r, _, err := winNCryptOpenStorageProvider.Call(uintptr(unsafe.Pointer(&hProv)), uintptr(unsafe.Pointer(pname)), 0)
   291  	if r == 0 {
   292  		return hProv, nil
   293  	}
   294  	return hProv, fmt.Errorf("NCryptOpenStorageProvider returned %X: %v", r, err)
   295  }
   296  
   297  // winFindCert wraps the CertFindCertificateInStore library call. Note that any cert context passed
   298  // into prev will be freed. If no certificate was found, nil will be returned.
   299  func winFindCert(store windows.Handle, enc, findFlags, findType uint32, para *uint16, prev *windows.CertContext) (*windows.CertContext, error) {
   300  	h, _, err := winCertFindCertificateInStore.Call(
   301  		uintptr(store),
   302  		uintptr(enc),
   303  		uintptr(findFlags),
   304  		uintptr(findType),
   305  		uintptr(unsafe.Pointer(para)),
   306  		uintptr(unsafe.Pointer(prev)),
   307  	)
   308  	if h == 0 {
   309  		// Actual error, or simply not found?
   310  		if errno, ok := err.(syscall.Errno); ok && errno == winCryptENotFound {
   311  			return nil, ErrFailedCertSearch
   312  		}
   313  		return nil, ErrFailedCertSearch
   314  	}
   315  	// nolint:govet
   316  	return (*windows.CertContext)(unsafe.Pointer(h)), nil
   317  }
   318  
   319  // winCertStore is a store implementation for the Windows Certificate Store
   320  type winCertStore struct {
   321  	Prov     uintptr
   322  	ProvName string
   323  	stores   map[string]*winStoreHandle
   324  	mu       sync.Mutex
   325  }
   326  
   327  // winOpenCertStore creates a winCertStore
   328  func winOpenCertStore(provider string) (*winCertStore, error) {
   329  	cngProv, err := winOpenProvider(provider)
   330  	if err != nil {
   331  		// pass through error from winOpenProvider
   332  		return nil, err
   333  	}
   334  
   335  	wcs := &winCertStore{
   336  		Prov:     cngProv,
   337  		ProvName: provider,
   338  		stores:   make(map[string]*winStoreHandle),
   339  	}
   340  
   341  	return wcs, nil
   342  }
   343  
   344  // winCertContextToX509 creates an x509.Certificate from a Windows cert context.
   345  func winCertContextToX509(ctx *windows.CertContext) (*x509.Certificate, error) {
   346  	var der []byte
   347  	slice := (*reflect.SliceHeader)(unsafe.Pointer(&der))
   348  	slice.Data = uintptr(unsafe.Pointer(ctx.EncodedCert))
   349  	slice.Len = int(ctx.Length)
   350  	slice.Cap = int(ctx.Length)
   351  	return x509.ParseCertificate(der)
   352  }
   353  
   354  // certByIssuer matches and returns the first certificate found by passed issuer.
   355  // CertContext pointer returned allows subsequent key operations like Sign. Caller specifies
   356  // current user's personal certs or local machine's personal certs using storeType.
   357  // See CERT_FIND_ISSUER_STR description at https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindcertificateinstore
   358  func (w *winCertStore) certByIssuer(issuer string, storeType uint32) (*x509.Certificate, *windows.CertContext, error) {
   359  	return w.certSearch(winFindIssuerStr, issuer, winMyStore, storeType)
   360  }
   361  
   362  // certBySubject matches and returns the first certificate found by passed subject field.
   363  // CertContext pointer returned allows subsequent key operations like Sign. Caller specifies
   364  // current user's personal certs or local machine's personal certs using storeType.
   365  // See CERT_FIND_SUBJECT_STR description at https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindcertificateinstore
   366  func (w *winCertStore) certBySubject(subject string, storeType uint32) (*x509.Certificate, *windows.CertContext, error) {
   367  	return w.certSearch(winFindSubjectStr, subject, winMyStore, storeType)
   368  }
   369  
   370  // caCertsBySubjectMatch matches and returns all matching certificates of the subject field.
   371  //
   372  // The following locations are searched:
   373  // 1) Root (Trusted Root Certification Authorities)
   374  // 2) AuthRoot (Third-Party Root Certification Authorities)
   375  // 3) CA (Intermediate Certification Authorities)
   376  //
   377  // Caller specifies current user's personal certs or local machine's personal certs using storeType.
   378  // See CERT_FIND_SUBJECT_STR description at https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindcertificateinstore
   379  func (w *winCertStore) caCertsBySubjectMatch(subject string, storeType uint32) ([]*x509.Certificate, error) {
   380  	var (
   381  		leaf            *x509.Certificate
   382  		searchLocations = [3]*uint16{winRootStore, winAuthRootStore, winIntermediateCAStore}
   383  		rv              []*x509.Certificate
   384  	)
   385  	// surprisingly, an empty string returns a result. We'll treat this as an error.
   386  	if subject == "" {
   387  		return nil, ErrBadCaCertMatchField
   388  	}
   389  	for _, sr := range searchLocations {
   390  		var err error
   391  		if leaf, _, err = w.certSearch(winFindSubjectStr, subject, sr, storeType); err == nil {
   392  			rv = append(rv, leaf)
   393  		} else {
   394  			// Ignore the failed search from a single location. Errors we catch include
   395  			// ErrFailedX509Extract (resulting from a malformed certificate) and errors
   396  			// around invalid attributes, unsupported algorithms, etc. These are corner
   397  			// cases as certificates with these errors shouldn't have been allowed
   398  			// to be added to the store in the first place.
   399  			if err != ErrFailedCertSearch {
   400  				return nil, err
   401  			}
   402  		}
   403  	}
   404  	// Not found anywhere
   405  	if len(rv) == 0 {
   406  		return nil, ErrFailedCertSearch
   407  	}
   408  	return rv, nil
   409  }
   410  
   411  // certSearch is a helper function to lookup certificates based on search type and match value.
   412  // store is used to specify which store to perform the lookup in (system or user).
   413  func (w *winCertStore) certSearch(searchType uint32, matchValue string, searchRoot *uint16, store uint32) (*x509.Certificate, *windows.CertContext, error) {
   414  	// store handle to "MY" store
   415  	h, err := w.storeHandle(store, searchRoot)
   416  	if err != nil {
   417  		return nil, nil, err
   418  	}
   419  
   420  	var prev *windows.CertContext
   421  	var cert *x509.Certificate
   422  
   423  	i, err := windows.UTF16PtrFromString(matchValue)
   424  	if err != nil {
   425  		return nil, nil, ErrFailedCertSearch
   426  	}
   427  
   428  	// pass 0 as the third parameter because it is not used
   429  	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa376064(v=vs.85).aspx
   430  	nc, err := winFindCert(h, winEncodingX509ASN|winEncodingPKCS7, 0, searchType, i, prev)
   431  	if err != nil {
   432  		return nil, nil, err
   433  	}
   434  	if nc != nil {
   435  		// certificate found
   436  		prev = nc
   437  
   438  		// Extract the DER-encoded certificate from the cert context
   439  		xc, err := winCertContextToX509(nc)
   440  		if err == nil {
   441  			cert = xc
   442  		} else {
   443  			return nil, nil, ErrFailedX509Extract
   444  		}
   445  	} else {
   446  		return nil, nil, ErrFailedCertSearch
   447  	}
   448  
   449  	if cert == nil {
   450  		return nil, nil, ErrFailedX509Extract
   451  	}
   452  
   453  	return cert, prev, nil
   454  }
   455  
   456  type winStoreHandle struct {
   457  	handle *windows.Handle
   458  }
   459  
   460  func winNewStoreHandle(provider uint32, store *uint16) (*winStoreHandle, error) {
   461  	var s winStoreHandle
   462  	if s.handle != nil {
   463  		return &s, nil
   464  	}
   465  	st, err := windows.CertOpenStore(
   466  		winCertStoreProvSystem,
   467  		0,
   468  		0,
   469  		provider,
   470  		uintptr(unsafe.Pointer(store)))
   471  	if err != nil {
   472  		return nil, ErrBadCryptoStoreProvider
   473  	}
   474  	s.handle = &st
   475  	return &s, nil
   476  }
   477  
   478  // winKey implements crypto.Signer and crypto.Decrypter for key based operations.
   479  type winKey struct {
   480  	handle         uintptr
   481  	pub            crypto.PublicKey
   482  	Container      string
   483  	AlgorithmGroup string
   484  }
   485  
   486  // Public exports a public key to implement crypto.Signer
   487  func (k winKey) Public() crypto.PublicKey {
   488  	return k.pub
   489  }
   490  
   491  // Sign returns the signature of a hash to implement crypto.Signer
   492  func (k winKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
   493  	switch k.AlgorithmGroup {
   494  	case "ECDSA", "ECDH":
   495  		return winSignECDSA(k.handle, digest)
   496  	case "RSA":
   497  		hf := opts.HashFunc()
   498  		algID, ok := winAlgIDs[hf]
   499  		if !ok {
   500  			return nil, ErrBadRSAHashAlgorithm
   501  		}
   502  		switch opts.(type) {
   503  		case *rsa.PSSOptions:
   504  			return winSignRSAPSSPadding(k.handle, digest, algID)
   505  		default:
   506  			return winSignRSAPKCS1Padding(k.handle, digest, algID)
   507  		}
   508  	default:
   509  		return nil, ErrBadSigningAlgorithm
   510  	}
   511  }
   512  
   513  func winSignECDSA(kh uintptr, digest []byte) ([]byte, error) {
   514  	var size uint32
   515  	// Obtain the size of the signature
   516  	r, _, _ := winNCryptSignHash.Call(
   517  		kh,
   518  		0,
   519  		uintptr(unsafe.Pointer(&digest[0])),
   520  		uintptr(len(digest)),
   521  		0,
   522  		0,
   523  		uintptr(unsafe.Pointer(&size)),
   524  		0)
   525  	if r != 0 {
   526  		return nil, ErrStoreECDSASigningError
   527  	}
   528  
   529  	// Obtain the signature data
   530  	buf := make([]byte, size)
   531  	r, _, _ = winNCryptSignHash.Call(
   532  		kh,
   533  		0,
   534  		uintptr(unsafe.Pointer(&digest[0])),
   535  		uintptr(len(digest)),
   536  		uintptr(unsafe.Pointer(&buf[0])),
   537  		uintptr(size),
   538  		uintptr(unsafe.Pointer(&size)),
   539  		0)
   540  	if r != 0 {
   541  		return nil, ErrStoreECDSASigningError
   542  	}
   543  	if len(buf) != int(size) {
   544  		return nil, ErrStoreECDSASigningError
   545  	}
   546  
   547  	return winPackECDSASigValue(bytes.NewReader(buf[:size]), len(digest))
   548  }
   549  
   550  func winPackECDSASigValue(r io.Reader, digestLength int) ([]byte, error) {
   551  	sigR := make([]byte, digestLength)
   552  	if _, err := io.ReadFull(r, sigR); err != nil {
   553  		return nil, ErrStoreECDSASigningError
   554  	}
   555  
   556  	sigS := make([]byte, digestLength)
   557  	if _, err := io.ReadFull(r, sigS); err != nil {
   558  		return nil, ErrStoreECDSASigningError
   559  	}
   560  
   561  	var b cryptobyte.Builder
   562  	b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
   563  		b.AddASN1BigInt(new(big.Int).SetBytes(sigR))
   564  		b.AddASN1BigInt(new(big.Int).SetBytes(sigS))
   565  	})
   566  	return b.Bytes()
   567  }
   568  
   569  func winSignRSAPKCS1Padding(kh uintptr, digest []byte, algID *uint16) ([]byte, error) {
   570  	// PKCS#1 v1.5 padding for some TLS 1.2
   571  	padInfo := winPKCS1PaddingInfo{pszAlgID: algID}
   572  	var size uint32
   573  	// Obtain the size of the signature
   574  	r, _, _ := winNCryptSignHash.Call(
   575  		kh,
   576  		uintptr(unsafe.Pointer(&padInfo)),
   577  		uintptr(unsafe.Pointer(&digest[0])),
   578  		uintptr(len(digest)),
   579  		0,
   580  		0,
   581  		uintptr(unsafe.Pointer(&size)),
   582  		winBCryptPadPKCS1)
   583  	if r != 0 {
   584  		return nil, ErrStoreRSASigningError
   585  	}
   586  
   587  	// Obtain the signature data
   588  	sig := make([]byte, size)
   589  	r, _, _ = winNCryptSignHash.Call(
   590  		kh,
   591  		uintptr(unsafe.Pointer(&padInfo)),
   592  		uintptr(unsafe.Pointer(&digest[0])),
   593  		uintptr(len(digest)),
   594  		uintptr(unsafe.Pointer(&sig[0])),
   595  		uintptr(size),
   596  		uintptr(unsafe.Pointer(&size)),
   597  		winBCryptPadPKCS1)
   598  	if r != 0 {
   599  		return nil, ErrStoreRSASigningError
   600  	}
   601  
   602  	return sig[:size], nil
   603  }
   604  
   605  func winSignRSAPSSPadding(kh uintptr, digest []byte, algID *uint16) ([]byte, error) {
   606  	// PSS padding for TLS 1.3 and some TLS 1.2
   607  	padInfo := winPSSPaddingInfo{pszAlgID: algID, cbSalt: winBCryptPadPSSSalt}
   608  
   609  	var size uint32
   610  	// Obtain the size of the signature
   611  	r, _, _ := winNCryptSignHash.Call(
   612  		kh,
   613  		uintptr(unsafe.Pointer(&padInfo)),
   614  		uintptr(unsafe.Pointer(&digest[0])),
   615  		uintptr(len(digest)),
   616  		0,
   617  		0,
   618  		uintptr(unsafe.Pointer(&size)),
   619  		winBCryptPadPSS)
   620  	if r != 0 {
   621  		return nil, ErrStoreRSASigningError
   622  	}
   623  
   624  	// Obtain the signature data
   625  	sig := make([]byte, size)
   626  	r, _, _ = winNCryptSignHash.Call(
   627  		kh,
   628  		uintptr(unsafe.Pointer(&padInfo)),
   629  		uintptr(unsafe.Pointer(&digest[0])),
   630  		uintptr(len(digest)),
   631  		uintptr(unsafe.Pointer(&sig[0])),
   632  		uintptr(size),
   633  		uintptr(unsafe.Pointer(&size)),
   634  		winBCryptPadPSS)
   635  	if r != 0 {
   636  		return nil, ErrStoreRSASigningError
   637  	}
   638  
   639  	return sig[:size], nil
   640  }
   641  
   642  // certKey wraps CryptAcquireCertificatePrivateKey. It obtains the CNG private
   643  // key of a known certificate and returns a pointer to a winKey which implements
   644  // both crypto.Signer. When a nil cert context is passed
   645  // a nil key is intentionally returned, to model the expected behavior of a
   646  // non-existent cert having no private key.
   647  // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecertificateprivatekey
   648  func (w *winCertStore) certKey(cert *windows.CertContext) (*winKey, error) {
   649  	// Return early if a nil cert was passed.
   650  	if cert == nil {
   651  		return nil, nil
   652  	}
   653  	var (
   654  		kh       uintptr
   655  		spec     uint32
   656  		mustFree int
   657  	)
   658  	r, _, _ := winCryptAcquireCertificatePrivateKey.Call(
   659  		uintptr(unsafe.Pointer(cert)),
   660  		winAcquireCached|winAcquireSilent|winAcquireOnlyNCryptKey,
   661  		0, // Reserved, must be null.
   662  		uintptr(unsafe.Pointer(&kh)),
   663  		uintptr(unsafe.Pointer(&spec)),
   664  		uintptr(unsafe.Pointer(&mustFree)),
   665  	)
   666  	// If the function succeeds, the return value is nonzero (TRUE).
   667  	if r == 0 {
   668  		return nil, ErrNoPrivateKeyStoreRef
   669  	}
   670  	if mustFree != 0 {
   671  		return nil, ErrNoPrivateKeyStoreRef
   672  	}
   673  	if spec != winNcryptKeySpec {
   674  		return nil, ErrNoPrivateKeyStoreRef
   675  	}
   676  
   677  	return winKeyMetadata(kh)
   678  }
   679  
   680  func winKeyMetadata(kh uintptr) (*winKey, error) {
   681  	// uc is used to populate the unique container name attribute of the private key
   682  	uc, err := winGetPropertyStr(kh, winNCryptUniqueNameProperty)
   683  	if err != nil {
   684  		// unable to determine key unique name
   685  		return nil, ErrExtractingPrivateKeyMetadata
   686  	}
   687  
   688  	alg, err := winGetPropertyStr(kh, winNCryptAlgorithmGroupProperty)
   689  	if err != nil {
   690  		// unable to determine key algorithm
   691  		return nil, ErrExtractingPrivateKeyMetadata
   692  	}
   693  
   694  	var pub crypto.PublicKey
   695  
   696  	switch alg {
   697  	case "ECDSA", "ECDH":
   698  		buf, err := winExport(kh, winBCryptECCPublicBlob)
   699  		if err != nil {
   700  			// failed to export ECC public key
   701  			return nil, ErrExtractingECCPublicKey
   702  		}
   703  		pub, err = unmarshalECC(buf, kh)
   704  		if err != nil {
   705  			return nil, ErrExtractingECCPublicKey
   706  		}
   707  	case "RSA":
   708  		buf, err := winExport(kh, winBCryptRSAPublicBlob)
   709  		if err != nil {
   710  			return nil, ErrExtractingRSAPublicKey
   711  		}
   712  		pub, err = winUnmarshalRSA(buf)
   713  		if err != nil {
   714  			return nil, ErrExtractingRSAPublicKey
   715  		}
   716  	default:
   717  		return nil, ErrBadPublicKeyAlgorithm
   718  	}
   719  
   720  	return &winKey{handle: kh, pub: pub, Container: uc, AlgorithmGroup: alg}, nil
   721  }
   722  
   723  func winGetProperty(kh uintptr, property *uint16) ([]byte, error) {
   724  	var strSize uint32
   725  	r, _, _ := winNCryptGetProperty.Call(
   726  		kh,
   727  		uintptr(unsafe.Pointer(property)),
   728  		0,
   729  		0,
   730  		uintptr(unsafe.Pointer(&strSize)),
   731  		0,
   732  		0)
   733  	if r != 0 {
   734  		return nil, ErrExtractPropertyFromKey
   735  	}
   736  
   737  	buf := make([]byte, strSize)
   738  	r, _, _ = winNCryptGetProperty.Call(
   739  		kh,
   740  		uintptr(unsafe.Pointer(property)),
   741  		uintptr(unsafe.Pointer(&buf[0])),
   742  		uintptr(strSize),
   743  		uintptr(unsafe.Pointer(&strSize)),
   744  		0,
   745  		0)
   746  	if r != 0 {
   747  		return nil, ErrExtractPropertyFromKey
   748  	}
   749  
   750  	return buf, nil
   751  }
   752  
   753  func winGetPropertyStr(kh uintptr, property *uint16) (string, error) {
   754  	buf, err := winFnGetProperty(kh, property)
   755  	if err != nil {
   756  		return "", ErrExtractPropertyFromKey
   757  	}
   758  	uc := bytes.ReplaceAll(buf, []byte{0x00}, []byte(""))
   759  	return string(uc), nil
   760  }
   761  
   762  func winExport(kh uintptr, blobType *uint16) ([]byte, error) {
   763  	var size uint32
   764  	// When obtaining the size of a public key, most parameters are not required
   765  	r, _, _ := winNCryptExportKey.Call(
   766  		kh,
   767  		0,
   768  		uintptr(unsafe.Pointer(blobType)),
   769  		0,
   770  		0,
   771  		0,
   772  		uintptr(unsafe.Pointer(&size)),
   773  		0)
   774  	if r != 0 {
   775  		return nil, ErrExtractingPublicKey
   776  	}
   777  
   778  	// Place the exported key in buf now that we know the size required
   779  	buf := make([]byte, size)
   780  	r, _, _ = winNCryptExportKey.Call(
   781  		kh,
   782  		0,
   783  		uintptr(unsafe.Pointer(blobType)),
   784  		0,
   785  		uintptr(unsafe.Pointer(&buf[0])),
   786  		uintptr(size),
   787  		uintptr(unsafe.Pointer(&size)),
   788  		0)
   789  	if r != 0 {
   790  		return nil, ErrExtractingPublicKey
   791  	}
   792  	return buf, nil
   793  }
   794  
   795  func unmarshalECC(buf []byte, kh uintptr) (*ecdsa.PublicKey, error) {
   796  	// BCRYPT_ECCKEY_BLOB from bcrypt.h
   797  	header := struct {
   798  		Magic uint32
   799  		Key   uint32
   800  	}{}
   801  
   802  	r := bytes.NewReader(buf)
   803  	if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
   804  		return nil, ErrExtractingECCPublicKey
   805  	}
   806  
   807  	curve, ok := winCurveIDs[header.Magic]
   808  	if !ok {
   809  		// Fix for b/185945636, where despite specifying the curve, nCrypt returns
   810  		// an incorrect response with BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC.
   811  		var err error
   812  		curve, err = winCurveName(kh)
   813  		if err != nil {
   814  			// unsupported header magic or cannot match the curve by name
   815  			return nil, err
   816  		}
   817  	}
   818  
   819  	keyX := make([]byte, header.Key)
   820  	if n, err := r.Read(keyX); n != int(header.Key) || err != nil {
   821  		// failed to read key X
   822  		return nil, ErrExtractingECCPublicKey
   823  	}
   824  
   825  	keyY := make([]byte, header.Key)
   826  	if n, err := r.Read(keyY); n != int(header.Key) || err != nil {
   827  		// failed to read key Y
   828  		return nil, ErrExtractingECCPublicKey
   829  	}
   830  
   831  	pub := &ecdsa.PublicKey{
   832  		Curve: curve,
   833  		X:     new(big.Int).SetBytes(keyX),
   834  		Y:     new(big.Int).SetBytes(keyY),
   835  	}
   836  	return pub, nil
   837  }
   838  
   839  // winCurveName reads the curve name property and returns the corresponding curve.
   840  func winCurveName(kh uintptr) (elliptic.Curve, error) {
   841  	cn, err := winGetPropertyStr(kh, winNCryptECCCurveNameProperty)
   842  	if err != nil {
   843  		// unable to determine the curve property name
   844  		return nil, ErrExtractPropertyFromKey
   845  	}
   846  	curve, ok := winCurveNames[cn]
   847  	if !ok {
   848  		// unknown curve name
   849  		return nil, ErrBadECCCurveName
   850  	}
   851  	return curve, nil
   852  }
   853  
   854  func winUnmarshalRSA(buf []byte) (*rsa.PublicKey, error) {
   855  	// BCRYPT_RSA_BLOB from bcrypt.h
   856  	header := struct {
   857  		Magic         uint32
   858  		BitLength     uint32
   859  		PublicExpSize uint32
   860  		ModulusSize   uint32
   861  		UnusedPrime1  uint32
   862  		UnusedPrime2  uint32
   863  	}{}
   864  
   865  	r := bytes.NewReader(buf)
   866  	if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
   867  		return nil, ErrExtractingRSAPublicKey
   868  	}
   869  
   870  	if header.Magic != winRSA1Magic {
   871  		// invalid header magic
   872  		return nil, ErrExtractingRSAPublicKey
   873  	}
   874  
   875  	if header.PublicExpSize > 8 {
   876  		// unsupported public exponent size
   877  		return nil, ErrExtractingRSAPublicKey
   878  	}
   879  
   880  	exp := make([]byte, 8)
   881  	if n, err := r.Read(exp[8-header.PublicExpSize:]); n != int(header.PublicExpSize) || err != nil {
   882  		// failed to read public exponent
   883  		return nil, ErrExtractingRSAPublicKey
   884  	}
   885  
   886  	mod := make([]byte, header.ModulusSize)
   887  	if n, err := r.Read(mod); n != int(header.ModulusSize) || err != nil {
   888  		// failed to read modulus
   889  		return nil, ErrExtractingRSAPublicKey
   890  	}
   891  
   892  	pub := &rsa.PublicKey{
   893  		N: new(big.Int).SetBytes(mod),
   894  		E: int(binary.BigEndian.Uint64(exp)),
   895  	}
   896  	return pub, nil
   897  }
   898  
   899  // storeHandle returns a handle to a given cert store, opening the handle as needed.
   900  func (w *winCertStore) storeHandle(provider uint32, store *uint16) (windows.Handle, error) {
   901  	w.mu.Lock()
   902  	defer w.mu.Unlock()
   903  
   904  	key := fmt.Sprintf("%d%s", provider, windows.UTF16PtrToString(store))
   905  	var err error
   906  	if w.stores[key] == nil {
   907  		w.stores[key], err = winNewStoreHandle(provider, store)
   908  		if err != nil {
   909  			return 0, ErrBadCryptoStoreProvider
   910  		}
   911  	}
   912  	return *w.stores[key].handle, nil
   913  }
   914  
   915  // Verify interface conformance.
   916  var _ credential = &winKey{}