Leaked source code of windows server 2003
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.

3068 lines
85 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. crypto.c
  5. Abstract:
  6. Interfaces for registering and deregistering crypto checkpoint
  7. handlers.
  8. Author:
  9. Jeff Spelman (jeffspel) 11/10/1998
  10. Revision History:
  11. Charlie Wickham (charlwi) 7/7/00
  12. added "how this works" section
  13. --*/
  14. #include "cpp.h"
  15. #include "wincrypt.h"
  16. #if 0
  17. How crypto checkpointing works
  18. Crypto checkpointing allows a crypto key container to be associated with a
  19. resource. When that resource is moved to another node in the cluster, the key
  20. container is constructed/updated from the checkpoint information on the previous
  21. hosting node. The key container is not replicated; it only appears on a node if
  22. the resource is moved to that node. Keys in the container must be exportable.
  23. The user identifies the crypto key container by passing in a string of the
  24. form "Type\Name\Key" where Type is CSP Provider type, Name is the provider
  25. name, and Key is the key container name. The key container must already exist
  26. prior to adding the checkpoint. They are created using the Crypto APIs.
  27. Checkpoints are added in CpckAddCryptoCheckpoint. Checkpoint information is
  28. stored in two places: in the CryptoSync key under the resource's GUID key and
  29. in a datafile on the quorum drive. A new key, called CryptoSync, is created
  30. under the resource key. In this key are values that are of the form 00000001,
  31. 00000002, etc. The data associated with the value is the string identifying
  32. the crypto key container. The value name is also used as the datafile name
  33. with a .CPR extension, i.e., if the value name is 00000001, then the
  34. associated datafile would be in a subdirectory of the quorum area which is
  35. named using the resource's GUID, and a filename of 00000001.CPR.
  36. The checkpoint datafile contains all the information to restore the crypto key
  37. container on another node in the cluster, i.e., a header
  38. (CRYPTO_KEY_FILE_DATA), the signature and exchange keys if they exist, and the
  39. security descriptor associated with key container.
  40. Upon receiving the control code, the cluster service cracks the string into
  41. its component parts and stores the data in a CRYPTO_KEY_INFO structure. The
  42. CryptoSync key is opened/created and a check is made to see if the checkpoint
  43. already exists. If not, an unused ID is found and the checkpoint is saved to a
  44. file on the quorum disk.
  45. When the resource is moved to another node, the FM calls CpckReplicateCryptoKeys
  46. to restore the keys on that node. This routine reads the file and creates the
  47. key container, imports the keys and sets the security descr. on the container.
  48. Delete cleans up registry entry and file.
  49. #endif
  50. //
  51. // Local type and structure definitions
  52. //
  53. // context structures are used during the DmEnumValues routine to pass data
  54. // into the callback routine.
  55. //
  56. typedef struct _CPCK_ADD_CONTEXT {
  57. BOOL fFound;
  58. BYTE *pbInfo;
  59. DWORD cbInfo;
  60. } CPCK_ADD_CONTEXT, *PCPCK_ADD_CONTEXT;
  61. typedef struct _CPCK_DEL_CONTEXT {
  62. DWORD dwId;
  63. BYTE *pbInfo;
  64. DWORD cbInfo;
  65. } CPCK_DEL_CONTEXT, *PCPCK_DEL_CONTEXT;
  66. typedef struct _CPCK_GET_CONTEXT {
  67. DWORD cCheckpoints;
  68. BOOL fNeedMoreData;
  69. DWORD cbAvailable;
  70. DWORD cbRequired;
  71. BYTE *pbOutput;
  72. } CPCK_GET_CONTEXT, *PCPCK_GET_CONTEXT;
  73. //
  74. // struct for Crypto Key information; breaks the container name into its
  75. // component parts.
  76. //
  77. typedef struct _CRYPTO_KEY_INFO {
  78. DWORD dwVersion;
  79. DWORD dwProvType;
  80. LPWSTR pwszProvName;
  81. LPWSTR pwszContainer;
  82. } CRYPTO_KEY_INFO, *PCRYPTO_KEY_INFO;
  83. // current version for the CRYPTO_KEY_INFO struct
  84. #define CRYPTO_KEY_INFO_VERSION 1
  85. //
  86. // struct for key data when writing and reading from files; additional memory
  87. // is allocated after the structure to hold the exported signature key (if
  88. // present), the exported exchange key (if present) and the optional security
  89. // descriptor. At least one of the optional key components must be present in
  90. // the container.
  91. //
  92. #define SALT_SIZE 16
  93. #define IV_SIZE 8
  94. typedef struct _CRYPTO_KEY_FILE_DATA {
  95. DWORD dwVersion;
  96. DWORD cbSig; // offset from beginning of struct to exported Signature Key
  97. DWORD cbExch; // offset from beginning of struct to exported Exchange Key
  98. DWORD cbSecDescr; // offset from beginning of struct to container security descr.
  99. struct _CRYPTO_KEY_FILE_INITIALIZATION_DATA {
  100. BYTE rgbSigIV[IV_SIZE];
  101. BYTE rgbExchIV[IV_SIZE];
  102. BYTE rgbSalt[SALT_SIZE];
  103. };
  104. } CRYPTO_KEY_FILE_DATA, *PCRYPTO_KEY_FILE_DATA;
  105. // current version for the CRYPTO_KEY_INFO struct
  106. #define CRYPTO_KEY_FILE_DATA_VERSION 1
  107. //
  108. // Table that specifies for w2k {Crypto provider, default key length for RC2, default effective key length for
  109. // RC2}.
  110. //
  111. CP_RC2_W2k_KEYLEN_STRUCT CP_RC2_W2k_KEYLEN_TABLE [] =
  112. {
  113. { MS_DEF_PROV, 40, 40 },
  114. { MS_ENHANCED_PROV, 128, 40 },
  115. { MS_STRONG_PROV, 40, 40 },
  116. { MS_DEF_DSS_DH_PROV, 40, 40},
  117. { MS_ENH_DSS_DH_PROV, 40, 40 }
  118. };
  119. //
  120. // Local function prototypes
  121. //
  122. BOOL
  123. CpckReplicateCallback(
  124. IN LPWSTR ValueName,
  125. IN LPVOID ValueData,
  126. IN DWORD ValueType,
  127. IN DWORD ValueSize,
  128. IN PFM_RESOURCE Resource
  129. );
  130. BOOL
  131. CpckAddCheckpointCallback(
  132. IN LPWSTR ValueName,
  133. IN LPVOID ValueData,
  134. IN DWORD ValueType,
  135. IN DWORD ValueSize,
  136. IN PCPCK_ADD_CONTEXT Context
  137. );
  138. BOOL
  139. CpckDeleteCheckpointCallback(
  140. IN LPWSTR ValueName,
  141. IN LPVOID ValueData,
  142. IN DWORD ValueType,
  143. IN DWORD ValueSize,
  144. IN PCPCK_DEL_CONTEXT Context
  145. );
  146. BOOL
  147. CpckGetCheckpointsCallback(
  148. IN LPWSTR ValueName,
  149. IN LPVOID ValueData,
  150. IN DWORD ValueType,
  151. IN DWORD ValueSize,
  152. IN PCPCK_GET_CONTEXT Context
  153. );
  154. DWORD
  155. CpckInstallKeyContainer(
  156. IN HCRYPTPROV hProv,
  157. IN LPWSTR FileName,
  158. IN PCRYPTO_KEY_INFO pCryptoKeyInfo
  159. );
  160. DWORD
  161. CpckCheckpoint(
  162. IN PFM_RESOURCE Resource,
  163. IN HCRYPTPROV hProv,
  164. IN DWORD dwId,
  165. IN CRYPTO_KEY_INFO *pCryptoKeyInfo
  166. );
  167. CL_NODE_ID
  168. CppGetQuorumNodeId(
  169. VOID
  170. );
  171. BOOL
  172. CpckGetKeyLength(
  173. IN PCRYPTO_KEY_INFO pCryptoKeyInfo,
  174. OUT PDWORD pdwKeyLength,
  175. OUT PDWORD pdwEffectiveKeyLength
  176. );
  177. DWORD
  178. CpckReplicateCryptoKeys(
  179. IN PFM_RESOURCE Resource
  180. )
  181. /*++
  182. Routine Description:
  183. Restores any crypto key checkpoints for this resource.
  184. Arguments:
  185. Resource - Supplies the resource.
  186. Return Value:
  187. ERROR_SUCCESS if successful
  188. Win32 error code otherwise
  189. --*/
  190. {
  191. HDMKEY ResourceKey;
  192. HDMKEY CryptoSyncKey;
  193. //
  194. // Open up the resource's key
  195. //
  196. ResourceKey = DmOpenKey(DmResourcesKey,
  197. OmObjectId(Resource),
  198. KEY_READ);
  199. if (ResourceKey != NULL) {
  200. //
  201. // Open up the CryptoSync key
  202. //
  203. CryptoSyncKey = DmOpenKey(ResourceKey,
  204. L"CryptoSync",
  205. KEY_READ);
  206. DmCloseKey(ResourceKey);
  207. if (CryptoSyncKey != NULL) {
  208. DmEnumValues(CryptoSyncKey,
  209. CpckReplicateCallback,
  210. Resource);
  211. DmCloseKey(CryptoSyncKey);
  212. }
  213. return(ERROR_SUCCESS);
  214. } else {
  215. DWORD status;
  216. status = GetLastError();
  217. ClRtlLogPrint(LOG_UNUSUAL,
  218. "[CPCK] CpckReplicateCryptoKeys - couldn't open Resource key. error %1!d!\n",
  219. status);
  220. return status;
  221. }
  222. } // CpckReplicateCryptoKeys
  223. void
  224. FreeCryptoKeyInfo(
  225. IN OUT CRYPTO_KEY_INFO *pCryptoKeyInfo
  226. )
  227. /*++
  228. Routine Description:
  229. Frees the string pointers in the structure.
  230. Arguments:
  231. CryptoKeyInfo - Pointer to the CRYPTO_KEY_INFO structure which
  232. --*/
  233. {
  234. if (NULL != pCryptoKeyInfo)
  235. {
  236. if (NULL != pCryptoKeyInfo->pwszProvName)
  237. {
  238. LocalFree(pCryptoKeyInfo->pwszProvName);
  239. pCryptoKeyInfo->pwszProvName = NULL;
  240. }
  241. if (NULL != pCryptoKeyInfo->pwszContainer)
  242. {
  243. LocalFree(pCryptoKeyInfo->pwszContainer);
  244. pCryptoKeyInfo->pwszContainer = NULL;
  245. }
  246. }
  247. } // FreeCryptoKeyInfo
  248. DWORD
  249. CpckValueToCryptoKeyInfo(
  250. OUT CRYPTO_KEY_INFO *pCryptoKeyInfo,
  251. IN LPVOID ValueData,
  252. IN DWORD ValueSize
  253. )
  254. /*++
  255. Routine Description:
  256. Converts from a binary blob into a CryptoKeyInfo structure. Basically
  257. this just does some value and pointer assignments. The blob is a string of
  258. the format "Provider Type\Provider Name\Container Name".
  259. Arguments:
  260. CryptoKeyInfo - Pointer to the CRYPTO_KEY_INFO structure which is filled in
  261. ValueData - Supplies the value data (this is the binary blob)
  262. ValueSize - Supplies the size of ValueData
  263. Return Value:
  264. ERROR_SUCCESS if successful
  265. Win32 error code otherwise
  266. --*/
  267. {
  268. DWORD *pdw;
  269. WCHAR *pwsz = (WCHAR*)ValueData;
  270. DWORD cb = sizeof(DWORD) * 2;
  271. DWORD cwch;
  272. DWORD i;
  273. DWORD Status = ERROR_SUCCESS;
  274. // make sure the length is OK (at least two slashes and a NULL?)
  275. if (ValueSize < sizeof(WCHAR) * 3)
  276. {
  277. Status = ERROR_INVALID_PARAMETER;
  278. goto Ret;
  279. }
  280. // first is the numerical Provider type; find the slash separating it from
  281. // the provider name
  282. for (i = 0; i < (ValueSize - 3) / sizeof(WCHAR); i++)
  283. {
  284. if (L'\\' == pwsz[i])
  285. {
  286. pwsz[i] = L'\0';
  287. break;
  288. }
  289. }
  290. if ((ValueSize - 3) / sizeof(WCHAR) == i)
  291. {
  292. pwsz[i] = L'\\';
  293. Status = ERROR_INVALID_PARAMETER;
  294. goto Ret;
  295. }
  296. pCryptoKeyInfo->dwProvType = _wtoi(pwsz);
  297. pwsz[i] = L'\\';
  298. cwch = i;
  299. // grab the provider name pointer
  300. for (i = i + 1; i < (ValueSize - 2) / sizeof(WCHAR); i++)
  301. {
  302. if (L'\\' == pwsz[i])
  303. {
  304. pwsz[i] = L'\0';
  305. break;
  306. }
  307. }
  308. if ((ValueSize - 2) / sizeof(WCHAR) == i)
  309. {
  310. pwsz[i] = L'\\';
  311. Status = ERROR_INVALID_PARAMETER;
  312. goto Ret;
  313. }
  314. cb = (wcslen(&pwsz[cwch + 1]) + 1) * sizeof(WCHAR);
  315. if (NULL == (pCryptoKeyInfo->pwszProvName =
  316. (WCHAR*)LocalAlloc(LMEM_ZEROINIT, cb)))
  317. {
  318. Status = ERROR_NOT_ENOUGH_MEMORY;
  319. goto Ret;
  320. }
  321. wcscpy(pCryptoKeyInfo->pwszProvName, &pwsz[cwch + 1]);
  322. pwsz[i] = L'\\';
  323. cwch = i;
  324. // grab the container name pointer
  325. cb = (wcslen(&pwsz[cwch + 1]) + 1) * sizeof(WCHAR);
  326. if (NULL == (pCryptoKeyInfo->pwszContainer =
  327. (WCHAR*)LocalAlloc(LMEM_ZEROINIT, cb)))
  328. {
  329. Status = ERROR_NOT_ENOUGH_MEMORY;
  330. goto Ret;
  331. }
  332. wcscpy(pCryptoKeyInfo->pwszContainer, &pwsz[cwch + 1]);
  333. Ret:
  334. return (Status);
  335. } // CpckValueToCryptoKeyInfo
  336. DWORD
  337. CpckOpenCryptoKeyContainer(
  338. IN CRYPTO_KEY_INFO *pCryptoKeyInfo,
  339. IN BOOL fCreate,
  340. OUT HCRYPTPROV *phProv
  341. )
  342. /*++
  343. Routine Description:
  344. Opens a crypto key container (always uses CRYPT_MACHINE_KEYSET). Checks
  345. for either a signature and/or an exchange key and that they are
  346. exportable.
  347. Arguments:
  348. pCryptKeyInfo - Supplies the information for opening the container
  349. fCreate - Flag indicating if container is to be created
  350. phProv - The resulting Crypto Provider handle
  351. Return Value:
  352. ERROR_SUCCESS if succeeds
  353. Crypto Error code if it fails
  354. --*/
  355. {
  356. BOOLEAN WasEnabled;
  357. HCRYPTKEY hSigKey = 0;
  358. HCRYPTKEY hExchKey = 0;
  359. DWORD dwPermissions;
  360. DWORD cbPermissions;
  361. DWORD Status = 0;
  362. //
  363. // Attempt to open the specified crypto key container.
  364. //
  365. if (!CryptAcquireContextW(phProv,
  366. pCryptoKeyInfo->pwszContainer,
  367. pCryptoKeyInfo->pwszProvName,
  368. pCryptoKeyInfo->dwProvType,
  369. CRYPT_MACHINE_KEYSET))
  370. {
  371. if (fCreate)
  372. {
  373. //
  374. // if unable to open then create the container
  375. //
  376. if (!CryptAcquireContextW(phProv,
  377. pCryptoKeyInfo->pwszContainer,
  378. pCryptoKeyInfo->pwszProvName,
  379. pCryptoKeyInfo->dwProvType,
  380. CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
  381. {
  382. Status = GetLastError();
  383. }
  384. }
  385. else
  386. {
  387. Status = GetLastError();
  388. }
  389. }
  390. // if failed then try with BACKUP/RESTORE privilege
  391. if (0 != Status)
  392. {
  393. //
  394. //
  395. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  396. &WasEnabled);
  397. if ( Status != ERROR_SUCCESS )
  398. {
  399. ClRtlLogPrint(LOG_CRITICAL,
  400. "[CPCK] CpckOpenCryptoKeyContainer failed to enable thread privilege %1!d!...\n",
  401. Status);
  402. goto Ret;
  403. }
  404. if (!CryptAcquireContextW(phProv,
  405. pCryptoKeyInfo->pwszContainer,
  406. pCryptoKeyInfo->pwszProvName,
  407. pCryptoKeyInfo->dwProvType,
  408. CRYPT_MACHINE_KEYSET))
  409. {
  410. if (fCreate)
  411. {
  412. //
  413. // if unable to open then create the container
  414. //
  415. if (!CryptAcquireContextW(phProv,
  416. pCryptoKeyInfo->pwszContainer,
  417. pCryptoKeyInfo->pwszProvName,
  418. pCryptoKeyInfo->dwProvType,
  419. CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
  420. {
  421. Status = GetLastError();
  422. }
  423. }
  424. else
  425. {
  426. Status = GetLastError();
  427. }
  428. }
  429. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  430. WasEnabled);
  431. }
  432. if ((0 == Status) && (!fCreate))
  433. {
  434. // check if there is a sig key
  435. if (CryptGetUserKey(*phProv, AT_SIGNATURE, &hSigKey))
  436. {
  437. // check if key is exportable
  438. cbPermissions = sizeof(DWORD);
  439. if (!CryptGetKeyParam(hSigKey,
  440. KP_PERMISSIONS,
  441. (BYTE*)&dwPermissions,
  442. &cbPermissions,
  443. 0))
  444. {
  445. Status = GetLastError();
  446. goto Ret;
  447. }
  448. if (!(dwPermissions & CRYPT_EXPORT))
  449. {
  450. Status = (DWORD)NTE_BAD_KEY;
  451. goto Ret;
  452. }
  453. }
  454. // check if there is an exchange key
  455. if (CryptGetUserKey(*phProv, AT_KEYEXCHANGE, &hExchKey))
  456. {
  457. // check if key is exportable
  458. cbPermissions = sizeof(DWORD);
  459. if (!CryptGetKeyParam(hExchKey,
  460. KP_PERMISSIONS,
  461. (BYTE*)&dwPermissions,
  462. &cbPermissions,
  463. 0))
  464. {
  465. Status = GetLastError();
  466. goto Ret;
  467. }
  468. if (!(dwPermissions & CRYPT_EXPORT))
  469. {
  470. Status = (DWORD)NTE_BAD_KEY;
  471. goto Ret;
  472. }
  473. }
  474. }
  475. Ret:
  476. if (hSigKey)
  477. CryptDestroyKey(hSigKey);
  478. if (hExchKey)
  479. CryptDestroyKey(hExchKey);
  480. return Status;
  481. } // CpckOpenCryptoKeyContainer
  482. BOOL
  483. CpckReplicateCallback(
  484. IN LPWSTR ValueName,
  485. IN LPVOID ValueData,
  486. IN DWORD ValueType,
  487. IN DWORD ValueSize,
  488. IN PFM_RESOURCE Resource
  489. )
  490. /*++
  491. Routine Description:
  492. Value enumeration callback for replicating a resource's crypto key
  493. checkpoints.
  494. Arguments:
  495. ValueName - Supplies the name of the value (this is the checkpoint ID)
  496. ValueData - Supplies the value data (this is the registry crypto key info)
  497. ValueType - Supplies the value type (must be REG_BINARY)
  498. ValueSize - Supplies the size of ValueData
  499. Resource - Supplies the resource this value is a crypto key checkpoint for
  500. Return Value:
  501. TRUE to continue enumeration
  502. --*/
  503. {
  504. DWORD Id;
  505. DWORD Status;
  506. WCHAR TempFile[MAX_PATH];
  507. CRYPTO_KEY_INFO CryptoKeyInfo;
  508. HCRYPTPROV hProv = 0;
  509. BOOL fRet = TRUE;
  510. memset(&CryptoKeyInfo, 0, sizeof(CryptoKeyInfo));
  511. Id = wcstol(ValueName, NULL, 16); // skip past the 'Crypto' prefix
  512. if (Id == 0) {
  513. ClRtlLogPrint(LOG_UNUSUAL,
  514. "[CPCK] CpckReplicateCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  515. ValueName,
  516. OmObjectName(Resource));
  517. goto Ret;
  518. }
  519. //
  520. // convert from binary blob into a Crypto Key Info structure
  521. //
  522. Status = CpckValueToCryptoKeyInfo(&CryptoKeyInfo,
  523. ValueData,
  524. ValueSize);
  525. if (Status != ERROR_SUCCESS) {
  526. ClRtlLogPrint(LOG_UNUSUAL,
  527. "[CPCK] CpckReplicateCallback invalid crypto info %1!ws! for resource %2!ws!\n",
  528. ValueName,
  529. OmObjectName(Resource));
  530. goto Ret;
  531. }
  532. Status = CpckOpenCryptoKeyContainer(&CryptoKeyInfo,
  533. TRUE,
  534. &hProv);
  535. if (Status != ERROR_SUCCESS) {
  536. ClRtlLogPrint(LOG_UNUSUAL,
  537. "[CPCK] CpckReplicateCallback CryptAcquireContext failed for %1!ws! %2!ws! with %3!d! for resource %4!ws!\n",
  538. CryptoKeyInfo.pwszContainer,
  539. CryptoKeyInfo.pwszProvName,
  540. Status,
  541. OmObjectName(Resource));
  542. goto Ret;
  543. }
  544. ClRtlLogPrint(LOG_NOISE,
  545. "[CPCK] CpckReplicateCallback retrieving crypto id %1!lx! for resource %2!ws\n",
  546. Id,
  547. OmObjectName(Resource));
  548. //
  549. // See if there is any checkpoint data for this ID.
  550. //
  551. Status = DmCreateTempFileName(TempFile);
  552. if (Status != ERROR_SUCCESS) {
  553. CL_UNEXPECTED_ERROR( Status );
  554. }
  555. Status = CpGetDataFile(Resource,
  556. Id,
  557. TempFile,
  558. TRUE);
  559. if (Status != ERROR_SUCCESS) {
  560. ClRtlLogPrint(LOG_UNUSUAL,
  561. "[CPCK] CpckReplicateCallback - CpGetDataFile for id %1!lx! resource %2!ws! failed %3!d!\n",
  562. Id,
  563. OmObjectName(Resource),
  564. Status);
  565. } else {
  566. //
  567. // Finally install the checkpointed file into the registry.
  568. //
  569. Status = CpckInstallKeyContainer(hProv, TempFile, &CryptoKeyInfo);
  570. if (Status != ERROR_SUCCESS) {
  571. ClRtlLogPrint(LOG_CRITICAL,
  572. "[CPCK] CpckReplicateCallback: could not restore temp file %1!ws! to container %2!ws! error %3!d!\n",
  573. TempFile,
  574. CryptoKeyInfo.pwszContainer,
  575. Status);
  576. // Log the event for crypto key failure
  577. CsLogEventData2(LOG_CRITICAL,
  578. CP_CRYPTO_CKPT_RESTORE_FAILED,
  579. sizeof(Status),
  580. &Status,
  581. OmObjectName(Resource),
  582. CryptoKeyInfo.pwszContainer);
  583. }
  584. }
  585. QfsDeleteFile(TempFile);
  586. //
  587. // watcher for crypto keys is not currently available or needed
  588. //
  589. Ret:
  590. FreeCryptoKeyInfo(&CryptoKeyInfo);
  591. if (hProv)
  592. CryptReleaseContext(hProv, 0);
  593. return fRet;
  594. } // CpckReplicateCallback
  595. DWORD
  596. CpckAddCryptoCheckpoint(
  597. IN PFM_RESOURCE Resource,
  598. IN PVOID InBuffer,
  599. IN DWORD InBufferSize
  600. )
  601. /*++
  602. Routine Description:
  603. Adds a new crypto key checkpoint to a resource's list.
  604. Arguments:
  605. Resource - supplies the resource the crypto key checkpoint should be added to.
  606. InBuffer - Supplies the crypto key information (always CRYPT_MACHINE_KEYSET)
  607. InBufferSize - Supplies the length of InBuffer
  608. Return Value:
  609. ERROR_SUCCESS if successful
  610. Win32 error code otherwise
  611. --*/
  612. {
  613. HDMKEY SyncKey;
  614. CPCK_ADD_CONTEXT Context;
  615. HDMKEY ResourceKey = NULL;
  616. HDMKEY CryptoSyncKey = NULL;
  617. DWORD Disposition;
  618. DWORD Id;
  619. WCHAR IdName[9];
  620. DWORD Status;
  621. CLUSTER_RESOURCE_STATE State;
  622. BOOLEAN WasEnabled;
  623. DWORD Count=60;
  624. CRYPTO_KEY_INFO CryptoKeyInfo;
  625. HCRYPTPROV hProv = 0;
  626. memset(&CryptoKeyInfo, 0, sizeof(CryptoKeyInfo));
  627. //
  628. // convert from binary blob into a Crypto Key Info structure
  629. //
  630. Status = CpckValueToCryptoKeyInfo(&CryptoKeyInfo,
  631. InBuffer,
  632. InBufferSize);
  633. if (Status != ERROR_SUCCESS) {
  634. ClRtlLogPrint(LOG_UNUSUAL,
  635. "[CPCK] CpckAddCryptoCheckpoint: invalid crypto info for resource %1!ws!\n",
  636. OmObjectName(Resource));
  637. goto Ret;
  638. }
  639. Status = CpckOpenCryptoKeyContainer(&CryptoKeyInfo,
  640. FALSE,
  641. &hProv);
  642. if (Status != ERROR_SUCCESS) {
  643. ClRtlLogPrint(LOG_UNUSUAL,
  644. "[CPCK] CpckAddCryptoCheckpoint: open key container failed for "
  645. "container %1!ws! (provider: %2!ws!) with %3!d! for resource %4!ws!\n",
  646. CryptoKeyInfo.pwszContainer,
  647. CryptoKeyInfo.pwszProvName,
  648. Status,
  649. OmObjectName(Resource));
  650. goto Ret;
  651. }
  652. //
  653. // Open up the resource's key
  654. //
  655. ResourceKey = DmOpenKey(DmResourcesKey,
  656. OmObjectId(Resource),
  657. KEY_READ);
  658. if( ResourceKey == NULL ) {
  659. Status = GetLastError();
  660. ClRtlLogPrint(LOG_CRITICAL,
  661. "[CPCK] CpckAddCryptoCheckpoint: couldn't open Resource key for %1!ws! error %2!d!\n",
  662. OmObjectName(Resource),
  663. Status);
  664. goto Ret;
  665. }
  666. //
  667. // Open up the CryptoSync key
  668. //
  669. CryptoSyncKey = DmCreateKey(ResourceKey,
  670. L"CryptoSync",
  671. 0,
  672. KEY_READ | KEY_WRITE,
  673. NULL,
  674. &Disposition);
  675. DmCloseKey(ResourceKey);
  676. if (CryptoSyncKey == NULL) {
  677. Status = GetLastError();
  678. ClRtlLogPrint(LOG_CRITICAL,
  679. "[CPCK] CpckAddCryptoCheckpoint: couldn't create CryptoSync key for "
  680. "resource %1!ws! error %2!d!\n",
  681. OmObjectName(Resource),
  682. Status);
  683. goto Ret;
  684. }
  685. if (Disposition == REG_OPENED_EXISTING_KEY) {
  686. //
  687. // Enumerate all the other values to make sure this key is
  688. // not already registered.
  689. //
  690. Context.fFound = FALSE;
  691. Context.pbInfo = InBuffer;
  692. Context.cbInfo = InBufferSize;
  693. DmEnumValues(CryptoSyncKey,
  694. CpckAddCheckpointCallback,
  695. &Context);
  696. if (Context.fFound) {
  697. //
  698. // This checkpoint already exists.
  699. //
  700. ClRtlLogPrint(LOG_UNUSUAL,
  701. "[CPCK] CpckAddCryptoCheckpoint: failing attempt to add duplicate "
  702. "checkpoint for resource %1!ws!, container %2!ws! (provider: %3!ws!)\n",
  703. OmObjectName(Resource),
  704. CryptoKeyInfo.pwszContainer,
  705. CryptoKeyInfo.pwszProvName);
  706. Status = ERROR_ALREADY_EXISTS;
  707. goto Ret;
  708. }
  709. //
  710. // Now we need to find a unique checkpoint ID for this registry subtree.
  711. // Start at 1 and keep trying value names until we get to one that does
  712. // not already exist.
  713. //
  714. for (Id=1; ; Id++) {
  715. DWORD dwType;
  716. DWORD cbData;
  717. wsprintfW(IdName,L"%08lx",Id);
  718. cbData = 0;
  719. Status = DmQueryValue(CryptoSyncKey,
  720. IdName,
  721. &dwType,
  722. NULL,
  723. &cbData);
  724. if (Status == ERROR_FILE_NOT_FOUND) {
  725. //
  726. // Found a free ID.
  727. //
  728. break;
  729. }
  730. }
  731. } else {
  732. //
  733. // The crypto sync reg key was just created, so this must be the only checkpoint
  734. // that exists.
  735. //
  736. Id = 1;
  737. wsprintfW(IdName, L"%08lx",Id);
  738. }
  739. ClRtlLogPrint(LOG_NOISE,
  740. "[CPCK] CpckAddCryptoCheckpoint: creating new checkpoint id %1!d! "
  741. "for resource %2!ws!, container %3!ws! (provider: %4!ws!)\n",
  742. Id,
  743. OmObjectName(Resource),
  744. CryptoKeyInfo.pwszContainer,
  745. CryptoKeyInfo.pwszProvName);
  746. Status = DmSetValue(CryptoSyncKey,
  747. IdName,
  748. REG_BINARY,
  749. (CONST BYTE *)InBuffer,
  750. InBufferSize);
  751. if (Status != ERROR_SUCCESS) {
  752. ClRtlLogPrint(LOG_CRITICAL,
  753. "[CPCK] CpckAddCryptoCheckpoint: failed to create new checkpoint id %1!d! "
  754. "for resource %2!ws!, container %3!ws! (provider: %4!ws!)\n",
  755. Id,
  756. OmObjectName(Resource),
  757. CryptoKeyInfo.pwszContainer,
  758. CryptoKeyInfo.pwszProvName);
  759. goto Ret;
  760. }
  761. RetryCheckpoint:
  762. //
  763. // Take the initial checkpoint
  764. //
  765. Status = CpckCheckpoint(Resource,
  766. hProv,
  767. Id,
  768. &CryptoKeyInfo);
  769. // this may fail due to quorum resource being offline. We could do one of
  770. // two things here, wait for quorum resource to come online or retry. We
  771. // retry as this may be called from the online routines of a resource and
  772. // we dont want to add any circular waits.
  773. if ((Status == ERROR_ACCESS_DENIED) ||
  774. (Status == ERROR_INVALID_FUNCTION) ||
  775. (Status == ERROR_NOT_READY) ||
  776. (Status == RPC_X_INVALID_PIPE_OPERATION) ||
  777. (Status == ERROR_BUSY) ||
  778. (Status == ERROR_SWAPERROR))
  779. {
  780. if (Count--)
  781. {
  782. Sleep(1000);
  783. goto RetryCheckpoint;
  784. }
  785. #if DBG
  786. else
  787. {
  788. if (IsDebuggerPresent())
  789. DebugBreak();
  790. }
  791. #endif
  792. }
  793. if (Status != ERROR_SUCCESS) {
  794. ClRtlLogPrint(LOG_CRITICAL,
  795. "[CPCK] CpckAddCryptoCheckpoint: failed to take initial checkpoint for "
  796. "resource %1!ws!, container %2!ws! (provider: %3!ws!), error %4!d!\n",
  797. OmObjectName(Resource),
  798. CryptoKeyInfo.pwszContainer,
  799. CryptoKeyInfo.pwszProvName,
  800. Status);
  801. goto Ret;
  802. }
  803. Ret:
  804. FreeCryptoKeyInfo(&CryptoKeyInfo);
  805. if (hProv)
  806. CryptReleaseContext(hProv, 0);
  807. if (CryptoSyncKey)
  808. DmCloseKey(CryptoSyncKey);
  809. return(Status);
  810. } // CpckAddCryptoCheckpoint
  811. BOOL
  812. CpckAddCheckpointCallback(
  813. IN LPWSTR ValueName,
  814. IN LPVOID ValueData,
  815. IN DWORD ValueType,
  816. IN DWORD ValueSize,
  817. IN PCPCK_ADD_CONTEXT Context
  818. )
  819. /*++
  820. Routine Description:
  821. Value enumeration callback for adding a new registry
  822. checkpoint subtrees. This is only used to see if the specified
  823. registry subtree is already being watched.
  824. Arguments:
  825. ValueName - Supplies the name of the value (this is the checkpoint ID)
  826. ValueData - Supplies the value data (this is the crypto key information)
  827. ValueType - Supplies the value type (must be REG_BINARY)
  828. ValueSize - Supplies the size of ValueData
  829. Context - Supplies the callback context
  830. Return Value:
  831. TRUE to continue enumeration
  832. FALSE if a match is found and enumeration should be stopped
  833. --*/
  834. {
  835. if (memcmp(ValueData, Context->pbInfo, Context->cbInfo) == 0) {
  836. //
  837. // Found a match
  838. //
  839. Context->fFound = TRUE;
  840. return(FALSE);
  841. }
  842. return(TRUE);
  843. } // CpckAddCheckpointCallback
  844. DWORD
  845. CpckDeleteCryptoCheckpoint(
  846. IN PFM_RESOURCE Resource,
  847. IN PVOID InBuffer,
  848. IN DWORD InBufferSize
  849. )
  850. /*++
  851. Routine Description:
  852. Removes a crypto key checkpoint from a resource's list.
  853. Arguments:
  854. Resource - supplies the resource the registry checkpoint should be added to.
  855. InBuffer - Supplies the crypto key information (always CRYPT_MACHINE_KEYSET)
  856. InBufferSize - Supplies the length of InBuffer
  857. Return Value:
  858. ERROR_SUCCESS if successful
  859. Win32 error code otherwise
  860. --*/
  861. {
  862. CPCK_DEL_CONTEXT Context;
  863. HDMKEY ResourceKey;
  864. HDMKEY CryptoSyncKey;
  865. DWORD Status;
  866. WCHAR ValueId[9];
  867. LPWSTR pszFileName=NULL;
  868. LPWSTR pszDirectoryName=NULL;
  869. CLUSTER_RESOURCE_STATE State;
  870. //
  871. // Open up the resource's key
  872. //
  873. ResourceKey = DmOpenKey(DmResourcesKey,
  874. OmObjectId(Resource),
  875. KEY_READ);
  876. if ( ResourceKey == NULL ) {
  877. Status = GetLastError();
  878. ClRtlLogPrint(LOG_NOISE,
  879. "[CPCK] CpckDeleteCryptoCheckpoint - couldn't open Resource key. error %1!d!\n",
  880. Status);
  881. return(Status);
  882. }
  883. //
  884. // Open up the CryptoSync key
  885. //
  886. CryptoSyncKey = DmOpenKey(ResourceKey,
  887. L"CryptoSync",
  888. KEY_READ | KEY_WRITE);
  889. DmCloseKey(ResourceKey);
  890. if (CryptoSyncKey == NULL) {
  891. Status = GetLastError();
  892. ClRtlLogPrint(LOG_NOISE,
  893. "[CPCK] CpckDeleteCryptoCheckpoint - couldn't open CryptoSync key error %1!d!\n",
  894. Status);
  895. return(Status);
  896. }
  897. //
  898. // Enumerate all the values to find this one
  899. //
  900. Context.dwId = 0;
  901. Context.pbInfo = InBuffer;
  902. Context.cbInfo = InBufferSize;
  903. DmEnumValues(CryptoSyncKey,
  904. CpckDeleteCheckpointCallback,
  905. &Context);
  906. if (Context.dwId == 0) {
  907. //
  908. // The specified tree was not found.
  909. //
  910. DmCloseKey(CryptoSyncKey);
  911. return(ERROR_FILE_NOT_FOUND);
  912. }
  913. wsprintfW(ValueId,L"%08lx",Context.dwId);
  914. Status = DmDeleteValue(CryptoSyncKey, ValueId);
  915. DmCloseKey(CryptoSyncKey);
  916. if (Status != ERROR_SUCCESS) {
  917. ClRtlLogPrint(LOG_CRITICAL,
  918. "[CPCK] CpckDeleteCryptoCheckpoint - couldn't delete value %1!ws! error %2!d!\n",
  919. ValueId,
  920. Status);
  921. return(Status);
  922. }
  923. //delete the file corresponding to this checkpoint
  924. Status = CpckDeleteCryptoFile(Resource, Context.dwId, NULL);
  925. if (Status != ERROR_SUCCESS) {
  926. ClRtlLogPrint(LOG_CRITICAL,
  927. "[CPCK] CpckDeleteCryptoCheckpoint - couldn't delete checkpoint file , error %1!d!\n",
  928. Status);
  929. return(Status);
  930. }
  931. return(Status);
  932. } // CpckDeleteCryptoCheckpoint
  933. DWORD
  934. CpckRemoveResourceCheckpoints(
  935. IN PFM_RESOURCE Resource
  936. )
  937. /*++
  938. Routine Description:
  939. This is called when a resource is deleted to remove all the checkpoints
  940. and the related stuff in the registry.
  941. Arguments:
  942. Resource - supplies the resource
  943. Return Value:
  944. ERROR_SUCCESS if successful
  945. Win32 error code otherwise
  946. --*/
  947. {
  948. DWORD Status;
  949. //delete all the checkpoints corresponding to this resource
  950. Status = CpckDeleteCryptoFile(Resource, 0, NULL);
  951. if (Status != ERROR_SUCCESS)
  952. {
  953. ClRtlLogPrint(LOG_CRITICAL,
  954. "[CPCK] CpckRemoveResourceCheckpoints, CpckDeleteCheckpointFile failed %1!d!\n",
  955. Status);
  956. goto FnExit;
  957. }
  958. FnExit:
  959. return(Status);
  960. } // CpckRemoveResourceCheckpoints
  961. BOOL
  962. CpckDeleteCheckpointCallback(
  963. IN LPWSTR ValueName,
  964. IN LPVOID ValueData,
  965. IN DWORD ValueType,
  966. IN DWORD ValueSize,
  967. IN PCPCK_DEL_CONTEXT Context
  968. )
  969. /*++
  970. Routine Description:
  971. Value enumeration callback for deleting an old registry
  972. checkpoint subtrees.
  973. Arguments:
  974. ValueName - Supplies the name of the value (this is the checkpoint ID)
  975. ValueData - Supplies the value data (this is the crypto info)
  976. ValueType - Supplies the value type (must be REG_BINARY)
  977. ValueSize - Supplies the size of ValueData
  978. Context - Supplies the callback context
  979. Return Value:
  980. TRUE to continue enumeration
  981. FALSE if a match is found and enumeration should be stopped
  982. --*/
  983. {
  984. if (memcmp(ValueData, Context->pbInfo, Context->cbInfo) == 0) {
  985. //
  986. // Found a match
  987. //
  988. Context->dwId = wcstol(ValueName, NULL, 16); // skip past the 'Crypto' prefix
  989. return(FALSE);
  990. }
  991. return(TRUE);
  992. } // CpckDeleteCheckpointCallback
  993. DWORD
  994. CpckGetCryptoCheckpoints(
  995. IN PFM_RESOURCE Resource,
  996. OUT PUCHAR OutBuffer,
  997. IN DWORD OutBufferSize,
  998. OUT LPDWORD BytesReturned,
  999. OUT LPDWORD Required
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Retrieves a list of the resource's crypto checkpoints
  1004. Arguments:
  1005. Resource - Supplies the resource whose crypto checkpoints should be retrieved.
  1006. OutBuffer - Supplies a pointer to the output buffer.
  1007. OutBufferSize - Supplies the size (in bytes) of the output buffer.
  1008. BytesReturned - Returns the number of bytes written to the output buffer.
  1009. Required - Returns the number of bytes required. (if the output buffer was insufficient)
  1010. Return Value:
  1011. ERROR_SUCCESS if successful
  1012. Win32 error code otherwise
  1013. --*/
  1014. {
  1015. CPCK_GET_CONTEXT Context;
  1016. HDMKEY ResourceKey;
  1017. HDMKEY CryptoSyncKey;
  1018. DWORD Status;
  1019. *BytesReturned = 0;
  1020. *Required = 0;
  1021. //
  1022. // Open up the resource's key
  1023. //
  1024. ResourceKey = DmOpenKey(DmResourcesKey,
  1025. OmObjectId(Resource),
  1026. KEY_READ);
  1027. if (ResourceKey == NULL) {
  1028. Status = GetLastError();
  1029. ClRtlLogPrint(LOG_UNUSUAL,
  1030. "[CPCK] CpckGetCryptoCheckpoints - couldn't open Resource key. error %1!d!\n",
  1031. Status);
  1032. return(Status);
  1033. }
  1034. //
  1035. // Open up the CryptoSync key
  1036. //
  1037. CryptoSyncKey = DmOpenKey(ResourceKey,
  1038. L"CryptoSync",
  1039. KEY_READ | KEY_WRITE);
  1040. DmCloseKey(ResourceKey);
  1041. if (CryptoSyncKey == NULL) {
  1042. //
  1043. // No reg sync key, therefore there are no subtrees
  1044. //
  1045. return(ERROR_SUCCESS);
  1046. }
  1047. Context.cCheckpoints = 0;
  1048. ZeroMemory(OutBuffer, OutBufferSize);
  1049. Context.cbRequired = sizeof(WCHAR);
  1050. if (OutBufferSize < sizeof(WCHAR) * 2)
  1051. {
  1052. Context.fNeedMoreData = TRUE;
  1053. Context.cbAvailable = 0;
  1054. *BytesReturned = 0;
  1055. }
  1056. else
  1057. {
  1058. Context.fNeedMoreData = FALSE;
  1059. Context.cbAvailable = OutBufferSize - sizeof(WCHAR);
  1060. Context.pbOutput = (BYTE*)(OutBuffer);
  1061. *BytesReturned = sizeof(WCHAR) * 2;
  1062. }
  1063. DmEnumValues(CryptoSyncKey,
  1064. CpckGetCheckpointsCallback,
  1065. &Context);
  1066. DmCloseKey(CryptoSyncKey);
  1067. if ((0 != Context.cCheckpoints) && Context.fNeedMoreData) {
  1068. Status = ERROR_MORE_DATA;
  1069. } else {
  1070. Status = ERROR_SUCCESS;
  1071. }
  1072. if ( 0 == Context.cCheckpoints ) {
  1073. *BytesReturned = 0;
  1074. *Required = 0;
  1075. } else {
  1076. if ( Context.fNeedMoreData ) {
  1077. *Required = Context.cbRequired;
  1078. } else {
  1079. *BytesReturned = (DWORD)(Context.pbOutput - OutBuffer);
  1080. }
  1081. }
  1082. return(Status);
  1083. } // CpckGetCryptoCheckpoints
  1084. BOOL
  1085. CpckGetCheckpointsCallback(
  1086. IN LPWSTR ValueName,
  1087. IN LPVOID ValueData,
  1088. IN DWORD ValueType,
  1089. IN DWORD ValueSize,
  1090. IN PCPCK_GET_CONTEXT Context
  1091. )
  1092. /*++
  1093. Routine Description:
  1094. Value enumeration callback for retrieving all of a resource's
  1095. checkpoint subtrees.
  1096. Arguments:
  1097. ValueName - Supplies the name of the value (this is the checkpoint ID)
  1098. ValueData - Supplies the value data (this is the crypto info)
  1099. ValueType - Supplies the value type (must be REG_BINARY)
  1100. ValueSize - Supplies the size of ValueData
  1101. Context - Supplies the callback context
  1102. Return Value:
  1103. TRUE to continue enumeration
  1104. --*/
  1105. {
  1106. Context->cbRequired += ValueSize;
  1107. Context->cCheckpoints++;
  1108. if (Context->cbAvailable >= ValueSize) {
  1109. CopyMemory(Context->pbOutput, ValueData, ValueSize);
  1110. Context->pbOutput += ValueSize;
  1111. Context->cbAvailable -= ValueSize;
  1112. } else {
  1113. Context->fNeedMoreData = TRUE;
  1114. }
  1115. return(TRUE);
  1116. } // CpckGetCheckpointsCallback
  1117. DWORD
  1118. CpckGenSymKey(
  1119. IN HCRYPTPROV hProv,
  1120. IN BYTE *pbSalt,
  1121. IN BYTE *pbIV,
  1122. IN PCRYPTO_KEY_INFO pCryptoKeyInfo,
  1123. IN DWORD dwKeyLength, OPTIONAL
  1124. IN DWORD dwEffectiveKeyLength, OPTIONAL
  1125. OUT HCRYPTKEY *phSymKey
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. Generate a session key based on the specified Salt and IV.
  1130. Arguments:
  1131. hProv - Handle to the crypto provider (key container)
  1132. pbSalt - Salt value
  1133. pbIV - IV value
  1134. pCryptoKeyInfo - Crypto key related information.
  1135. dwKeyLength - Key length to be used to generate the session key. OPTIONAL
  1136. dwEffectiveKeyLength - Effective key length to be used to generate the session key. OPTIONAL
  1137. phSymKey - Resulting symmetric key (CALG_RC2)
  1138. Return Value:
  1139. ERROR_SUCCESS if successful
  1140. Win32 error code otherwise
  1141. --*/
  1142. {
  1143. HCRYPTHASH hHash = 0;
  1144. DWORD cbPassword = 0;
  1145. DWORD Status;
  1146. if (!CryptCreateHash(hProv,
  1147. CALG_SHA1,
  1148. 0,
  1149. 0,
  1150. &hHash))
  1151. {
  1152. Status = GetLastError();
  1153. goto Ret;
  1154. }
  1155. if (!CryptHashData(hHash,
  1156. pbSalt,
  1157. SALT_SIZE,
  1158. 0))
  1159. {
  1160. Status = GetLastError();
  1161. goto Ret;
  1162. }
  1163. if ( ( dwKeyLength == 0 ) || ( dwEffectiveKeyLength == 0 ) )
  1164. {
  1165. //
  1166. // Get the RC2 key length and effective key length to be used for generating the
  1167. // session key. These are the values used by W2K. Thus, we want to ensure that session keys
  1168. // generated at W2K can import the data exported by Windows Server 2003 side and vice versa.
  1169. //
  1170. if ( !CpckGetKeyLength ( pCryptoKeyInfo, &dwKeyLength, &dwEffectiveKeyLength ) )
  1171. {
  1172. Status = GetLastError();
  1173. goto Ret;
  1174. }
  1175. }
  1176. // derive the key from the hash
  1177. if (!CryptDeriveKey(hProv,
  1178. CALG_RC2,
  1179. hHash,
  1180. dwKeyLength << 16, // Set key length. Don't rely on default that changes between OS versions.
  1181. phSymKey))
  1182. {
  1183. Status = GetLastError();
  1184. goto Ret;
  1185. }
  1186. // set the IV on the key
  1187. if (!CryptSetKeyParam(*phSymKey,
  1188. KP_IV,
  1189. pbIV,
  1190. 0))
  1191. {
  1192. Status = GetLastError();
  1193. goto Ret;
  1194. }
  1195. //
  1196. // Set the effective key length on the key. Don't rely on default that changes between OS versions.
  1197. //
  1198. if (!CryptSetKeyParam(*phSymKey,
  1199. KP_EFFECTIVE_KEYLEN,
  1200. (PBYTE)&dwEffectiveKeyLength,
  1201. 0))
  1202. {
  1203. Status = GetLastError();
  1204. goto Ret;
  1205. }
  1206. Status = ERROR_SUCCESS;
  1207. Ret:
  1208. if (hHash)
  1209. CryptDestroyHash(hHash);
  1210. return (Status);
  1211. } // CpckGenSymKey
  1212. DWORD
  1213. CpckExportPrivateKey(
  1214. IN HCRYPTPROV hProv,
  1215. IN HCRYPTKEY hKey,
  1216. IN BYTE *pbIV,
  1217. IN BYTE *pbSalt,
  1218. IN PCRYPTO_KEY_INFO pCryptoKeyInfo,
  1219. OUT BYTE *pbExportedKey,
  1220. OUT DWORD *pcbExportedKey
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Exports the private key data.
  1225. Arguments:
  1226. hProv - Handle to the crypto provider (key container)
  1227. hKey - Handle to the key to export
  1228. pbIV - IV for the symmetric key
  1229. pbSalt - Salt to generate symmetric key
  1230. pCryptoKeyInfo - Crypto key related information.
  1231. pbExportedKey - Supplies the buffer the key is to be exported into
  1232. pcbExportedKey - Supplies the length of the buffer, if pbExportedKey is
  1233. NULL then this will be the length of the key to export
  1234. Return Value:
  1235. ERROR_SUCCESS if successful
  1236. Win32 error code otherwise
  1237. --*/
  1238. {
  1239. HCRYPTKEY hSymKey = 0;
  1240. DWORD Status;
  1241. // create the symmetric key to encrypt the private key with
  1242. Status = CpckGenSymKey(hProv,
  1243. pbSalt,
  1244. pbIV,
  1245. pCryptoKeyInfo,
  1246. 0,
  1247. 0,
  1248. &hSymKey);
  1249. if (0 != Status)
  1250. {
  1251. goto Ret;
  1252. }
  1253. // Export the key
  1254. if (!CryptExportKey(hKey,
  1255. hSymKey,
  1256. PRIVATEKEYBLOB,
  1257. 0,
  1258. pbExportedKey,
  1259. pcbExportedKey))
  1260. {
  1261. Status = GetLastError();
  1262. goto Ret;
  1263. }
  1264. Status = ERROR_SUCCESS;
  1265. Ret:
  1266. if (hSymKey)
  1267. CryptDestroyKey(hSymKey);
  1268. return (Status);
  1269. } // CpckExportPrivateKey
  1270. DWORD
  1271. CpckGetKeyContainerSecDescr(
  1272. IN HCRYPTPROV hProv,
  1273. OUT PSECURITY_DESCRIPTOR *ppSecDescr,
  1274. OUT DWORD *pcbSecDescr
  1275. )
  1276. /*++
  1277. Routine Description:
  1278. Gets the key container security descriptor so that when replicated
  1279. the same descriptor may be set on the replicated key.
  1280. Arguments:
  1281. hProv - Handle to the crypto provider (key container)
  1282. ppSecDescr - Pointer to buffer holding security descriptor
  1283. pcbSecDescr - Pointer to the length of the returned security descriptor
  1284. Return Value:
  1285. ERROR_SUCCESS if successful
  1286. Win32 error code otherwise
  1287. --*/
  1288. {
  1289. PTOKEN_PRIVILEGES pPrevPriv = NULL;
  1290. DWORD cbPrevPriv = 0;
  1291. BYTE rgbNewPriv[ sizeof( TOKEN_PRIVILEGES ) + ( 2 * sizeof( LUID_AND_ATTRIBUTES )) ];
  1292. PTOKEN_PRIVILEGES pNewPriv = (PTOKEN_PRIVILEGES)rgbNewPriv;
  1293. SECURITY_DESCRIPTOR_CONTROL Control;
  1294. DWORD dwRevision;
  1295. HANDLE hThreadToken = 0;
  1296. PSECURITY_DESCRIPTOR pNewSD = NULL;
  1297. DWORD dw;
  1298. DWORD dwFlags;
  1299. DWORD Status = ERROR_SUCCESS;
  1300. BOOLEAN threadHasNoToken = TRUE;
  1301. //
  1302. // if we already have a thread token, use it for adjusting the privs
  1303. //
  1304. if (FALSE == OpenThreadToken(GetCurrentThread(),
  1305. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1306. TRUE,
  1307. &hThreadToken))
  1308. {
  1309. HANDLE hProcToken;
  1310. BOOL success;
  1311. //
  1312. // no thread token; dup the process token for eventual assignment to
  1313. // our thread. This way, privileges are enabled at the thread level
  1314. // instead of at the process level.
  1315. //
  1316. if (FALSE == OpenProcessToken( GetCurrentProcess(), TOKEN_DUPLICATE, &hProcToken ))
  1317. {
  1318. Status = GetLastError();
  1319. goto Ret;
  1320. }
  1321. success = DuplicateTokenEx(hProcToken,
  1322. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1323. NULL, // token attrs - use default SD
  1324. SecurityImpersonation,
  1325. TokenImpersonation,
  1326. &hThreadToken );
  1327. CloseHandle(hProcToken);
  1328. if ( !success )
  1329. {
  1330. Status = GetLastError();
  1331. goto Ret;
  1332. }
  1333. } else {
  1334. threadHasNoToken = FALSE;
  1335. }
  1336. //
  1337. // Adjust token privileges to enable SE_RESTORE_NAME and SE_SECURITY_NAME privileges.
  1338. // The former is needed since we are passing OWNER_SECURITY_INFORMATION flags to
  1339. // CryptGetProvParam and the latter is needed since we are passing SACL_SECURITY_INFORMATION
  1340. // flags.
  1341. //
  1342. memset(rgbNewPriv, 0, sizeof(rgbNewPriv));
  1343. pNewPriv->PrivilegeCount = 2;
  1344. if(!LookupPrivilegeValueW(NULL, SE_SECURITY_NAME,
  1345. &(pNewPriv->Privileges[0].Luid)))
  1346. {
  1347. Status = GetLastError();
  1348. goto Ret;
  1349. }
  1350. if(!LookupPrivilegeValueW(NULL, SE_RESTORE_NAME,
  1351. &(pNewPriv->Privileges[1].Luid)))
  1352. {
  1353. Status = GetLastError();
  1354. goto Ret;
  1355. }
  1356. pNewPriv->Privileges[0].Attributes = pNewPriv->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
  1357. // get the length of the previous state
  1358. AdjustTokenPrivileges(hThreadToken,
  1359. FALSE,
  1360. (PTOKEN_PRIVILEGES)pNewPriv,
  1361. sizeof(dw),
  1362. (PTOKEN_PRIVILEGES)&dw,
  1363. &cbPrevPriv);
  1364. // alloc for the previous state
  1365. if (NULL == (pPrevPriv = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_ZEROINIT,
  1366. cbPrevPriv)))
  1367. {
  1368. Status = ERROR_NOT_ENOUGH_MEMORY;
  1369. goto Ret;
  1370. }
  1371. // adjust the privileges and get the previous state
  1372. if (!AdjustTokenPrivileges(hThreadToken,
  1373. FALSE,
  1374. pNewPriv,
  1375. cbPrevPriv,
  1376. (PTOKEN_PRIVILEGES)pPrevPriv,
  1377. &cbPrevPriv))
  1378. {
  1379. Status = GetLastError();
  1380. goto Ret;
  1381. }
  1382. if ( threadHasNoToken ) {
  1383. if ( FALSE == SetThreadToken( NULL, hThreadToken )) {
  1384. Status = GetLastError();
  1385. goto Ret;
  1386. }
  1387. }
  1388. dwFlags = OWNER_SECURITY_INFORMATION |
  1389. GROUP_SECURITY_INFORMATION |
  1390. DACL_SECURITY_INFORMATION |
  1391. SACL_SECURITY_INFORMATION ;
  1392. // get the security descriptor
  1393. if (CryptGetProvParam(hProv,
  1394. PP_KEYSET_SEC_DESCR,
  1395. NULL,
  1396. pcbSecDescr,
  1397. dwFlags))
  1398. {
  1399. if (NULL != (*ppSecDescr =
  1400. (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_ZEROINIT,
  1401. *pcbSecDescr)))
  1402. {
  1403. if (!CryptGetProvParam(hProv,
  1404. PP_KEYSET_SEC_DESCR,
  1405. (BYTE*)(*ppSecDescr),
  1406. pcbSecDescr,
  1407. dwFlags))
  1408. {
  1409. Status = GetLastError();
  1410. }
  1411. }
  1412. else
  1413. {
  1414. Status = ERROR_NOT_ENOUGH_MEMORY;
  1415. }
  1416. }
  1417. else
  1418. {
  1419. Status = GetLastError();
  1420. }
  1421. //
  1422. // revert back to previous privilege level
  1423. //
  1424. if ( threadHasNoToken ) {
  1425. if ( FALSE == SetThreadToken( NULL, NULL )) {
  1426. Status = GetLastError();
  1427. goto Ret;
  1428. }
  1429. } else {
  1430. if (!AdjustTokenPrivileges(hThreadToken,
  1431. FALSE,
  1432. pPrevPriv,
  1433. 0,
  1434. NULL,
  1435. NULL))
  1436. {
  1437. Status = GetLastError();
  1438. goto Ret;
  1439. }
  1440. }
  1441. //
  1442. // bail if we encountered any errors while getting SD info
  1443. //
  1444. if (ERROR_SUCCESS != Status)
  1445. {
  1446. goto Ret;
  1447. }
  1448. // ge the control on the security descriptor to check if self relative
  1449. if (!GetSecurityDescriptorControl(*ppSecDescr,
  1450. &Control,
  1451. &dwRevision))
  1452. {
  1453. Status = GetLastError();
  1454. goto Ret;
  1455. }
  1456. // if not self relative then make a self relative copy
  1457. if (!(SE_SELF_RELATIVE & Control))
  1458. {
  1459. if (NULL == (pNewSD =
  1460. (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_ZEROINIT,
  1461. *pcbSecDescr)))
  1462. {
  1463. Status = ERROR_NOT_ENOUGH_MEMORY;
  1464. goto Ret;
  1465. }
  1466. if (!MakeSelfRelativeSD(*ppSecDescr,
  1467. pNewSD,
  1468. pcbSecDescr))
  1469. {
  1470. Status = GetLastError();
  1471. goto Ret;
  1472. }
  1473. LocalFree(*ppSecDescr);
  1474. *ppSecDescr = (BYTE*)pNewSD;
  1475. pNewSD = NULL;
  1476. }
  1477. Status = ERROR_SUCCESS;
  1478. Ret:
  1479. if (pPrevPriv)
  1480. LocalFree(pPrevPriv);
  1481. if (pNewSD)
  1482. LocalFree(pNewSD);
  1483. if (hThreadToken)
  1484. CloseHandle(hThreadToken);
  1485. return Status;
  1486. } // CpckGetKeyContainerSecDescr
  1487. DWORD
  1488. CpckStoreKeyContainer(
  1489. IN HCRYPTPROV hProv,
  1490. IN CRYPTO_KEY_INFO *pCryptoKeyInfo,
  1491. IN LPWSTR TempFile
  1492. )
  1493. /*++
  1494. Routine Description:
  1495. Writes the key container associated with the provider handle to a
  1496. the specified file.
  1497. Arguments:
  1498. hProv - Handle to the crypto provider (key container)
  1499. pCryptoKeyInfo - Crypto key information (password if given)
  1500. TempFile - Supplies the file which the key data is to be written to
  1501. Return Value:
  1502. ERROR_SUCCESS if successful
  1503. Win32 error code otherwise
  1504. --*/
  1505. {
  1506. CRYPTO_KEY_FILE_DATA KeyFileData;
  1507. HCRYPTKEY hSigKey = 0;
  1508. HCRYPTKEY hExchKey = 0;
  1509. BYTE *pb = NULL;
  1510. DWORD cb = 0;
  1511. DWORD dwBytesWritten;
  1512. QfsHANDLE hFile = QfsINVALID_HANDLE_VALUE;
  1513. DWORD dwPermissions = 0;
  1514. DWORD cbPermissions ;
  1515. PSECURITY_DESCRIPTOR pSecDescr = NULL;
  1516. DWORD cbSecDescr;
  1517. DWORD Status;
  1518. memset(&KeyFileData, 0, sizeof(KeyFileData));
  1519. // generate the necessary random data for salt and IVs.
  1520. // calls with the sig IV buffer but this will fill the
  1521. // exch IV and Salt as well since the buffer len is 32
  1522. if (!CryptGenRandom(hProv,
  1523. sizeof(struct _CRYPTO_KEY_FILE_INITIALIZATION_DATA),
  1524. KeyFileData.rgbSigIV))
  1525. {
  1526. Status = GetLastError();
  1527. goto Ret;
  1528. }
  1529. KeyFileData.dwVersion = CRYPTO_KEY_FILE_DATA_VERSION;
  1530. // calculate the length of key data
  1531. cb = sizeof(KeyFileData);
  1532. // get the self relative security descriptor
  1533. Status = CpckGetKeyContainerSecDescr(hProv,
  1534. &pSecDescr,
  1535. &cbSecDescr);
  1536. if (ERROR_SUCCESS != Status)
  1537. {
  1538. goto Ret;
  1539. }
  1540. cb += cbSecDescr;
  1541. // get sig key length if necessary
  1542. if (CryptGetUserKey(hProv, AT_SIGNATURE, &hSigKey))
  1543. {
  1544. // check if key is exportable
  1545. cbPermissions = sizeof(DWORD);
  1546. if (!CryptGetKeyParam(hSigKey,
  1547. KP_PERMISSIONS,
  1548. (BYTE*)&dwPermissions,
  1549. &cbPermissions,
  1550. 0))
  1551. {
  1552. Status = GetLastError();
  1553. goto Ret;
  1554. }
  1555. if (!(dwPermissions & CRYPT_EXPORT))
  1556. {
  1557. Status = (DWORD)NTE_BAD_KEY;
  1558. goto Ret;
  1559. }
  1560. // get the sig key length
  1561. Status = CpckExportPrivateKey(hProv,
  1562. hSigKey,
  1563. KeyFileData.rgbSigIV,
  1564. KeyFileData.rgbSalt,
  1565. pCryptoKeyInfo,
  1566. NULL,
  1567. &(KeyFileData.cbSig));
  1568. if (0 != Status)
  1569. {
  1570. goto Ret;
  1571. }
  1572. cb += KeyFileData.cbSig;
  1573. }
  1574. // get key exchange key length if necessary
  1575. if (CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hExchKey))
  1576. {
  1577. // check if key is exportable
  1578. dwPermissions = 0;
  1579. cbPermissions = sizeof(DWORD);
  1580. if (!CryptGetKeyParam(hExchKey,
  1581. KP_PERMISSIONS,
  1582. (BYTE*)&dwPermissions,
  1583. &cbPermissions,
  1584. 0))
  1585. {
  1586. Status = GetLastError();
  1587. goto Ret;
  1588. }
  1589. if (!(dwPermissions & CRYPT_EXPORT))
  1590. {
  1591. Status = (DWORD)NTE_BAD_KEY;
  1592. goto Ret;
  1593. }
  1594. // get the exchange key length
  1595. Status = CpckExportPrivateKey(hProv,
  1596. hExchKey,
  1597. KeyFileData.rgbExchIV,
  1598. KeyFileData.rgbSalt,
  1599. pCryptoKeyInfo,
  1600. NULL,
  1601. &(KeyFileData.cbExch));
  1602. if (0 != Status)
  1603. {
  1604. goto Ret;
  1605. }
  1606. cb += KeyFileData.cbExch;
  1607. }
  1608. // allocate space for the keys
  1609. if (NULL == (pb = LocalAlloc(LMEM_ZEROINIT, cb)))
  1610. {
  1611. Status = ERROR_NOT_ENOUGH_MEMORY;
  1612. goto Ret;
  1613. }
  1614. // copy the key file data into the pb
  1615. cb = sizeof(KeyFileData);
  1616. // copy the signature key
  1617. if (0 != hSigKey)
  1618. {
  1619. Status = CpckExportPrivateKey(hProv,
  1620. hSigKey,
  1621. KeyFileData.rgbSigIV,
  1622. KeyFileData.rgbSalt,
  1623. pCryptoKeyInfo,
  1624. pb + cb,
  1625. &(KeyFileData.cbSig));
  1626. if (0 != Status)
  1627. {
  1628. goto Ret;
  1629. }
  1630. cb += KeyFileData.cbSig;
  1631. }
  1632. // copy the key exchange key
  1633. if (0 != hExchKey)
  1634. {
  1635. Status = CpckExportPrivateKey(hProv,
  1636. hExchKey,
  1637. KeyFileData.rgbExchIV,
  1638. KeyFileData.rgbSalt,
  1639. pCryptoKeyInfo,
  1640. pb + cb,
  1641. &(KeyFileData.cbExch));
  1642. if (0 != Status)
  1643. {
  1644. goto Ret;
  1645. }
  1646. cb += KeyFileData.cbExch;
  1647. }
  1648. // copy the security descriptor
  1649. CopyMemory(pb + cb, (BYTE*)pSecDescr, cbSecDescr);
  1650. cb += cbSecDescr;
  1651. // copy the lengths
  1652. CopyMemory(pb, &KeyFileData, sizeof(KeyFileData));
  1653. // write the buffer to the file
  1654. hFile = QfsCreateFile(TempFile,
  1655. GENERIC_WRITE,
  1656. 0,
  1657. NULL,
  1658. OPEN_ALWAYS,
  1659. FILE_FLAG_SEQUENTIAL_SCAN,
  1660. NULL);
  1661. if ( !QfsIsHandleValid(hFile) )
  1662. {
  1663. Status = GetLastError();
  1664. goto Ret;
  1665. }
  1666. if (!QfsWriteFile(hFile, pb, cb, &dwBytesWritten, NULL))
  1667. {
  1668. Status = GetLastError();
  1669. goto Ret;
  1670. }
  1671. Status = ERROR_SUCCESS;
  1672. Ret:
  1673. if (pSecDescr)
  1674. LocalFree(pSecDescr);
  1675. QfsCloseHandleIfValid(hFile);
  1676. if (pb)
  1677. LocalFree(pb);
  1678. if (hSigKey)
  1679. CryptDestroyKey(hSigKey);
  1680. if (hExchKey)
  1681. CryptDestroyKey(hExchKey);
  1682. return (Status);
  1683. } // CpckStoreKeyContainer
  1684. DWORD
  1685. CpckSaveCheckpointToFile(
  1686. IN HCRYPTPROV hProv,
  1687. IN CRYPTO_KEY_INFO *pCryptoKeyInfo,
  1688. IN LPWSTR TempFile)
  1689. /*++
  1690. Routine Description:
  1691. have DM create a temp file and call the routine that exports the keys and
  1692. writes the checkpoint file.
  1693. Arguments:
  1694. hProv - Handle to the crypto provider (key container)
  1695. pCryptoKeyInfo - Crypto key information (password if given)
  1696. TempFile - Supplies the file which the key data is to be written to
  1697. Return Value:
  1698. ERROR_SUCCESS if successful
  1699. Win32 error code otherwise
  1700. --*/
  1701. {
  1702. DWORD Status;
  1703. Status = DmCreateTempFileName(TempFile);
  1704. if (Status != ERROR_SUCCESS) {
  1705. CL_UNEXPECTED_ERROR( Status );
  1706. TempFile[0] = L'\0';
  1707. return(Status);
  1708. }
  1709. // put the key information into the file
  1710. Status = CpckStoreKeyContainer(hProv, pCryptoKeyInfo, TempFile);
  1711. if (Status != ERROR_SUCCESS)
  1712. {
  1713. ClRtlLogPrint(LOG_UNUSUAL,
  1714. "[CPCK] CpckSaveCheckpointToFile failed to get store container %1!ws! %2!ws! to file %3!ws! error %4!d!\n",
  1715. pCryptoKeyInfo->pwszContainer,
  1716. pCryptoKeyInfo->pwszProvName,
  1717. TempFile,
  1718. Status);
  1719. CL_LOGFAILURE(Status);
  1720. QfsDeleteFile(TempFile);
  1721. TempFile[0] = L'\0';
  1722. }
  1723. return(Status);
  1724. } // CpckSaveCheckpointToFile
  1725. DWORD
  1726. CpckCheckpoint(
  1727. IN PFM_RESOURCE Resource,
  1728. IN HCRYPTPROV hProv,
  1729. IN DWORD dwId,
  1730. IN CRYPTO_KEY_INFO *pCryptoKeyInfo
  1731. )
  1732. /*++
  1733. Routine Description:
  1734. Takes a checkpoint of the specified crypto key.
  1735. Arguments:
  1736. Resource - Supplies the resource this is a checkpoint for.
  1737. hKey - Supplies the crypto info to checkpoint
  1738. dwId - Supplies the checkpoint ID.
  1739. KeyName - Supplies the name of the registry key.
  1740. Return Value:
  1741. ERROR_SUCCESS if successful
  1742. Win32 error code otherwise
  1743. --*/
  1744. {
  1745. DWORD Status;
  1746. WCHAR TempFile[MAX_PATH];
  1747. Status = CpckSaveCheckpointToFile(hProv, pCryptoKeyInfo, TempFile);
  1748. if (Status == ERROR_SUCCESS)
  1749. {
  1750. //
  1751. // Got a file with the right bits in it. Checkpoint the
  1752. // file.
  1753. //
  1754. Status = CpSaveDataFile(Resource,
  1755. dwId,
  1756. TempFile,
  1757. TRUE);
  1758. if (Status != ERROR_SUCCESS) {
  1759. ClRtlLogPrint(LOG_CRITICAL,
  1760. "[CPCK] CpckCheckpoint - CpSaveData failed %1!d!\n",
  1761. Status);
  1762. }
  1763. }
  1764. //if the file was created, delete it
  1765. if (TempFile[0] != L'\0')
  1766. QfsDeleteFile(TempFile);
  1767. return(Status);
  1768. } // CpckCheckpoint
  1769. DWORD
  1770. CpckSetKeyContainerSecDescr(
  1771. IN HCRYPTPROV hProv,
  1772. IN BYTE *pbSecDescr,
  1773. IN DWORD cbSecDescr
  1774. )
  1775. /*++
  1776. Routine Description:
  1777. Sets the key container security descriptor.
  1778. Arguments:
  1779. hProv - Handle to the crypto provider (key container)
  1780. pbSecDescr - Buffer holding security descriptor
  1781. cbSecDescr - Length of the security descriptor
  1782. Return Value:
  1783. ERROR_SUCCESS if successful
  1784. Win32 error code otherwise
  1785. --*/
  1786. {
  1787. PTOKEN_PRIVILEGES pPrevPriv = NULL;
  1788. DWORD cbPrevPriv = 0;
  1789. BYTE rgbNewPriv[ sizeof( TOKEN_PRIVILEGES ) + ( 2 * sizeof( LUID_AND_ATTRIBUTES )) ];
  1790. PTOKEN_PRIVILEGES pNewPriv = (PTOKEN_PRIVILEGES)rgbNewPriv;
  1791. HANDLE hThreadToken = 0;
  1792. DWORD dw;
  1793. DWORD dwFlags;
  1794. DWORD Status = ERROR_SUCCESS;
  1795. BOOLEAN threadHasNoToken = TRUE;
  1796. //
  1797. // if we already have a thread token, use it for adjusting the privs
  1798. //
  1799. if (FALSE == OpenThreadToken(GetCurrentThread(),
  1800. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1801. TRUE,
  1802. &hThreadToken))
  1803. {
  1804. HANDLE hProcToken;
  1805. BOOL success;
  1806. //
  1807. // no thread token; dup the process token for eventual assignment to
  1808. // our thread. This way, privileges are enabled at the thread level
  1809. // instead of at the process level.
  1810. //
  1811. if (FALSE == OpenProcessToken( GetCurrentProcess(), TOKEN_DUPLICATE, &hProcToken ))
  1812. {
  1813. Status = GetLastError();
  1814. goto Ret;
  1815. }
  1816. success = DuplicateTokenEx(hProcToken,
  1817. TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1818. NULL, // token attrs - use default SD
  1819. SecurityImpersonation,
  1820. TokenImpersonation,
  1821. &hThreadToken );
  1822. CloseHandle(hProcToken);
  1823. if ( !success )
  1824. {
  1825. Status = GetLastError();
  1826. goto Ret;
  1827. }
  1828. } else {
  1829. threadHasNoToken = FALSE;
  1830. }
  1831. //
  1832. // Adjust token privileges to enable SE_RESTORE_NAME and SE_SECURITY_NAME privileges.
  1833. // The former is needed since we are passing OWNER_SECURITY_INFORMATION flags to
  1834. // CryptSetProvParam and the latter is needed since we are passing SACL_SECURITY_INFORMATION
  1835. // flags.
  1836. //
  1837. memset(rgbNewPriv, 0, sizeof(rgbNewPriv));
  1838. pNewPriv->PrivilegeCount = 2;
  1839. if(!LookupPrivilegeValueW(NULL, SE_SECURITY_NAME,
  1840. &(pNewPriv->Privileges[0].Luid)))
  1841. {
  1842. Status = GetLastError();
  1843. goto Ret;
  1844. }
  1845. if(!LookupPrivilegeValueW(NULL, SE_RESTORE_NAME,
  1846. &(pNewPriv->Privileges[1].Luid)))
  1847. {
  1848. Status = GetLastError();
  1849. goto Ret;
  1850. }
  1851. pNewPriv->Privileges[0].Attributes = pNewPriv->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
  1852. // get the length of the previous state
  1853. AdjustTokenPrivileges(hThreadToken,
  1854. FALSE,
  1855. (PTOKEN_PRIVILEGES)pNewPriv,
  1856. sizeof(dw),
  1857. (PTOKEN_PRIVILEGES)&dw,
  1858. &cbPrevPriv);
  1859. // alloc for the previous state
  1860. if (NULL == (pPrevPriv = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_ZEROINIT,
  1861. cbPrevPriv)))
  1862. {
  1863. Status = ERROR_NOT_ENOUGH_MEMORY;
  1864. goto Ret;
  1865. }
  1866. // adjust the privileges and get the previous state
  1867. if ( !AdjustTokenPrivileges(hThreadToken,
  1868. FALSE,
  1869. pNewPriv,
  1870. cbPrevPriv,
  1871. (PTOKEN_PRIVILEGES)pPrevPriv,
  1872. &cbPrevPriv))
  1873. {
  1874. Status = GetLastError();
  1875. goto Ret;
  1876. }
  1877. if ( threadHasNoToken ) {
  1878. if ( FALSE == SetThreadToken( NULL, hThreadToken )) {
  1879. Status = GetLastError();
  1880. goto Ret;
  1881. }
  1882. }
  1883. dwFlags = OWNER_SECURITY_INFORMATION |
  1884. GROUP_SECURITY_INFORMATION |
  1885. DACL_SECURITY_INFORMATION |
  1886. SACL_SECURITY_INFORMATION ;
  1887. // get the security descriptor
  1888. if (!CryptSetProvParam(hProv,
  1889. PP_KEYSET_SEC_DESCR,
  1890. pbSecDescr,
  1891. dwFlags))
  1892. {
  1893. Status = GetLastError();
  1894. }
  1895. //
  1896. // revert back to previous privilege level
  1897. //
  1898. if ( threadHasNoToken ) {
  1899. if ( FALSE == SetThreadToken( NULL, NULL )) {
  1900. Status = GetLastError();
  1901. goto Ret;
  1902. }
  1903. } else {
  1904. if (!AdjustTokenPrivileges(hThreadToken,
  1905. FALSE,
  1906. pPrevPriv,
  1907. 0,
  1908. NULL,
  1909. NULL))
  1910. {
  1911. Status = GetLastError();
  1912. goto Ret;
  1913. }
  1914. }
  1915. if (ERROR_SUCCESS != Status)
  1916. {
  1917. goto Ret;
  1918. }
  1919. Status = ERROR_SUCCESS;
  1920. Ret:
  1921. if (pPrevPriv)
  1922. LocalFree(pPrevPriv);
  1923. if (hThreadToken)
  1924. CloseHandle(hThreadToken);
  1925. return Status;
  1926. } // CpCkSetKeyContainerSecDescr
  1927. DWORD
  1928. CpckImportPrivateKey(
  1929. IN HCRYPTPROV hProv,
  1930. IN BYTE *pbIV,
  1931. IN BYTE *pbSalt,
  1932. IN BYTE *pbKey,
  1933. IN DWORD cbKey,
  1934. IN PCRYPTO_KEY_INFO pCryptoKeyInfo
  1935. )
  1936. /*++
  1937. Routine Description:
  1938. Exports the private key data.
  1939. Arguments:
  1940. hProv - Handle to the crypto provider (key container)
  1941. hKey - Handle to the key to export
  1942. pbIV - IV for the symmetric key
  1943. pbSalt - Salt to generate symmetric key
  1944. pbKey - Supplies the buffer the key is in
  1945. cbKey - Supplies the length of the key buffer
  1946. pCryptoKeyInfo - Crypto key related information.
  1947. Return Value:
  1948. ERROR_SUCCESS if successful
  1949. Win32 error code otherwise
  1950. --*/
  1951. {
  1952. BOOLEAN WasEnabled;
  1953. HCRYPTKEY hSymKey = 0;
  1954. HCRYPTKEY hKey = 0;
  1955. DWORD Status = ERROR_SUCCESS;
  1956. //
  1957. // Create the symmetric key to encrypt the private key with
  1958. //
  1959. Status = CpckGenSymKey(hProv,
  1960. pbSalt,
  1961. pbIV,
  1962. pCryptoKeyInfo,
  1963. 0,
  1964. 0,
  1965. &hSymKey);
  1966. if (0 != Status)
  1967. {
  1968. goto Ret;
  1969. }
  1970. //
  1971. // Import the key
  1972. //
  1973. if (!CryptImportKey(hProv,
  1974. pbKey,
  1975. cbKey,
  1976. hSymKey,
  1977. CRYPT_EXPORTABLE,
  1978. &hKey))
  1979. {
  1980. //
  1981. // If failed then try with BACKUP/RESTORE privilege enabled
  1982. //
  1983. Status = ClRtlEnableThreadPrivilege(SE_RESTORE_PRIVILEGE,
  1984. &WasEnabled);
  1985. if (Status != ERROR_SUCCESS)
  1986. {
  1987. ClRtlLogPrint(LOG_CRITICAL, "[CPCK] CpckImportPrivateKey: Failed to enable thread privilege, status %1!d!\n",
  1988. Status);
  1989. goto Ret;
  1990. }
  1991. if (!CryptImportKey(hProv,
  1992. pbKey,
  1993. cbKey,
  1994. hSymKey,
  1995. CRYPT_EXPORTABLE,
  1996. &hKey))
  1997. {
  1998. ClRtlLogPrint(LOG_UNUSUAL, "[CPCK] CpckImportPrivateKey: Failed to import key for provider %1!ws!, status %2!d!\n",
  1999. pCryptoKeyInfo->pwszProvName,
  2000. GetLastError());
  2001. if ( hSymKey )
  2002. {
  2003. CryptDestroyKey( hSymKey );
  2004. hSymKey = 0;
  2005. }
  2006. //
  2007. // If the key was unable to be imported even after enabling the restore privilege,
  2008. // give the import a last chance by specifying the key lengths to be 40 bits. This
  2009. // retry is necessary since the Windows Server 2003 RC1 already had a bug by which
  2010. // it exported the keys with these parameters. To import those keys, this is the only
  2011. // way out.
  2012. //
  2013. Status = CpckGenSymKey(hProv,
  2014. pbSalt,
  2015. pbIV,
  2016. pCryptoKeyInfo,
  2017. 40,
  2018. 40,
  2019. &hSymKey);
  2020. if (Status != ERROR_SUCCESS)
  2021. {
  2022. goto Ret;
  2023. }
  2024. //
  2025. // Import the key with 40 bit key lengths
  2026. //
  2027. if (!CryptImportKey(hProv,
  2028. pbKey,
  2029. cbKey,
  2030. hSymKey,
  2031. CRYPT_EXPORTABLE,
  2032. &hKey))
  2033. {
  2034. Status = GetLastError();
  2035. ClRtlLogPrint(LOG_CRITICAL, "[CPCK] CpckImportPrivateKey: Failed to import key for provider %1!ws! with 40 bit session key lengths, status %2!d!\n",
  2036. pCryptoKeyInfo->pwszProvName,
  2037. Status);
  2038. }
  2039. }
  2040. ClRtlRestoreThreadPrivilege(SE_RESTORE_PRIVILEGE,
  2041. WasEnabled);
  2042. }
  2043. Ret:
  2044. if (hSymKey)
  2045. CryptDestroyKey(hSymKey);
  2046. if (hKey)
  2047. CryptDestroyKey(hKey);
  2048. return (Status);
  2049. } // CpckImportPrivateKey
  2050. DWORD
  2051. CpckInstallKeyContainer(
  2052. IN HCRYPTPROV hProv,
  2053. IN LPWSTR FileName,
  2054. IN PCRYPTO_KEY_INFO pCryptoKeyInfo
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. Installs new crypto key information from a specified file.
  2059. Arguments:
  2060. hProv - Supplies the provider handle where FileName will be installed to.
  2061. FileName - The name of the file from which to read the crypto key info
  2062. to install.
  2063. pCryptoKeyInfo - Crypto key related information.
  2064. Return Value:
  2065. ERROR_SUCCESS if the installation completed successfully
  2066. Win32 error code otherwise.
  2067. --*/
  2068. {
  2069. HANDLE hMap = NULL;
  2070. BYTE *pbFile = NULL;
  2071. QfsHANDLE hFile = QfsINVALID_HANDLE_VALUE;
  2072. DWORD cbFile = 0;
  2073. DWORD *pdwVersion;
  2074. CRYPTO_KEY_FILE_DATA *pKeyFileData;
  2075. DWORD Status;
  2076. // read the key data from the file
  2077. hFile = QfsCreateFile(FileName,
  2078. GENERIC_READ,
  2079. FILE_SHARE_READ,
  2080. NULL,
  2081. OPEN_EXISTING,
  2082. FILE_FLAG_SEQUENTIAL_SCAN,
  2083. NULL);
  2084. if (!QfsIsHandleValid(hFile) )
  2085. {
  2086. Status = GetLastError();
  2087. goto Ret;
  2088. }
  2089. if (0xFFFFFFFF == (cbFile = QfsGetFileSize(hFile, NULL)))
  2090. {
  2091. Status = GetLastError();
  2092. goto Ret;
  2093. }
  2094. if (sizeof(CRYPTO_KEY_FILE_DATA) > cbFile)
  2095. {
  2096. Status = ERROR_FILE_INVALID;
  2097. goto Ret;
  2098. }
  2099. if (NULL == (hMap = QfsCreateFileMapping(hFile, NULL, PAGE_READONLY,
  2100. 0, 0, NULL)))
  2101. {
  2102. Status = GetLastError();
  2103. goto Ret;
  2104. }
  2105. if (NULL == (pbFile = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ,
  2106. 0, 0, 0 )))
  2107. {
  2108. Status = GetLastError();
  2109. goto Ret;
  2110. }
  2111. // get the length information out of the file
  2112. pKeyFileData = (CRYPTO_KEY_FILE_DATA*)pbFile;
  2113. if (CRYPTO_KEY_FILE_DATA_VERSION != pKeyFileData->dwVersion)
  2114. {
  2115. Status = ERROR_FILE_INVALID;
  2116. goto Ret;
  2117. }
  2118. if ((sizeof(CRYPTO_KEY_FILE_DATA) + pKeyFileData->cbSig +
  2119. pKeyFileData->cbExch) > cbFile)
  2120. {
  2121. Status = ERROR_FILE_INVALID;
  2122. goto Ret;
  2123. }
  2124. if (pKeyFileData->cbSig)
  2125. {
  2126. // import the sig key if there is one
  2127. Status = CpckImportPrivateKey(hProv,
  2128. pKeyFileData->rgbSigIV,
  2129. pKeyFileData->rgbSalt,
  2130. pbFile + sizeof(CRYPTO_KEY_FILE_DATA),
  2131. pKeyFileData->cbSig,
  2132. pCryptoKeyInfo);
  2133. if (0 != Status)
  2134. {
  2135. goto Ret;
  2136. }
  2137. }
  2138. if (pKeyFileData->cbExch)
  2139. {
  2140. // import the exch key if there is one
  2141. Status = CpckImportPrivateKey(hProv,
  2142. pKeyFileData->rgbExchIV,
  2143. pKeyFileData->rgbSalt,
  2144. pbFile + sizeof(CRYPTO_KEY_FILE_DATA) +
  2145. pKeyFileData->cbSig,
  2146. pKeyFileData->cbExch,
  2147. pCryptoKeyInfo);
  2148. if (0 != Status)
  2149. {
  2150. goto Ret;
  2151. }
  2152. }
  2153. Status = CpckSetKeyContainerSecDescr(hProv,
  2154. pbFile + sizeof(CRYPTO_KEY_FILE_DATA) +
  2155. pKeyFileData->cbSig + pKeyFileData->cbExch,
  2156. pKeyFileData->cbSecDescr);
  2157. if (ERROR_SUCCESS != Status)
  2158. {
  2159. goto Ret;
  2160. }
  2161. Status = ERROR_SUCCESS;
  2162. Ret:
  2163. if(pbFile)
  2164. UnmapViewOfFile(pbFile);
  2165. if(hMap)
  2166. CloseHandle(hMap);
  2167. QfsCloseHandleIfValid(hFile);
  2168. return(Status);
  2169. } // CpckInstallKeyContainer
  2170. DWORD
  2171. CpckDeleteFile(
  2172. IN PFM_RESOURCE Resource,
  2173. IN DWORD dwCheckpointId,
  2174. IN OPTIONAL LPCWSTR lpszQuorumPath
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. Gets the file corresponding to the checkpoint id relative
  2179. to the supplied path and deletes it.
  2180. Arguments:
  2181. PFM_RESOURCE - Supplies the pointer to the resource.
  2182. dwCheckpointId - The checkpoint id to be deleted. If 0, all
  2183. checkpoints are deleted.
  2184. lpszQuorumPath - If specified, the checkpoint file relative
  2185. to this path is deleted.
  2186. Return Value:
  2187. ERROR_SUCCESS if the completed successfully
  2188. Win32 error code otherwise.
  2189. --*/
  2190. {
  2191. DWORD Status;
  2192. LPWSTR pszFileName=NULL;
  2193. LPWSTR pszDirectoryName=NULL;
  2194. Status = CppGetCheckpointFile(Resource, dwCheckpointId,
  2195. &pszDirectoryName, &pszFileName, lpszQuorumPath, TRUE);
  2196. if (Status != ERROR_SUCCESS) {
  2197. ClRtlLogPrint(LOG_CRITICAL,
  2198. "[CPCK] CpckDeleteFile- couldnt get checkpoint file name, error %1!d!\n",
  2199. Status);
  2200. goto FnExit;
  2201. }
  2202. if (!QfsDeleteFile(pszFileName))
  2203. {
  2204. Status = GetLastError();
  2205. ClRtlLogPrint(LOG_CRITICAL,
  2206. "[CPCK] CpckDeleteFile - couldn't delete the file, error %1!d!\n",
  2207. Status);
  2208. goto FnExit;
  2209. }
  2210. //
  2211. // Now try and delete the directory.
  2212. //
  2213. if (!QfsRemoveDirectory(pszDirectoryName))
  2214. {
  2215. //if there is a failure, we still return success
  2216. //because it may not be possible to delete a directory
  2217. //when it is not empty
  2218. ClRtlLogPrint(LOG_UNUSUAL,
  2219. "[CPCK] CpckDeleteFile- unable to remove directory %1!ws!, error %2!d!\n",
  2220. pszDirectoryName,
  2221. GetLastError());
  2222. }
  2223. FnExit:
  2224. if (pszFileName)
  2225. LocalFree(pszFileName);
  2226. if (pszDirectoryName)
  2227. LocalFree(pszDirectoryName);
  2228. return(Status);
  2229. } // CpckDeleteFile
  2230. BOOL
  2231. CpckRemoveCheckpointFileCallback(
  2232. IN LPWSTR ValueName,
  2233. IN LPVOID ValueData,
  2234. IN DWORD ValueType,
  2235. IN DWORD ValueSize,
  2236. IN PCP_CALLBACK_CONTEXT Context
  2237. )
  2238. /*++
  2239. Routine Description:
  2240. Registry value enumeration callback used when the quorum resource
  2241. is changing. Deletes the specified checkpoint file from the old
  2242. quorum directory.
  2243. Arguments:
  2244. ValueName - Supplies the name of the value (this is the checkpoint ID)
  2245. ValueData - Supplies the value data (this is the crypto info)
  2246. ValueType - Supplies the value type (must be REG_BINARY)
  2247. ValueSize - Supplies the size of ValueData
  2248. Context - Supplies the quorum change context (old path and resource)
  2249. Return Value:
  2250. TRUE to continue enumeration
  2251. --*/
  2252. {
  2253. DWORD Status;
  2254. DWORD Id;
  2255. Id = wcstol(ValueName, NULL, 16);
  2256. if (Id == 0) {
  2257. ClRtlLogPrint(LOG_UNUSUAL,
  2258. "[CPCK] CpckRemoveCheckpointFileCallback invalid checkpoint ID %1!ws! for resource %2!ws!\n",
  2259. ValueName,
  2260. OmObjectName(Context->Resource));
  2261. return(TRUE);
  2262. }
  2263. Status = CpckDeleteFile(Context->Resource, Id, Context->lpszPathName);
  2264. return(TRUE);
  2265. } // CpckRemoveCheckpointFileCallback
  2266. DWORD
  2267. CpckDeleteCheckpointFile(
  2268. IN PFM_RESOURCE Resource,
  2269. IN DWORD dwCheckpointId,
  2270. IN OPTIONAL LPCWSTR lpszQuorumPath
  2271. )
  2272. /*++
  2273. Routine Description:
  2274. Deletes the checkpoint file corresponding the resource.
  2275. This node must be the owner of the quorum resource
  2276. Arguments:
  2277. PFM_RESOURCE - Supplies the pointer to the resource.
  2278. dwCheckpointId - The checkpoint id to be deleted. If 0, all
  2279. checkpoints are deleted.
  2280. lpszQuorumPath - If specified, the checkpoint file relative
  2281. to this path is deleted.
  2282. Return Value:
  2283. ERROR_SUCCESS if completed successfully
  2284. Win32 error code otherwise.
  2285. --*/
  2286. {
  2287. DWORD Status = ERROR_SUCCESS;
  2288. if (dwCheckpointId)
  2289. {
  2290. Status = CpckDeleteFile(Resource, dwCheckpointId, lpszQuorumPath);
  2291. }
  2292. else
  2293. {
  2294. HDMKEY ResourceKey;
  2295. HDMKEY CryptoSyncKey;
  2296. CP_CALLBACK_CONTEXT Context;
  2297. //delete all checkpoints corresponding to this resource
  2298. //
  2299. // Open up the resource's key
  2300. //
  2301. ResourceKey = DmOpenKey(DmResourcesKey,
  2302. OmObjectId(Resource),
  2303. KEY_READ);
  2304. if (ResourceKey == NULL) {
  2305. Status = GetLastError();
  2306. ClRtlLogPrint(LOG_NOISE,
  2307. "[CPCK] CpckDeleteCheckpointFile - couldn't open Resource key. error %1!d!\n",
  2308. Status);
  2309. goto FnExit;
  2310. }
  2311. //
  2312. // Open up the CryptoSync key
  2313. //
  2314. CryptoSyncKey = DmOpenKey(ResourceKey,
  2315. L"CryptoSync",
  2316. KEY_READ | KEY_WRITE);
  2317. DmCloseKey(ResourceKey);
  2318. if (CryptoSyncKey == NULL)
  2319. {
  2320. Status = GetLastError();
  2321. ClRtlLogPrint(LOG_NOISE,
  2322. "[CPCK] CpckDeleteCheckpointFile- couldn't open CryptoSync key error %1!d!\n",
  2323. Status);
  2324. goto FnExit;
  2325. }
  2326. Context.lpszPathName = lpszQuorumPath;
  2327. Context.Resource = Resource;
  2328. //
  2329. // Enumerate all the values and delete them one by one.
  2330. //
  2331. DmEnumValues(CryptoSyncKey,
  2332. CpckRemoveCheckpointFileCallback,
  2333. &Context);
  2334. DmCloseKey(CryptoSyncKey);
  2335. }
  2336. FnExit:
  2337. return(Status);
  2338. } // CpckDeleteCheckpointFile
  2339. DWORD
  2340. CpckDeleteCryptoFile(
  2341. IN PFM_RESOURCE Resource,
  2342. IN DWORD dwCheckpointId,
  2343. IN OPTIONAL LPCWSTR lpszQuorumPath
  2344. )
  2345. /*++
  2346. Routine Description:
  2347. This function removes the checkpoint file correspoinding to the
  2348. checkpoint id for a given resource from the given directory.
  2349. Arguments:
  2350. Resource - Supplies the resource associated with this data.
  2351. dwCheckpointId - Supplies the unique checkpoint ID describing this data. The caller is responsible
  2352. for ensuring the uniqueness of the checkpoint ID.
  2353. lpszQuorumPath - Supplies the path of the cluster files on a quorum device.
  2354. Return Value:
  2355. ERROR_SUCCESS if successful
  2356. Win32 error code otherwise
  2357. --*/
  2358. {
  2359. CL_NODE_ID OwnerNode;
  2360. DWORD Status;
  2361. do {
  2362. OwnerNode = CppGetQuorumNodeId();
  2363. ClRtlLogPrint(LOG_NOISE,
  2364. "[CPCK] CpckDeleteCryptoFile: removing checkpoint file for id %1!d! at quorum node %2!d!\n",
  2365. dwCheckpointId,
  2366. OwnerNode);
  2367. if (OwnerNode == NmLocalNodeId)
  2368. {
  2369. Status = CpckDeleteCheckpointFile(Resource, dwCheckpointId, lpszQuorumPath);
  2370. }
  2371. else
  2372. {
  2373. Status = CpDeleteCryptoCheckpoint(Session[OwnerNode],
  2374. OmObjectId(Resource),
  2375. dwCheckpointId,
  2376. lpszQuorumPath);
  2377. //talking to an old server, cant perform this function
  2378. //ignore the error
  2379. if (Status == RPC_S_PROCNUM_OUT_OF_RANGE)
  2380. Status = ERROR_SUCCESS;
  2381. }
  2382. if (Status == ERROR_HOST_NODE_NOT_RESOURCE_OWNER) {
  2383. //
  2384. // This node no longer owns the quorum resource, retry.
  2385. //
  2386. ClRtlLogPrint(LOG_UNUSUAL,
  2387. "[CPCK] CpckDeleteCryptoFile: quorum owner %1!d! no longer owner\n",
  2388. OwnerNode);
  2389. }
  2390. } while ( Status == ERROR_HOST_NODE_NOT_RESOURCE_OWNER );
  2391. return(Status);
  2392. } // CpckDeleteCryptoFile
  2393. BOOL
  2394. CpckGetKeyLength(
  2395. IN PCRYPTO_KEY_INFO pCryptoKeyInfo,
  2396. OUT PDWORD pdwKeyLength,
  2397. OUT PDWORD pdwEffectiveKeyLength
  2398. )
  2399. /*++
  2400. Routine Description:
  2401. This routine gets the key lengths for a specific provider for the RC2 algorithm. It first looks
  2402. at the cluster private property area and if not found, it will look at the predefined table.
  2403. Arguments:
  2404. pCryptoKeyInfo - Crypto key related information.
  2405. pdwKeyLength - Key length.
  2406. pdwEffectiveKeyLength - Effective key length.
  2407. Return Value:
  2408. TRUE - Call was successful, FALSE otherwise.
  2409. --*/
  2410. {
  2411. DWORD i;
  2412. BOOL fStatus = FALSE;
  2413. DWORD dwStatus, cbKeyLengths = 0, dwStringIndex;
  2414. LPWSTR pmszKeyLengths = NULL;
  2415. HDMKEY hClusterParamsKey = NULL;
  2416. //
  2417. // Look at the cluster private properties if the user specified the key lengths for
  2418. // the provider.
  2419. //
  2420. hClusterParamsKey = DmOpenKey ( DmClusterParametersKey,
  2421. CLUSREG_KEYNAME_PARAMETERS,
  2422. KEY_READ );
  2423. if ( hClusterParamsKey != NULL )
  2424. {
  2425. dwStatus = DmQueryMultiSz( hClusterParamsKey,
  2426. pCryptoKeyInfo->pwszProvName,
  2427. &pmszKeyLengths,
  2428. &cbKeyLengths,
  2429. &cbKeyLengths );
  2430. if ( dwStatus == ERROR_SUCCESS )
  2431. {
  2432. for ( dwStringIndex = 0; ; dwStringIndex++ )
  2433. {
  2434. LPCWSTR pszKeyLength;
  2435. pszKeyLength = ClRtlMultiSzEnum( pmszKeyLengths,
  2436. cbKeyLengths / sizeof( WCHAR ),
  2437. dwStringIndex );
  2438. if ( pszKeyLength == NULL )
  2439. {
  2440. break;
  2441. }
  2442. switch ( dwStringIndex )
  2443. {
  2444. case 0:
  2445. *pdwKeyLength = wcstoul ( pszKeyLength, NULL, 10 );
  2446. break;
  2447. case 1:
  2448. *pdwEffectiveKeyLength = wcstoul ( pszKeyLength, NULL, 10 );
  2449. fStatus = TRUE;
  2450. ClRtlLogPrint(LOG_NOISE, "[CPCK] CpckGetKeyLength: [From cluster property] Provider %1!ws!, key length = %2!u!, effective length = %3!u!\n",
  2451. pCryptoKeyInfo->pwszProvName,
  2452. *pdwKeyLength,
  2453. *pdwEffectiveKeyLength);
  2454. goto FnExit;
  2455. default:
  2456. break;
  2457. } // switch
  2458. } // for
  2459. } // if
  2460. } // if
  2461. //
  2462. // No key lengths were specified in the private properties area or there were some errors
  2463. // reading them. Search the table.
  2464. //
  2465. for ( i=0; i<RTL_NUMBER_OF ( CP_RC2_W2k_KEYLEN_TABLE ); i++ )
  2466. {
  2467. if ( lstrcmpi ( pCryptoKeyInfo->pwszProvName, CP_RC2_W2k_KEYLEN_TABLE[i].lpszProviderName ) == 0 )
  2468. {
  2469. fStatus = TRUE;
  2470. *pdwKeyLength = CP_RC2_W2k_KEYLEN_TABLE[i].dwDefaultKeyLength;
  2471. *pdwEffectiveKeyLength = CP_RC2_W2k_KEYLEN_TABLE[i].dwDefaultEffectiveKeyLength;
  2472. ClRtlLogPrint(LOG_NOISE, "[CPCK] CpckGetKeyLength: [From table] Provider %1!ws!, key length = %2!u!, effective length = %3!u!\n",
  2473. pCryptoKeyInfo->pwszProvName,
  2474. *pdwKeyLength,
  2475. *pdwEffectiveKeyLength);
  2476. goto FnExit;
  2477. } // if
  2478. } // for
  2479. ClRtlLogPrint(LOG_CRITICAL, "[CPCK] CpckGetKeyLength: Unable to find provider %1!ws! entry in table or in cluster private props\n",
  2480. pCryptoKeyInfo->pwszProvName);
  2481. SetLastError ( ERROR_NOT_FOUND );
  2482. FnExit:
  2483. if ( hClusterParamsKey ) DmCloseKey ( hClusterParamsKey );
  2484. LocalFree ( pmszKeyLengths );
  2485. return ( fStatus );
  2486. } // CpckGetKeyLength