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{}