Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2178 lines
50 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Copyright (c) 1997-1999 Microsoft Corporation
  4. //
  5. // File: tlscert.cpp
  6. //
  7. // Contents: Certificate routines
  8. //
  9. // History:
  10. //
  11. //---------------------------------------------------------------------------
  12. #include "pch.cpp"
  13. #include "server.h"
  14. #include "globals.h"
  15. #include "tlscert.h"
  16. #include "gencert.h"
  17. #define MAX_KEY_CONTAINER_LENGTH 25
  18. //////////////////////////////////////////////////////////////////
  19. BOOL
  20. VerifyCertValidity(
  21. IN PCCERT_CONTEXT pCertContext
  22. )
  23. /*++
  24. --*/
  25. {
  26. BOOL bValid;
  27. FILETIME ft;
  28. GetSystemTimeAsFileTime(&ft);
  29. bValid = (CompareFileTime(
  30. &ft,
  31. &(pCertContext->pCertInfo->NotAfter)
  32. ) < 0);
  33. return bValid;
  34. }
  35. //////////////////////////////////////////////////////////////////
  36. void
  37. DeleteBadIssuerCertFromStore(
  38. IN HCERTSTORE hCertStore,
  39. IN PCCERT_CONTEXT pSubjectContext
  40. )
  41. /*++
  42. --*/
  43. {
  44. PCCERT_CONTEXT pCertIssuer = NULL;
  45. DWORD dwFlags;
  46. DWORD dwStatus;
  47. BOOL bExpiredCert = FALSE;
  48. do {
  49. dwFlags = CERT_STORE_SIGNATURE_FLAG;
  50. pCertIssuer = CertGetIssuerCertificateFromStore(
  51. hCertStore,
  52. pSubjectContext,
  53. NULL,
  54. &dwFlags
  55. );
  56. if(pCertIssuer == NULL)
  57. {
  58. // can't find issuer certificate
  59. break;
  60. }
  61. bExpiredCert = (VerifyCertValidity(pCertIssuer) == FALSE);
  62. if(dwFlags != 0 || bExpiredCert == TRUE)
  63. {
  64. CertDeleteCertificateFromStore(pCertIssuer);
  65. }
  66. else
  67. {
  68. break;
  69. }
  70. } while(TRUE);
  71. return;
  72. }
  73. //////////////////////////////////////////////////////////////////
  74. PCCERT_CONTEXT
  75. GetIssuerCertificateFromStore(
  76. IN HCERTSTORE hCertStore,
  77. IN PCCERT_CONTEXT pSubjectContext,
  78. IN BOOL bDelBadIssuerCert
  79. )
  80. /*++
  81. --*/
  82. {
  83. PCCERT_CONTEXT pCertIssuer = NULL;
  84. DWORD dwFlags;
  85. BOOL bExpiredCert = FALSE;
  86. SetLastError(ERROR_SUCCESS);
  87. do {
  88. dwFlags = CERT_STORE_SIGNATURE_FLAG;
  89. pCertIssuer = CertGetIssuerCertificateFromStore(
  90. hCertStore,
  91. pSubjectContext,
  92. pCertIssuer,
  93. &dwFlags
  94. );
  95. if(pCertIssuer == NULL)
  96. {
  97. // can't find issuer certificate
  98. break;
  99. }
  100. bExpiredCert = (VerifyCertValidity(pCertIssuer) == FALSE);
  101. if(dwFlags == 0 && bExpiredCert == FALSE)
  102. {
  103. //
  104. // find a good issuer's certificate
  105. //
  106. break;
  107. }
  108. //if(pCertIssuer != NULL)
  109. //{
  110. // CertFreeCertificateContext(pCertIssuer);
  111. //}
  112. } while(TRUE);
  113. if(bDelBadIssuerCert == TRUE && pCertIssuer)
  114. {
  115. //
  116. // Only delete bad certificate if we can't find a good one.
  117. //
  118. DeleteBadIssuerCertFromStore(
  119. hCertStore,
  120. pSubjectContext
  121. );
  122. }
  123. if(bExpiredCert == TRUE && pCertIssuer == NULL)
  124. {
  125. SetLastError(TLS_E_EXPIRE_CERT);
  126. }
  127. return pCertIssuer;
  128. }
  129. //////////////////////////////////////////////////////////////////////////
  130. DWORD
  131. TLSVerifyCertChain(
  132. IN HCRYPTPROV hCryptProv,
  133. IN HCERTSTORE hCertStore,
  134. IN PCCERT_CONTEXT pSubjectContext,
  135. OUT FILETIME* pftMinExpireTime
  136. )
  137. /*++
  138. --*/
  139. {
  140. DWORD dwStatus = ERROR_SUCCESS;
  141. PCCERT_CONTEXT pCertIssuer = NULL;
  142. PCCERT_CONTEXT pCurrentSubject;
  143. //
  144. // Increase reference count on Subject context.
  145. pCurrentSubject = CertDuplicateCertificateContext(
  146. pSubjectContext
  147. );
  148. while( TRUE )
  149. {
  150. pCertIssuer = GetIssuerCertificateFromStore(
  151. hCertStore,
  152. pCurrentSubject,
  153. FALSE
  154. );
  155. if(!pCertIssuer)
  156. {
  157. // Could not find issuer's certificate or
  158. // a good issuer's certificate
  159. dwStatus = GetLastError();
  160. break;
  161. }
  162. if(CompareFileTime(pftMinExpireTime, &(pCertIssuer->pCertInfo->NotAfter)) > 0)
  163. {
  164. *pftMinExpireTime = pCertIssuer->pCertInfo->NotAfter;
  165. }
  166. if(pCurrentSubject != NULL)
  167. {
  168. CertFreeCertificateContext(pCurrentSubject);
  169. }
  170. pCurrentSubject = pCertIssuer;
  171. }
  172. if(dwStatus == CRYPT_E_SELF_SIGNED)
  173. {
  174. dwStatus = ERROR_SUCCESS;
  175. }
  176. if(pCertIssuer != NULL)
  177. {
  178. CertFreeCertificateContext(pCertIssuer);
  179. }
  180. if(pCurrentSubject != NULL)
  181. {
  182. CertFreeCertificateContext(pCurrentSubject);
  183. }
  184. SetLastError(dwStatus);
  185. return dwStatus;
  186. }
  187. //////////////////////////////////////////////////////////////////
  188. DWORD
  189. VerifyLicenseServerCertificate(
  190. IN HCRYPTPROV hCryptProv,
  191. IN PCCERT_CONTEXT pCertContext,
  192. IN DWORD dwCertType
  193. )
  194. /*++
  195. --*/
  196. {
  197. BOOL bFound=FALSE;
  198. PCERT_INFO pCertInfo = pCertContext->pCertInfo;
  199. PCERT_EXTENSION pCertExtension=pCertInfo->rgExtension;
  200. PCERT_PUBLIC_KEY_INFO pbPublicKey=NULL;
  201. DWORD dwStatus = ERROR_SUCCESS;
  202. DWORD dwSize = 0;
  203. //
  204. // Must have a CH root extension.
  205. //
  206. for(DWORD i=0;
  207. i < pCertInfo->cExtension && bFound == FALSE;
  208. i++, pCertExtension++)
  209. {
  210. bFound=(strcmp(pCertExtension->pszObjId, szOID_PKIX_HYDRA_CERT_ROOT) == 0);
  211. }
  212. if(bFound == TRUE)
  213. {
  214. //
  215. // Public Key must be the same
  216. //
  217. dwStatus = TLSExportPublicKey(
  218. hCryptProv,
  219. dwCertType,
  220. &dwSize,
  221. &pbPublicKey
  222. );
  223. if(dwStatus == ERROR_SUCCESS)
  224. {
  225. bFound = CertComparePublicKeyInfo(
  226. X509_ASN_ENCODING,
  227. pbPublicKey,
  228. &(pCertContext->pCertInfo->SubjectPublicKeyInfo)
  229. );
  230. if(bFound == FALSE)
  231. {
  232. dwStatus = TLS_E_MISMATCHPUBLICKEY;
  233. }
  234. }
  235. }
  236. else
  237. {
  238. dwStatus = TLS_E_INVALIDLSCERT;
  239. }
  240. FreeMemory(pbPublicKey);
  241. return dwStatus;
  242. }
  243. //////////////////////////////////////////////////////////////////////
  244. DWORD
  245. TLSVerifyServerCertAndChain(
  246. IN HCRYPTPROV hCryptProv,
  247. IN HCERTSTORE hCertStore,
  248. IN DWORD dwCertType,
  249. IN PBYTE pbCert,
  250. IN DWORD cbCert,
  251. IN OUT FILETIME* pExpiredTime
  252. )
  253. /*++
  254. --*/
  255. {
  256. DWORD dwStatus = ERROR_SUCCESS;
  257. PCCERT_CONTEXT pCertContext = NULL;
  258. //
  259. // Verify License Server's own certificate
  260. //
  261. pCertContext = CertCreateCertificateContext(
  262. X509_ASN_ENCODING,
  263. pbCert,
  264. cbCert
  265. );
  266. if(pCertContext == NULL)
  267. {
  268. dwStatus = GetLastError();
  269. goto cleanup;
  270. }
  271. //
  272. // Verify License Server's certificate first
  273. //
  274. dwStatus = VerifyLicenseServerCertificate(
  275. hCryptProv,
  276. pCertContext,
  277. dwCertType
  278. );
  279. if(dwStatus != ERROR_SUCCESS)
  280. {
  281. goto cleanup;
  282. }
  283. //
  284. // Verify Certificate Chain
  285. //
  286. dwStatus = TLSVerifyCertChain(
  287. hCryptProv,
  288. hCertStore,
  289. pCertContext,
  290. pExpiredTime
  291. );
  292. if(dwStatus != ERROR_SUCCESS)
  293. {
  294. goto cleanup;
  295. }
  296. cleanup:
  297. if(pCertContext != NULL)
  298. {
  299. CertFreeCertificateContext(pCertContext);
  300. }
  301. return dwStatus;
  302. }
  303. //////////////////////////////////////////////////////////////////
  304. DWORD
  305. TLSValidateServerCertficates(
  306. IN HCRYPTPROV hCryptProv,
  307. IN HCERTSTORE hCertStore,
  308. IN PBYTE pbSignCert,
  309. IN DWORD cbSignCert,
  310. IN PBYTE pbExchCert,
  311. IN DWORD cbExchCert,
  312. OUT FILETIME* pftExpireTime
  313. )
  314. /*++
  315. --*/
  316. {
  317. #if ENFORCE_LICENSING
  318. DWORD dwStatus;
  319. pftExpireTime->dwLowDateTime = 0xFFFFFFFF;
  320. pftExpireTime->dwHighDateTime = 0xFFFFFFFF;
  321. dwStatus = TLSVerifyServerCertAndChain(
  322. hCryptProv,
  323. hCertStore,
  324. AT_SIGNATURE,
  325. pbSignCert,
  326. cbSignCert,
  327. pftExpireTime
  328. );
  329. if(TLS_ERROR(dwStatus) == TRUE)
  330. {
  331. goto cleanup;
  332. }
  333. dwStatus = TLSVerifyServerCertAndChain(
  334. hCryptProv,
  335. hCertStore,
  336. AT_KEYEXCHANGE,
  337. pbExchCert,
  338. cbExchCert,
  339. pftExpireTime
  340. );
  341. cleanup:
  342. return dwStatus;
  343. #else
  344. return ERROR_SUCCESS;
  345. #endif
  346. }
  347. //////////////////////////////////////////////////////////////////
  348. DWORD
  349. TLSDestroyCryptContext(
  350. HCRYPTPROV hCryptProv
  351. )
  352. /*++
  353. --*/
  354. {
  355. DWORD dwStatus;
  356. BOOL bSuccess;
  357. PBYTE pbData = NULL;
  358. DWORD cbData = 0;
  359. if(hCryptProv == NULL)
  360. {
  361. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  362. goto cleanup;
  363. }
  364. //
  365. // Get the container name.
  366. //
  367. bSuccess = CryptGetProvParam(
  368. hCryptProv,
  369. PP_CONTAINER,
  370. NULL,
  371. &cbData,
  372. 0
  373. );
  374. if(bSuccess != FALSE)
  375. {
  376. dwStatus = GetLastError();
  377. goto cleanup;
  378. }
  379. pbData = (PBYTE)AllocateMemory(cbData + sizeof(TCHAR));
  380. if(pbData == NULL)
  381. {
  382. dwStatus = GetLastError();
  383. goto cleanup;
  384. }
  385. bSuccess = CryptGetProvParam(
  386. hCryptProv,
  387. PP_CONTAINER,
  388. pbData,
  389. &cbData,
  390. 0
  391. );
  392. if(bSuccess == FALSE)
  393. {
  394. dwStatus = GetLastError();
  395. goto cleanup;
  396. }
  397. //
  398. // Release the context
  399. //
  400. bSuccess = CryptReleaseContext(
  401. hCryptProv,
  402. 0
  403. );
  404. if(bSuccess == FALSE)
  405. {
  406. dwStatus = GetLastError();
  407. goto cleanup;
  408. }
  409. //
  410. // Delete key set
  411. //
  412. bSuccess = CryptAcquireContext(
  413. &hCryptProv,
  414. (LPCTSTR)pbData,
  415. DEFAULT_CSP,
  416. PROVIDER_TYPE,
  417. CRYPT_DELETEKEYSET
  418. );
  419. if(bSuccess == FALSE)
  420. {
  421. dwStatus = GetLastError();
  422. }
  423. cleanup:
  424. FreeMemory(pbData);
  425. return dwStatus;
  426. }
  427. //////////////////////////////////////////////////////////////////
  428. DWORD
  429. InitCryptoProv(
  430. LPCTSTR pszKeyContainer,
  431. HCRYPTPROV* phCryptProv
  432. )
  433. /*++
  434. --*/
  435. {
  436. DWORD dwStatus = ERROR_SUCCESS;
  437. TCHAR szKeyContainer[MAX_KEY_CONTAINER_LENGTH+1];
  438. LPCTSTR pszContainer;
  439. if(pszKeyContainer == NULL)
  440. {
  441. //
  442. // Randomly create a key container
  443. //
  444. memset(szKeyContainer, 0, sizeof(szKeyContainer));
  445. _sntprintf(
  446. szKeyContainer,
  447. MAX_KEY_CONTAINER_LENGTH,
  448. _TEXT("TlsContainer%d"),
  449. GetCurrentThreadId()
  450. );
  451. pszContainer = szKeyContainer;
  452. }
  453. else
  454. {
  455. pszContainer = pszKeyContainer;
  456. }
  457. //
  458. // Delete the key container, ignore error here
  459. //
  460. CryptAcquireContext(
  461. phCryptProv,
  462. pszContainer,
  463. DEFAULT_CSP,
  464. PROVIDER_TYPE,
  465. CRYPT_DELETEKEYSET
  466. );
  467. //
  468. // Re-create key container
  469. //
  470. if(!CryptAcquireContext(
  471. phCryptProv,
  472. pszContainer,
  473. DEFAULT_CSP,
  474. PROVIDER_TYPE,
  475. 0))
  476. {
  477. // Create default key container.
  478. if(!CryptAcquireContext(
  479. phCryptProv,
  480. pszContainer,
  481. DEFAULT_CSP,
  482. PROVIDER_TYPE,
  483. CRYPT_NEWKEYSET))
  484. {
  485. dwStatus = GetLastError();
  486. }
  487. }
  488. return dwStatus;
  489. }
  490. //////////////////////////////////////////////////////////////////
  491. DWORD
  492. TLSLoadSavedCryptKeyFromLsa(
  493. OUT PBYTE* ppbSignKey,
  494. OUT PDWORD pcbSignKey,
  495. OUT PBYTE* ppbExchKey,
  496. OUT PDWORD pcbExchKey
  497. )
  498. /*++
  499. ++*/
  500. {
  501. DWORD dwStatus;
  502. PBYTE pbSKey = NULL;
  503. DWORD cbSKey = 0;
  504. PBYTE pbEKey = NULL;
  505. DWORD cbEKey = 0;
  506. dwStatus = RetrieveKey(
  507. LSERVER_LSA_PRIVATEKEY_EXCHANGE,
  508. &pbEKey,
  509. &cbEKey
  510. );
  511. if(dwStatus == ERROR_SUCCESS)
  512. {
  513. dwStatus = RetrieveKey(
  514. LSERVER_LSA_PRIVATEKEY_SIGNATURE,
  515. &pbSKey,
  516. &cbSKey
  517. );
  518. }
  519. if(dwStatus != ERROR_SUCCESS)
  520. {
  521. if(pbEKey != NULL)
  522. {
  523. LocalFree(pbEKey);
  524. }
  525. if(pbSKey != NULL)
  526. {
  527. LocalFree(pbSKey);
  528. }
  529. }
  530. else
  531. {
  532. *ppbSignKey = pbSKey;
  533. *pcbSignKey = cbEKey;
  534. *ppbExchKey = pbEKey;
  535. *pcbExchKey = cbEKey;
  536. }
  537. return dwStatus;
  538. }
  539. //////////////////////////////////////////////////////////////////
  540. DWORD
  541. TLSSaveCryptKeyToLsa(
  542. IN PBYTE pbSignKey,
  543. IN DWORD cbSignKey,
  544. IN PBYTE pbExchKey,
  545. IN DWORD cbExchKey
  546. )
  547. /*++
  548. --*/
  549. {
  550. DWORD dwStatus;
  551. //
  552. // Save the key to LSA.
  553. //
  554. dwStatus = StoreKey(
  555. LSERVER_LSA_PRIVATEKEY_SIGNATURE,
  556. pbSignKey,
  557. cbSignKey
  558. );
  559. if(dwStatus == ERROR_SUCCESS)
  560. {
  561. dwStatus = StoreKey(
  562. LSERVER_LSA_PRIVATEKEY_EXCHANGE,
  563. pbExchKey,
  564. cbExchKey
  565. );
  566. }
  567. return dwStatus;
  568. }
  569. /////////////////////////////////////////////////////////////////////////////
  570. DWORD
  571. TLSCryptGenerateNewKeys(
  572. OUT PBYTE* pbSignKey,
  573. OUT DWORD* cbSignKey,
  574. OUT PBYTE* pbExchKey,
  575. OUT DWORD* cbExchKey
  576. )
  577. /*++
  578. Abstract:
  579. Generate a new pair of public/private key. First randomly create
  580. a key container and use it to create new keys.
  581. Parameters:
  582. *pbSignKey : Pointer to PBYTE to receive new signature key.
  583. *cbSignKey : Pointer to DWORD to receive size of new sign. key.
  584. *pbExchKey : Pointer to PBYTE to receive new exchange key.
  585. *cbExchKey : Pointer to DWORD to receive size of new exchange key.
  586. Return:
  587. ERROR_SUCCESS or CRYPTO Error Code.
  588. --*/
  589. {
  590. TCHAR szKeyContainer[MAX_KEY_CONTAINER_LENGTH+1];
  591. HCRYPTPROV hCryptProv = NULL;
  592. HCRYPTKEY hSignKey = NULL;
  593. HCRYPTKEY hExchKey = NULL;
  594. DWORD dwStatus;
  595. *pbSignKey = NULL;
  596. *pbExchKey = NULL;
  597. //
  598. // Randomly create a key container
  599. //
  600. memset(szKeyContainer, 0, sizeof(szKeyContainer));
  601. _sntprintf(
  602. szKeyContainer,
  603. MAX_KEY_CONTAINER_LENGTH,
  604. _TEXT("TlsContainer%d"),
  605. GetCurrentThreadId()
  606. );
  607. //
  608. // Delete this key container, ignore error.
  609. //
  610. CryptAcquireContext(
  611. &hCryptProv,
  612. szKeyContainer,
  613. DEFAULT_CSP,
  614. PROVIDER_TYPE,
  615. CRYPT_DELETEKEYSET
  616. );
  617. //
  618. // Open a default key container
  619. //
  620. if(!CryptAcquireContext(
  621. &hCryptProv,
  622. szKeyContainer,
  623. DEFAULT_CSP,
  624. PROVIDER_TYPE,
  625. CRYPT_NEWKEYSET
  626. ))
  627. {
  628. TLSLogEvent(
  629. EVENTLOG_ERROR_TYPE,
  630. TLS_E_GENERATEKEYS,
  631. TLS_E_CRYPT_ACQUIRE_CONTEXT,
  632. dwStatus = GetLastError()
  633. );
  634. goto cleanup;
  635. }
  636. //
  637. // Generate a signature public/private key pair
  638. //
  639. if(!CryptGetUserKey(hCryptProv, AT_SIGNATURE, &hSignKey))
  640. {
  641. dwStatus=GetLastError();
  642. if( GetLastError() != NTE_NO_KEY ||
  643. !CryptGenKey(hCryptProv, AT_SIGNATURE, CRYPT_EXPORTABLE, &hSignKey))
  644. {
  645. TLSLogEvent(
  646. EVENTLOG_ERROR_TYPE,
  647. TLS_E_GENERATEKEYS,
  648. TLS_E_CRYPT_CREATE_KEY,
  649. dwStatus=GetLastError()
  650. );
  651. goto cleanup;
  652. }
  653. }
  654. dwStatus = ERROR_SUCCESS;
  655. //
  656. // export the public/private key of signature key
  657. //
  658. if( !CryptExportKey(hSignKey, NULL, PRIVATEKEYBLOB, 0, *pbSignKey, cbSignKey) &&
  659. GetLastError() != ERROR_MORE_DATA)
  660. {
  661. TLSLogEvent(
  662. EVENTLOG_ERROR_TYPE,
  663. TLS_E_GENERATEKEYS,
  664. TLS_E_EXPORT_KEY,
  665. dwStatus=GetLastError()
  666. );
  667. goto cleanup;
  668. }
  669. *pbSignKey=(PBYTE)AllocateMemory(*cbSignKey);
  670. if(*pbSignKey == NULL)
  671. {
  672. TLSLogErrorEvent(TLS_E_ALLOCATE_MEMORY);
  673. dwStatus=GetLastError();
  674. goto cleanup;
  675. }
  676. if(!CryptExportKey(hSignKey, NULL, PRIVATEKEYBLOB, 0, *pbSignKey, cbSignKey))
  677. {
  678. TLSLogEvent(
  679. EVENTLOG_ERROR_TYPE,
  680. TLS_E_GENERATEKEYS,
  681. TLS_E_EXPORT_KEY,
  682. dwStatus=GetLastError()
  683. );
  684. goto cleanup;
  685. }
  686. //
  687. // Generate a exchange public/private key pair
  688. if(!CryptGetUserKey(hCryptProv, AT_KEYEXCHANGE, &hExchKey))
  689. {
  690. dwStatus=GetLastError();
  691. if( GetLastError() != NTE_NO_KEY ||
  692. !CryptGenKey(hCryptProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hExchKey))
  693. {
  694. TLSLogEvent(
  695. EVENTLOG_ERROR_TYPE,
  696. TLS_E_GENERATEKEYS,
  697. TLS_E_CRYPT_CREATE_KEY,
  698. dwStatus=GetLastError()
  699. );
  700. goto cleanup;
  701. }
  702. }
  703. dwStatus = ERROR_SUCCESS;
  704. //
  705. // export the public/private key of exchange key
  706. //
  707. if( !CryptExportKey(hExchKey, NULL, PRIVATEKEYBLOB, 0, *pbExchKey, cbExchKey) &&
  708. GetLastError() != ERROR_MORE_DATA)
  709. {
  710. TLSLogEvent(
  711. EVENTLOG_ERROR_TYPE,
  712. TLS_E_GENERATEKEYS,
  713. TLS_E_EXPORT_KEY,
  714. dwStatus=GetLastError()
  715. );
  716. goto cleanup;
  717. }
  718. *pbExchKey=(PBYTE)AllocateMemory(*cbExchKey);
  719. if(*pbExchKey == NULL)
  720. {
  721. TLSLogErrorEvent(TLS_E_ALLOCATE_MEMORY);
  722. dwStatus = GetLastError();
  723. goto cleanup;
  724. }
  725. if(!CryptExportKey(hExchKey, NULL, PRIVATEKEYBLOB, 0, *pbExchKey, cbExchKey))
  726. {
  727. TLSLogEvent(
  728. EVENTLOG_ERROR_TYPE,
  729. TLS_E_GENERATEKEYS,
  730. TLS_E_EXPORT_KEY,
  731. dwStatus=GetLastError()
  732. );
  733. goto cleanup;
  734. }
  735. cleanup:
  736. if(hSignKey != NULL)
  737. {
  738. CryptDestroyKey(hSignKey);
  739. }
  740. if(hExchKey != NULL)
  741. {
  742. CryptDestroyKey(hExchKey);
  743. }
  744. if(hCryptProv)
  745. {
  746. CryptReleaseContext(hCryptProv, 0);
  747. }
  748. hCryptProv=NULL;
  749. //
  750. // Delete key container and ignore error
  751. //
  752. CryptAcquireContext(
  753. &hCryptProv,
  754. szKeyContainer,
  755. DEFAULT_CSP,
  756. PROVIDER_TYPE,
  757. CRYPT_DELETEKEYSET
  758. );
  759. if(dwStatus != ERROR_SUCCESS)
  760. {
  761. FreeMemory(*pbSignKey);
  762. FreeMemory(*pbExchKey);
  763. }
  764. return dwStatus;
  765. }
  766. /////////////////////////////////////////////////////////////////////////////
  767. DWORD
  768. TLSImportSavedKey(
  769. IN HCRYPTPROV hCryptProv,
  770. IN PBYTE pbSignKey,
  771. IN DWORD cbSignKey,
  772. IN PBYTE pbExchKey,
  773. IN DWORD cbExchKey,
  774. OUT HCRYPTKEY* pSignKey,
  775. OUT HCRYPTKEY* pExchKey
  776. )
  777. /*
  778. */
  779. {
  780. DWORD status=ERROR_SUCCESS;
  781. if(!CryptImportKey(
  782. hCryptProv,
  783. pbSignKey,
  784. cbSignKey,
  785. NULL,
  786. 0,
  787. pSignKey
  788. ))
  789. {
  790. status = GetLastError();
  791. goto cleanup;
  792. }
  793. if(!CryptImportKey(
  794. hCryptProv,
  795. pbExchKey,
  796. cbExchKey,
  797. NULL,
  798. 0,
  799. pExchKey
  800. ))
  801. {
  802. status = GetLastError();
  803. }
  804. cleanup:
  805. if(status != ERROR_SUCCESS)
  806. {
  807. TLSLogEvent(
  808. EVENTLOG_ERROR_TYPE,
  809. TLS_E_SERVICEINIT,
  810. TLS_E_CRYPT_IMPORT_KEY,
  811. status
  812. );
  813. }
  814. return status;
  815. }
  816. /////////////////////////////////////////////////////////////////////////////
  817. DWORD
  818. TLSLoadSelfSignCertificates(
  819. IN HCRYPTPROV hCryptProv,
  820. IN PBYTE pbSPK,
  821. IN DWORD cbSPK,
  822. OUT PDWORD pcbSignCert,
  823. OUT PBYTE* ppbSignCert,
  824. OUT PDWORD pcbExchCert,
  825. OUT PBYTE* ppbExchCert
  826. )
  827. /*
  828. Abstract:
  829. Create a self-signed signature/exchange certificate.
  830. Parameters:
  831. pcbSignCert : Pointer to DWORD to receive size of sign. certificate.
  832. ppbSignCert : Pointer to PBYTE to receive self-signed sign. certificate.
  833. pcbExchCert : Pointer to DWORD to receive size of exch. certificate.
  834. ppbExchCert : Pointer to PBYTE to receive self-signed exch. certificate.
  835. Returns:
  836. */
  837. {
  838. DWORD status;
  839. DWORD dwDisposition;
  840. DWORD cbSign=0;
  841. PBYTE pbSign=NULL;
  842. DWORD cbExch=0;
  843. PBYTE pbExch=NULL;
  844. do {
  845. //
  846. // Create Signature and Exchange certificate
  847. //
  848. status=TLSCreateSelfSignCertificate(
  849. hCryptProv,
  850. AT_SIGNATURE,
  851. pbSPK,
  852. cbSPK,
  853. 0,
  854. NULL,
  855. &cbSign,
  856. &pbSign
  857. );
  858. if(status != ERROR_SUCCESS)
  859. {
  860. status=TLS_E_CREATE_SELFSIGN_CERT;
  861. break;
  862. }
  863. status=TLSCreateSelfSignCertificate(
  864. hCryptProv,
  865. AT_KEYEXCHANGE,
  866. pbSPK,
  867. cbSPK,
  868. 0,
  869. NULL,
  870. &cbExch,
  871. &pbExch
  872. );
  873. if(status != ERROR_SUCCESS)
  874. {
  875. status=TLS_E_CREATE_SELFSIGN_CERT;
  876. break;
  877. }
  878. } while(FALSE);
  879. if(status == ERROR_SUCCESS)
  880. {
  881. *pcbSignCert = cbSign;
  882. *ppbSignCert = pbSign;
  883. *pcbExchCert = cbExch;
  884. *ppbExchCert = pbExch;
  885. }
  886. else
  887. {
  888. FreeMemory(pbExch);
  889. FreeMemory(pbSign);
  890. }
  891. return status;
  892. }
  893. ////////////////////////////////////////////////////////////////
  894. DWORD
  895. TLSLoadCHEndosedCertificate(
  896. PDWORD pcbSignCert,
  897. PBYTE* ppbSignCert,
  898. PDWORD pcbExchCert,
  899. PBYTE* ppbExchCert
  900. )
  901. /*
  902. */
  903. {
  904. LONG status;
  905. #if ENFORCE_LICENSING
  906. DWORD cbSign=0;
  907. PBYTE pbSign=NULL;
  908. DWORD cbExch=0;
  909. PBYTE pbExch=NULL;
  910. //
  911. // look into registry to see if our certificate is there
  912. //
  913. HKEY hKey=NULL;
  914. LPTSTR lpSubkey=LSERVER_SERVER_CERTIFICATE_REGKEY;
  915. do {
  916. status=RegOpenKeyEx(
  917. HKEY_LOCAL_MACHINE,
  918. lpSubkey,
  919. 0,
  920. KEY_ALL_ACCESS,
  921. &hKey
  922. );
  923. if(status != ERROR_SUCCESS)
  924. {
  925. break;
  926. }
  927. //
  928. // Load Signature certificate
  929. //
  930. status = RegQueryValueEx(
  931. hKey,
  932. LSERVER_SIGNATURE_CERT_KEY,
  933. NULL,
  934. NULL,
  935. NULL,
  936. &cbSign
  937. );
  938. if(status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
  939. {
  940. break;
  941. }
  942. if(!(pbSign=(PBYTE)AllocateMemory(cbSign)))
  943. {
  944. status = GetLastError();
  945. break;
  946. }
  947. status = RegQueryValueEx(
  948. hKey,
  949. LSERVER_SIGNATURE_CERT_KEY,
  950. NULL,
  951. NULL,
  952. pbSign,
  953. &cbSign
  954. );
  955. if(status != ERROR_SUCCESS)
  956. {
  957. break;
  958. }
  959. //
  960. // Load Exchange certificate
  961. //
  962. status = RegQueryValueEx(
  963. hKey,
  964. LSERVER_EXCHANGE_CERT_KEY,
  965. NULL,
  966. NULL,
  967. NULL,
  968. &cbExch
  969. );
  970. if(status != ERROR_MORE_DATA && status != ERROR_SUCCESS)
  971. {
  972. break;
  973. }
  974. if(!(pbExch=(PBYTE)AllocateMemory(cbExch)))
  975. {
  976. status = GetLastError();
  977. break;
  978. }
  979. status = RegQueryValueEx(
  980. hKey,
  981. LSERVER_EXCHANGE_CERT_KEY,
  982. NULL,
  983. NULL,
  984. pbExch,
  985. &cbExch
  986. );
  987. if(status != ERROR_SUCCESS)
  988. {
  989. break;
  990. }
  991. } while(FALSE);
  992. //
  993. // Must have both certificate
  994. //
  995. if(status == ERROR_SUCCESS && pbExch && pbSign)
  996. {
  997. *pcbSignCert = cbSign;
  998. *ppbSignCert = pbSign;
  999. *pcbExchCert = cbExch;
  1000. *ppbExchCert = pbExch;
  1001. }
  1002. else
  1003. {
  1004. FreeMemory(pbExch);
  1005. FreeMemory(pbSign);
  1006. status = TLS_E_NO_CERTIFICATE;
  1007. }
  1008. if(hKey)
  1009. {
  1010. RegCloseKey(hKey);
  1011. }
  1012. #else
  1013. //
  1014. // Non enfoce version always return no certificate
  1015. //
  1016. status = TLS_E_NO_CERTIFICATE;
  1017. #endif
  1018. return status;
  1019. }
  1020. /////////////////////////////////////////////////////////////////////////////
  1021. DWORD
  1022. TLSInstallLsCertificate(
  1023. DWORD cbLsSignCert,
  1024. PBYTE pbLsSignCert,
  1025. DWORD cbLsExchCert,
  1026. PBYTE pbLsExchCert
  1027. )
  1028. /*
  1029. */
  1030. {
  1031. HKEY hKey=NULL;
  1032. LONG status=ERROR_SUCCESS;
  1033. DWORD dwDisposition;
  1034. PCCERT_CONTEXT pCertContext=NULL;
  1035. DWORD cbNameBlob=0;
  1036. LPTSTR pbNameBlob=NULL;
  1037. #if ENFORCE_LICENSING
  1038. do {
  1039. status = RegCreateKeyEx(
  1040. HKEY_LOCAL_MACHINE,
  1041. LSERVER_SERVER_CERTIFICATE_REGKEY,
  1042. 0,
  1043. NULL,
  1044. REG_OPTION_NON_VOLATILE,
  1045. KEY_ALL_ACCESS,
  1046. NULL,
  1047. &hKey,
  1048. &dwDisposition
  1049. );
  1050. if(status != ERROR_SUCCESS)
  1051. {
  1052. TLSLogEvent(
  1053. EVENTLOG_ERROR_TYPE,
  1054. TLS_E_STORELSCERTIFICATE,
  1055. TLS_E_ACCESS_REGISTRY,
  1056. status
  1057. );
  1058. break;
  1059. }
  1060. if(pbLsExchCert)
  1061. {
  1062. status = RegSetValueEx(
  1063. hKey,
  1064. LSERVER_EXCHANGE_CERT_KEY,
  1065. 0,
  1066. REG_BINARY,
  1067. pbLsExchCert,
  1068. cbLsExchCert
  1069. );
  1070. if(status != ERROR_SUCCESS)
  1071. {
  1072. TLSLogEvent(
  1073. EVENTLOG_ERROR_TYPE,
  1074. TLS_E_STORELSCERTIFICATE,
  1075. TLS_E_ACCESS_REGISTRY,
  1076. status
  1077. );
  1078. break;
  1079. }
  1080. }
  1081. if(pbLsSignCert)
  1082. {
  1083. status = RegSetValueEx(
  1084. hKey,
  1085. LSERVER_SIGNATURE_CERT_KEY,
  1086. 0,
  1087. REG_BINARY,
  1088. pbLsSignCert,
  1089. cbLsSignCert
  1090. );
  1091. if(status != ERROR_SUCCESS)
  1092. {
  1093. TLSLogEvent(
  1094. EVENTLOG_ERROR_TYPE,
  1095. TLS_E_STORELSCERTIFICATE,
  1096. TLS_E_ACCESS_REGISTRY,
  1097. status
  1098. );
  1099. break;
  1100. }
  1101. //
  1102. // extract Subject field in exchange certificate and save i registry
  1103. // When issuing new license, we need to use this as Issuer.
  1104. //
  1105. pCertContext = CertCreateCertificateContext(
  1106. X509_ASN_ENCODING,
  1107. pbLsSignCert,
  1108. cbLsSignCert
  1109. );
  1110. cbNameBlob=CertNameToStr(
  1111. X509_ASN_ENCODING,
  1112. &pCertContext->pCertInfo->Subject,
  1113. CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
  1114. NULL,
  1115. 0
  1116. );
  1117. if(cbNameBlob)
  1118. {
  1119. pbNameBlob=(LPTSTR)AllocateMemory((cbNameBlob+1) * sizeof(TCHAR));
  1120. if(pbNameBlob)
  1121. {
  1122. CertNameToStr(
  1123. X509_ASN_ENCODING,
  1124. &pCertContext->pCertInfo->Subject,
  1125. CERT_X500_NAME_STR | CERT_NAME_STR_CRLF_FLAG,
  1126. pbNameBlob,
  1127. cbNameBlob
  1128. );
  1129. }
  1130. }
  1131. status = RegSetValueEx(
  1132. hKey,
  1133. LSERVER_CLIENT_CERTIFICATE_ISSUER,
  1134. 0,
  1135. REG_BINARY,
  1136. (PBYTE)pbNameBlob,
  1137. cbNameBlob+sizeof(TCHAR)
  1138. );
  1139. if(status != ERROR_SUCCESS)
  1140. {
  1141. TLSLogEvent(
  1142. EVENTLOG_ERROR_TYPE,
  1143. TLS_E_STORELSCERTIFICATE,
  1144. TLS_E_ACCESS_REGISTRY,
  1145. status
  1146. );
  1147. break;
  1148. }
  1149. }
  1150. if(hKey)
  1151. {
  1152. //
  1153. // Close registry, got error while try to load it again???
  1154. //
  1155. RegCloseKey(hKey);
  1156. hKey = NULL;
  1157. }
  1158. //
  1159. // Only reload certificate when we have both
  1160. //
  1161. if(pbLsSignCert && pbLsExchCert)
  1162. {
  1163. //
  1164. // All RPC calls are blocked.
  1165. //
  1166. FreeMemory(g_pbSignatureEncodedCert);
  1167. FreeMemory(g_pbExchangeEncodedCert);
  1168. g_cbSignatureEncodedCert = 0;
  1169. g_cbExchangeEncodedCert = 0;
  1170. //TLSLoadServerCertificate();
  1171. }
  1172. } while(FALSE);
  1173. FreeMemory(pbNameBlob);
  1174. if(pCertContext)
  1175. {
  1176. CertFreeCertificateContext(pCertContext);
  1177. }
  1178. if(hKey)
  1179. {
  1180. RegCloseKey(hKey);
  1181. }
  1182. #endif
  1183. return status;
  1184. }
  1185. ////////////////////////////////////////////////////////////////
  1186. DWORD
  1187. TLSUninstallLsCertificate()
  1188. {
  1189. HKEY hKey=NULL;
  1190. DWORD status;
  1191. status=RegOpenKeyEx(
  1192. HKEY_LOCAL_MACHINE,
  1193. LSERVER_SERVER_CERTIFICATE_REGKEY,
  1194. 0,
  1195. KEY_ALL_ACCESS,
  1196. &hKey
  1197. );
  1198. if(status == ERROR_SUCCESS)
  1199. {
  1200. //
  1201. // Ignore error
  1202. RegDeleteValue(
  1203. hKey,
  1204. LSERVER_SIGNATURE_CERT_KEY
  1205. );
  1206. RegDeleteValue(
  1207. hKey,
  1208. LSERVER_EXCHANGE_CERT_KEY
  1209. );
  1210. RegDeleteValue(
  1211. hKey,
  1212. LSERVER_CLIENT_CERTIFICATE_ISSUER
  1213. );
  1214. }
  1215. if(hKey != NULL)
  1216. {
  1217. RegCloseKey(hKey);
  1218. }
  1219. //
  1220. // Delete all certificate in registry store including all backup
  1221. // ignore error on deleting backup store.
  1222. //
  1223. TLSRegDeleteKey(
  1224. HKEY_LOCAL_MACHINE,
  1225. LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP1
  1226. );
  1227. TLSRegDeleteKey(
  1228. HKEY_LOCAL_MACHINE,
  1229. LSERVER_SERVER_CERTIFICATE_REGKEY_BACKUP2
  1230. );
  1231. status = TLSRegDeleteKey(
  1232. HKEY_LOCAL_MACHINE,
  1233. LSERVER_SERVER_CERTIFICATE_REGKEY
  1234. );
  1235. return status;
  1236. }
  1237. /////////////////////////////////////////////////////////////////////////////
  1238. DWORD
  1239. TLSInitCryptoProv(
  1240. IN LPCTSTR pszKeyContainer,
  1241. IN PBYTE pbSignKey,
  1242. IN DWORD cbSignKey,
  1243. IN PBYTE pbExchKey,
  1244. IN DWORD cbExchKey,
  1245. OUT HCRYPTPROV* phCryptProv,
  1246. OUT HCRYPTKEY* phSignKey,
  1247. OUT HCRYPTKEY* phExchKey
  1248. )
  1249. /*
  1250. Abstract:
  1251. Routine to create a clean Crypto. Prov, generate a new pair of keys and
  1252. import these keys into newly created Crypt. prov.
  1253. Parameters:
  1254. pszKeyContainer : Name of the key container.
  1255. phCryptProv : Pointer to HCRYPTPROV to receive new handle to Crypto. prov.
  1256. */
  1257. {
  1258. DWORD dwStatus;
  1259. if( pbSignKey == NULL || cbSignKey == NULL ||
  1260. pbExchKey == NULL || cbExchKey == NULL ||
  1261. phCryptProv == NULL || phSignKey == NULL ||
  1262. phExchKey == NULL )
  1263. {
  1264. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1265. }
  1266. else
  1267. {
  1268. //
  1269. // Initialize a clean Crypt.
  1270. //
  1271. dwStatus = InitCryptoProv(
  1272. pszKeyContainer,
  1273. phCryptProv
  1274. );
  1275. if(dwStatus == ERROR_SUCCESS)
  1276. {
  1277. //
  1278. // Import Key into Crypt.
  1279. //
  1280. dwStatus = TLSImportSavedKey(
  1281. *phCryptProv,
  1282. pbSignKey,
  1283. cbSignKey,
  1284. pbExchKey,
  1285. cbExchKey,
  1286. phSignKey,
  1287. phExchKey
  1288. );
  1289. }
  1290. }
  1291. return dwStatus;
  1292. }
  1293. //-----------------------------------------------------------
  1294. DWORD
  1295. TLSVerifyCertChainInMomory(
  1296. IN HCRYPTPROV hCryptProv,
  1297. IN PBYTE pbData,
  1298. IN DWORD cbData
  1299. )
  1300. /*++
  1301. Abstract:
  1302. Verify PKCS7 certificate chain in memory.
  1303. Parameters:
  1304. pbData : Input PKCS7 ceritifcate chain.
  1305. cbData : size of pbData
  1306. Returns:
  1307. ++*/
  1308. {
  1309. PCCERT_CONTEXT pCertContext=NULL;
  1310. PCCERT_CONTEXT pCertPrevContext=NULL;
  1311. HCERTSTORE hCertStore=NULL;
  1312. DWORD dwStatus=ERROR_SUCCESS;
  1313. DWORD dwLastVerification;
  1314. CRYPT_DATA_BLOB Serialized;
  1315. FILETIME ft;
  1316. if(hCryptProv == NULL || pbData == NULL || cbData == NULL)
  1317. {
  1318. SetLastError(dwStatus = ERROR_INVALID_PARAMETER);
  1319. goto cleanup;
  1320. }
  1321. Serialized.pbData = pbData;
  1322. Serialized.cbData = cbData;
  1323. hCertStore=CertOpenStore(
  1324. szLICENSE_BLOB_SAVEAS_TYPE,
  1325. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1326. hCryptProv,
  1327. CERT_STORE_NO_CRYPT_RELEASE_FLAG,
  1328. &Serialized
  1329. );
  1330. if(!hCertStore)
  1331. {
  1332. dwStatus=GetLastError();
  1333. goto cleanup;
  1334. }
  1335. //
  1336. // Enumerate all certificates.
  1337. //
  1338. dwStatus = ERROR_SUCCESS;
  1339. do {
  1340. pCertPrevContext = pCertContext;
  1341. pCertContext = CertEnumCertificatesInStore(
  1342. hCertStore,
  1343. pCertPrevContext
  1344. );
  1345. if(pCertContext == NULL)
  1346. {
  1347. dwStatus = GetLastError();
  1348. if(dwStatus = CRYPT_E_NOT_FOUND)
  1349. {
  1350. dwStatus = ERROR_SUCCESS;
  1351. break;
  1352. }
  1353. }
  1354. dwStatus = TLSVerifyCertChain(
  1355. hCryptProv,
  1356. hCertStore,
  1357. pCertContext,
  1358. &ft
  1359. );
  1360. } while (pCertContext != NULL && dwStatus == ERROR_SUCCESS);
  1361. cleanup:
  1362. if(pCertContext != NULL)
  1363. {
  1364. CertFreeCertificateContext(pCertContext);
  1365. }
  1366. if(hCertStore)
  1367. {
  1368. CertCloseStore(
  1369. hCertStore,
  1370. CERT_CLOSE_STORE_FORCE_FLAG
  1371. );
  1372. }
  1373. return dwStatus;
  1374. }
  1375. /////////////////////////////////////////////////////////////////////////////
  1376. DWORD
  1377. TLSRegDeleteKey(
  1378. IN HKEY hRegKey,
  1379. IN LPCTSTR pszSubKey
  1380. )
  1381. /*++
  1382. Abstract:
  1383. Recursively delete entire registry key.
  1384. Parameter:
  1385. HKEY :
  1386. pszSubKey :
  1387. Returns:
  1388. ERROR_SUCCESS or error code.
  1389. ++*/
  1390. {
  1391. DWORD dwStatus;
  1392. HKEY hSubKey = NULL;
  1393. int index;
  1394. DWORD dwNumSubKeys;
  1395. DWORD dwMaxSubKeyLength;
  1396. DWORD dwSubKeyLength;
  1397. LPTSTR pszSubKeyName = NULL;
  1398. DWORD dwMaxValueNameLen;
  1399. LPTSTR pszValueName = NULL;
  1400. DWORD dwValueNameLength;
  1401. dwStatus = RegOpenKeyEx(
  1402. hRegKey,
  1403. pszSubKey,
  1404. 0,
  1405. KEY_ALL_ACCESS,
  1406. &hSubKey
  1407. );
  1408. if(dwStatus != ERROR_SUCCESS)
  1409. {
  1410. // key does not exist
  1411. return dwStatus;
  1412. }
  1413. //
  1414. // Query number of subkeys
  1415. //
  1416. dwStatus = RegQueryInfoKey(
  1417. hSubKey,
  1418. NULL,
  1419. NULL,
  1420. NULL,
  1421. &dwNumSubKeys,
  1422. &dwMaxSubKeyLength,
  1423. NULL,
  1424. NULL,
  1425. &dwMaxValueNameLen,
  1426. NULL,
  1427. NULL,
  1428. NULL
  1429. );
  1430. if(dwStatus != ERROR_SUCCESS)
  1431. {
  1432. goto cleanup;
  1433. }
  1434. dwMaxValueNameLen++;
  1435. pszValueName = (LPTSTR)AllocateMemory(dwMaxValueNameLen * sizeof(TCHAR));
  1436. if(pszValueName == NULL)
  1437. {
  1438. goto cleanup;
  1439. }
  1440. if(dwNumSubKeys > 0)
  1441. {
  1442. // allocate buffer for subkeys.
  1443. dwMaxSubKeyLength++;
  1444. pszSubKeyName = (LPTSTR)AllocateMemory(dwMaxSubKeyLength * sizeof(TCHAR));
  1445. if(pszSubKeyName == NULL)
  1446. {
  1447. goto cleanup;
  1448. }
  1449. //for(index = 0; index < dwNumSubKeys; index++)
  1450. for(;dwStatus == ERROR_SUCCESS;)
  1451. {
  1452. // delete this subkey.
  1453. dwSubKeyLength = dwMaxSubKeyLength;
  1454. memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
  1455. // retrieve subkey name
  1456. dwStatus = RegEnumKeyEx(
  1457. hSubKey,
  1458. (DWORD)0,
  1459. pszSubKeyName,
  1460. &dwSubKeyLength,
  1461. NULL,
  1462. NULL,
  1463. NULL,
  1464. NULL
  1465. );
  1466. if(dwStatus == ERROR_SUCCESS)
  1467. {
  1468. dwStatus = TLSRegDeleteKey( hSubKey, pszSubKeyName );
  1469. }
  1470. // ignore any error and continue on
  1471. }
  1472. }
  1473. cleanup:
  1474. for(dwStatus = ERROR_SUCCESS; pszValueName != NULL && dwStatus == ERROR_SUCCESS;)
  1475. {
  1476. dwValueNameLength = dwMaxValueNameLen;
  1477. memset(pszValueName, 0, dwMaxValueNameLen * sizeof(TCHAR));
  1478. dwStatus = RegEnumValue(
  1479. hSubKey,
  1480. 0,
  1481. pszValueName,
  1482. &dwValueNameLength,
  1483. NULL,
  1484. NULL,
  1485. NULL,
  1486. NULL
  1487. );
  1488. if(dwStatus == ERROR_SUCCESS)
  1489. {
  1490. RegDeleteValue(hSubKey, pszValueName);
  1491. }
  1492. }
  1493. // close the key before trying to delete it.
  1494. if(hSubKey != NULL)
  1495. {
  1496. RegCloseKey(hSubKey);
  1497. }
  1498. // try to delete this key, will fail if any of the subkey
  1499. // failed to delete in loop
  1500. dwStatus = RegDeleteKey(
  1501. hRegKey,
  1502. pszSubKey
  1503. );
  1504. if(pszValueName != NULL)
  1505. {
  1506. FreeMemory(pszValueName);
  1507. }
  1508. if(pszSubKeyName != NULL)
  1509. {
  1510. FreeMemory(pszSubKeyName);
  1511. }
  1512. return dwStatus;
  1513. }
  1514. /////////////////////////////////////////////////////////////////////////////
  1515. DWORD
  1516. TLSTreeCopyRegKey(
  1517. IN HKEY hSourceRegKey,
  1518. IN LPCTSTR pszSourceSubKey,
  1519. IN HKEY hDestRegKey,
  1520. IN LPCTSTR pszDestSubKey
  1521. )
  1522. /*++
  1523. Abstract:
  1524. Tree copy of a registry key to another.
  1525. Parameters:
  1526. hSourceRegKey : Source registry key.
  1527. pszSourceSubKey : Source subkey name.
  1528. hDestRegKey : Destination key.
  1529. pszDestSubKey : Destination key name
  1530. Returns:
  1531. ERROR_SUCCESS or WIN32 error code.
  1532. Note:
  1533. This routine doesn't deal with security...
  1534. ++*/
  1535. {
  1536. DWORD dwStatus;
  1537. HKEY hSourceSubKey = NULL;
  1538. HKEY hDestSubKey = NULL;
  1539. int index;
  1540. DWORD dwNumSubKeys;
  1541. DWORD dwMaxSubKeyLength;
  1542. DWORD dwSubKeyLength;
  1543. LPTSTR pszSubKeyName = NULL;
  1544. DWORD dwMaxValueNameLen;
  1545. LPTSTR pszValueName = NULL;
  1546. DWORD dwValueNameLength;
  1547. DWORD dwNumValues = 0;
  1548. DWORD dwMaxValueLength;
  1549. PBYTE pbValue = NULL;
  1550. DWORD dwDisposition;
  1551. DWORD cbSecurityDescriptor;
  1552. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1553. //
  1554. // Open source registry key, must exist
  1555. //
  1556. dwStatus = RegOpenKeyEx(
  1557. hSourceRegKey,
  1558. pszSourceSubKey,
  1559. 0,
  1560. KEY_ALL_ACCESS,
  1561. &hSourceSubKey
  1562. );
  1563. if(dwStatus != ERROR_SUCCESS)
  1564. {
  1565. // key does not exist
  1566. goto cleanup;
  1567. }
  1568. //
  1569. // Query number of subkeys
  1570. //
  1571. dwStatus = RegQueryInfoKey(
  1572. hSourceSubKey,
  1573. NULL,
  1574. NULL,
  1575. NULL,
  1576. &dwNumSubKeys, // number of subkey
  1577. &dwMaxSubKeyLength, // max. subkey length
  1578. NULL,
  1579. &dwNumValues,
  1580. &dwMaxValueNameLen, // max. value length
  1581. &dwMaxValueLength, // max. value size.
  1582. &cbSecurityDescriptor, // size of security descriptor
  1583. NULL
  1584. );
  1585. if(dwStatus != ERROR_SUCCESS)
  1586. {
  1587. goto cleanup;
  1588. }
  1589. #if 0
  1590. //
  1591. // TODO - get this to work, currently, we don't need security
  1592. //
  1593. if(cbSecurityDescriptor > 0)
  1594. {
  1595. //
  1596. // Retrieve security descriptor for this key.
  1597. //
  1598. pSecurityDescriptor = (PSECURITY_DESCRIPTOR)AllocateMemory(cbSecurityDescriptor * sizeof(BYTE));
  1599. if(pSecurityDescriptor == NULL)
  1600. {
  1601. dwStatus = GetLastError();
  1602. goto cleanup;
  1603. }
  1604. dwStatus = RegGetKeySecurity(
  1605. hSourceSubKey,
  1606. OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  1607. pSecurityDescriptor,
  1608. &cbSecurityDescriptor
  1609. );
  1610. if(dwStatus != ERROR_SUCCESS)
  1611. {
  1612. goto cleanup;
  1613. }
  1614. }
  1615. #endif
  1616. //
  1617. // Create destination key
  1618. //
  1619. dwStatus = RegCreateKeyEx(
  1620. hDestRegKey,
  1621. pszDestSubKey,
  1622. 0,
  1623. NULL,
  1624. REG_OPTION_NON_VOLATILE,
  1625. KEY_ALL_ACCESS,
  1626. NULL,
  1627. &hDestSubKey,
  1628. &dwDisposition
  1629. );
  1630. if(dwStatus != ERROR_SUCCESS)
  1631. {
  1632. goto cleanup;
  1633. }
  1634. #if 0
  1635. //
  1636. // TODO - get this to work, currently, we don't need security.
  1637. //
  1638. if(pSecurityDescriptor != NULL)
  1639. {
  1640. dwStatus = RegSetKeySecurity(
  1641. hDestRegKey,
  1642. OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  1643. pSecurityDescriptor
  1644. );
  1645. if(dwStatus != ERROR_SUCCESS)
  1646. {
  1647. goto cleanup;
  1648. }
  1649. if(pSecurityDescriptor != NULL)
  1650. {
  1651. FreeMemory(pSecurityDescriptor);
  1652. pSecurityDescriptor = NULL;
  1653. }
  1654. }
  1655. #endif
  1656. //
  1657. // Copy all subkeys first, we are doing recursive so copy subkey first will
  1658. // save us some memory.
  1659. //
  1660. if(dwNumSubKeys > 0)
  1661. {
  1662. // allocate buffer for subkeys.
  1663. dwMaxSubKeyLength++;
  1664. pszSubKeyName = (LPTSTR)AllocateMemory(dwMaxSubKeyLength * sizeof(TCHAR));
  1665. if(pszSubKeyName == NULL)
  1666. {
  1667. dwStatus = GetLastError();
  1668. goto cleanup;
  1669. }
  1670. for(index = 0, dwStatus = ERROR_SUCCESS;
  1671. dwStatus == ERROR_SUCCESS;
  1672. index++)
  1673. {
  1674. dwSubKeyLength = dwMaxSubKeyLength;
  1675. memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
  1676. // retrieve subkey name
  1677. dwStatus = RegEnumKeyEx(
  1678. hSourceSubKey,
  1679. (DWORD)index,
  1680. pszSubKeyName,
  1681. &dwSubKeyLength,
  1682. NULL,
  1683. NULL,
  1684. NULL,
  1685. NULL
  1686. );
  1687. if(dwStatus == ERROR_SUCCESS)
  1688. {
  1689. dwStatus = TLSTreeCopyRegKey(
  1690. hSourceSubKey,
  1691. pszSubKeyName,
  1692. hDestSubKey,
  1693. pszSubKeyName
  1694. );
  1695. }
  1696. }
  1697. if(dwStatus == ERROR_NO_MORE_ITEMS)
  1698. {
  1699. dwStatus = ERROR_SUCCESS;
  1700. }
  1701. }
  1702. if(pszSubKeyName != NULL)
  1703. {
  1704. FreeMemory(pszSubKeyName);
  1705. pszSubKeyName = NULL;
  1706. }
  1707. if(dwNumValues > 0)
  1708. {
  1709. //
  1710. // allocate space for value name.
  1711. //
  1712. dwMaxValueNameLen++;
  1713. pszValueName = (LPTSTR)AllocateMemory(dwMaxValueNameLen * sizeof(TCHAR));
  1714. if(pszValueName == NULL)
  1715. {
  1716. dwStatus = GetLastError();
  1717. goto cleanup;
  1718. }
  1719. //
  1720. // allocate buffer for value
  1721. //
  1722. dwMaxValueLength += 2 * sizeof(TCHAR); // in case of string
  1723. pbValue = (PBYTE)AllocateMemory(dwMaxValueLength * sizeof(BYTE));
  1724. if(pbValue == NULL)
  1725. {
  1726. dwStatus = GetLastError();
  1727. goto cleanup;
  1728. }
  1729. //
  1730. // Copy all value first
  1731. //
  1732. for(index=0, dwStatus = ERROR_SUCCESS;
  1733. pszValueName != NULL && dwStatus == ERROR_SUCCESS;
  1734. index ++)
  1735. {
  1736. DWORD dwValueType = 0;
  1737. DWORD cbValue = dwMaxValueLength;
  1738. dwValueNameLength = dwMaxValueNameLen;
  1739. memset(pszValueName, 0, dwMaxValueNameLen * sizeof(TCHAR));
  1740. dwStatus = RegEnumValue(
  1741. hSourceSubKey,
  1742. index,
  1743. pszValueName,
  1744. &dwValueNameLength,
  1745. NULL,
  1746. &dwValueType,
  1747. pbValue,
  1748. &cbValue
  1749. );
  1750. if(dwStatus == ERROR_SUCCESS)
  1751. {
  1752. //
  1753. // Copy value
  1754. //
  1755. dwStatus = RegSetValueEx(
  1756. hDestSubKey,
  1757. pszValueName,
  1758. 0,
  1759. dwValueType,
  1760. pbValue,
  1761. cbValue
  1762. );
  1763. }
  1764. }
  1765. if(dwStatus == ERROR_NO_MORE_ITEMS)
  1766. {
  1767. dwStatus = ERROR_SUCCESS;
  1768. }
  1769. if(dwStatus != ERROR_SUCCESS)
  1770. {
  1771. goto cleanup;
  1772. }
  1773. }
  1774. cleanup:
  1775. // close the key before trying to delete it.
  1776. if(hSourceSubKey != NULL)
  1777. {
  1778. RegCloseKey(hSourceSubKey);
  1779. }
  1780. if(hDestSubKey != NULL)
  1781. {
  1782. RegCloseKey(hDestSubKey);
  1783. }
  1784. if(pszValueName != NULL)
  1785. {
  1786. FreeMemory(pszValueName);
  1787. }
  1788. if(pszSubKeyName != NULL)
  1789. {
  1790. FreeMemory(pszSubKeyName);
  1791. }
  1792. if(pbValue != NULL)
  1793. {
  1794. FreeMemory(pbValue);
  1795. }
  1796. if(pSecurityDescriptor != NULL)
  1797. {
  1798. FreeMemory(pSecurityDescriptor);
  1799. pSecurityDescriptor = NULL;
  1800. }
  1801. return dwStatus;
  1802. }