get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/certstore/certstore_windows.go (about)

     1  // Copyright 2022-2023 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
   115  	winMyStore = winWide("MY")
   116  
   117  	// These DLLs must be available on all Windows hosts
   118  	winCrypt32 = windows.MustLoadDLL("crypt32.dll")
   119  	winNCrypt  = windows.MustLoadDLL("ncrypt.dll")
   120  
   121  	winCertFindCertificateInStore        = winCrypt32.MustFindProc("CertFindCertificateInStore")
   122  	winCryptAcquireCertificatePrivateKey = winCrypt32.MustFindProc("CryptAcquireCertificatePrivateKey")
   123  	winNCryptExportKey                   = winNCrypt.MustFindProc("NCryptExportKey")
   124  	winNCryptOpenStorageProvider         = winNCrypt.MustFindProc("NCryptOpenStorageProvider")
   125  	winNCryptGetProperty                 = winNCrypt.MustFindProc("NCryptGetProperty")
   126  	winNCryptSignHash                    = winNCrypt.MustFindProc("NCryptSignHash")
   127  
   128  	winFnGetProperty = winGetProperty
   129  )
   130  
   131  type winPKCS1PaddingInfo struct {
   132  	pszAlgID *uint16
   133  }
   134  
   135  type winPSSPaddingInfo struct {
   136  	pszAlgID *uint16
   137  	cbSalt   uint32
   138  }
   139  
   140  // TLSConfig fulfills the same function as reading cert and key pair from pem files but
   141  // sources the Windows certificate store instead
   142  func TLSConfig(certStore StoreType, certMatchBy MatchByType, certMatch string, config *tls.Config) error {
   143  	var (
   144  		leaf     *x509.Certificate
   145  		leafCtx  *windows.CertContext
   146  		pk       *winKey
   147  		vOpts    = x509.VerifyOptions{}
   148  		chains   [][]*x509.Certificate
   149  		chain    []*x509.Certificate
   150  		rawChain [][]byte
   151  	)
   152  
   153  	// By StoreType, open a store
   154  	if certStore == windowsCurrentUser || certStore == windowsLocalMachine {
   155  		var scope uint32
   156  		cs, err := winOpenCertStore(providerMSSoftware)
   157  		if err != nil || cs == nil {
   158  			return err
   159  		}
   160  		if certStore == windowsCurrentUser {
   161  			scope = winCertStoreCurrentUser
   162  		}
   163  		if certStore == windowsLocalMachine {
   164  			scope = winCertStoreLocalMachine
   165  		}
   166  
   167  		// certByIssuer or certBySubject
   168  		if certMatchBy == matchBySubject || certMatchBy == MATCHBYEMPTY {
   169  			leaf, leafCtx, err = cs.certBySubject(certMatch, scope)
   170  		} else if certMatchBy == matchByIssuer {
   171  			leaf, leafCtx, err = cs.certByIssuer(certMatch, scope)
   172  		} else {
   173  			return ErrBadMatchByType
   174  		}
   175  		if err != nil {
   176  			// pass through error from cert search
   177  			return err
   178  		}
   179  		if leaf == nil || leafCtx == nil {
   180  			return ErrFailedCertSearch
   181  		}
   182  		pk, err = cs.certKey(leafCtx)
   183  		if err != nil {
   184  			return err
   185  		}
   186  		if pk == nil {
   187  			return ErrNoPrivateKeyStoreRef
   188  		}
   189  	} else {
   190  		return ErrBadCertStore
   191  	}
   192  
   193  	// Get intermediates in the cert store for the found leaf IFF there is a full chain of trust in the store
   194  	// otherwise just use leaf as the final chain.
   195  	//
   196  	// Using std lib Verify as a reliable way to get valid chains out of the win store for the leaf; however,
   197  	// using empty options since server TLS stanza could be TLS role as server identity or client identity.
   198  	chains, err := leaf.Verify(vOpts)
   199  	if err != nil || len(chains) == 0 {
   200  		chains = append(chains, []*x509.Certificate{leaf})
   201  	}
   202  
   203  	// We have at least one verified chain so pop the first chain and remove the self-signed CA cert (if present)
   204  	// from the end of the chain
   205  	chain = chains[0]
   206  	if len(chain) > 1 {
   207  		chain = chain[:len(chain)-1]
   208  	}
   209  
   210  	// For tls.Certificate.Certificate need a [][]byte from []*x509.Certificate
   211  	// Approximate capacity for efficiency
   212  	rawChain = make([][]byte, 0, len(chain))
   213  	for _, link := range chain {
   214  		rawChain = append(rawChain, link.Raw)
   215  	}
   216  
   217  	tlsCert := tls.Certificate{
   218  		Certificate: rawChain,
   219  		PrivateKey:  pk,
   220  		Leaf:        leaf,
   221  	}
   222  	config.Certificates = []tls.Certificate{tlsCert}
   223  
   224  	// note: pk is a windows pointer (not freed by Go) but needs to live the life of the server for Signing.
   225  	// The cert context (leafCtx) windows pointer must not be freed underneath the pk so also life of the server.
   226  	return nil
   227  }
   228  
   229  // winWide returns a pointer to uint16 representing the equivalent
   230  // to a Windows LPCWSTR.
   231  func winWide(s string) *uint16 {
   232  	w := utf16.Encode([]rune(s))
   233  	w = append(w, 0)
   234  	return &w[0]
   235  }
   236  
   237  // winOpenProvider gets a provider handle for subsequent calls
   238  func winOpenProvider(provider string) (uintptr, error) {
   239  	var hProv uintptr
   240  	pname := winWide(provider)
   241  	// Open the provider, the last parameter is not used
   242  	r, _, err := winNCryptOpenStorageProvider.Call(uintptr(unsafe.Pointer(&hProv)), uintptr(unsafe.Pointer(pname)), 0)
   243  	if r == 0 {
   244  		return hProv, nil
   245  	}
   246  	return hProv, fmt.Errorf("NCryptOpenStorageProvider returned %X: %v", r, err)
   247  }
   248  
   249  // winFindCert wraps the CertFindCertificateInStore library call. Note that any cert context passed
   250  // into prev will be freed. If no certificate was found, nil will be returned.
   251  func winFindCert(store windows.Handle, enc, findFlags, findType uint32, para *uint16, prev *windows.CertContext) (*windows.CertContext, error) {
   252  	h, _, err := winCertFindCertificateInStore.Call(
   253  		uintptr(store),
   254  		uintptr(enc),
   255  		uintptr(findFlags),
   256  		uintptr(findType),
   257  		uintptr(unsafe.Pointer(para)),
   258  		uintptr(unsafe.Pointer(prev)),
   259  	)
   260  	if h == 0 {
   261  		// Actual error, or simply not found?
   262  		if errno, ok := err.(syscall.Errno); ok && errno == winCryptENotFound {
   263  			return nil, ErrFailedCertSearch
   264  		}
   265  		return nil, ErrFailedCertSearch
   266  	}
   267  	// nolint:govet
   268  	return (*windows.CertContext)(unsafe.Pointer(h)), nil
   269  }
   270  
   271  // winCertStore is a store implementation for the Windows Certificate Store
   272  type winCertStore struct {
   273  	Prov     uintptr
   274  	ProvName string
   275  	stores   map[string]*winStoreHandle
   276  	mu       sync.Mutex
   277  }
   278  
   279  // winOpenCertStore creates a winCertStore
   280  func winOpenCertStore(provider string) (*winCertStore, error) {
   281  	cngProv, err := winOpenProvider(provider)
   282  	if err != nil {
   283  		// pass through error from winOpenProvider
   284  		return nil, err
   285  	}
   286  
   287  	wcs := &winCertStore{
   288  		Prov:     cngProv,
   289  		ProvName: provider,
   290  		stores:   make(map[string]*winStoreHandle),
   291  	}
   292  
   293  	return wcs, nil
   294  }
   295  
   296  // winCertContextToX509 creates an x509.Certificate from a Windows cert context.
   297  func winCertContextToX509(ctx *windows.CertContext) (*x509.Certificate, error) {
   298  	var der []byte
   299  	slice := (*reflect.SliceHeader)(unsafe.Pointer(&der))
   300  	slice.Data = uintptr(unsafe.Pointer(ctx.EncodedCert))
   301  	slice.Len = int(ctx.Length)
   302  	slice.Cap = int(ctx.Length)
   303  	return x509.ParseCertificate(der)
   304  }
   305  
   306  // certByIssuer matches and returns the first certificate found by passed issuer.
   307  // CertContext pointer returned allows subsequent key operations like Sign. Caller specifies
   308  // current user's personal certs or local machine's personal certs using storeType.
   309  // See CERT_FIND_ISSUER_STR description at https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindcertificateinstore
   310  func (w *winCertStore) certByIssuer(issuer string, storeType uint32) (*x509.Certificate, *windows.CertContext, error) {
   311  	return w.certSearch(winFindIssuerStr, issuer, winMyStore, storeType)
   312  }
   313  
   314  // certBySubject matches and returns the first certificate found by passed subject field.
   315  // CertContext pointer returned allows subsequent key operations like Sign. Caller specifies
   316  // current user's personal certs or local machine's personal certs using storeType.
   317  // See CERT_FIND_SUBJECT_STR description at https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindcertificateinstore
   318  func (w *winCertStore) certBySubject(subject string, storeType uint32) (*x509.Certificate, *windows.CertContext, error) {
   319  	return w.certSearch(winFindSubjectStr, subject, winMyStore, storeType)
   320  }
   321  
   322  // certSearch is a helper function to lookup certificates based on search type and match value.
   323  // store is used to specify which store to perform the lookup in (system or user).
   324  func (w *winCertStore) certSearch(searchType uint32, matchValue string, searchRoot *uint16, store uint32) (*x509.Certificate, *windows.CertContext, error) {
   325  	// store handle to "MY" store
   326  	h, err := w.storeHandle(store, searchRoot)
   327  	if err != nil {
   328  		return nil, nil, err
   329  	}
   330  
   331  	var prev *windows.CertContext
   332  	var cert *x509.Certificate
   333  
   334  	i, err := windows.UTF16PtrFromString(matchValue)
   335  	if err != nil {
   336  		return nil, nil, ErrFailedCertSearch
   337  	}
   338  
   339  	// pass 0 as the third parameter because it is not used
   340  	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa376064(v=vs.85).aspx
   341  	nc, err := winFindCert(h, winEncodingX509ASN|winEncodingPKCS7, 0, searchType, i, prev)
   342  	if err != nil {
   343  		return nil, nil, err
   344  	}
   345  	if nc != nil {
   346  		// certificate found
   347  		prev = nc
   348  
   349  		// Extract the DER-encoded certificate from the cert context
   350  		xc, err := winCertContextToX509(nc)
   351  		if err == nil {
   352  			cert = xc
   353  		} else {
   354  			return nil, nil, ErrFailedX509Extract
   355  		}
   356  	} else {
   357  		return nil, nil, ErrFailedCertSearch
   358  	}
   359  
   360  	if cert == nil {
   361  		return nil, nil, ErrFailedX509Extract
   362  	}
   363  
   364  	return cert, prev, nil
   365  }
   366  
   367  type winStoreHandle struct {
   368  	handle *windows.Handle
   369  }
   370  
   371  func winNewStoreHandle(provider uint32, store *uint16) (*winStoreHandle, error) {
   372  	var s winStoreHandle
   373  	if s.handle != nil {
   374  		return &s, nil
   375  	}
   376  	st, err := windows.CertOpenStore(
   377  		winCertStoreProvSystem,
   378  		0,
   379  		0,
   380  		provider,
   381  		uintptr(unsafe.Pointer(store)))
   382  	if err != nil {
   383  		return nil, ErrBadCryptoStoreProvider
   384  	}
   385  	s.handle = &st
   386  	return &s, nil
   387  }
   388  
   389  // winKey implements crypto.Signer and crypto.Decrypter for key based operations.
   390  type winKey struct {
   391  	handle         uintptr
   392  	pub            crypto.PublicKey
   393  	Container      string
   394  	AlgorithmGroup string
   395  }
   396  
   397  // Public exports a public key to implement crypto.Signer
   398  func (k winKey) Public() crypto.PublicKey {
   399  	return k.pub
   400  }
   401  
   402  // Sign returns the signature of a hash to implement crypto.Signer
   403  func (k winKey) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
   404  	switch k.AlgorithmGroup {
   405  	case "ECDSA", "ECDH":
   406  		return winSignECDSA(k.handle, digest)
   407  	case "RSA":
   408  		hf := opts.HashFunc()
   409  		algID, ok := winAlgIDs[hf]
   410  		if !ok {
   411  			return nil, ErrBadRSAHashAlgorithm
   412  		}
   413  		switch opts.(type) {
   414  		case *rsa.PSSOptions:
   415  			return winSignRSAPSSPadding(k.handle, digest, algID)
   416  		default:
   417  			return winSignRSAPKCS1Padding(k.handle, digest, algID)
   418  		}
   419  	default:
   420  		return nil, ErrBadSigningAlgorithm
   421  	}
   422  }
   423  
   424  func winSignECDSA(kh uintptr, digest []byte) ([]byte, error) {
   425  	var size uint32
   426  	// Obtain the size of the signature
   427  	r, _, _ := winNCryptSignHash.Call(
   428  		kh,
   429  		0,
   430  		uintptr(unsafe.Pointer(&digest[0])),
   431  		uintptr(len(digest)),
   432  		0,
   433  		0,
   434  		uintptr(unsafe.Pointer(&size)),
   435  		0)
   436  	if r != 0 {
   437  		return nil, ErrStoreECDSASigningError
   438  	}
   439  
   440  	// Obtain the signature data
   441  	buf := make([]byte, size)
   442  	r, _, _ = winNCryptSignHash.Call(
   443  		kh,
   444  		0,
   445  		uintptr(unsafe.Pointer(&digest[0])),
   446  		uintptr(len(digest)),
   447  		uintptr(unsafe.Pointer(&buf[0])),
   448  		uintptr(size),
   449  		uintptr(unsafe.Pointer(&size)),
   450  		0)
   451  	if r != 0 {
   452  		return nil, ErrStoreECDSASigningError
   453  	}
   454  	if len(buf) != int(size) {
   455  		return nil, ErrStoreECDSASigningError
   456  	}
   457  
   458  	return winPackECDSASigValue(bytes.NewReader(buf[:size]), len(digest))
   459  }
   460  
   461  func winPackECDSASigValue(r io.Reader, digestLength int) ([]byte, error) {
   462  	sigR := make([]byte, digestLength)
   463  	if _, err := io.ReadFull(r, sigR); err != nil {
   464  		return nil, ErrStoreECDSASigningError
   465  	}
   466  
   467  	sigS := make([]byte, digestLength)
   468  	if _, err := io.ReadFull(r, sigS); err != nil {
   469  		return nil, ErrStoreECDSASigningError
   470  	}
   471  
   472  	var b cryptobyte.Builder
   473  	b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
   474  		b.AddASN1BigInt(new(big.Int).SetBytes(sigR))
   475  		b.AddASN1BigInt(new(big.Int).SetBytes(sigS))
   476  	})
   477  	return b.Bytes()
   478  }
   479  
   480  func winSignRSAPKCS1Padding(kh uintptr, digest []byte, algID *uint16) ([]byte, error) {
   481  	// PKCS#1 v1.5 padding for some TLS 1.2
   482  	padInfo := winPKCS1PaddingInfo{pszAlgID: algID}
   483  	var size uint32
   484  	// Obtain the size of the signature
   485  	r, _, _ := winNCryptSignHash.Call(
   486  		kh,
   487  		uintptr(unsafe.Pointer(&padInfo)),
   488  		uintptr(unsafe.Pointer(&digest[0])),
   489  		uintptr(len(digest)),
   490  		0,
   491  		0,
   492  		uintptr(unsafe.Pointer(&size)),
   493  		winBCryptPadPKCS1)
   494  	if r != 0 {
   495  		return nil, ErrStoreRSASigningError
   496  	}
   497  
   498  	// Obtain the signature data
   499  	sig := make([]byte, size)
   500  	r, _, _ = winNCryptSignHash.Call(
   501  		kh,
   502  		uintptr(unsafe.Pointer(&padInfo)),
   503  		uintptr(unsafe.Pointer(&digest[0])),
   504  		uintptr(len(digest)),
   505  		uintptr(unsafe.Pointer(&sig[0])),
   506  		uintptr(size),
   507  		uintptr(unsafe.Pointer(&size)),
   508  		winBCryptPadPKCS1)
   509  	if r != 0 {
   510  		return nil, ErrStoreRSASigningError
   511  	}
   512  
   513  	return sig[:size], nil
   514  }
   515  
   516  func winSignRSAPSSPadding(kh uintptr, digest []byte, algID *uint16) ([]byte, error) {
   517  	// PSS padding for TLS 1.3 and some TLS 1.2
   518  	padInfo := winPSSPaddingInfo{pszAlgID: algID, cbSalt: winBCryptPadPSSSalt}
   519  
   520  	var size uint32
   521  	// Obtain the size of the signature
   522  	r, _, _ := winNCryptSignHash.Call(
   523  		kh,
   524  		uintptr(unsafe.Pointer(&padInfo)),
   525  		uintptr(unsafe.Pointer(&digest[0])),
   526  		uintptr(len(digest)),
   527  		0,
   528  		0,
   529  		uintptr(unsafe.Pointer(&size)),
   530  		winBCryptPadPSS)
   531  	if r != 0 {
   532  		return nil, ErrStoreRSASigningError
   533  	}
   534  
   535  	// Obtain the signature data
   536  	sig := make([]byte, size)
   537  	r, _, _ = winNCryptSignHash.Call(
   538  		kh,
   539  		uintptr(unsafe.Pointer(&padInfo)),
   540  		uintptr(unsafe.Pointer(&digest[0])),
   541  		uintptr(len(digest)),
   542  		uintptr(unsafe.Pointer(&sig[0])),
   543  		uintptr(size),
   544  		uintptr(unsafe.Pointer(&size)),
   545  		winBCryptPadPSS)
   546  	if r != 0 {
   547  		return nil, ErrStoreRSASigningError
   548  	}
   549  
   550  	return sig[:size], nil
   551  }
   552  
   553  // certKey wraps CryptAcquireCertificatePrivateKey. It obtains the CNG private
   554  // key of a known certificate and returns a pointer to a winKey which implements
   555  // both crypto.Signer. When a nil cert context is passed
   556  // a nil key is intentionally returned, to model the expected behavior of a
   557  // non-existent cert having no private key.
   558  // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecertificateprivatekey
   559  func (w *winCertStore) certKey(cert *windows.CertContext) (*winKey, error) {
   560  	// Return early if a nil cert was passed.
   561  	if cert == nil {
   562  		return nil, nil
   563  	}
   564  	var (
   565  		kh       uintptr
   566  		spec     uint32
   567  		mustFree int
   568  	)
   569  	r, _, _ := winCryptAcquireCertificatePrivateKey.Call(
   570  		uintptr(unsafe.Pointer(cert)),
   571  		winAcquireCached|winAcquireSilent|winAcquireOnlyNCryptKey,
   572  		0, // Reserved, must be null.
   573  		uintptr(unsafe.Pointer(&kh)),
   574  		uintptr(unsafe.Pointer(&spec)),
   575  		uintptr(unsafe.Pointer(&mustFree)),
   576  	)
   577  	// If the function succeeds, the return value is nonzero (TRUE).
   578  	if r == 0 {
   579  		return nil, ErrNoPrivateKeyStoreRef
   580  	}
   581  	if mustFree != 0 {
   582  		return nil, ErrNoPrivateKeyStoreRef
   583  	}
   584  	if spec != winNcryptKeySpec {
   585  		return nil, ErrNoPrivateKeyStoreRef
   586  	}
   587  
   588  	return winKeyMetadata(kh)
   589  }
   590  
   591  func winKeyMetadata(kh uintptr) (*winKey, error) {
   592  	// uc is used to populate the unique container name attribute of the private key
   593  	uc, err := winGetPropertyStr(kh, winNCryptUniqueNameProperty)
   594  	if err != nil {
   595  		// unable to determine key unique name
   596  		return nil, ErrExtractingPrivateKeyMetadata
   597  	}
   598  
   599  	alg, err := winGetPropertyStr(kh, winNCryptAlgorithmGroupProperty)
   600  	if err != nil {
   601  		// unable to determine key algorithm
   602  		return nil, ErrExtractingPrivateKeyMetadata
   603  	}
   604  
   605  	var pub crypto.PublicKey
   606  
   607  	switch alg {
   608  	case "ECDSA", "ECDH":
   609  		buf, err := winExport(kh, winBCryptECCPublicBlob)
   610  		if err != nil {
   611  			// failed to export ECC public key
   612  			return nil, ErrExtractingECCPublicKey
   613  		}
   614  		pub, err = unmarshalECC(buf, kh)
   615  		if err != nil {
   616  			return nil, ErrExtractingECCPublicKey
   617  		}
   618  	case "RSA":
   619  		buf, err := winExport(kh, winBCryptRSAPublicBlob)
   620  		if err != nil {
   621  			return nil, ErrExtractingRSAPublicKey
   622  		}
   623  		pub, err = winUnmarshalRSA(buf)
   624  		if err != nil {
   625  			return nil, ErrExtractingRSAPublicKey
   626  		}
   627  	default:
   628  		return nil, ErrBadPublicKeyAlgorithm
   629  	}
   630  
   631  	return &winKey{handle: kh, pub: pub, Container: uc, AlgorithmGroup: alg}, nil
   632  }
   633  
   634  func winGetProperty(kh uintptr, property *uint16) ([]byte, error) {
   635  	var strSize uint32
   636  	r, _, _ := winNCryptGetProperty.Call(
   637  		kh,
   638  		uintptr(unsafe.Pointer(property)),
   639  		0,
   640  		0,
   641  		uintptr(unsafe.Pointer(&strSize)),
   642  		0,
   643  		0)
   644  	if r != 0 {
   645  		return nil, ErrExtractPropertyFromKey
   646  	}
   647  
   648  	buf := make([]byte, strSize)
   649  	r, _, _ = winNCryptGetProperty.Call(
   650  		kh,
   651  		uintptr(unsafe.Pointer(property)),
   652  		uintptr(unsafe.Pointer(&buf[0])),
   653  		uintptr(strSize),
   654  		uintptr(unsafe.Pointer(&strSize)),
   655  		0,
   656  		0)
   657  	if r != 0 {
   658  		return nil, ErrExtractPropertyFromKey
   659  	}
   660  
   661  	return buf, nil
   662  }
   663  
   664  func winGetPropertyStr(kh uintptr, property *uint16) (string, error) {
   665  	buf, err := winFnGetProperty(kh, property)
   666  	if err != nil {
   667  		return "", ErrExtractPropertyFromKey
   668  	}
   669  	uc := bytes.ReplaceAll(buf, []byte{0x00}, []byte(""))
   670  	return string(uc), nil
   671  }
   672  
   673  func winExport(kh uintptr, blobType *uint16) ([]byte, error) {
   674  	var size uint32
   675  	// When obtaining the size of a public key, most parameters are not required
   676  	r, _, _ := winNCryptExportKey.Call(
   677  		kh,
   678  		0,
   679  		uintptr(unsafe.Pointer(blobType)),
   680  		0,
   681  		0,
   682  		0,
   683  		uintptr(unsafe.Pointer(&size)),
   684  		0)
   685  	if r != 0 {
   686  		return nil, ErrExtractingPublicKey
   687  	}
   688  
   689  	// Place the exported key in buf now that we know the size required
   690  	buf := make([]byte, size)
   691  	r, _, _ = winNCryptExportKey.Call(
   692  		kh,
   693  		0,
   694  		uintptr(unsafe.Pointer(blobType)),
   695  		0,
   696  		uintptr(unsafe.Pointer(&buf[0])),
   697  		uintptr(size),
   698  		uintptr(unsafe.Pointer(&size)),
   699  		0)
   700  	if r != 0 {
   701  		return nil, ErrExtractingPublicKey
   702  	}
   703  	return buf, nil
   704  }
   705  
   706  func unmarshalECC(buf []byte, kh uintptr) (*ecdsa.PublicKey, error) {
   707  	// BCRYPT_ECCKEY_BLOB from bcrypt.h
   708  	header := struct {
   709  		Magic uint32
   710  		Key   uint32
   711  	}{}
   712  
   713  	r := bytes.NewReader(buf)
   714  	if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
   715  		return nil, ErrExtractingECCPublicKey
   716  	}
   717  
   718  	curve, ok := winCurveIDs[header.Magic]
   719  	if !ok {
   720  		// Fix for b/185945636, where despite specifying the curve, nCrypt returns
   721  		// an incorrect response with BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC.
   722  		var err error
   723  		curve, err = winCurveName(kh)
   724  		if err != nil {
   725  			// unsupported header magic or cannot match the curve by name
   726  			return nil, err
   727  		}
   728  	}
   729  
   730  	keyX := make([]byte, header.Key)
   731  	if n, err := r.Read(keyX); n != int(header.Key) || err != nil {
   732  		// failed to read key X
   733  		return nil, ErrExtractingECCPublicKey
   734  	}
   735  
   736  	keyY := make([]byte, header.Key)
   737  	if n, err := r.Read(keyY); n != int(header.Key) || err != nil {
   738  		// failed to read key Y
   739  		return nil, ErrExtractingECCPublicKey
   740  	}
   741  
   742  	pub := &ecdsa.PublicKey{
   743  		Curve: curve,
   744  		X:     new(big.Int).SetBytes(keyX),
   745  		Y:     new(big.Int).SetBytes(keyY),
   746  	}
   747  	return pub, nil
   748  }
   749  
   750  // winCurveName reads the curve name property and returns the corresponding curve.
   751  func winCurveName(kh uintptr) (elliptic.Curve, error) {
   752  	cn, err := winGetPropertyStr(kh, winNCryptECCCurveNameProperty)
   753  	if err != nil {
   754  		// unable to determine the curve property name
   755  		return nil, ErrExtractPropertyFromKey
   756  	}
   757  	curve, ok := winCurveNames[cn]
   758  	if !ok {
   759  		// unknown curve name
   760  		return nil, ErrBadECCCurveName
   761  	}
   762  	return curve, nil
   763  }
   764  
   765  func winUnmarshalRSA(buf []byte) (*rsa.PublicKey, error) {
   766  	// BCRYPT_RSA_BLOB from bcrypt.h
   767  	header := struct {
   768  		Magic         uint32
   769  		BitLength     uint32
   770  		PublicExpSize uint32
   771  		ModulusSize   uint32
   772  		UnusedPrime1  uint32
   773  		UnusedPrime2  uint32
   774  	}{}
   775  
   776  	r := bytes.NewReader(buf)
   777  	if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
   778  		return nil, ErrExtractingRSAPublicKey
   779  	}
   780  
   781  	if header.Magic != winRSA1Magic {
   782  		// invalid header magic
   783  		return nil, ErrExtractingRSAPublicKey
   784  	}
   785  
   786  	if header.PublicExpSize > 8 {
   787  		// unsupported public exponent size
   788  		return nil, ErrExtractingRSAPublicKey
   789  	}
   790  
   791  	exp := make([]byte, 8)
   792  	if n, err := r.Read(exp[8-header.PublicExpSize:]); n != int(header.PublicExpSize) || err != nil {
   793  		// failed to read public exponent
   794  		return nil, ErrExtractingRSAPublicKey
   795  	}
   796  
   797  	mod := make([]byte, header.ModulusSize)
   798  	if n, err := r.Read(mod); n != int(header.ModulusSize) || err != nil {
   799  		// failed to read modulus
   800  		return nil, ErrExtractingRSAPublicKey
   801  	}
   802  
   803  	pub := &rsa.PublicKey{
   804  		N: new(big.Int).SetBytes(mod),
   805  		E: int(binary.BigEndian.Uint64(exp)),
   806  	}
   807  	return pub, nil
   808  }
   809  
   810  // storeHandle returns a handle to a given cert store, opening the handle as needed.
   811  func (w *winCertStore) storeHandle(provider uint32, store *uint16) (windows.Handle, error) {
   812  	w.mu.Lock()
   813  	defer w.mu.Unlock()
   814  
   815  	key := fmt.Sprintf("%d%s", provider, windows.UTF16PtrToString(store))
   816  	var err error
   817  	if w.stores[key] == nil {
   818  		w.stores[key], err = winNewStoreHandle(provider, store)
   819  		if err != nil {
   820  			return 0, ErrBadCryptoStoreProvider
   821  		}
   822  	}
   823  	return *w.stores[key].handle, nil
   824  }
   825  
   826  // Verify interface conformance.
   827  var _ credential = &winKey{}