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.

5486 lines
149 KiB

  1. /*++
  2. Copyright (c) 1997, 1998 Microsoft Corporation
  3. Module Name:
  4. keyman.cpp
  5. Abstract:
  6. This module contains routines to manage master keys on behalf of the
  7. client. This includes retrieval, backup and restore.
  8. Author:
  9. Scott Field (sfield) 09-Sep-97
  10. Revision History:
  11. Scott Field (sfield) 01-Mar-98
  12. Use files as the backing store.
  13. Storage of all masterkey pieces a single atomic operation.
  14. --*/
  15. #include <pch.cpp>
  16. #pragma hdrstop
  17. #include <msaudite.h>
  18. #define REENCRYPT_MASTER_KEY 1
  19. #define ADD_MASTER_KEY_TO_CACHE 2
  20. //
  21. // preferred masterkey selection query/set
  22. //
  23. NTSTATUS
  24. GetPreferredMasterKeyGuid(
  25. IN PVOID pvContext,
  26. IN LPCWSTR szUserStorageArea,
  27. IN OUT GUID *pguidMasterKey
  28. );
  29. BOOL
  30. SetPreferredMasterKeyGuid(
  31. IN PVOID pvContext,
  32. IN LPCWSTR szUserStorageArea,
  33. IN GUID *pguidMasterKey
  34. );
  35. //
  36. // masterkey creation and query
  37. //
  38. DWORD
  39. CreateMasterKey(
  40. IN PVOID pvContext,
  41. IN LPCWSTR szUserStorageArea,
  42. OUT GUID *pguidMasterKey,
  43. IN BOOL fRequireBackup
  44. );
  45. BOOL
  46. GetMasterKeyByGuid(
  47. IN PVOID pvContext,
  48. IN LPCWSTR szUserStorageArea,
  49. IN PSID pSid,
  50. IN BOOL fMigrate,
  51. IN GUID *pguidMasterKey,
  52. OUT LPBYTE *ppbMasterKey,
  53. OUT DWORD *pcbMasterKey,
  54. OUT DWORD *pdwMasterKeyDisposition // refer to MK_DISP_ constants
  55. );
  56. BOOL
  57. GetMasterKey(
  58. IN PVOID pvContext,
  59. IN LPCWSTR szUserStorageArea,
  60. IN PSID pSid,
  61. IN BOOL fMigrate,
  62. IN WCHAR wszMasterKey[MAX_GUID_SZ_CHARS],
  63. OUT LPBYTE *ppbMasterKey,
  64. OUT DWORD *pcbMasterKey,
  65. OUT DWORD *pdwMasterKeyDisposition
  66. );
  67. //
  68. // helper functions used during key retrieval and storage.
  69. //
  70. BOOL
  71. ReadMasterKey(
  72. IN PVOID pvContext, // if NULL, caller is assumed to be impersonating
  73. IN PMASTERKEY_STORED phMasterKey
  74. );
  75. BOOL
  76. WriteMasterKey(
  77. IN PVOID pvContext, // if NULL, caller is assumed to be impersonating
  78. IN PMASTERKEY_STORED phMasterKey
  79. );
  80. BOOL
  81. CheckToStompMasterKey(
  82. IN PMASTERKEY_STORED_ON_DISK phMasterKeyCandidate, // masterkey to check if worthy to stomp over existing
  83. IN HANDLE hFile, // file handle to existing masterkey
  84. IN OUT BOOL *pfStomp // stomp the existing masterkey?
  85. );
  86. BOOL
  87. DuplicateMasterKey(
  88. IN PMASTERKEY_STORED phMasterKeyIn,
  89. IN PMASTERKEY_STORED phMasterKeyOut
  90. );
  91. BOOL
  92. CloseMasterKey(
  93. IN PVOID pvContext, // if NULL, caller is assumed to be impersonating
  94. IN PMASTERKEY_STORED phMasterKey,
  95. IN BOOL fPersist // persist any changes to storage?
  96. );
  97. VOID
  98. FreeMasterKey(
  99. IN PMASTERKEY_STORED phMasterKey
  100. );
  101. //
  102. // low-level crypto enabled key persistence query/set
  103. //
  104. DWORD
  105. DecryptMasterKeyFromStorage(
  106. IN PMASTERKEY_STORED phMasterKey,
  107. IN DWORD dwMKLoc,
  108. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  109. OUT BOOL *pfUpgradeEncryption,
  110. OUT PBYTE *ppbMasterKey,
  111. OUT DWORD *pcbMasterKey
  112. );
  113. DWORD
  114. DecryptMasterKeyToMemory(
  115. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  116. IN PBYTE pbMasterKeyIn,
  117. IN DWORD cbMasterKeyIn,
  118. OUT BOOL *pfUpgradeEncryption,
  119. OUT PBYTE *ppbMasterKeyOut,
  120. OUT DWORD *pcbMasterKeyOut
  121. );
  122. DWORD
  123. EncryptMasterKeyToStorage(
  124. IN PMASTERKEY_STORED phMasterKey,
  125. IN DWORD dwMKLoc,
  126. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  127. IN PBYTE pbMasterKey,
  128. IN DWORD cbMasterKey
  129. );
  130. DWORD
  131. EncryptMasterKeyToMemory(
  132. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  133. IN DWORD cIterationCount,
  134. IN PBYTE pbMasterKey,
  135. IN DWORD cbMasterKey,
  136. OUT PBYTE *ppbMasterKeyOut,
  137. OUT DWORD *pcbMasterKeyOut
  138. );
  139. DWORD
  140. PersistMasterKeyToStorage(
  141. IN PMASTERKEY_STORED phMasterKey,
  142. IN DWORD dwMKLoc,
  143. IN PBYTE pbMasterKeyOut,
  144. IN DWORD cbMasterKeyOut
  145. );
  146. DWORD
  147. QueryMasterKeyFromStorage(
  148. IN PMASTERKEY_STORED phMasterKey,
  149. IN DWORD dwMKLoc,
  150. IN OUT PBYTE *ppbMasterKeyOut,
  151. IN OUT DWORD *pcbMasterKeyOut
  152. );
  153. //
  154. // per-user credential derivation
  155. //
  156. BOOL
  157. GetMasterKeyUserEncryptionKey(
  158. IN PVOID pvContext,
  159. IN GUID *pCredentialID,
  160. IN PSID pSid,
  161. IN DWORD dwFlags,
  162. IN OUT BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN]
  163. );
  164. BOOL
  165. GetLocalKeyUserEncryptionKey(
  166. IN PVOID pvContext,
  167. IN PMASTERKEY_STORED phMasterKey,
  168. IN OUT BYTE rgbLKEncrytionKey[A_SHA_DIGEST_LEN]
  169. );
  170. //
  171. // backup/restore operations.
  172. //
  173. BOOL
  174. IsBackupMasterKeyRequired(
  175. IN PMASTERKEY_STORED phMasterKey,
  176. IN OUT BOOL *pfPhaseTwo // is phase two required?
  177. );
  178. DWORD
  179. BackupMasterKey(
  180. IN PVOID pvContext,
  181. IN PMASTERKEY_STORED phMasterKey,
  182. IN LPBYTE pbMasterKey,
  183. IN DWORD cbMasterKey,
  184. IN BOOL fPhaseTwo, // is phase two required?
  185. IN BOOL fAsynchronous // asynchronous call?
  186. );
  187. DWORD
  188. QueueBackupMasterKey(
  189. IN PVOID pvContext,
  190. IN PMASTERKEY_STORED phMasterKey,
  191. IN PBYTE pbLocalKey,
  192. IN DWORD cbLocalKey,
  193. IN PBYTE pbMasterKey,
  194. IN DWORD cbMasterKey,
  195. IN DWORD dwWaitTimeout // amount of time to wait for operation to complete
  196. );
  197. DWORD
  198. RestoreMasterKey(
  199. IN PVOID pvContext,
  200. IN PSID pSid,
  201. IN PMASTERKEY_STORED phMasterKey,
  202. IN DWORD dwReason,
  203. OUT LPBYTE *ppbMasterKey,
  204. OUT DWORD *pcbMasterKey
  205. );
  206. //
  207. // asyncrhonous work functions for:
  208. // 1. Backup operations
  209. // 2. Masterkey synchronization operations
  210. //
  211. DWORD
  212. WINAPI
  213. QueueBackupMasterKeyThreadFunc(
  214. IN LPVOID lpThreadArgument
  215. );
  216. DWORD
  217. WINAPI
  218. QueueSyncMasterKeysThreadFunc(
  219. IN LPVOID lpThreadArgument
  220. );
  221. //
  222. // backup/restore policy operations
  223. //
  224. BOOL
  225. InitializeMasterKeyPolicy(
  226. IN PVOID pvContext,
  227. IN MASTERKEY_STORED *phMasterKey,
  228. OUT BOOL *fLocalAccount
  229. );
  230. BOOL
  231. IsDomainBackupRequired(
  232. IN PVOID pvContext
  233. );
  234. DWORD
  235. InitiateSynchronizeMasterKeys(
  236. IN PVOID pvContext // server context
  237. )
  238. /*++
  239. Force Synchronization of all masterkeys associated with the caller.
  240. This can include per-machine keys if the call was made with the per-machine
  241. flag turned on. Otherwise, the masterkeys associated with the client
  242. user security context are synchronized.
  243. Synchronization is required to support a variety of login credential
  244. change scenarios:
  245. 1. Domain Administrator assigns new password to user.
  246. 2. User changes password locally.
  247. 3. User changes password from another machine on the network.
  248. 4. User which is primarily disconnected from the network requests new
  249. password from Domain Administrator, connect to network long enough
  250. to refresh Netlogon cache with new credential.
  251. --*/
  252. {
  253. PQUEUED_SYNC pQueuedSync = NULL;
  254. DWORD cbQueuedSync = sizeof(QUEUED_SYNC);
  255. DWORD dwLastError = ERROR_SUCCESS;
  256. D_DebugLog((DEB_TRACE_API, "SynchronizeMasterKeys\n"));
  257. pQueuedSync = (PQUEUED_SYNC)SSAlloc( cbQueuedSync );
  258. if( pQueuedSync == NULL ) {
  259. dwLastError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  260. goto cleanup;
  261. }
  262. ZeroMemory( pQueuedSync, cbQueuedSync );
  263. pQueuedSync->cbSize = cbQueuedSync;
  264. //
  265. // duplicate the outstanding server context.
  266. //
  267. dwLastError = CPSDuplicateContext(pvContext, &(pQueuedSync->pvContext));
  268. if( dwLastError != ERROR_SUCCESS )
  269. goto cleanup;
  270. #if 1
  271. //
  272. // create the worker thread to handle the synchronize request.
  273. //
  274. if( !QueueUserWorkItem(
  275. QueueSyncMasterKeysThreadFunc,
  276. pQueuedSync,
  277. WT_EXECUTELONGFUNCTION
  278. ))
  279. {
  280. dwLastError = GetLastError();
  281. }
  282. #else
  283. //
  284. // Perform the synchronization in the current thread.
  285. //
  286. dwLastError = SynchronizeMasterKeys(pQueuedSync->pvContext, 0);
  287. if(pQueuedSync->pvContext)
  288. {
  289. CPSFreeContext( pQueuedSync->pvContext );
  290. }
  291. if( pQueuedSync )
  292. SSFree( pQueuedSync );
  293. dwLastError = ERROR_SUCCESS;
  294. #endif
  295. cleanup:
  296. if( dwLastError != ERROR_SUCCESS ) {
  297. //
  298. // free resources locally since a thread was not successfully created;
  299. // normally, the worker thread will free these resources.
  300. //
  301. if( pQueuedSync ) {
  302. if( pQueuedSync->pvContext )
  303. CPSFreeContext( pQueuedSync->pvContext );
  304. SSFree( pQueuedSync );
  305. }
  306. }
  307. return dwLastError;
  308. }
  309. DWORD
  310. WINAPI
  311. QueueSyncMasterKeysThreadFunc(
  312. IN LPVOID lpThreadArgument
  313. )
  314. /*++
  315. This routine performs asyncronous masterkey synchronization associated
  316. with the client security context that invoked the operation.
  317. All masterkeys associated with the security context are queried which
  318. in turn causes a re-encrypt/sync if necessary.
  319. --*/
  320. {
  321. PQUEUED_SYNC pQueuedSync = (PQUEUED_SYNC)lpThreadArgument;
  322. PVOID pvContext = NULL;
  323. DWORD dwLastError = ERROR_SUCCESS;
  324. if( pQueuedSync == NULL ||
  325. pQueuedSync->cbSize != sizeof(QUEUED_SYNC) ||
  326. pQueuedSync->pvContext == NULL )
  327. {
  328. dwLastError = ERROR_INVALID_PARAMETER;
  329. goto cleanup;
  330. }
  331. pvContext = pQueuedSync->pvContext;
  332. dwLastError = SynchronizeMasterKeys(pvContext, 0);
  333. cleanup:
  334. RevertToSelf();
  335. if( pvContext )
  336. {
  337. CPSFreeContext( pvContext );
  338. }
  339. if( pQueuedSync )
  340. SSFree( pQueuedSync );
  341. return dwLastError;
  342. }
  343. //+---------------------------------------------------------------------------
  344. //
  345. // Function: ReencryptMasterKey
  346. //
  347. // Synopsis: Read in the specified (machine) master key file, encrypt it
  348. // using the current DPAPI LSA secret, and write it back out.
  349. // This routine is only called when updating the DPAPI LSA
  350. // secret (e.g., by sysprep).
  351. //
  352. // Arguments: [pvContext] -- Server context.
  353. //
  354. // [pLogonId] -- User logon session.
  355. //
  356. // [pszUserStorageArea] -- Path to user profile.
  357. //
  358. // [pszFilename] -- Filename of the master key file.
  359. //
  360. // Returns: ERROR_SUCCESS if the operation was successful, a Windows
  361. // error code otherwise.
  362. //
  363. // History:
  364. //
  365. // Notes: This function should only be called for machine master keys,
  366. // since these are typically the only ones that are encrypted
  367. // using the LSA secret.
  368. //
  369. //----------------------------------------------------------------------------
  370. DWORD
  371. WINAPI
  372. ReencryptMasterKey(
  373. PVOID pvContext,
  374. PLUID pLogonId,
  375. LPWSTR pszUserStorageArea,
  376. LPWSTR pszFilename)
  377. {
  378. MASTERKEY_STORED hMasterKey;
  379. DWORD cbFilePath;
  380. LPBYTE pbMasterKey;
  381. DWORD cbMasterKey;
  382. GUID guidMasterKey;
  383. BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN];
  384. BOOL fUserCredentialValid;
  385. GUID CredentialID;
  386. DWORD dwLastError;
  387. //
  388. // Validate input parameters.
  389. //
  390. if((pszUserStorageArea == NULL) || (pszFilename == NULL))
  391. {
  392. return ERROR_INVALID_PARAMETER;
  393. }
  394. if(WSZ_BYTECOUNT(pszFilename) > sizeof(hMasterKey.wszguidMasterKey))
  395. {
  396. return ERROR_INVALID_PARAMETER;
  397. }
  398. //
  399. // Initialize master key memory block.
  400. //
  401. ZeroMemory( &hMasterKey, sizeof(hMasterKey) );
  402. hMasterKey.fModified = TRUE;
  403. cbFilePath = WSZ_BYTECOUNT(pszUserStorageArea);
  404. hMasterKey.szFilePath = (LPWSTR)SSAlloc( cbFilePath );
  405. if(hMasterKey.szFilePath == NULL)
  406. {
  407. dwLastError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  408. return dwLastError;
  409. }
  410. CopyMemory(hMasterKey.szFilePath, pszUserStorageArea, cbFilePath);
  411. CopyMemory(hMasterKey.wszguidMasterKey, pszFilename, WSZ_BYTECOUNT(pszFilename));
  412. //
  413. // read the master key components into memory.
  414. //
  415. if(!ReadMasterKey( pvContext, &hMasterKey ))
  416. {
  417. D_DebugLog((DEB_WARN, "ReadMasterKey failed: 0x%x\n", GetLastError()));
  418. CloseMasterKey(pvContext, &hMasterKey, FALSE);
  419. return ERROR_NOT_FOUND;
  420. }
  421. //
  422. // read the master key from the cache
  423. //
  424. dwLastError = MyGuidFromStringW(hMasterKey.wszguidMasterKey, &guidMasterKey);
  425. if(dwLastError != ERROR_SUCCESS)
  426. {
  427. CloseMasterKey(pvContext, &hMasterKey, FALSE);
  428. return dwLastError;
  429. }
  430. pbMasterKey = NULL;
  431. if(!SearchMasterKeyCache( pLogonId, &guidMasterKey, &pbMasterKey, &cbMasterKey ))
  432. {
  433. D_DebugLog((DEB_ERROR, "Master key %ls not found in cache!\n", hMasterKey.wszguidMasterKey));
  434. CloseMasterKey(pvContext, &hMasterKey, FALSE);
  435. return ERROR_NOT_FOUND;
  436. }
  437. //
  438. // Get encryption key
  439. //
  440. ZeroMemory(&CredentialID, sizeof(CredentialID));
  441. fUserCredentialValid = GetMasterKeyUserEncryptionKey(pvContext,
  442. &CredentialID,
  443. NULL,
  444. USE_DPAPI_OWF | USE_ROOT_CREDENTIAL,
  445. rgbMKEncryptionKey);
  446. if(fUserCredentialValid)
  447. {
  448. hMasterKey.dwPolicy |= POLICY_DPAPI_OWF;
  449. }
  450. else
  451. {
  452. D_DebugLog((DEB_ERROR, "Unable to get user encryption key\n"));
  453. CloseMasterKey(pvContext, &hMasterKey, FALSE);
  454. return ERROR_NOT_FOUND;
  455. }
  456. //
  457. // re-encrypt the masterkey.
  458. //
  459. dwLastError = EncryptMasterKeyToStorage(
  460. &hMasterKey,
  461. REGVAL_MASTER_KEY,
  462. rgbMKEncryptionKey,
  463. pbMasterKey,
  464. cbMasterKey
  465. );
  466. SSFree(pbMasterKey);
  467. if(dwLastError != ERROR_SUCCESS)
  468. {
  469. D_DebugLog((DEB_WARN, "Error encrypting master key!\n"));
  470. CloseMasterKey(pvContext, &hMasterKey, FALSE);
  471. return dwLastError;
  472. }
  473. //
  474. // Save the master key to disk.
  475. //
  476. if(!CloseMasterKey(pvContext, &hMasterKey, TRUE))
  477. {
  478. D_DebugLog((DEB_WARN, "Error saving master key!\n"));
  479. return ERROR_NOT_FOUND;
  480. }
  481. return ERROR_SUCCESS;
  482. }
  483. //+---------------------------------------------------------------------------
  484. //
  485. // Function: SynchronizeMasterKeys
  486. //
  487. // Synopsis: Enumerate all of the master keys, and update their encryption
  488. // state as necessary.
  489. //
  490. // Arguments: [pvContext] -- Server context.
  491. //
  492. // [dwMode] -- Operation to perform on the master keys.
  493. //
  494. // Returns: ERROR_SUCCESS if the operation was successful, a Windows
  495. // error code otherwise.
  496. //
  497. // History:
  498. //
  499. // Notes: By default, this function will read in each of the master
  500. // keys belonging to the specified user. If necessary, a key
  501. // recovery operation will be done, and the reencrypted key
  502. // will be written back out to disk.
  503. //
  504. // If the dwMode parameter is non-zero, then one of the
  505. // following operations will be done:
  506. //
  507. // ADD_MASTER_KEY_TO_CACHE
  508. // Read each master key into the master key cache. Fail
  509. // if any of the keys cannot be successfully read. This
  510. // operation is done before the DPAPI LSA secret is updated.
  511. //
  512. // REENCRYPT_MASTER_KEY
  513. // Re-encrypt each master key (from the cache), and write
  514. // them back out to disk. This operation is performed after
  515. // the DPAPI LSA secret is updated.
  516. //
  517. //----------------------------------------------------------------------------
  518. DWORD
  519. WINAPI
  520. SynchronizeMasterKeys(
  521. IN PVOID pvContext,
  522. IN DWORD dwMode)
  523. {
  524. LPWSTR szUserStorageArea = NULL;
  525. BOOL fImpersonated = FALSE;
  526. DWORD cbUserStorageArea;
  527. HANDLE hFindData = INVALID_HANDLE_VALUE;
  528. // note: tis a shame that ? doesn't map to wildcard a single character...
  529. // const WCHAR szFileName[] = L"????????-????-????-????-????????????";
  530. const WCHAR szFileName[] = L"*";
  531. LPWSTR szFileMatch = NULL;
  532. DWORD cbFileMatch;
  533. WIN32_FIND_DATAW FindFileData;
  534. DWORD dwLastError;
  535. PSID *apsidHistory = NULL;
  536. DWORD cSids = 0;
  537. DWORD iSid = 0;
  538. LUID LogonId;
  539. BOOL fLogonIdValid = FALSE;
  540. GUID guidMasterKey;
  541. D_DebugLog((DEB_TRACE_API, "SynchronizeMasterKeys called\n"));
  542. D_DebugLog((DEB_TRACE_API, " dwMode: 0x%x\n", dwMode));
  543. //
  544. // get LogonId associated with client security context.
  545. //
  546. dwLastError = CPSImpersonateClient( pvContext );
  547. if( dwLastError == ERROR_SUCCESS )
  548. {
  549. if(GetThreadAuthenticationId(GetCurrentThread(), &LogonId))
  550. {
  551. fLogonIdValid = TRUE;
  552. }
  553. CPSRevertToSelf( pvContext );
  554. }
  555. //
  556. // Get the sid history for this user, so
  557. // we can sync all keys
  558. //
  559. dwLastError = CPSGetSidHistory(pvContext,
  560. &apsidHistory,
  561. &cSids);
  562. if(ERROR_SUCCESS != dwLastError)
  563. {
  564. goto cleanup;
  565. }
  566. for(iSid=0; iSid < cSids; iSid++)
  567. {
  568. //
  569. // get the path to the per-user master key storage area on disk
  570. //
  571. dwLastError = CPSGetUserStorageArea( pvContext,
  572. (iSid > 0)?apsidHistory[iSid]:NULL,
  573. FALSE,
  574. &szUserStorageArea );
  575. if( dwLastError != ERROR_SUCCESS )
  576. {
  577. if(dwLastError == ERROR_PATH_NOT_FOUND || dwLastError == ERROR_FILE_NOT_FOUND)
  578. {
  579. dwLastError = ERROR_SUCCESS;
  580. }
  581. goto cleanup;
  582. }
  583. //
  584. // build the wild card search path.
  585. //
  586. cbUserStorageArea = lstrlenW( szUserStorageArea ) * sizeof(WCHAR);
  587. cbFileMatch = cbUserStorageArea + sizeof(szFileName);
  588. szFileMatch = (LPWSTR)SSAlloc( cbFileMatch );
  589. if(NULL == szFileMatch)
  590. {
  591. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  592. goto cleanup;
  593. }
  594. CopyMemory( szFileMatch, szUserStorageArea, cbUserStorageArea );
  595. CopyMemory( ((LPBYTE)szFileMatch)+cbUserStorageArea, szFileName, sizeof(szFileName) );
  596. //
  597. // impersonate the client security context via the duplicated context.
  598. //
  599. dwLastError = CPSImpersonateClient( pvContext );
  600. if( dwLastError != ERROR_SUCCESS )
  601. goto cleanup;
  602. fImpersonated = TRUE;
  603. //
  604. // now enumerate the files looking for ones that look interesting.
  605. //
  606. hFindData = FindFirstFileW( szFileMatch, &FindFileData );
  607. if( hFindData == INVALID_HANDLE_VALUE )
  608. goto cleanup;
  609. do {
  610. LPBYTE pbMasterKey = NULL;
  611. DWORD cbMasterKey = 0;
  612. DWORD dwMasterKeyDisposition;
  613. if( FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  614. continue;
  615. //
  616. // ignore files which don't look like a textual GUID.
  617. //
  618. if( lstrlenW( FindFileData.cFileName ) != 36 )
  619. continue;
  620. if( FindFileData.cFileName[ 8 ] != L'-' ||
  621. FindFileData.cFileName[ 13 ] != L'-' ||
  622. FindFileData.cFileName[ 18 ] != L'-' ||
  623. FindFileData.cFileName[ 23 ] != L'-' ) {
  624. continue;
  625. }
  626. switch(dwMode)
  627. {
  628. case ADD_MASTER_KEY_TO_CACHE:
  629. //
  630. // Add this master key to the master key cache. Abort the
  631. // entire function if the operation is not successful for
  632. // any reason.
  633. //
  634. if(!fLogonIdValid)
  635. {
  636. dwLastError = ERROR_ACCESS_DENIED;
  637. goto cleanup;
  638. }
  639. dwLastError = MyGuidFromStringW(FindFileData.cFileName, &guidMasterKey);
  640. if(dwLastError != ERROR_SUCCESS)
  641. {
  642. goto cleanup;
  643. }
  644. // Fetch the specified key.
  645. if(!GetMasterKey(pvContext,
  646. szUserStorageArea,
  647. apsidHistory[iSid],
  648. iSid > 0,
  649. FindFileData.cFileName,
  650. &pbMasterKey,
  651. &cbMasterKey,
  652. &dwMasterKeyDisposition))
  653. {
  654. dwLastError = ERROR_ACCESS_DENIED;
  655. goto cleanup;
  656. }
  657. // Add the key to the cache.
  658. if(!InsertMasterKeyCache(&LogonId,
  659. &guidMasterKey,
  660. pbMasterKey,
  661. cbMasterKey))
  662. {
  663. if(pbMasterKey)
  664. {
  665. RtlSecureZeroMemory( pbMasterKey, cbMasterKey );
  666. SSFree( pbMasterKey );
  667. }
  668. dwLastError = ERROR_ACCESS_DENIED;
  669. goto cleanup;
  670. }
  671. // Scrub and free the master key.
  672. if(pbMasterKey)
  673. {
  674. RtlSecureZeroMemory( pbMasterKey, cbMasterKey );
  675. SSFree( pbMasterKey );
  676. }
  677. break;
  678. case REENCRYPT_MASTER_KEY:
  679. //
  680. // The DPAPI LSA secret has changed, so read the master key
  681. // from the cache and reencrypt it to storage. This mode will
  682. // only be used for the local machine master keys.
  683. //
  684. if(!fLogonIdValid)
  685. {
  686. dwLastError = ERROR_ACCESS_DENIED;
  687. goto cleanup;
  688. }
  689. // Ignore the returned error code, since there's little
  690. // we can do about it now...
  691. ReencryptMasterKey(pvContext,
  692. &LogonId,
  693. szUserStorageArea,
  694. FindFileData.cFileName);
  695. break;
  696. default:
  697. //
  698. // fetch the specified key; this will cause a credential re-sync
  699. // if necessary.
  700. //
  701. if(GetMasterKey(
  702. pvContext,
  703. szUserStorageArea,
  704. apsidHistory[iSid],
  705. iSid > 0,
  706. FindFileData.cFileName,
  707. &pbMasterKey,
  708. &cbMasterKey,
  709. &dwMasterKeyDisposition
  710. ) )
  711. {
  712. // Scrub and free the master key.
  713. if( pbMasterKey )
  714. {
  715. RtlSecureZeroMemory( pbMasterKey, cbMasterKey );
  716. SSFree( pbMasterKey );
  717. }
  718. }
  719. break;
  720. }
  721. } while( FindNextFileW( hFindData, &FindFileData ) );
  722. dwLastError = ERROR_SUCCESS;
  723. SSFree(szUserStorageArea);
  724. szUserStorageArea = NULL;
  725. }
  726. cleanup:
  727. if( pvContext )
  728. {
  729. if( fImpersonated )
  730. CPSRevertToSelf( pvContext );
  731. }
  732. if( hFindData != INVALID_HANDLE_VALUE )
  733. FindClose( hFindData );
  734. if( szUserStorageArea )
  735. SSFree( szUserStorageArea );
  736. if( szFileMatch )
  737. SSFree( szFileMatch );
  738. if(apsidHistory)
  739. SSFree( apsidHistory );
  740. D_DebugLog((DEB_TRACE_API, "SynchronizeMasterKeys returned 0x%x\n", dwLastError));
  741. return dwLastError;
  742. }
  743. VOID
  744. DPAPISynchronizeMasterKeys(
  745. IN HANDLE hUserToken)
  746. {
  747. CRYPT_SERVER_CONTEXT ServerContext;
  748. BOOL fContextCreated = FALSE;
  749. HANDLE hOldUser = NULL;
  750. DWORD dwError;
  751. D_DebugLog((DEB_TRACE_API, "DPAPISynchronizeMasterKeys\n"));
  752. //
  753. // Create a server context.
  754. //
  755. if(hUserToken)
  756. {
  757. if(!OpenThreadToken(GetCurrentThread(),
  758. TOKEN_IMPERSONATE | TOKEN_READ,
  759. TRUE,
  760. &hOldUser))
  761. {
  762. hOldUser = NULL;
  763. }
  764. if(!ImpersonateLoggedOnUser(hUserToken))
  765. {
  766. dwError = GetLastError();
  767. CloseHandle(hOldUser);
  768. goto cleanup;
  769. }
  770. }
  771. dwError = CPSCreateServerContext(&ServerContext, NULL);
  772. if(hOldUser)
  773. {
  774. if (!SetThreadToken(NULL, hOldUser))
  775. {
  776. if (ERROR_SUCCESS == dwError)
  777. {
  778. dwError = GetLastError();
  779. fContextCreated = TRUE;
  780. }
  781. }
  782. CloseHandle(hOldUser);
  783. hOldUser = NULL;
  784. }
  785. if(dwError != ERROR_SUCCESS)
  786. {
  787. goto cleanup;
  788. }
  789. fContextCreated = TRUE;
  790. //
  791. // Synchronize the master keys.
  792. //
  793. dwError = InitiateSynchronizeMasterKeys(&ServerContext);
  794. if(dwError != ERROR_SUCCESS)
  795. {
  796. goto cleanup;
  797. }
  798. cleanup:
  799. if(fContextCreated)
  800. {
  801. CPSDeleteServerContext( &ServerContext );
  802. }
  803. D_DebugLog((DEB_TRACE_API, "DPAPISynchronizeMasterKeys returned 0x%x\n", dwError));
  804. }
  805. DWORD
  806. GetSpecifiedMasterKey(
  807. IN PVOID pvContext, // server context
  808. IN OUT GUID *pguidMasterKey,
  809. OUT LPBYTE *ppbMasterKey,
  810. OUT DWORD *pcbMasterKey,
  811. IN BOOL fSpecified // get specified pguidMasterKey key ?
  812. )
  813. /*++
  814. This function returns the caller a decrypted master key.
  815. If fSpecified is TRUE, the returned master key is the one specified by
  816. the GUID pointed to by pguidMasterKey. Otherwise, the returned master key
  817. is the preferred master key, and pguidMasterKey is filled with the GUID
  818. value associated with the preferred master key.
  819. The proper way to utilize the fSpecified parameter is to specify FALSE
  820. when obtaining a masterkey associated with an encrypt operation;
  821. specify TRUE and supply valid GUID in pguidMasterKey when doing a decrypt
  822. operation. For an encrypt operation, the caller will store the GUID
  823. returned in pguidMasterKey alongside any data encrypted with that master
  824. key.
  825. On success, the return value is ERROR_SUCCESS. The caller must free the buffer
  826. pointed to by ppbMasterKey using SSFree() when finished with it. The
  827. caller should keep this buffer around for the shortest possible time, to
  828. avoid pagefile exposure.
  829. On failure, the return value is not ERROR_SUCCESS. The caller need not free the
  830. buffer pointed to ppbMasterKey.
  831. --*/
  832. {
  833. LUID LogonId;
  834. BOOL fCached = FALSE; // masterkey found in cache?
  835. LPWSTR szUserStorageArea = NULL;
  836. DWORD dwMasterKeyDisposition = 0;
  837. DWORD dwLocalError;
  838. DWORD dwLastError;
  839. BOOL fSetPreferred = FALSE; // update preferred guid?
  840. BOOL fSuccess = FALSE;
  841. PSID *apsidHistory = NULL;
  842. DWORD cSids = 0;
  843. DWORD i;
  844. NTSTATUS Status;
  845. D_DebugLog((DEB_TRACE_API, "GetSpecifiedMasterKey called\n"));
  846. //
  847. // get LogonId associated with client security context.
  848. //
  849. dwLastError = CPSImpersonateClient( pvContext );
  850. if( dwLastError != ERROR_SUCCESS )
  851. {
  852. D_DebugLog((DEB_TRACE_API, "GetSpecifiedMasterKey returned 0x%x\n", dwLastError));
  853. return dwLastError;
  854. }
  855. fSuccess = GetThreadAuthenticationId(GetCurrentThread(), &LogonId);
  856. if( !fSuccess )
  857. {
  858. dwLastError = GetLastError();
  859. }
  860. CPSRevertToSelf( pvContext );
  861. if( !fSuccess )
  862. {
  863. D_DebugLog((DEB_TRACE_API, "GetSpecifiedMasterKey returned 0x%x\n", dwLastError));
  864. return dwLastError;
  865. }
  866. fSuccess = FALSE;
  867. //
  868. // Get the preferred key GUID if no master key was specified by name.
  869. //
  870. if( !fSpecified )
  871. {
  872. //
  873. // get the path to the per-user master key storage area on disk
  874. //
  875. dwLastError = CPSGetUserStorageArea( pvContext, NULL, TRUE, &szUserStorageArea );
  876. if(dwLastError != ERROR_SUCCESS)
  877. {
  878. D_DebugLog((DEB_WARN, "CPSGetUserStorageArea failed: 0x%x\n", dwLastError));
  879. goto cleanup;
  880. }
  881. D_DebugLog((DEB_TRACE, "Master key user path: %ls\n", szUserStorageArea));
  882. //
  883. // determine what is the preferred master key.
  884. // if none exists, create one, and set it as being preferred.
  885. //
  886. Status = GetPreferredMasterKeyGuid( pvContext, szUserStorageArea, pguidMasterKey );
  887. if(!NT_SUCCESS(Status))
  888. {
  889. if(Status == STATUS_PASSWORD_EXPIRED)
  890. {
  891. GUID guidNewMasterKey;
  892. // A preferred master key exists, but it has expired. Attempt to generate
  893. // a new master key, but fall back to the old one if we're unable to
  894. // create a proper backup for the new master key.
  895. dwLastError = CreateMasterKey( pvContext, szUserStorageArea, &guidNewMasterKey, TRUE );
  896. if(dwLastError == ERROR_SUCCESS)
  897. {
  898. // Use new key.
  899. memcpy(pguidMasterKey, &guidNewMasterKey, sizeof(GUID));
  900. // update preferred guid.
  901. fSetPreferred = TRUE;
  902. }
  903. }
  904. else
  905. {
  906. // No preferred master key currently exists, so generate a new one.
  907. dwLastError = CreateMasterKey( pvContext, szUserStorageArea, pguidMasterKey, FALSE );
  908. if(dwLastError != ERROR_SUCCESS)
  909. {
  910. goto cleanup;
  911. }
  912. // update preferred guid.
  913. fSetPreferred = TRUE;
  914. }
  915. }
  916. }
  917. //
  918. // search cache for specified masterkey.
  919. //
  920. if(SearchMasterKeyCache( &LogonId, pguidMasterKey, ppbMasterKey, pcbMasterKey ))
  921. {
  922. D_DebugLog((DEB_TRACE, "Master key found in cache.\n"));
  923. fCached = TRUE;
  924. fSuccess = TRUE;
  925. goto cleanup;
  926. }
  927. //
  928. // get the path to the per-user master key storage area on disk
  929. //
  930. if(szUserStorageArea == NULL)
  931. {
  932. dwLastError = CPSGetUserStorageArea( pvContext, NULL, TRUE, &szUserStorageArea );
  933. if(dwLastError != ERROR_SUCCESS)
  934. {
  935. D_DebugLog((DEB_WARN, "CPSGetUserStorageArea failed: 0x%x\n", dwLastError));
  936. goto cleanup;
  937. }
  938. D_DebugLog((DEB_TRACE, "Master key user path: %ls\n", szUserStorageArea));
  939. }
  940. //
  941. // If it's not in the cache, we need to load it.
  942. // By default, we have the users primary sid
  943. //
  944. cSids = 1;
  945. if(fSpecified)
  946. {
  947. //
  948. // If the GUID was specified, we need to find it, so get
  949. // the SID History so we can search all SIDS the user has
  950. // been for this one.
  951. //
  952. dwLastError = CPSGetSidHistory(pvContext,
  953. &apsidHistory,
  954. &cSids);
  955. if(ERROR_SUCCESS != dwLastError)
  956. {
  957. D_DebugLog((DEB_WARN, "CPSGetSidHistory failed: 0x%x\n", dwLastError));
  958. goto cleanup;
  959. }
  960. }
  961. for(i=0; i < cSids; i++)
  962. {
  963. if((fSpecified) && (i > 0))
  964. {
  965. // for sid's beyond the 0th one (the current user's sid),
  966. // we need to grab the new storage area.
  967. if(szUserStorageArea)
  968. {
  969. SSFree(szUserStorageArea);
  970. szUserStorageArea = NULL;
  971. }
  972. dwLocalError = CPSGetUserStorageArea( pvContext,
  973. apsidHistory[i],
  974. FALSE,
  975. &szUserStorageArea );
  976. if(dwLocalError != ERROR_SUCCESS)
  977. {
  978. // There is no storage area for this SID, so try the next
  979. continue;
  980. }
  981. }
  982. //
  983. // get the master key.
  984. //
  985. fSuccess = GetMasterKeyByGuid(
  986. pvContext,
  987. szUserStorageArea,
  988. (i > 0)?apsidHistory[i]:NULL,
  989. i > 0,
  990. pguidMasterKey,
  991. ppbMasterKey,
  992. pcbMasterKey,
  993. &dwMasterKeyDisposition);
  994. D_DebugLog((DEB_TRACE, "GetMasterKeyByGuid disposition: %s\n",
  995. (dwMasterKeyDisposition == MK_DISP_OK) ? "Normal" :
  996. (dwMasterKeyDisposition == MK_DISP_BCK_LCL) ? "Local backup" :
  997. (dwMasterKeyDisposition == MK_DISP_BCK_DC) ? "DC backup" :
  998. (dwMasterKeyDisposition == MK_DISP_STORAGE_ERR) ? "Storage error" :
  999. (dwMasterKeyDisposition == MK_DISP_DELEGATION_ERR) ? "Delegation error" :
  1000. "Unknown error"));
  1001. if(!fSuccess)
  1002. {
  1003. if(MK_DISP_STORAGE_ERR != dwMasterKeyDisposition)
  1004. {
  1005. // The disposition was not a storage error, so the key does
  1006. // exist in this area, but there was some other error.
  1007. break;
  1008. }
  1009. }
  1010. else
  1011. {
  1012. break;
  1013. }
  1014. }
  1015. //
  1016. // if this was an encrypt operation, and we failed to get at the preferred key,
  1017. // create a new key and set it preferred.
  1018. //
  1019. if(!fSuccess &&
  1020. !fSpecified &&
  1021. ((dwMasterKeyDisposition == MK_DISP_STORAGE_ERR) ||
  1022. (dwMasterKeyDisposition == MK_DISP_DELEGATION_ERR) ))
  1023. {
  1024. dwLastError = CreateMasterKey( pvContext, szUserStorageArea, pguidMasterKey, FALSE );
  1025. if(dwLastError != ERROR_SUCCESS)
  1026. goto cleanup;
  1027. fSuccess = GetMasterKeyByGuid(
  1028. pvContext,
  1029. szUserStorageArea,
  1030. NULL,
  1031. FALSE,
  1032. pguidMasterKey,
  1033. ppbMasterKey,
  1034. pcbMasterKey,
  1035. &dwMasterKeyDisposition
  1036. );
  1037. fSetPreferred = fSuccess;
  1038. }
  1039. if( fSuccess && fSetPreferred )
  1040. {
  1041. //
  1042. // masterkey creation succeeded, and usage of the key succeeded.
  1043. // set key as being preferred.
  1044. //
  1045. SetPreferredMasterKeyGuid( pvContext, szUserStorageArea, pguidMasterKey );
  1046. }
  1047. cleanup:
  1048. if(szUserStorageArea)
  1049. {
  1050. SSFree(szUserStorageArea);
  1051. }
  1052. if(apsidHistory)
  1053. {
  1054. SSFree(apsidHistory);
  1055. }
  1056. if(fSuccess)
  1057. {
  1058. //
  1059. // add entry to cache if it wasn't found there.
  1060. //
  1061. if( !fCached )
  1062. {
  1063. InsertMasterKeyCache( &LogonId, pguidMasterKey, *ppbMasterKey, *pcbMasterKey );
  1064. }
  1065. D_DebugLog((DEB_TRACE_API, "GetSpecifiedMasterKey returned 0x%x\n", ERROR_SUCCESS));
  1066. return ERROR_SUCCESS;
  1067. }
  1068. if(dwLastError == ERROR_SUCCESS)
  1069. {
  1070. dwLastError = (DWORD)NTE_BAD_KEY_STATE;
  1071. }
  1072. if(MK_DISP_DELEGATION_ERR == dwMasterKeyDisposition)
  1073. {
  1074. dwLastError = (DWORD)SEC_E_DELEGATION_REQUIRED;
  1075. }
  1076. D_DebugLog((DEB_TRACE_API, "GetSpecifiedMasterKey returned 0x%x\n", dwLastError));
  1077. return dwLastError;
  1078. }
  1079. DWORD
  1080. CreateMasterKey(
  1081. IN PVOID pvContext,
  1082. IN LPCWSTR szUserStorageArea,
  1083. OUT GUID *pguidMasterKey,
  1084. IN BOOL fRequireBackup)
  1085. {
  1086. MASTERKEY_STORED hMasterKey;
  1087. DWORD cbFilePath;
  1088. BYTE pbMasterKey[ MASTERKEY_MATERIAL_SIZE ];
  1089. DWORD cbMasterKey = sizeof(pbMasterKey);
  1090. BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN]; // masterkey encryption key
  1091. BYTE pbLocalKey[ LOCALKEY_MATERIAL_SIZE ];
  1092. DWORD cbLocalKey = sizeof(pbLocalKey);
  1093. BYTE rgbLKEncryptionKey[A_SHA_DIGEST_LEN]; // localkey encryption key
  1094. BOOL fUserCredentialValid = FALSE;
  1095. DWORD dwLastError;
  1096. BOOL fSuccess = FALSE;
  1097. BOOL fLocalAccount = FALSE;
  1098. GUID CredentialID;
  1099. D_DebugLog((DEB_TRACE, "CreateMasterKey\n"));
  1100. ZeroMemory(&CredentialID, sizeof(CredentialID));
  1101. //
  1102. // generate new GUID
  1103. //
  1104. dwLastError = UuidCreate( pguidMasterKey );
  1105. if( dwLastError ) {
  1106. if( dwLastError == RPC_S_UUID_LOCAL_ONLY ) {
  1107. dwLastError = ERROR_SUCCESS;
  1108. } else {
  1109. return dwLastError;
  1110. }
  1111. }
  1112. //
  1113. // initialize masterkey
  1114. //
  1115. ZeroMemory( &hMasterKey, sizeof(hMasterKey));
  1116. hMasterKey.dwVersion = MASTERKEY_STORED_VERSION;
  1117. hMasterKey.fModified = TRUE;
  1118. //
  1119. // set initial (default) masterkey policy.
  1120. // Do this whenever we determine a new masterkey is created/selected.
  1121. // This allows us future flexibility if we want to pull policy bits
  1122. // from some admin defined place.
  1123. //
  1124. InitializeMasterKeyPolicy( pvContext, &hMasterKey , &fLocalAccount);
  1125. //
  1126. // copy path to key file into masterkey memory block.
  1127. //
  1128. cbFilePath = (lstrlenW( szUserStorageArea ) + 1) * sizeof(WCHAR);
  1129. hMasterKey.szFilePath = (LPWSTR)SSAlloc( cbFilePath );
  1130. if(hMasterKey.szFilePath == NULL)
  1131. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  1132. CopyMemory(hMasterKey.szFilePath, szUserStorageArea, cbFilePath);
  1133. if( MyGuidToStringW( pguidMasterKey, hMasterKey.wszguidMasterKey ) != 0 )
  1134. {
  1135. dwLastError = ERROR_INVALID_DATA;
  1136. goto cleanup;
  1137. }
  1138. #ifdef COMPILED_BY_DEVELOPER
  1139. D_DebugLog((DEB_TRACE, "Master key GUID:%ls\n", hMasterKey.wszguidMasterKey));
  1140. #endif
  1141. //
  1142. // generate random masterkey in memory.
  1143. //
  1144. if(!RtlGenRandom(pbMasterKey, cbMasterKey))
  1145. {
  1146. dwLastError = GetLastError();
  1147. goto cleanup;
  1148. }
  1149. #ifdef COMPILED_BY_DEVELOPER
  1150. D_DebugLog((DEB_TRACE, "Master key:\n"));
  1151. D_DPAPIDumpHexData(DEB_TRACE, " ", pbMasterKey, cbMasterKey);
  1152. #endif
  1153. //
  1154. // generate random localkey in memory.
  1155. //
  1156. if(!RtlGenRandom(pbLocalKey, cbLocalKey))
  1157. {
  1158. dwLastError = GetLastError();
  1159. goto cleanup;
  1160. }
  1161. #ifdef COMPILED_BY_DEVELOPER
  1162. D_DebugLog((DEB_TRACE, "Local key:\n"));
  1163. D_DPAPIDumpHexData(DEB_TRACE, " ", pbLocalKey, cbLocalKey);
  1164. #endif
  1165. //
  1166. // get current masterkey encryption key.
  1167. //
  1168. if(fLocalAccount)
  1169. {
  1170. fUserCredentialValid = GetMasterKeyUserEncryptionKey(pvContext,
  1171. &CredentialID,
  1172. NULL,
  1173. USE_DPAPI_OWF | USE_ROOT_CREDENTIAL,
  1174. rgbMKEncryptionKey);
  1175. if(fUserCredentialValid)
  1176. {
  1177. hMasterKey.dwPolicy |= POLICY_DPAPI_OWF;
  1178. #ifdef COMPILED_BY_DEVELOPER
  1179. D_DebugLog((DEB_TRACE, "MK Encryption key:\n"));
  1180. D_DPAPIDumpHexData(DEB_TRACE, " ", rgbMKEncryptionKey, sizeof(rgbMKEncryptionKey));
  1181. D_DebugLog((DEB_TRACE, "MK Encryption key GUID:\n"));
  1182. D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)&CredentialID, sizeof(CredentialID));
  1183. #endif
  1184. }
  1185. else
  1186. {
  1187. D_DebugLog((DEB_WARN, "Unable to get SHA OWF user encryption key!\n"));
  1188. }
  1189. }
  1190. if(!fUserCredentialValid)
  1191. {
  1192. //
  1193. // If we couldn't use the DPAPI owf, then do something else
  1194. //
  1195. fUserCredentialValid = GetMasterKeyUserEncryptionKey(pvContext,
  1196. fLocalAccount?(&CredentialID):NULL,
  1197. NULL,
  1198. USE_ROOT_CREDENTIAL,
  1199. rgbMKEncryptionKey);
  1200. if(fUserCredentialValid)
  1201. {
  1202. #ifdef COMPILED_BY_DEVELOPER
  1203. D_DebugLog((DEB_TRACE, "MK Encryption key:\n"));
  1204. D_DPAPIDumpHexData(DEB_TRACE, " ", rgbMKEncryptionKey, sizeof(rgbMKEncryptionKey));
  1205. if(fLocalAccount)
  1206. {
  1207. D_DebugLog((DEB_TRACE, "MK Encryption key GUID:\n"));
  1208. D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)&CredentialID, sizeof(CredentialID));
  1209. }
  1210. #endif
  1211. }
  1212. else
  1213. {
  1214. D_DebugLog((DEB_WARN, "Unable to get NT OWF user encryption key!\n"));
  1215. }
  1216. }
  1217. //
  1218. // if the user credential is not intact or available, generate a random
  1219. // one for the time being. When fUserCredentialIntact is FALSE, we also
  1220. // do not attempt to backup/restore the key to phase 1 status.
  1221. // When fUserCredentialIntact eventually becomes TRUE, we will upgrade to
  1222. // phase 2 transparently.
  1223. //
  1224. if( !fUserCredentialValid )
  1225. {
  1226. //
  1227. // if no backup was specified in policy, we can't run with an
  1228. // random credential, as it won't be backed up to support temporary
  1229. // credential-less operation (eg: delegation).
  1230. //
  1231. if(fLocalAccount)
  1232. {
  1233. dwLastError = ERROR_ACCESS_DENIED;
  1234. goto cleanup;
  1235. }
  1236. if(hMasterKey.dwPolicy & POLICY_NO_BACKUP)
  1237. {
  1238. dwLastError = ERROR_ACCESS_DENIED;
  1239. goto cleanup;
  1240. }
  1241. RtlGenRandom(rgbMKEncryptionKey, sizeof(rgbMKEncryptionKey));
  1242. #ifdef COMPILED_BY_DEVELOPER
  1243. D_DebugLog((DEB_TRACE, "MK Encryption key:\n"));
  1244. D_DPAPIDumpHexData(DEB_TRACE, " ", rgbMKEncryptionKey, sizeof(rgbMKEncryptionKey));
  1245. #endif
  1246. }
  1247. if(fLocalAccount)
  1248. {
  1249. //
  1250. // Save the local backup information
  1251. //
  1252. LOCAL_BACKUP_DATA LocalBackupData;
  1253. LocalBackupData.dwVersion = MASTERKEY_BLOB_LOCALKEY_BACKUP;
  1254. CopyMemory(&LocalBackupData.CredentialID, &CredentialID, sizeof(CredentialID));
  1255. dwLastError = PersistMasterKeyToStorage(
  1256. &hMasterKey,
  1257. REGVAL_BACKUP_LCL_KEY,
  1258. (PBYTE)&LocalBackupData,
  1259. sizeof(LocalBackupData)
  1260. );
  1261. if(ERROR_SUCCESS != dwLastError)
  1262. {
  1263. goto cleanup;
  1264. }
  1265. }
  1266. //
  1267. // get localkey user encryption key.
  1268. //
  1269. if(!GetLocalKeyUserEncryptionKey(pvContext, &hMasterKey, rgbLKEncryptionKey))
  1270. goto cleanup;
  1271. #ifdef COMPILED_BY_DEVELOPER
  1272. D_DebugLog((DEB_TRACE, "LK Encryption key:\n"));
  1273. D_DPAPIDumpHexData(DEB_TRACE, " ", rgbLKEncryptionKey, sizeof(rgbLKEncryptionKey));
  1274. #endif
  1275. //
  1276. // now, encrypt and store the master key.
  1277. //
  1278. dwLastError = EncryptMasterKeyToStorage(
  1279. &hMasterKey,
  1280. REGVAL_MASTER_KEY,
  1281. rgbMKEncryptionKey,
  1282. pbMasterKey,
  1283. cbMasterKey
  1284. );
  1285. if(dwLastError == ERROR_SUCCESS)
  1286. {
  1287. //
  1288. // now, encrypt and store the local key.
  1289. //
  1290. dwLastError = EncryptMasterKeyToStorage(
  1291. &hMasterKey,
  1292. REGVAL_LOCAL_KEY,
  1293. rgbLKEncryptionKey,
  1294. pbLocalKey,
  1295. cbLocalKey
  1296. );
  1297. }
  1298. if(dwLastError == ERROR_SUCCESS)
  1299. {
  1300. BOOL fPhaseTwo = FALSE;
  1301. fSuccess = TRUE;
  1302. //
  1303. // after creation, do initial backup if necessary.
  1304. //
  1305. if(IsBackupMasterKeyRequired( &hMasterKey, &fPhaseTwo ))
  1306. {
  1307. DWORD dwBackupError;
  1308. dwBackupError = BackupMasterKey(
  1309. pvContext,
  1310. &hMasterKey,
  1311. pbMasterKey,
  1312. cbMasterKey,
  1313. fPhaseTwo, // phase two backup required?
  1314. fUserCredentialValid // async only if cred valid
  1315. );
  1316. if(dwBackupError != ERROR_SUCCESS)
  1317. {
  1318. if(!fUserCredentialValid || fRequireBackup)
  1319. {
  1320. //
  1321. // no valid credential, and backup failed, fail creation of
  1322. // this key.
  1323. //
  1324. dwLastError = SEC_E_DELEGATION_REQUIRED;
  1325. fSuccess = FALSE;
  1326. }
  1327. }
  1328. }
  1329. }
  1330. cleanup:
  1331. RtlSecureZeroMemory(pbMasterKey, sizeof(pbMasterKey));
  1332. RtlSecureZeroMemory(rgbMKEncryptionKey, sizeof(rgbMKEncryptionKey));
  1333. RtlSecureZeroMemory(rgbLKEncryptionKey, sizeof(rgbLKEncryptionKey));
  1334. //
  1335. // note: it's possible for a race to occur closing the master key
  1336. // at this point, because the key may be backed up asynchronously.
  1337. // this isn't a problem because when a key is persisted to disk,
  1338. // we will not downgrade the backed up blob to non-backed up, as the
  1339. // CloseMasterKey() code includes logic to prevent that situation from
  1340. // occuring.
  1341. //
  1342. if(!CloseMasterKey(pvContext, &hMasterKey, fSuccess))
  1343. fSuccess = FALSE;
  1344. if(fSuccess)
  1345. return ERROR_SUCCESS;
  1346. if(dwLastError == ERROR_SUCCESS)
  1347. dwLastError = ERROR_INVALID_PARAMETER;
  1348. return dwLastError;
  1349. }
  1350. BOOL
  1351. GetMasterKeyByGuid(
  1352. IN PVOID pvContext,
  1353. IN LPCWSTR szUserStorageArea,
  1354. IN PSID pSid,
  1355. IN BOOL fMigrate,
  1356. IN GUID *pguidMasterKey,
  1357. OUT LPBYTE *ppbMasterKey,
  1358. OUT DWORD *pcbMasterKey,
  1359. OUT DWORD *pdwMasterKeyDisposition // refer to MK_DISP_ constants
  1360. )
  1361. {
  1362. WCHAR wszguidMasterKey[MAX_GUID_SZ_CHARS];
  1363. *pdwMasterKeyDisposition = MK_DISP_UNKNOWN_ERR;
  1364. if( MyGuidToStringW( pguidMasterKey, wszguidMasterKey ) != 0 )
  1365. return FALSE;
  1366. return GetMasterKey(
  1367. pvContext,
  1368. szUserStorageArea,
  1369. pSid,
  1370. fMigrate,
  1371. wszguidMasterKey,
  1372. ppbMasterKey,
  1373. pcbMasterKey,
  1374. pdwMasterKeyDisposition
  1375. );
  1376. }
  1377. BOOL
  1378. GetMasterKey(
  1379. IN PVOID pvContext,
  1380. IN LPCWSTR szUserStorageArea,
  1381. IN PSID pSid,
  1382. IN BOOL fMigrate,
  1383. IN WCHAR wszMasterKey[MAX_GUID_SZ_CHARS],
  1384. OUT LPBYTE *ppbMasterKey,
  1385. OUT DWORD *pcbMasterKey,
  1386. OUT DWORD *pdwMasterKeyDisposition
  1387. )
  1388. {
  1389. MASTERKEY_STORED hMasterKey;
  1390. DWORD cbFilePath;
  1391. BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN]; // masterkey encryption key
  1392. DWORD dwLastError = (DWORD)NTE_BAD_KEY;
  1393. BOOL fUserCredentialValid;
  1394. BOOL fSuccess = FALSE;
  1395. BOOL fUpgradeEncryption = FALSE;
  1396. LPWSTR wszOldFilePath = NULL;
  1397. GUID CredentialID;
  1398. D_DebugLog((DEB_TRACE_API, "GetMasterKey: %ls\n", wszMasterKey));
  1399. *pdwMasterKeyDisposition = MK_DISP_UNKNOWN_ERR;
  1400. ZeroMemory( &hMasterKey, sizeof(hMasterKey) );
  1401. hMasterKey.fModified = FALSE;
  1402. //
  1403. // copy path to key file into masterkey memory block.
  1404. //
  1405. cbFilePath = (lstrlenW( szUserStorageArea ) + 1) * sizeof(WCHAR);
  1406. hMasterKey.szFilePath = (LPWSTR)SSAlloc( cbFilePath );
  1407. if(hMasterKey.szFilePath == NULL)
  1408. {
  1409. SetLastError( ERROR_NOT_ENOUGH_SERVER_MEMORY );
  1410. return FALSE;
  1411. }
  1412. CopyMemory(hMasterKey.szFilePath, szUserStorageArea, cbFilePath);
  1413. CopyMemory(hMasterKey.wszguidMasterKey, wszMasterKey, sizeof(hMasterKey.wszguidMasterKey));
  1414. //
  1415. // read the masterkey components into memory.
  1416. //
  1417. if(!ReadMasterKey( pvContext, &hMasterKey ))
  1418. {
  1419. D_DebugLog((DEB_WARN, "ReadMasterKey failed: 0x%x\n", GetLastError()));
  1420. SetLastError( (DWORD)NTE_BAD_KEY );
  1421. *pdwMasterKeyDisposition = MK_DISP_STORAGE_ERR;
  1422. return FALSE;
  1423. }
  1424. //
  1425. // get current masterkey encryption key.
  1426. //
  1427. ZeroMemory(&CredentialID, sizeof(CredentialID));
  1428. fUserCredentialValid = GetMasterKeyUserEncryptionKey(pvContext,
  1429. &CredentialID,
  1430. pSid,
  1431. USE_ROOT_CREDENTIAL |
  1432. ((hMasterKey.dwPolicy & POLICY_DPAPI_OWF)?USE_DPAPI_OWF:0),
  1433. rgbMKEncryptionKey);
  1434. if( fUserCredentialValid )
  1435. {
  1436. //
  1437. // retrieve and decrypt MK with current credential.
  1438. // if success, see if pending phase one/two backup required [make it so]
  1439. //
  1440. #ifdef COMPILED_BY_DEVELOPER
  1441. D_DebugLog((DEB_TRACE, "MK decryption key:\n"));
  1442. D_DPAPIDumpHexData(DEB_TRACE, " ", rgbMKEncryptionKey, sizeof(rgbMKEncryptionKey));
  1443. #endif
  1444. dwLastError = DecryptMasterKeyFromStorage(
  1445. &hMasterKey,
  1446. REGVAL_MASTER_KEY,
  1447. rgbMKEncryptionKey,
  1448. &fUpgradeEncryption,
  1449. ppbMasterKey,
  1450. pcbMasterKey
  1451. );
  1452. #if DBG
  1453. if(dwLastError == ERROR_SUCCESS)
  1454. {
  1455. #ifdef COMPILED_BY_DEVELOPER
  1456. D_DebugLog((DEB_TRACE, "Master key:\n"));
  1457. D_DPAPIDumpHexData(DEB_TRACE, " ", *ppbMasterKey, *pcbMasterKey);
  1458. #endif
  1459. }
  1460. else
  1461. {
  1462. D_DebugLog((DEB_WARN, "Decryption with current user MK failed\n"));
  1463. }
  1464. #endif
  1465. }
  1466. else
  1467. {
  1468. D_DebugLog((DEB_WARN, "GetMasterKeyUserEncryptionKey failed: 0x%x\n", GetLastError()));
  1469. }
  1470. if( fUpgradeEncryption || fMigrate || (dwLastError != ERROR_SUCCESS ))
  1471. {
  1472. //
  1473. // if the MK fails to decrypt, attempt recovery.
  1474. // if recovery succeeds, re-encrypt MK with current credential.
  1475. //
  1476. if(dwLastError != ERROR_SUCCESS)
  1477. {
  1478. dwLastError = RestoreMasterKey(
  1479. pvContext,
  1480. pSid,
  1481. &hMasterKey,
  1482. dwLastError,
  1483. ppbMasterKey,
  1484. pcbMasterKey
  1485. );
  1486. fUpgradeEncryption = TRUE;
  1487. }
  1488. //
  1489. // If this is a migration, we must get the current real user storage
  1490. // area, not the one that the key was retrieved from.
  1491. //
  1492. if((ERROR_SUCCESS == dwLastError) &&
  1493. (fMigrate))
  1494. {
  1495. wszOldFilePath = hMasterKey.szFilePath;
  1496. hMasterKey.szFilePath = NULL;
  1497. dwLastError = CPSGetUserStorageArea( pvContext,
  1498. NULL,
  1499. FALSE,
  1500. &hMasterKey.szFilePath );
  1501. }
  1502. //
  1503. // recovery succeeded, re-encrypt the masterkey if the user credential
  1504. // is valid.
  1505. // Also re-encrypt if fUpgradeEncryption indicates that we're
  1506. // not meeting current policy with this master key.
  1507. //
  1508. if( fUpgradeEncryption && (dwLastError == ERROR_SUCCESS ))
  1509. {
  1510. if( fUserCredentialValid )
  1511. {
  1512. D_DebugLog((DEB_TRACE, "Update master key encryption.\n"));
  1513. dwLastError = EncryptMasterKeyToStorage(
  1514. &hMasterKey,
  1515. REGVAL_MASTER_KEY,
  1516. rgbMKEncryptionKey,
  1517. *ppbMasterKey,
  1518. *pcbMasterKey
  1519. );
  1520. if(dwLastError != ERROR_SUCCESS)
  1521. {
  1522. D_DebugLog((DEB_WARN, "Error encrypting master key!\n"));
  1523. }
  1524. // Update the local backup information
  1525. if(dwLastError == ERROR_SUCCESS)
  1526. {
  1527. LOCAL_BACKUP_DATA LocalBackupData;
  1528. if(hMasterKey.pbBK != NULL && hMasterKey.cbBK >= sizeof(LocalBackupData))
  1529. {
  1530. CopyMemory(&LocalBackupData, hMasterKey.pbBK, sizeof(LocalBackupData));
  1531. if(LocalBackupData.dwVersion == MASTERKEY_BLOB_LOCALKEY_BACKUP)
  1532. {
  1533. #ifdef COMPILED_BY_DEVELOPER
  1534. D_DebugLog((DEB_TRACE, "New MK encryption key GUID:\n"));
  1535. D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)&LocalBackupData.CredentialID, sizeof(LocalBackupData.CredentialID));
  1536. #endif
  1537. CopyMemory(&LocalBackupData.CredentialID, &CredentialID, sizeof(CredentialID));
  1538. PersistMasterKeyToStorage(
  1539. &hMasterKey,
  1540. REGVAL_BACKUP_LCL_KEY,
  1541. (PBYTE)&LocalBackupData,
  1542. sizeof(LocalBackupData)
  1543. );
  1544. }
  1545. }
  1546. }
  1547. }
  1548. }
  1549. if(ERROR_SUCCESS != dwLastError)
  1550. {
  1551. //
  1552. // treat recovery failure as storage error so that a new key can
  1553. // be created for Protect operations.
  1554. //
  1555. if(dwLastError == SEC_E_DELEGATION_REQUIRED)
  1556. {
  1557. *pdwMasterKeyDisposition = MK_DISP_DELEGATION_ERR;
  1558. }
  1559. else
  1560. {
  1561. *pdwMasterKeyDisposition = MK_DISP_STORAGE_ERR;
  1562. }
  1563. }
  1564. }
  1565. if( dwLastError == ERROR_SUCCESS )
  1566. {
  1567. //
  1568. // after access, do backup if necessary.
  1569. // we check this each access to see if deferred backup required.
  1570. // (note: employ a back-off interval so we don't bang the network
  1571. // constantly when it isn't around).
  1572. //
  1573. BOOL fPhaseTwo;
  1574. if(fUserCredentialValid && IsBackupMasterKeyRequired( &hMasterKey, &fPhaseTwo ))
  1575. {
  1576. if(BackupMasterKey(
  1577. pvContext,
  1578. &hMasterKey,
  1579. *ppbMasterKey,
  1580. *pcbMasterKey,
  1581. fPhaseTwo, // phase two backup required?
  1582. TRUE // always asynchronous during key retrieve
  1583. ) == ERROR_SUCCESS)
  1584. {
  1585. if(fPhaseTwo)
  1586. *pdwMasterKeyDisposition = MK_DISP_BCK_DC;
  1587. else
  1588. *pdwMasterKeyDisposition = MK_DISP_BCK_LCL;
  1589. }
  1590. }
  1591. if( *pdwMasterKeyDisposition == MK_DISP_UNKNOWN_ERR )
  1592. {
  1593. *pdwMasterKeyDisposition = MK_DISP_OK;
  1594. }
  1595. fSuccess = TRUE;
  1596. }
  1597. if(!CloseMasterKey(pvContext, &hMasterKey, fSuccess))
  1598. {
  1599. fSuccess = FALSE;
  1600. }
  1601. if(fSuccess && (NULL != wszOldFilePath))
  1602. {
  1603. LPWSTR wszDeleteFilePath = NULL;
  1604. // Delete the old key, now that the new one has been migrated.
  1605. wszDeleteFilePath = (LPWSTR)SSAlloc((wcslen(wszOldFilePath) +
  1606. wcslen(wszMasterKey) +
  1607. 2) * sizeof(WCHAR));
  1608. if(NULL != wszDeleteFilePath)
  1609. {
  1610. wcscpy(wszDeleteFilePath, wszOldFilePath);
  1611. wcscat(wszDeleteFilePath, L"\\");
  1612. wcscat(wszDeleteFilePath, wszMasterKey);
  1613. DeleteFile(wszDeleteFilePath);
  1614. SSFree(wszDeleteFilePath);
  1615. }
  1616. }
  1617. return fSuccess;
  1618. }
  1619. BOOL
  1620. GetMasterKeyUserEncryptionKey(
  1621. IN PVOID pvContext,
  1622. OUT GUID *pCredentialID,
  1623. IN PSID pSid,
  1624. IN DWORD dwFlags,
  1625. IN OUT BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN]
  1626. )
  1627. /*++
  1628. This routine gets the key used to encrypt and decrypt the persisted
  1629. master key MK. This routine returns a copy of a function of the per-user
  1630. logon credential used during Windows NT logon.
  1631. If the function succeeds, the return value is TRUE, and the buffer
  1632. specified with by the rgbMKEncryptionKey parameter is filled with the
  1633. masterkey encryption key.
  1634. The return value is FALSE if the encryption key could not be obtained.
  1635. --*/
  1636. {
  1637. BOOL fLocalMachine = FALSE;
  1638. DWORD dwAccount = 0;
  1639. LPWSTR pszUserName = NULL;
  1640. DWORD cchUserName;
  1641. DWORD dwLastError;
  1642. BOOL fSystemCred = FALSE;
  1643. BOOL fSuccess = TRUE;
  1644. //
  1645. // see if the call is for shared, CRYPT_PROTECT_LOCAL_MACHINE
  1646. // disposition.
  1647. //
  1648. CPSOverrideToLocalSystem(
  1649. pvContext,
  1650. NULL, // don't change current over-ride BOOL
  1651. &fLocalMachine
  1652. );
  1653. CPSQueryWellKnownAccount(
  1654. pvContext,
  1655. &dwAccount);
  1656. //
  1657. // if the context specified per-machine, we know that it's a system credential.
  1658. // also, we don't need to get the user name in this scenario.
  1659. //
  1660. if(fLocalMachine || (dwAccount != 0))
  1661. {
  1662. fSystemCred = TRUE;
  1663. }
  1664. if( !fSystemCred )
  1665. {
  1666. if(pSid)
  1667. {
  1668. WCHAR wszTextualSid[MAX_PATH+1];
  1669. cchUserName = MAX_PATH+1;
  1670. if(!GetTextualSid(pSid, wszTextualSid, &cchUserName))
  1671. {
  1672. SetLastError(ERROR_INVALID_PARAMETER);
  1673. return FALSE;
  1674. }
  1675. pszUserName = (LPWSTR)SSAlloc(cchUserName*sizeof(WCHAR));
  1676. if(NULL == pszUserName)
  1677. {
  1678. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1679. return FALSE;
  1680. }
  1681. wcscpy(pszUserName, wszTextualSid);
  1682. cchUserName = wcslen(pszUserName) + 1;
  1683. }
  1684. else
  1685. {
  1686. //
  1687. // use the user name (actually Sid), as the mixing bytes.
  1688. //
  1689. dwLastError = CPSGetUserName(
  1690. pvContext,
  1691. &pszUserName,
  1692. &cchUserName
  1693. );
  1694. if( dwLastError != ERROR_SUCCESS )
  1695. {
  1696. SetLastError( dwLastError );
  1697. return FALSE;
  1698. }
  1699. }
  1700. }
  1701. //
  1702. // pickup credential for the local system account.
  1703. //
  1704. if( fSystemCred )
  1705. {
  1706. dwLastError = CPSGetSystemCredential(
  1707. pvContext,
  1708. fLocalMachine,
  1709. rgbMKEncryptionKey
  1710. );
  1711. if(pCredentialID)
  1712. {
  1713. ZeroMemory(pCredentialID, sizeof(GUID));
  1714. }
  1715. }
  1716. else
  1717. {
  1718. dwLastError = CPSGetDerivedCredential(
  1719. pvContext,
  1720. pCredentialID,
  1721. dwFlags,
  1722. (PBYTE)pszUserName,
  1723. cchUserName * sizeof(WCHAR),
  1724. rgbMKEncryptionKey
  1725. );
  1726. }
  1727. if( pszUserName )
  1728. SSFree( pszUserName );
  1729. if( dwLastError != ERROR_SUCCESS )
  1730. {
  1731. SetLastError( dwLastError );
  1732. fSuccess = FALSE;
  1733. }
  1734. return fSuccess;
  1735. }
  1736. BOOL
  1737. GetLocalKeyUserEncryptionKey(
  1738. IN PVOID pvContext,
  1739. IN PMASTERKEY_STORED phMasterKey,
  1740. IN OUT BYTE rgbLKEncryptionKey[A_SHA_DIGEST_LEN]
  1741. )
  1742. /*++
  1743. This routine gets the key used to encrypt and decrypt the persisted
  1744. local key MK. This routine returns a copy of a function of the per-user
  1745. logon name or Sid. This is a fixed, derivable key which is required in
  1746. order to satisfy minimal stand-alone entropy.
  1747. If the function succeeds, the return value is TRUE, and the buffer
  1748. specified with by the rgbLKEncryptionKey parameter is filled with the
  1749. masterkey encryption key.
  1750. The return value is FALSE if the encryption key could not be obtained.
  1751. --*/
  1752. {
  1753. A_SHA_CTX shaContext;
  1754. LPWSTR wszUserName;
  1755. DWORD cchUserName; // includes terminal NULL
  1756. BOOL fSuccess = TRUE;
  1757. if( CPSGetUserName(
  1758. pvContext,
  1759. &wszUserName,
  1760. &cchUserName
  1761. ) != ERROR_SUCCESS) {
  1762. return FALSE;
  1763. }
  1764. A_SHAInit( &shaContext );
  1765. A_SHAUpdate( &shaContext, (PBYTE)wszUserName, cchUserName * sizeof(WCHAR) );
  1766. //
  1767. // if it's above version 1, and it's local only policy, mix in LSA keys.
  1768. //
  1769. if( phMasterKey->dwVersion > 1 && phMasterKey->dwPolicy & POLICY_LOCAL_BACKUP ) {
  1770. BYTE rgbEncryptionKey[ A_SHA_DIGEST_LEN ];
  1771. DWORD dwLastError;
  1772. dwLastError = CPSGetSystemCredential(
  1773. pvContext,
  1774. TRUE,
  1775. rgbEncryptionKey
  1776. );
  1777. if( dwLastError == ERROR_SUCCESS ) {
  1778. A_SHAUpdate( &shaContext, rgbEncryptionKey, sizeof(rgbEncryptionKey) );
  1779. dwLastError = CPSGetSystemCredential(
  1780. pvContext,
  1781. FALSE,
  1782. rgbEncryptionKey
  1783. );
  1784. A_SHAUpdate( &shaContext, rgbEncryptionKey, sizeof(rgbEncryptionKey) );
  1785. }
  1786. RtlSecureZeroMemory( rgbEncryptionKey, sizeof(rgbEncryptionKey) );
  1787. if( dwLastError != ERROR_SUCCESS )
  1788. fSuccess = FALSE;
  1789. }
  1790. A_SHAFinal( &shaContext, rgbLKEncryptionKey );
  1791. SSFree(wszUserName);
  1792. return fSuccess;
  1793. }
  1794. DWORD
  1795. DecryptMasterKeyToMemory(
  1796. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  1797. IN PBYTE pbMasterKeyIn,
  1798. IN DWORD cbMasterKeyIn,
  1799. OUT BOOL *pfUpgradeEncryption,
  1800. OUT PBYTE *ppbMasterKeyOut,
  1801. OUT DWORD *pcbMasterKeyOut
  1802. )
  1803. {
  1804. PMASTERKEY_BLOB pMasterKeyBlob;
  1805. DWORD cbMasterKeyBlob = cbMasterKeyIn;
  1806. PMASTERKEY_INNER_BLOB pMasterKeyInnerBlob;
  1807. DWORD cIterationCount = 0;
  1808. DWORD cbMasterKeyBlobHeader;
  1809. PBYTE pbMasterKey;
  1810. DWORD cbMasterKey;
  1811. ALG_ID EncryptionAlg = CALG_RC4;
  1812. ALG_ID PKCS5Alg = CALG_HMAC;
  1813. BYTE rgbSymKey[A_SHA_DIGEST_LEN*2]; // big enough to handle 3des keys
  1814. BYTE rgbMacKey[A_SHA_DIGEST_LEN];
  1815. BYTE rgbMacCandidate[A_SHA_DIGEST_LEN];
  1816. DWORD dwLastError = (DWORD)NTE_BAD_KEY;
  1817. DWORD KeyBlocks = 1;
  1818. if(pfUpgradeEncryption)
  1819. {
  1820. *pfUpgradeEncryption = FALSE;
  1821. }
  1822. //
  1823. // Alloc, so we do not modify passed in data
  1824. //
  1825. pMasterKeyBlob = (PMASTERKEY_BLOB)SSAlloc( cbMasterKeyBlob );
  1826. if(pMasterKeyBlob == NULL)
  1827. return (DWORD)NTE_BAD_KEY;
  1828. CopyMemory( pMasterKeyBlob, pbMasterKeyIn, cbMasterKeyBlob );
  1829. if(pMasterKeyBlob->dwVersion > MASTERKEY_BLOB_VERSION)
  1830. goto cleanup;
  1831. if(MASTERKEY_BLOB_VERSION_W2K == pMasterKeyBlob->dwVersion)
  1832. {
  1833. pMasterKeyInnerBlob =
  1834. (PMASTERKEY_INNER_BLOB)(((PMASTERKEY_BLOB_W2K)pMasterKeyBlob) + 1);
  1835. cIterationCount = 0;
  1836. cbMasterKeyBlobHeader = sizeof(MASTERKEY_BLOB_W2K);
  1837. }
  1838. else
  1839. {
  1840. pMasterKeyInnerBlob = (PMASTERKEY_INNER_BLOB)(pMasterKeyBlob + 1);
  1841. cIterationCount = pMasterKeyBlob->IterationCount;
  1842. cbMasterKeyBlobHeader = sizeof(MASTERKEY_BLOB);
  1843. PKCS5Alg = (ALG_ID)pMasterKeyBlob->KEYGENAlg;
  1844. EncryptionAlg = (ALG_ID)pMasterKeyBlob->EncryptionAlg;
  1845. if(CALG_3DES == EncryptionAlg)
  1846. {
  1847. KeyBlocks = 2; // enough blocks for 3des
  1848. }
  1849. else
  1850. {
  1851. KeyBlocks = 1;
  1852. }
  1853. }
  1854. if(pfUpgradeEncryption)
  1855. {
  1856. if(!FIsLegacyCompliant())
  1857. {
  1858. //
  1859. // If we're not in legacy mode, upgrade the master key encryption
  1860. // if we're not using CALG_3DES or enough iterations
  1861. if((cIterationCount < GetIterationCount()) ||
  1862. (CALG_3DES != EncryptionAlg))
  1863. {
  1864. *pfUpgradeEncryption = TRUE;
  1865. }
  1866. }
  1867. }
  1868. if(cIterationCount)
  1869. {
  1870. DWORD j;
  1871. //
  1872. // derive symetric key via rgbMKEncryptionKey and random R2
  1873. // using PKCS#5 keying function PBKDF2
  1874. //
  1875. for(j=0; j < KeyBlocks; j++)
  1876. {
  1877. if(!PKCS5DervivePBKDF2( rgbMKEncryptionKey,
  1878. A_SHA_DIGEST_LEN,
  1879. pMasterKeyBlob->R2,
  1880. MASTERKEY_R2_LEN,
  1881. PKCS5Alg,
  1882. cIterationCount,
  1883. j+1,
  1884. rgbSymKey + j*A_SHA_DIGEST_LEN))
  1885. goto cleanup;
  1886. }
  1887. }
  1888. else
  1889. {
  1890. //
  1891. // derive symetric key via rgbMKEncryptionKey and random R2
  1892. // using the weak W2K mechanism
  1893. //
  1894. if(!FMyPrimitiveHMACParam(
  1895. rgbMKEncryptionKey,
  1896. A_SHA_DIGEST_LEN,
  1897. pMasterKeyBlob->R2,
  1898. MASTERKEY_R2_LEN,
  1899. rgbSymKey
  1900. ))
  1901. goto cleanup;
  1902. }
  1903. //
  1904. // decrypt data R3, MAC, pbMasterKey beyond masterkey blob
  1905. //
  1906. if(CALG_RC4 == EncryptionAlg)
  1907. {
  1908. RC4_KEYSTRUCT sRC4Key; //
  1909. // initialize rc4 key
  1910. //
  1911. rc4_key(&sRC4Key, A_SHA_DIGEST_LEN, rgbSymKey);
  1912. rc4(&sRC4Key,
  1913. cbMasterKeyBlob - cbMasterKeyBlobHeader,
  1914. (PBYTE)pMasterKeyInnerBlob);
  1915. }
  1916. else if (CALG_3DES == EncryptionAlg)
  1917. {
  1918. DES3TABLE s3DESKey;
  1919. BYTE InputBlock[DES_BLOCKLEN];
  1920. DWORD iBlock;
  1921. DWORD cBlocks = (cbMasterKeyBlob - cbMasterKeyBlobHeader)/DES_BLOCKLEN;
  1922. BYTE feedback[ DES_BLOCKLEN ];
  1923. // initialize 3des key
  1924. //
  1925. if(cBlocks*DES_BLOCKLEN != (cbMasterKeyBlob - cbMasterKeyBlobHeader))
  1926. {
  1927. // Master key must be a multiple of DES_BLOCKLEN
  1928. return (DWORD)NTE_BAD_KEY;
  1929. }
  1930. tripledes3key(&s3DESKey, rgbSymKey);
  1931. //
  1932. // IV is derived from the DES_BLOCKLEN bytes of the calculated
  1933. // rgbSymKey, after the 3des key
  1934. CopyMemory(feedback, rgbSymKey + DES3_KEYSIZE, DES_BLOCKLEN);
  1935. for(iBlock=0; iBlock < cBlocks; iBlock++)
  1936. {
  1937. CopyMemory(InputBlock,
  1938. ((PBYTE)pMasterKeyInnerBlob)+iBlock*DES_BLOCKLEN,
  1939. DES_BLOCKLEN);
  1940. CBC(tripledes,
  1941. DES_BLOCKLEN,
  1942. ((PBYTE)pMasterKeyInnerBlob)+iBlock*DES_BLOCKLEN,
  1943. InputBlock,
  1944. &s3DESKey,
  1945. DECRYPT,
  1946. feedback);
  1947. }
  1948. }
  1949. else
  1950. {
  1951. // Unknown cipher....
  1952. return (DWORD)NTE_BAD_KEY;
  1953. }
  1954. //
  1955. // adjust cipher start point to include R3 and MAC.
  1956. //
  1957. if(MASTERKEY_BLOB_VERSION_W2K == pMasterKeyBlob->dwVersion)
  1958. {
  1959. pbMasterKey =
  1960. (PBYTE)(((PMASTERKEY_INNER_BLOB_W2K)pMasterKeyInnerBlob) + 1);
  1961. cbMasterKey = cbMasterKeyBlob - cbMasterKeyBlobHeader - sizeof(MASTERKEY_INNER_BLOB_W2K);
  1962. }
  1963. else
  1964. {
  1965. pbMasterKey = (PBYTE)(pMasterKeyInnerBlob + 1);
  1966. cbMasterKey = cbMasterKeyBlob - cbMasterKeyBlobHeader - sizeof(MASTERKEY_INNER_BLOB);
  1967. }
  1968. //
  1969. // derive MAC key via HMAC from rgbMKEncryptionKey and random R3.
  1970. //
  1971. if(!FMyPrimitiveHMACParam(
  1972. rgbMKEncryptionKey,
  1973. A_SHA_DIGEST_LEN,
  1974. pMasterKeyInnerBlob->R3,
  1975. MASTERKEY_R3_LEN,
  1976. rgbMacKey
  1977. ))
  1978. {
  1979. goto cleanup;
  1980. }
  1981. //
  1982. // use MAC key to derive result from pbMasterKey
  1983. //
  1984. if(!FMyPrimitiveHMACParam(
  1985. rgbMacKey,
  1986. sizeof(rgbMacKey),
  1987. pbMasterKey,
  1988. cbMasterKey,
  1989. rgbMacCandidate // resultant MAC for verification.
  1990. ))
  1991. goto cleanup;
  1992. //
  1993. // verify MAC equality
  1994. //
  1995. if(memcmp(pMasterKeyInnerBlob->MAC, rgbMacCandidate, A_SHA_DIGEST_LEN) != 0)
  1996. goto cleanup;
  1997. //
  1998. // give caller results.
  1999. //
  2000. *ppbMasterKeyOut = (LPBYTE)SSAlloc( cbMasterKey );
  2001. if(*ppbMasterKeyOut == NULL) {
  2002. dwLastError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2003. goto cleanup;
  2004. }
  2005. CopyMemory(*ppbMasterKeyOut, pbMasterKey, cbMasterKey);
  2006. *pcbMasterKeyOut = cbMasterKey;
  2007. dwLastError = ERROR_SUCCESS;
  2008. cleanup:
  2009. if(pMasterKeyBlob) {
  2010. RtlSecureZeroMemory(pMasterKeyBlob, cbMasterKeyBlob);
  2011. SSFree( pMasterKeyBlob );
  2012. }
  2013. return dwLastError;
  2014. }
  2015. DWORD
  2016. DecryptMasterKeyFromStorage(
  2017. IN PMASTERKEY_STORED phMasterKey,
  2018. IN DWORD dwMKLoc,
  2019. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  2020. OUT BOOL *pfUpgradeEncryption,
  2021. OUT PBYTE *ppbMasterKey,
  2022. OUT DWORD *pcbMasterKey
  2023. )
  2024. {
  2025. PBYTE pbRegData;
  2026. DWORD cbRegData;
  2027. //
  2028. // fetch blob from storage.
  2029. //
  2030. switch( dwMKLoc ) {
  2031. case REGVAL_MASTER_KEY:
  2032. pbRegData = phMasterKey->pbMK;
  2033. cbRegData = phMasterKey->cbMK;
  2034. break;
  2035. case REGVAL_LOCAL_KEY:
  2036. pbRegData = phMasterKey->pbLK;
  2037. cbRegData = phMasterKey->cbLK;
  2038. break;
  2039. case REGVAL_BACKUP_LCL_KEY:
  2040. pbRegData = phMasterKey->pbBK;
  2041. cbRegData = phMasterKey->cbBK;
  2042. break;
  2043. case REGVAL_BACKUP_DC_KEY:
  2044. pbRegData = phMasterKey->pbBBK;
  2045. cbRegData = phMasterKey->cbBBK;
  2046. break;
  2047. default:
  2048. return NTE_BAD_KEY;
  2049. }
  2050. if( cbRegData == 0 || pbRegData == NULL )
  2051. return (DWORD)NTE_BAD_KEY;
  2052. return DecryptMasterKeyToMemory(
  2053. rgbMKEncryptionKey,
  2054. pbRegData,
  2055. cbRegData,
  2056. pfUpgradeEncryption,
  2057. ppbMasterKey,
  2058. pcbMasterKey
  2059. );
  2060. }
  2061. DWORD
  2062. EncryptMasterKeyToStorage(
  2063. IN PMASTERKEY_STORED phMasterKey,
  2064. IN DWORD dwMKLoc,
  2065. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  2066. IN PBYTE pbMasterKey,
  2067. IN DWORD cbMasterKey
  2068. )
  2069. /*++
  2070. Encrypt the pbMasterKey using rgbMKEncryptionKey, storing (persisting) the
  2071. result to the registry key and location specified by hMasterKey, wszMKLoc.
  2072. --*/
  2073. {
  2074. PBYTE pbMasterKeyOut = NULL;
  2075. DWORD cbMasterKeyOut;
  2076. DWORD dwLastError;
  2077. DWORD dwIterationCount = 1;
  2078. D_DebugLog((DEB_TRACE_API, "EncryptMasterKeyToStorage\n"));
  2079. if(dwMKLoc == REGVAL_MASTER_KEY)
  2080. {
  2081. dwIterationCount = GetIterationCount();
  2082. }
  2083. dwLastError = EncryptMasterKeyToMemory(
  2084. rgbMKEncryptionKey,
  2085. dwIterationCount,
  2086. pbMasterKey,
  2087. cbMasterKey,
  2088. &pbMasterKeyOut,
  2089. &cbMasterKeyOut
  2090. );
  2091. if(dwLastError != ERROR_SUCCESS)
  2092. {
  2093. goto cleanup;
  2094. }
  2095. dwLastError = PersistMasterKeyToStorage(
  2096. phMasterKey,
  2097. dwMKLoc,
  2098. pbMasterKeyOut,
  2099. cbMasterKeyOut
  2100. );
  2101. if( pbMasterKeyOut ) {
  2102. RtlSecureZeroMemory(pbMasterKeyOut, cbMasterKeyOut);
  2103. SSFree(pbMasterKeyOut);
  2104. }
  2105. cleanup:
  2106. D_DebugLog((DEB_TRACE_API, "EncryptMasterKeyToStorage returned 0x%x\n", dwLastError));
  2107. return dwLastError;
  2108. }
  2109. DWORD
  2110. PersistMasterKeyToStorage(
  2111. IN PMASTERKEY_STORED phMasterKey,
  2112. IN DWORD dwMKLoc,
  2113. IN PBYTE pbMasterKeyOut,
  2114. IN DWORD cbMasterKeyOut
  2115. )
  2116. /*++
  2117. Persist the specified key output material to storage.
  2118. --*/
  2119. {
  2120. PBYTE *ppbData;
  2121. DWORD *pcbData;
  2122. //
  2123. // fetch blob from storage.
  2124. //
  2125. switch( dwMKLoc ) {
  2126. case REGVAL_MASTER_KEY:
  2127. ppbData = &(phMasterKey->pbMK);
  2128. pcbData = &(phMasterKey->cbMK);
  2129. break;
  2130. case REGVAL_LOCAL_KEY:
  2131. ppbData = &(phMasterKey->pbLK);
  2132. pcbData = &(phMasterKey->cbLK);
  2133. break;
  2134. case REGVAL_BACKUP_LCL_KEY:
  2135. ppbData = &(phMasterKey->pbBK);
  2136. pcbData = &(phMasterKey->cbBK);
  2137. break;
  2138. case REGVAL_BACKUP_DC_KEY:
  2139. ppbData = &(phMasterKey->pbBBK);
  2140. pcbData = &(phMasterKey->cbBBK);
  2141. break;
  2142. default:
  2143. return NTE_BAD_KEY;
  2144. }
  2145. if( pbMasterKeyOut == NULL && cbMasterKeyOut == 0 ) {
  2146. //
  2147. // discard existing block if present.
  2148. //
  2149. if( *ppbData ) {
  2150. RtlSecureZeroMemory( *ppbData, *pcbData );
  2151. SSFree( *ppbData );
  2152. }
  2153. *ppbData = NULL;
  2154. *pcbData = 0;
  2155. return ERROR_SUCCESS;
  2156. }
  2157. //
  2158. // free the in-memory buffer associated with this data block if one
  2159. // was allocated previously.
  2160. //
  2161. if( *ppbData ) {
  2162. RtlSecureZeroMemory( *ppbData, *pcbData );
  2163. if( *pcbData < cbMasterKeyOut ) {
  2164. SSFree( *ppbData );
  2165. *ppbData = (LPBYTE)SSAlloc( cbMasterKeyOut );
  2166. }
  2167. } else {
  2168. *ppbData = (LPBYTE)SSAlloc( cbMasterKeyOut );
  2169. }
  2170. *pcbData = 0;
  2171. if( *ppbData == NULL )
  2172. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2173. *pcbData = cbMasterKeyOut ;
  2174. CopyMemory( *ppbData, pbMasterKeyOut, cbMasterKeyOut );
  2175. //
  2176. // a change occured in the master key.
  2177. //
  2178. phMasterKey->fModified = TRUE;
  2179. return ERROR_SUCCESS;
  2180. }
  2181. DWORD
  2182. QueryMasterKeyFromStorage(
  2183. IN PMASTERKEY_STORED phMasterKey,
  2184. IN DWORD dwMKLoc,
  2185. IN OUT PBYTE *ppbMasterKeyOut,
  2186. IN OUT DWORD *pcbMasterKeyOut
  2187. )
  2188. /*++
  2189. Query raw masterkey material from storage, returning a pointer to the
  2190. requested element for the caller.
  2191. On Success, the return value is ERROR_SUCCESS.
  2192. --*/
  2193. {
  2194. PBYTE pbData;
  2195. DWORD cbData;
  2196. //
  2197. // fetch blob from storage.
  2198. //
  2199. switch( dwMKLoc ) {
  2200. case REGVAL_MASTER_KEY:
  2201. pbData = phMasterKey->pbMK;
  2202. cbData = phMasterKey->cbMK;
  2203. break;
  2204. case REGVAL_LOCAL_KEY:
  2205. pbData = phMasterKey->pbLK;
  2206. cbData = phMasterKey->cbLK;
  2207. break;
  2208. case REGVAL_BACKUP_LCL_KEY:
  2209. pbData = phMasterKey->pbBK;
  2210. cbData = phMasterKey->cbBK;
  2211. break;
  2212. case REGVAL_BACKUP_DC_KEY:
  2213. pbData = phMasterKey->pbBBK;
  2214. cbData = phMasterKey->cbBBK;
  2215. break;
  2216. default:
  2217. return (DWORD)NTE_BAD_KEY;
  2218. }
  2219. if(cbData == 0 || pbData == NULL)
  2220. return (DWORD)NTE_BAD_KEY;
  2221. *ppbMasterKeyOut = pbData;
  2222. *pcbMasterKeyOut = cbData;
  2223. return ERROR_SUCCESS;
  2224. }
  2225. DWORD
  2226. EncryptMasterKeyToMemory(
  2227. IN BYTE rgbMKEncryptionKey[A_SHA_DIGEST_LEN],
  2228. IN DWORD cIterationCount,
  2229. IN PBYTE pbMasterKey,
  2230. IN DWORD cbMasterKey,
  2231. OUT PBYTE *ppbMasterKeyOut,
  2232. OUT DWORD *pcbMasterKeyOut
  2233. )
  2234. {
  2235. PMASTERKEY_BLOB pMasterKeyBlob;
  2236. DWORD cbMasterKeyBlob;
  2237. DWORD cbMasterInnerKeyBlob;
  2238. PMASTERKEY_INNER_BLOB pMasterKeyInnerBlob;
  2239. PBYTE pbCipherBegin;
  2240. BYTE rgbMacKey[A_SHA_DIGEST_LEN];
  2241. DWORD dwLastError = (DWORD)NTE_BAD_KEY;
  2242. BOOL fLegacyBlob = (FIsLegacyCompliant() || (0 == cIterationCount));
  2243. ALG_ID EncryptionAlg = CALG_3DES;
  2244. ALG_ID PKCS5Alg = CALG_HMAC;
  2245. BYTE rgbSymKey[A_SHA_DIGEST_LEN*2]; // big enough to handle 3des keys
  2246. DWORD KeyBlocks = 1;
  2247. if(!fLegacyBlob)
  2248. {
  2249. cbMasterInnerKeyBlob = sizeof(MASTERKEY_INNER_BLOB) +
  2250. cbMasterKey ;
  2251. cbMasterKeyBlob = sizeof(MASTERKEY_BLOB) +
  2252. cbMasterInnerKeyBlob;
  2253. }
  2254. else
  2255. {
  2256. EncryptionAlg = CALG_RC4;
  2257. cbMasterInnerKeyBlob = sizeof(MASTERKEY_INNER_BLOB_W2K) +
  2258. cbMasterKey ;
  2259. cbMasterKeyBlob = sizeof(MASTERKEY_BLOB_W2K) +
  2260. cbMasterInnerKeyBlob;
  2261. }
  2262. if(CALG_3DES == EncryptionAlg)
  2263. {
  2264. KeyBlocks = 2;
  2265. if(cbMasterInnerKeyBlob%DES_BLOCKLEN)
  2266. {
  2267. return NTE_BAD_KEY;
  2268. }
  2269. }
  2270. pMasterKeyBlob = (PMASTERKEY_BLOB)SSAlloc( cbMasterKeyBlob );
  2271. if(pMasterKeyBlob == NULL)
  2272. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  2273. if(!fLegacyBlob)
  2274. {
  2275. pMasterKeyBlob->dwVersion = MASTERKEY_BLOB_VERSION;
  2276. pMasterKeyInnerBlob = (PMASTERKEY_INNER_BLOB)(pMasterKeyBlob + 1);
  2277. }
  2278. else
  2279. {
  2280. pMasterKeyBlob->dwVersion = MASTERKEY_BLOB_VERSION_W2K;
  2281. pMasterKeyInnerBlob =
  2282. (PMASTERKEY_INNER_BLOB)(((PMASTERKEY_BLOB_W2K)pMasterKeyBlob) + 1);
  2283. }
  2284. //
  2285. // generate random R2 for SymKey
  2286. //
  2287. if(!RtlGenRandom(pMasterKeyBlob->R2, MASTERKEY_R2_LEN))
  2288. goto cleanup;
  2289. //
  2290. // generate random R3 for MAC
  2291. //
  2292. if(!RtlGenRandom(pMasterKeyInnerBlob->R3, MASTERKEY_R3_LEN))
  2293. goto cleanup;
  2294. if(!fLegacyBlob)
  2295. {
  2296. DWORD j;
  2297. //
  2298. // derive symetric key via rgbMKEncryptionKey and random R2
  2299. //
  2300. for(j=0; j < KeyBlocks; j++)
  2301. {
  2302. if(!PKCS5DervivePBKDF2(
  2303. rgbMKEncryptionKey,
  2304. A_SHA_DIGEST_LEN,
  2305. pMasterKeyBlob->R2,
  2306. MASTERKEY_R2_LEN,
  2307. PKCS5Alg,
  2308. cIterationCount,
  2309. j+1,
  2310. rgbSymKey+j*A_SHA_DIGEST_LEN
  2311. ))
  2312. goto cleanup;
  2313. }
  2314. pMasterKeyBlob->IterationCount = cIterationCount;
  2315. pMasterKeyBlob->EncryptionAlg = EncryptionAlg;
  2316. pMasterKeyBlob->KEYGENAlg = PKCS5Alg;
  2317. pbCipherBegin = (PBYTE)(pMasterKeyInnerBlob+1);
  2318. }
  2319. else
  2320. {
  2321. //
  2322. // derive symetric key via rgbMKEncryptionKey and random R2
  2323. //
  2324. if(!FMyPrimitiveHMACParam(
  2325. rgbMKEncryptionKey,
  2326. A_SHA_DIGEST_LEN,
  2327. pMasterKeyBlob->R2,
  2328. MASTERKEY_R2_LEN,
  2329. rgbSymKey
  2330. ))
  2331. goto cleanup;
  2332. pbCipherBegin = (PBYTE)(((PMASTERKEY_INNER_BLOB_W2K)pMasterKeyInnerBlob)+1);
  2333. }
  2334. //
  2335. // derive MAC key via HMAC from rgbMKEncryptionKey and random R3.
  2336. //
  2337. if(!FMyPrimitiveHMACParam(
  2338. rgbMKEncryptionKey,
  2339. A_SHA_DIGEST_LEN,
  2340. pMasterKeyInnerBlob->R3,
  2341. MASTERKEY_R3_LEN,
  2342. rgbMacKey // resultant MAC key
  2343. ))
  2344. {
  2345. goto cleanup;
  2346. }
  2347. //
  2348. // copy pbMasterKey following inner MAC'ish blob.
  2349. //
  2350. CopyMemory( pbCipherBegin, pbMasterKey, cbMasterKey );
  2351. //
  2352. // use MAC key to derive result from pbMasterKey
  2353. //
  2354. if(!FMyPrimitiveHMACParam(
  2355. rgbMacKey,
  2356. sizeof(rgbMacKey),
  2357. pbMasterKey,
  2358. cbMasterKey,
  2359. pMasterKeyInnerBlob->MAC // resultant MAC for verification.
  2360. ))
  2361. goto cleanup;
  2362. if(CALG_RC4 == EncryptionAlg)
  2363. {
  2364. RC4_KEYSTRUCT sRC4Key; //
  2365. // initialize rc4 key
  2366. //
  2367. rc4_key(&sRC4Key, A_SHA_DIGEST_LEN, rgbSymKey);
  2368. rc4(&sRC4Key,
  2369. cbMasterInnerKeyBlob,
  2370. (PBYTE)pMasterKeyInnerBlob);
  2371. }
  2372. else if (CALG_3DES == EncryptionAlg)
  2373. {
  2374. DES3TABLE s3DESKey;
  2375. BYTE InputBlock[DES_BLOCKLEN];
  2376. DWORD iBlock;
  2377. DWORD cBlocks = cbMasterInnerKeyBlob/DES_BLOCKLEN;
  2378. BYTE feedback[ DES_BLOCKLEN ];
  2379. // initialize 3des key
  2380. //
  2381. if(cBlocks*DES_BLOCKLEN != cbMasterInnerKeyBlob)
  2382. {
  2383. // Master key must be a multiple of DES_BLOCKLEN
  2384. return (DWORD)NTE_BAD_KEY;
  2385. }
  2386. tripledes3key(&s3DESKey, rgbSymKey);
  2387. //
  2388. // IV is derived from the DES_BLOCKLEN bytes of the calculated
  2389. // rgbSymKey, after the 3des key
  2390. CopyMemory(feedback, rgbSymKey + DES3_KEYSIZE, DES_BLOCKLEN);
  2391. for(iBlock=0; iBlock < cBlocks; iBlock++)
  2392. {
  2393. CopyMemory(InputBlock,
  2394. ((PBYTE)pMasterKeyInnerBlob)+iBlock*DES_BLOCKLEN,
  2395. DES_BLOCKLEN);
  2396. CBC(tripledes,
  2397. DES_BLOCKLEN,
  2398. ((PBYTE)pMasterKeyInnerBlob)+iBlock*DES_BLOCKLEN,
  2399. InputBlock,
  2400. &s3DESKey,
  2401. ENCRYPT,
  2402. feedback);
  2403. }
  2404. }
  2405. else
  2406. {
  2407. // Unknown cipher....
  2408. return (DWORD)NTE_BAD_KEY;
  2409. }
  2410. *ppbMasterKeyOut = (PBYTE)pMasterKeyBlob;
  2411. *pcbMasterKeyOut = cbMasterKeyBlob;
  2412. pMasterKeyBlob = NULL; // prevent free of blob on success (caller does it).
  2413. dwLastError = ERROR_SUCCESS;
  2414. cleanup:
  2415. if(pMasterKeyBlob) {
  2416. RtlSecureZeroMemory(pMasterKeyBlob, cbMasterKeyBlob);
  2417. SSFree(pMasterKeyBlob);
  2418. }
  2419. return dwLastError;
  2420. }
  2421. BOOL
  2422. IsBackupMasterKeyRequired(
  2423. IN PMASTERKEY_STORED phMasterKey,
  2424. IN OUT BOOL *pfPhaseTwo // is phase two required?
  2425. )
  2426. /*++
  2427. Determine if we need to do a phase one or phase two backup.
  2428. Return value is TRUE if phase one or phase two backup required.
  2429. pfPhaseTwo set TRUE if phase two backup required.
  2430. Return value is FALSE when backup not required.
  2431. --*/
  2432. {
  2433. DWORD dwMasterKeyPolicy;
  2434. PBYTE pbMasterKeyOut;
  2435. DWORD cbMasterKeyOut;
  2436. DWORD dwLastError;
  2437. dwMasterKeyPolicy = phMasterKey->dwPolicy;
  2438. if(dwMasterKeyPolicy & POLICY_NO_BACKUP)
  2439. return FALSE;
  2440. //
  2441. // evaluate what phase backup required based on policy.
  2442. //
  2443. *pfPhaseTwo = FALSE;
  2444. if(!(dwMasterKeyPolicy & POLICY_LOCAL_BACKUP)) {
  2445. dwLastError = QueryMasterKeyFromStorage(
  2446. phMasterKey,
  2447. REGVAL_BACKUP_DC_KEY,
  2448. &pbMasterKeyOut,
  2449. &cbMasterKeyOut
  2450. );
  2451. if(dwLastError != ERROR_SUCCESS) {
  2452. *pfPhaseTwo = TRUE;
  2453. return TRUE;
  2454. }
  2455. } else {
  2456. dwLastError = QueryMasterKeyFromStorage(
  2457. phMasterKey,
  2458. REGVAL_BACKUP_LCL_KEY,
  2459. &pbMasterKeyOut,
  2460. &cbMasterKeyOut
  2461. );
  2462. if(dwLastError != ERROR_SUCCESS)
  2463. return TRUE;
  2464. }
  2465. return FALSE;
  2466. }
  2467. BOOL
  2468. IsNT4Domain(void)
  2469. {
  2470. NTSTATUS Status;
  2471. LSA_HANDLE PolicyHandle = NULL;
  2472. OBJECT_ATTRIBUTES PolicyObjectAttributes;
  2473. PPOLICY_DNS_DOMAIN_INFO pDnsDomainInfo = NULL;
  2474. BOOL fRet = FALSE;
  2475. InitializeObjectAttributes( &PolicyObjectAttributes,
  2476. NULL, // Name
  2477. 0, // Attributes
  2478. NULL, // Root
  2479. NULL); // Security Descriptor
  2480. Status = LsaOpenPolicy(NULL,
  2481. &PolicyObjectAttributes,
  2482. POLICY_VIEW_LOCAL_INFORMATION,
  2483. &PolicyHandle);
  2484. if(!NT_SUCCESS(Status))
  2485. {
  2486. goto cleanup;
  2487. }
  2488. Status = LsaQueryInformationPolicy(PolicyHandle,
  2489. PolicyDnsDomainInformation,
  2490. (PVOID *)&pDnsDomainInfo);
  2491. if(!NT_SUCCESS(Status))
  2492. {
  2493. goto cleanup;
  2494. }
  2495. if((pDnsDomainInfo != NULL) &&
  2496. (pDnsDomainInfo->DnsDomainName.Buffer == NULL))
  2497. {
  2498. fRet = TRUE;
  2499. }
  2500. cleanup:
  2501. if(pDnsDomainInfo)
  2502. LsaFreeMemory(pDnsDomainInfo);
  2503. if(PolicyHandle)
  2504. LsaClose(PolicyHandle);
  2505. return fRet;
  2506. }
  2507. DWORD
  2508. BackupMasterKey(
  2509. IN PVOID pvContext,
  2510. IN PMASTERKEY_STORED phMasterKey,
  2511. IN LPBYTE pbMasterKey,
  2512. IN DWORD cbMasterKey,
  2513. IN BOOL fPhaseTwo, // is phase two required?
  2514. IN BOOL fAsynchronous // asynchronous call?
  2515. )
  2516. {
  2517. BYTE rgbLKEncryptionKey[ A_SHA_DIGEST_LEN ];
  2518. BYTE rgbBKEncryptionKey[ A_SHA_DIGEST_LEN ];
  2519. PBYTE pbLocalKey = NULL;
  2520. DWORD cbLocalKey = 0;
  2521. PBYTE pbBackupKeyPhaseOne = NULL;
  2522. DWORD cbBackupKeyPhaseOne = 0;
  2523. PBYTE pbBackupKeyPhaseTwo = NULL;
  2524. DWORD cbBackupKeyPhaseTwo = 0;
  2525. DWORD dwLastError = (DWORD)NTE_BAD_KEY;
  2526. BOOL fLegacy = FIsLegacyCompliant();
  2527. PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
  2528. //
  2529. // get current localkey encryption key.
  2530. //
  2531. if(!GetLocalKeyUserEncryptionKey(pvContext, phMasterKey, rgbLKEncryptionKey))
  2532. goto cleanup;
  2533. //
  2534. // retrieve and decrypt LK with current credential.
  2535. //
  2536. dwLastError = DecryptMasterKeyFromStorage(
  2537. phMasterKey,
  2538. REGVAL_LOCAL_KEY,
  2539. rgbLKEncryptionKey,
  2540. NULL,
  2541. &pbLocalKey,
  2542. &cbLocalKey
  2543. );
  2544. if(dwLastError != ERROR_SUCCESS)
  2545. goto cleanup;
  2546. //
  2547. // Are we running in an NT4 domain? If so, then force legacy mode so that
  2548. // the master key is backed up using the lsa secret scheme. Otherwise, the
  2549. // master key won't be recoverable following a password change.
  2550. //
  2551. if(FIsLegacyNt4Domain())
  2552. {
  2553. if(IsNT4Domain())
  2554. {
  2555. D_DebugLog((DEB_WARN,"NT4 domain detected, so force legacy backup mode!\n"));
  2556. fLegacy = TRUE;
  2557. }
  2558. }
  2559. if(fLegacy)
  2560. {
  2561. //
  2562. // derive BK encryption key from decrypted Local Key.
  2563. //
  2564. FMyPrimitiveSHA( pbLocalKey, cbLocalKey, rgbBKEncryptionKey );
  2565. //
  2566. // encrypt masterkey to phase one backup key, using encryption key derived
  2567. // from local key. do it in memory, such that we only commit it to disk if
  2568. // phase two backup key cannot be generated/persisted.
  2569. //
  2570. dwLastError = EncryptMasterKeyToMemory(
  2571. rgbBKEncryptionKey,
  2572. 0,
  2573. pbMasterKey,
  2574. cbMasterKey,
  2575. &pbBackupKeyPhaseOne,
  2576. &cbBackupKeyPhaseOne
  2577. );
  2578. if(dwLastError != ERROR_SUCCESS)
  2579. goto cleanup;
  2580. // Copy this in directly, so we do not set the modified flag
  2581. }
  2582. //
  2583. // attempt phase two backup (if policy permits).
  2584. //
  2585. if( fPhaseTwo ) {
  2586. DWORD dwWaitTimeout;
  2587. dwLastError = ERROR_SUCCESS;
  2588. //
  2589. // We only attempt a local backup if we
  2590. // have user keying material. Otherwise,
  2591. // we directly contact the DC
  2592. //
  2593. if(fAsynchronous && (!fLegacy))
  2594. {
  2595. if(ERROR_SUCCESS == dwLastError)
  2596. {
  2597. //
  2598. // Try to do this locally, without going
  2599. // off machine
  2600. dwLastError = AttemptLocalBackup(
  2601. FALSE,
  2602. pServerContext->hToken,
  2603. phMasterKey,
  2604. pbMasterKey,
  2605. cbMasterKey,
  2606. pbLocalKey,
  2607. cbLocalKey,
  2608. &pbBackupKeyPhaseTwo,
  2609. &cbBackupKeyPhaseTwo
  2610. );
  2611. }
  2612. if(ERROR_SUCCESS == dwLastError)
  2613. {
  2614. dwLastError = PersistMasterKeyToStorage(
  2615. phMasterKey,
  2616. REGVAL_BACKUP_DC_KEY,
  2617. pbBackupKeyPhaseTwo,
  2618. cbBackupKeyPhaseTwo
  2619. );
  2620. if(ERROR_SUCCESS == dwLastError)
  2621. {
  2622. // Zero out any local backup key that might
  2623. // be present
  2624. PersistMasterKeyToStorage(
  2625. phMasterKey,
  2626. REGVAL_BACKUP_LCL_KEY,
  2627. NULL,
  2628. 0
  2629. );
  2630. }
  2631. }
  2632. }
  2633. if(fLegacy || (!fAsynchronous) || (ERROR_SUCCESS != dwLastError))
  2634. {
  2635. //
  2636. // We couldn't back up locally
  2637. // so we need to go off machine
  2638. //
  2639. if( fAsynchronous )
  2640. dwWaitTimeout = 2000;
  2641. else
  2642. dwWaitTimeout = 20000;
  2643. dwLastError = QueueBackupMasterKey(
  2644. pvContext,
  2645. phMasterKey,
  2646. pbLocalKey,
  2647. cbLocalKey,
  2648. pbMasterKey,
  2649. cbMasterKey,
  2650. dwWaitTimeout
  2651. );
  2652. }
  2653. }
  2654. if( !fPhaseTwo || dwLastError != ERROR_SUCCESS ) {
  2655. DWORD dwTempError = ERROR_SUCCESS;
  2656. //
  2657. // couldn't (or policy didn't allow) backup to phase two.
  2658. // persist phase one key, if one was generated
  2659. //
  2660. if(pbBackupKeyPhaseOne)
  2661. {
  2662. // This will overwrite our local backup data indicating which credential
  2663. // will be able to decrypt the master key. However, since we have a
  2664. // phase one backup key anyway, it doesn't matter.
  2665. //
  2666. // This should only happen if fLegacy is true
  2667. dwTempError = PersistMasterKeyToStorage(
  2668. phMasterKey,
  2669. REGVAL_BACKUP_LCL_KEY,
  2670. pbBackupKeyPhaseOne,
  2671. cbBackupKeyPhaseOne
  2672. );
  2673. }
  2674. //
  2675. // if it was async, prop correct error code back.
  2676. //
  2677. if( fAsynchronous || !fPhaseTwo ) {
  2678. dwLastError = dwTempError;
  2679. } else {
  2680. if( dwLastError == ERROR_SUCCESS && dwTempError != ERROR_SUCCESS )
  2681. dwLastError = dwTempError;
  2682. }
  2683. }
  2684. cleanup:
  2685. RtlSecureZeroMemory( rgbLKEncryptionKey, sizeof(rgbLKEncryptionKey) );
  2686. RtlSecureZeroMemory( rgbBKEncryptionKey, sizeof(rgbBKEncryptionKey) );
  2687. if(pbLocalKey) {
  2688. RtlSecureZeroMemory(pbLocalKey, cbLocalKey);
  2689. SSFree(pbLocalKey);
  2690. }
  2691. if(pbBackupKeyPhaseOne) {
  2692. RtlSecureZeroMemory(pbBackupKeyPhaseOne, cbBackupKeyPhaseOne);
  2693. SSFree(pbBackupKeyPhaseOne);
  2694. }
  2695. if(pbBackupKeyPhaseTwo) {
  2696. RtlSecureZeroMemory(pbBackupKeyPhaseTwo, cbBackupKeyPhaseTwo);
  2697. SSFree(pbBackupKeyPhaseTwo);
  2698. }
  2699. return dwLastError;
  2700. }
  2701. DWORD
  2702. QueueBackupMasterKey(
  2703. IN PVOID pvContext,
  2704. IN PMASTERKEY_STORED phMasterKey,
  2705. IN PBYTE pbLocalKey,
  2706. IN DWORD cbLocalKey,
  2707. IN PBYTE pbMasterKey,
  2708. IN DWORD cbMasterKey,
  2709. IN DWORD dwWaitTimeout // amount of time to wait for operation to complete
  2710. )
  2711. {
  2712. HANDLE hDuplicateToken = NULL;
  2713. PMASTERKEY_STORED phDuplicatedMasterKey = NULL;
  2714. PQUEUED_BACKUP pQueuedBackup = NULL;
  2715. HANDLE hEventThread = NULL;
  2716. HANDLE hEventSuccess = NULL;
  2717. HANDLE hDuplicateEvent = NULL;
  2718. HANDLE hDuplicateEvent2 = NULL;
  2719. DWORD dwLastError;
  2720. //
  2721. // allocate memory for the structure and any trailing contents.
  2722. //
  2723. pQueuedBackup = (PQUEUED_BACKUP)SSAlloc(
  2724. sizeof(QUEUED_BACKUP) +
  2725. cbMasterKey +
  2726. cbLocalKey
  2727. );
  2728. if( pQueuedBackup == NULL )
  2729. return ERROR_OUTOFMEMORY;
  2730. pQueuedBackup->cbSize = sizeof(QUEUED_BACKUP);
  2731. //
  2732. // duplicate the phase one backup blob.
  2733. //
  2734. pQueuedBackup->pbLocalKey = (LPBYTE)(pQueuedBackup+1);
  2735. pQueuedBackup->cbLocalKey = cbLocalKey;
  2736. CopyMemory(pQueuedBackup->pbLocalKey, pbLocalKey, cbLocalKey);
  2737. // BUGBUG: pQueueBackup should not be pagable or should be protected.
  2738. pQueuedBackup->pbMasterKey = pQueuedBackup->pbLocalKey + cbLocalKey;
  2739. pQueuedBackup->cbMasterKey = cbMasterKey;
  2740. CopyMemory(pQueuedBackup->pbMasterKey, pbMasterKey, cbMasterKey);
  2741. //
  2742. // make a duplicate of the client access token.
  2743. //
  2744. dwLastError = CPSDuplicateClientAccessToken( pvContext, &hDuplicateToken );
  2745. if( dwLastError != ERROR_SUCCESS )
  2746. goto cleanup;
  2747. //
  2748. // duplicate the open masterkey
  2749. //
  2750. if(!DuplicateMasterKey( phMasterKey, &(pQueuedBackup->hMasterKey) )) {
  2751. dwLastError = ERROR_OUTOFMEMORY;
  2752. goto cleanup;
  2753. }
  2754. pQueuedBackup->hToken = hDuplicateToken;
  2755. phDuplicatedMasterKey = &(pQueuedBackup->hMasterKey);
  2756. hEventThread = CreateEventW( NULL, TRUE, FALSE, NULL );
  2757. if( hEventThread ) {
  2758. if( DuplicateHandle(
  2759. GetCurrentProcess(),
  2760. hEventThread,
  2761. GetCurrentProcess(),
  2762. &hDuplicateEvent,
  2763. 0,
  2764. FALSE,
  2765. DUPLICATE_SAME_ACCESS
  2766. )) {
  2767. pQueuedBackup->hEventThread = hDuplicateEvent;
  2768. } else {
  2769. hDuplicateEvent = NULL;
  2770. }
  2771. }
  2772. //
  2773. // create event which indicates success.
  2774. //
  2775. hEventSuccess = CreateEventW( NULL, TRUE, FALSE, NULL );
  2776. if( hEventSuccess ) {
  2777. if( DuplicateHandle(
  2778. GetCurrentProcess(),
  2779. hEventSuccess,
  2780. GetCurrentProcess(),
  2781. &hDuplicateEvent2,
  2782. 0,
  2783. FALSE,
  2784. DUPLICATE_SAME_ACCESS
  2785. )) {
  2786. pQueuedBackup->hEventSuccess = hDuplicateEvent2;
  2787. } else {
  2788. hDuplicateEvent2 = NULL;
  2789. }
  2790. }
  2791. //
  2792. // finally, create the worker thread.
  2793. //
  2794. if( !QueueUserWorkItem(
  2795. QueueBackupMasterKeyThreadFunc,
  2796. pQueuedBackup,
  2797. WT_EXECUTELONGFUNCTION
  2798. )) {
  2799. dwLastError = GetLastError();
  2800. goto cleanup;
  2801. }
  2802. //
  2803. // if the thread is still active, we write the master key out.
  2804. //
  2805. if( hEventThread ) {
  2806. if(WAIT_OBJECT_0 != WaitForSingleObject( hEventThread, dwWaitTimeout ))
  2807. dwLastError = STILL_ACTIVE;
  2808. }
  2809. if( hEventSuccess && dwLastError == ERROR_SUCCESS ) {
  2810. //
  2811. // check if operation succeeded.
  2812. // if not, indicate an error condition.
  2813. //
  2814. if(WAIT_OBJECT_0 != WaitForSingleObject( hEventSuccess, 0 ))
  2815. dwLastError = STILL_ACTIVE;
  2816. }
  2817. cleanup:
  2818. //
  2819. // if thread creation failed, we cleanup resources that were handed
  2820. // to the thread, since it cannot possibly clean them up.
  2821. //
  2822. if( dwLastError != ERROR_SUCCESS && dwLastError != STILL_ACTIVE ) {
  2823. if( hDuplicateToken )
  2824. CloseHandle( hDuplicateToken );
  2825. if( hDuplicateEvent )
  2826. CloseHandle( hDuplicateEvent );
  2827. if( hDuplicateEvent2 )
  2828. CloseHandle( hDuplicateEvent2 );
  2829. if( phDuplicatedMasterKey )
  2830. CloseMasterKey( pvContext, phDuplicatedMasterKey, FALSE );
  2831. if( pQueuedBackup )
  2832. SSFree( pQueuedBackup );
  2833. }
  2834. if( hEventThread )
  2835. CloseHandle( hEventThread );
  2836. if( hEventSuccess )
  2837. CloseHandle( hEventSuccess );
  2838. return dwLastError;
  2839. }
  2840. DWORD
  2841. WINAPI
  2842. QueueBackupMasterKeyThreadFunc(
  2843. IN LPVOID lpThreadArgument
  2844. )
  2845. {
  2846. PQUEUED_BACKUP pQueuedBackup = (PQUEUED_BACKUP)lpThreadArgument;
  2847. HANDLE hToken = NULL;
  2848. HANDLE hEventThread;
  2849. HANDLE hEventSuccess;
  2850. PMASTERKEY_STORED phMasterKey = NULL;
  2851. PBYTE pbBackupKeyPhaseOne = NULL;
  2852. DWORD cbBackupKeyPhaseOne = 0;
  2853. PBYTE pbBackupKeyPhaseTwo = NULL;
  2854. DWORD cbBackupKeyPhaseTwo = 0;
  2855. BOOL fImpersonated = FALSE;
  2856. DWORD dwLastError = ERROR_SUCCESS;
  2857. BOOL fSuccess = FALSE;
  2858. BOOL fSuccessClose = FALSE;
  2859. BOOL fLegacy = FIsLegacyCompliant();
  2860. //
  2861. // check structure version.
  2862. //
  2863. if(pQueuedBackup == NULL || pQueuedBackup->cbSize != sizeof(QUEUED_BACKUP))
  2864. return ERROR_INVALID_PARAMETER;
  2865. hToken = pQueuedBackup->hToken;
  2866. hEventThread = pQueuedBackup->hEventThread;
  2867. hEventSuccess = pQueuedBackup->hEventSuccess;
  2868. phMasterKey = &(pQueuedBackup->hMasterKey);
  2869. if(!fLegacy)
  2870. {
  2871. //
  2872. // Public was not available, so
  2873. // we need to try to retrieve it
  2874. //
  2875. dwLastError = AttemptLocalBackup(TRUE,
  2876. hToken,
  2877. phMasterKey,
  2878. pQueuedBackup->pbMasterKey,
  2879. pQueuedBackup->cbMasterKey,
  2880. pQueuedBackup->pbLocalKey,
  2881. pQueuedBackup->cbLocalKey,
  2882. &pbBackupKeyPhaseTwo,
  2883. &cbBackupKeyPhaseTwo
  2884. );
  2885. }
  2886. //
  2887. // impersonate the client user.
  2888. //
  2889. fImpersonated = SetThreadToken( NULL, hToken );
  2890. if(!fImpersonated)
  2891. {
  2892. dwLastError = GetLastError();
  2893. goto cleanup;
  2894. }
  2895. if((ERROR_SUCCESS != dwLastError) || fLegacy)
  2896. {
  2897. BYTE rgbBKEncryptionKey[ A_SHA_DIGEST_LEN ];
  2898. //
  2899. // derive BK encryption key from decrypted Local Key.
  2900. //
  2901. FMyPrimitiveSHA( pQueuedBackup->pbLocalKey, pQueuedBackup->cbLocalKey, rgbBKEncryptionKey );
  2902. //
  2903. // encrypt masterkey to phase one backup key, using encryption key derived
  2904. // from local key. do it in memory, such that we only commit it to disk if
  2905. // phase two backup key cannot be generated/persisted.
  2906. //
  2907. dwLastError = EncryptMasterKeyToMemory(
  2908. rgbBKEncryptionKey,
  2909. 0,
  2910. pQueuedBackup->pbMasterKey,
  2911. pQueuedBackup->cbMasterKey,
  2912. &pbBackupKeyPhaseOne,
  2913. &cbBackupKeyPhaseOne
  2914. );
  2915. RtlSecureZeroMemory(rgbBKEncryptionKey, sizeof(rgbBKEncryptionKey));
  2916. if(dwLastError != ERROR_SUCCESS)
  2917. goto cleanup;
  2918. // Copy this in directly, so we do not set the modified flag
  2919. // Perform a legacy style backup
  2920. dwLastError = BackupRestoreData(
  2921. NULL,
  2922. phMasterKey,
  2923. pbBackupKeyPhaseOne,
  2924. cbBackupKeyPhaseOne,
  2925. &pbBackupKeyPhaseTwo,
  2926. &cbBackupKeyPhaseTwo,
  2927. TRUE // backup data
  2928. );
  2929. }
  2930. if( dwLastError == ERROR_SUCCESS ) {
  2931. //
  2932. // perist phase two backup key to storage.
  2933. //
  2934. dwLastError = PersistMasterKeyToStorage(
  2935. phMasterKey,
  2936. REGVAL_BACKUP_DC_KEY,
  2937. pbBackupKeyPhaseTwo,
  2938. cbBackupKeyPhaseTwo
  2939. );
  2940. if( dwLastError == ERROR_SUCCESS ) {
  2941. //
  2942. // successful phase two backup+persist, nuke phase one backup
  2943. // master key.
  2944. //
  2945. PersistMasterKeyToStorage(
  2946. phMasterKey,
  2947. REGVAL_BACKUP_LCL_KEY,
  2948. NULL,
  2949. 0
  2950. );
  2951. fSuccess = TRUE;
  2952. }
  2953. }
  2954. cleanup:
  2955. //
  2956. // always close/free master key. Only if impersonation succeeeded
  2957. // do we attempt to flush it out.
  2958. //
  2959. fSuccessClose = CloseMasterKey( NULL, phMasterKey, fSuccess ) ;
  2960. if( hEventSuccess ) {
  2961. if( fSuccess && fSuccessClose )
  2962. SetEvent( hEventSuccess );
  2963. CloseHandle( hEventSuccess );
  2964. }
  2965. if( fImpersonated )
  2966. RevertToSelf();
  2967. if( hToken )
  2968. CloseHandle(hToken);
  2969. if( hEventThread ) {
  2970. SetEvent( hEventThread );
  2971. CloseHandle( hEventThread );
  2972. }
  2973. if(pbBackupKeyPhaseOne) {
  2974. RtlSecureZeroMemory(pbBackupKeyPhaseOne, cbBackupKeyPhaseOne);
  2975. SSFree(pbBackupKeyPhaseOne);
  2976. }
  2977. if(pbBackupKeyPhaseTwo) {
  2978. RtlSecureZeroMemory(pbBackupKeyPhaseTwo, cbBackupKeyPhaseTwo);
  2979. SSFree(pbBackupKeyPhaseTwo);
  2980. }
  2981. if( lpThreadArgument )
  2982. SSFree( lpThreadArgument );
  2983. return dwLastError;
  2984. }
  2985. DWORD
  2986. RestoreMasterKey(
  2987. IN PVOID pvContext,
  2988. IN PSID pSid,
  2989. IN PMASTERKEY_STORED phMasterKey,
  2990. IN DWORD dwReason,
  2991. OUT LPBYTE *ppbMasterKey,
  2992. OUT DWORD *pcbMasterKey
  2993. )
  2994. /*++
  2995. Recover the master key associated with the specified master key.
  2996. The current state of the masterkey dictates what level of recovery is
  2997. attempted.
  2998. --*/
  2999. {
  3000. static const GUID guidRestoreW2K = BACKUPKEY_RESTORE_GUID_W2K;
  3001. BYTE rgbLKEncryptionKey[ A_SHA_DIGEST_LEN ];
  3002. BYTE rgbBKEncryptionKey[ A_SHA_DIGEST_LEN ];
  3003. PBYTE pbLocalKey = NULL;
  3004. DWORD cbLocalKey = 0;
  3005. PBYTE pbBackupKeyPhaseOne = NULL;
  3006. DWORD cbBackupKeyPhaseOne = 0;
  3007. BOOL fAllocatedPhaseOne = FALSE;
  3008. DWORD dwLastError = (DWORD)NTE_BAD_KEY;
  3009. D_DebugLog((DEB_TRACE, "RestoreMasterKey:%ls\n", phMasterKey->wszguidMasterKey));
  3010. if(phMasterKey->pbBK)
  3011. {
  3012. LOCAL_BACKUP_DATA LocalBackupData;
  3013. // First, see if we have any local password-change recovery
  3014. // information.
  3015. if(phMasterKey->cbBK >= sizeof(LocalBackupData))
  3016. {
  3017. CopyMemory(&LocalBackupData, phMasterKey->pbBK, sizeof(LocalBackupData));
  3018. }
  3019. else
  3020. {
  3021. ZeroMemory(&LocalBackupData, sizeof(LocalBackupData));
  3022. }
  3023. if(MASTERKEY_BLOB_LOCALKEY_BACKUP == LocalBackupData.dwVersion)
  3024. {
  3025. D_DebugLog((DEB_TRACE, "Attempt local recovery.\n"));
  3026. #ifdef COMPILED_BY_DEVELOPER
  3027. D_DebugLog((DEB_TRACE, "MK decryption key GUID:\n"));
  3028. D_DPAPIDumpHexData(DEB_TRACE, " ", (PBYTE)&LocalBackupData.CredentialID, sizeof(LocalBackupData.CredentialID));
  3029. #endif
  3030. if(GetMasterKeyUserEncryptionKey(pvContext,
  3031. &LocalBackupData.CredentialID,
  3032. pSid,
  3033. ((phMasterKey->dwPolicy & POLICY_DPAPI_OWF)?USE_DPAPI_OWF:0),
  3034. rgbBKEncryptionKey))
  3035. {
  3036. //
  3037. // retrieve and decrypt MK with current credential.
  3038. //
  3039. #ifdef COMPILED_BY_DEVELOPER
  3040. D_DebugLog((DEB_TRACE, "MK decryption key:\n"));
  3041. D_DPAPIDumpHexData(DEB_TRACE, " ", rgbBKEncryptionKey, sizeof(rgbBKEncryptionKey));
  3042. #endif
  3043. dwLastError = DecryptMasterKeyFromStorage(
  3044. phMasterKey,
  3045. REGVAL_MASTER_KEY,
  3046. rgbBKEncryptionKey,
  3047. NULL,
  3048. ppbMasterKey,
  3049. pcbMasterKey
  3050. );
  3051. if(ERROR_SUCCESS == dwLastError)
  3052. {
  3053. #ifdef COMPILED_BY_DEVELOPER
  3054. D_DebugLog((DEB_TRACE, "Master key:\n"));
  3055. D_DPAPIDumpHexData(DEB_TRACE, " ", *ppbMasterKey, *pcbMasterKey);
  3056. #endif
  3057. goto cleanup;
  3058. }
  3059. else
  3060. {
  3061. D_DebugLog((DEB_WARN, "Unable to decrypt MK with local decryption key.\n"));
  3062. }
  3063. }
  3064. else
  3065. {
  3066. D_DebugLog((DEB_WARN, "Unable to locate local MK decryption key.\n"));
  3067. }
  3068. }
  3069. }
  3070. if(phMasterKey->pbBBK) {
  3071. //
  3072. // do phase two recovery.
  3073. // undoing phase two backup blob gives us phase one backup blob.
  3074. //
  3075. dwLastError = CPSImpersonateClient( pvContext );
  3076. if( dwLastError == ERROR_SUCCESS ) {
  3077. dwLastError = BackupRestoreData(
  3078. ((PCRYPT_SERVER_CONTEXT)pvContext)->hToken,
  3079. phMasterKey,
  3080. phMasterKey->pbBBK,
  3081. phMasterKey->cbBBK,
  3082. &pbBackupKeyPhaseOne,
  3083. &cbBackupKeyPhaseOne,
  3084. FALSE // do not backup data
  3085. );
  3086. if(ERROR_SUCCESS != dwLastError)
  3087. {
  3088. //
  3089. // Attempt a restore through the w2k restore port
  3090. //
  3091. dwLastError = LocalBackupRestoreData(
  3092. ((PCRYPT_SERVER_CONTEXT)pvContext)->hToken,
  3093. phMasterKey,
  3094. phMasterKey->pbBBK,
  3095. phMasterKey->cbBBK,
  3096. &pbBackupKeyPhaseOne,
  3097. &cbBackupKeyPhaseOne,
  3098. &guidRestoreW2K);
  3099. }
  3100. if(dwLastError == ERROR_SUCCESS)
  3101. fAllocatedPhaseOne = TRUE;
  3102. CPSRevertToSelf( pvContext );
  3103. }
  3104. } else {
  3105. //
  3106. // try phase one blob.
  3107. //
  3108. dwLastError = QueryMasterKeyFromStorage(
  3109. phMasterKey,
  3110. REGVAL_BACKUP_LCL_KEY,
  3111. &pbBackupKeyPhaseOne,
  3112. &cbBackupKeyPhaseOne
  3113. );
  3114. }
  3115. if(dwLastError != ERROR_SUCCESS)
  3116. goto cleanup;
  3117. //
  3118. // Check to see if this really is a phase one blob
  3119. //
  3120. if(cbBackupKeyPhaseOne < sizeof(DWORD))
  3121. {
  3122. goto cleanup;
  3123. }
  3124. if(*((DWORD *)pbBackupKeyPhaseOne) != MASTERKEY_BLOB_RAW_VERSION)
  3125. {
  3126. //
  3127. // we successfully got an phase one blob.
  3128. // decrypt it to get the original masterkey.
  3129. //
  3130. //
  3131. // get current localkey encryption key.
  3132. //
  3133. if(!GetLocalKeyUserEncryptionKey(pvContext, phMasterKey, rgbLKEncryptionKey))
  3134. goto cleanup;
  3135. //
  3136. // retrieve and decrypt LK with current credential.
  3137. //
  3138. dwLastError = DecryptMasterKeyFromStorage(
  3139. phMasterKey,
  3140. REGVAL_LOCAL_KEY,
  3141. rgbLKEncryptionKey,
  3142. NULL,
  3143. &pbLocalKey,
  3144. &cbLocalKey
  3145. );
  3146. if(dwLastError != ERROR_SUCCESS)
  3147. goto cleanup;
  3148. //
  3149. // derive BK encryption key from decrypted Local Key.
  3150. //
  3151. FMyPrimitiveSHA( pbLocalKey, cbLocalKey, rgbBKEncryptionKey );
  3152. //
  3153. // finally, decrypt BK using derived BKEncryptionKey
  3154. //
  3155. dwLastError = DecryptMasterKeyToMemory(
  3156. rgbBKEncryptionKey,
  3157. pbBackupKeyPhaseOne,
  3158. cbBackupKeyPhaseOne,
  3159. NULL,
  3160. ppbMasterKey,
  3161. pcbMasterKey
  3162. );
  3163. }
  3164. else
  3165. {
  3166. *ppbMasterKey = (PBYTE)SSAlloc(cbBackupKeyPhaseOne - sizeof(DWORD));
  3167. if(NULL == *ppbMasterKey)
  3168. {
  3169. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  3170. goto cleanup;
  3171. }
  3172. CopyMemory(*ppbMasterKey,
  3173. pbBackupKeyPhaseOne + sizeof(DWORD),
  3174. cbBackupKeyPhaseOne - sizeof(DWORD));
  3175. *pcbMasterKey = cbBackupKeyPhaseOne - sizeof(DWORD);
  3176. }
  3177. cleanup:
  3178. RtlSecureZeroMemory( rgbLKEncryptionKey, sizeof(rgbLKEncryptionKey) );
  3179. RtlSecureZeroMemory( rgbBKEncryptionKey, sizeof(rgbBKEncryptionKey) );
  3180. if(pbLocalKey) {
  3181. RtlSecureZeroMemory(pbLocalKey, cbLocalKey);
  3182. SSFree(pbLocalKey);
  3183. }
  3184. if(fAllocatedPhaseOne && pbBackupKeyPhaseOne) {
  3185. RtlSecureZeroMemory(pbBackupKeyPhaseOne, cbBackupKeyPhaseOne);
  3186. SSFree(pbBackupKeyPhaseOne);
  3187. }
  3188. D_DebugLog((DEB_TRACE, "RestoreMasterKey returned 0x%x\n", dwLastError));
  3189. return dwLastError;
  3190. }
  3191. //
  3192. // per-user root level policy query, set
  3193. //
  3194. BOOL
  3195. InitializeMasterKeyPolicy(
  3196. IN PVOID pvContext,
  3197. IN PMASTERKEY_STORED phMasterKey,
  3198. OUT BOOL *fLocalAccount
  3199. )
  3200. {
  3201. DWORD dwMasterKeyPolicy = 0;
  3202. DWORD dwAccount = 0;
  3203. BOOL fLocalMachine = FALSE;
  3204. //
  3205. // get current top-level policy.
  3206. //
  3207. dwMasterKeyPolicy = phMasterKey->dwPolicy | GetMasterKeyDefaultPolicy();
  3208. *fLocalAccount = !IsDomainBackupRequired( pvContext );
  3209. if( !(dwMasterKeyPolicy & POLICY_NO_BACKUP) &&
  3210. !(dwMasterKeyPolicy & POLICY_LOCAL_BACKUP) )
  3211. {
  3212. //
  3213. // See if domain controller (phase two) backup is required/appropriate.
  3214. //
  3215. if( !(*fLocalAccount) )
  3216. {
  3217. phMasterKey->dwPolicy = dwMasterKeyPolicy;
  3218. return TRUE;
  3219. }
  3220. }
  3221. //
  3222. // see if the call is for shared, CRYPT_PROTECT_LOCAL_MACHINE
  3223. // disposition.
  3224. //
  3225. CPSOverrideToLocalSystem(
  3226. pvContext,
  3227. NULL, // don't change current over-ride BOOL
  3228. &fLocalMachine
  3229. );
  3230. CPSQueryWellKnownAccount(
  3231. pvContext,
  3232. &dwAccount);
  3233. //
  3234. // if the context specified per-machine, we know that it's a system credential.
  3235. // also, we don't need to get the user name in this scenario.
  3236. //
  3237. if(fLocalMachine || (dwAccount != 0))
  3238. {
  3239. //
  3240. // a SYSTEM (user or per-machine disposition) key is the focus
  3241. // of our attention; never back these up.
  3242. //
  3243. dwMasterKeyPolicy |= POLICY_NO_BACKUP;
  3244. dwMasterKeyPolicy &= ~POLICY_LOCAL_BACKUP;
  3245. }
  3246. else
  3247. {
  3248. //
  3249. // otherwise assume it's a key associated with a local account...
  3250. // (local only backup).
  3251. //
  3252. dwMasterKeyPolicy |= POLICY_LOCAL_BACKUP;
  3253. }
  3254. //
  3255. // don't persist a default value as this implies that somebody really
  3256. // specified a policy. (maximum forward compatibility).
  3257. //
  3258. phMasterKey->dwPolicy = dwMasterKeyPolicy;
  3259. return TRUE;
  3260. }
  3261. BOOL
  3262. IsDomainBackupRequired(
  3263. IN PVOID pvContext
  3264. )
  3265. /*++
  3266. Determine if the current security context dictates whether domain controller
  3267. (phase two) based backup is required/appropriate.
  3268. --*/
  3269. {
  3270. PSID pSidUser = NULL;
  3271. DWORD dwSubauthorityCount;
  3272. PUSER_MODALS_INFO_2 pumi2 = NULL;
  3273. NET_API_STATUS nas;
  3274. BOOL fBackupRequired = FALSE; // assume backup not required.
  3275. BOOL fSuccess;
  3276. PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
  3277. //
  3278. // get the Sid associated with the client security context.
  3279. // see if the Sid only has one subauthority. If so, no associated DC.
  3280. // see if current machine a DC. If so, backup is required.
  3281. //
  3282. fSuccess = GetTokenUserSid(pServerContext->hToken, &pSidUser);
  3283. if(!fSuccess)
  3284. goto cleanup;
  3285. //
  3286. // see if the Sid has only one subauthority. If so, no associated DC,
  3287. // no DC backup possible.
  3288. //
  3289. dwSubauthorityCount = *GetSidSubAuthorityCount( pSidUser );
  3290. if( dwSubauthorityCount == 1 ) {
  3291. fBackupRequired = FALSE;
  3292. goto cleanup;
  3293. }
  3294. //
  3295. // if current machine is a domain controller, backup is required.
  3296. //
  3297. if(IsDomainController()) {
  3298. fBackupRequired = TRUE;
  3299. goto cleanup;
  3300. }
  3301. //
  3302. // if the Sid contains local machine domain prefix Sid, backup is not
  3303. // required, as no DC is associated with the account.
  3304. //
  3305. nas = NetUserModalsGet( NULL, 2, (LPBYTE*)&pumi2 );
  3306. if(nas != NERR_Success)
  3307. goto cleanup;
  3308. if(!IsUserSidInDomain( pumi2->usrmod2_domain_id, pSidUser )) {
  3309. fBackupRequired = TRUE;
  3310. goto cleanup;
  3311. }
  3312. //
  3313. // defaulted to backup not required.
  3314. //
  3315. fBackupRequired = FALSE;
  3316. cleanup:
  3317. if(pumi2)
  3318. NetApiBufferFree(pumi2);
  3319. if(pSidUser)
  3320. SSFree(pSidUser);
  3321. return fBackupRequired;
  3322. }
  3323. NTSTATUS
  3324. GetPreferredMasterKeyGuid(
  3325. IN PVOID pvContext,
  3326. IN LPCWSTR szUserStorageArea,
  3327. IN OUT GUID *pguidMasterKey
  3328. )
  3329. /*++
  3330. Given a registry handle to the MasterKeys portion of the registry,
  3331. tells the caller what the preferred master key GUID is.
  3332. If a valid preferred key is configured, then the return value is
  3333. STATUS_SUCCESS, and the pguidMasterKey buffer is filled with the
  3334. GUID associated with the preferred master key.
  3335. If the preferred key is expired, then the return value is
  3336. STATUS_PASSWORD_EXPIRED, and the pguidMasterKey buffer is filled
  3337. with the GUID associated with the preferred master key. In this case,
  3338. the caller may not want to use this key, except perhaps if a new
  3339. master key cannot be successfully created.
  3340. On failure, an NTSTATUS error code is returned. The caller can assume
  3341. there is no preferred master key configured in this case, and a new one
  3342. is to be created and subsequently selected via SetPreferredMasterKeyGuid().
  3343. --*/
  3344. {
  3345. HANDLE hFile = INVALID_HANDLE_VALUE;
  3346. DWORD dwBytesRead;
  3347. MASTERKEY_PREFERRED_INFO sMKPreferred;
  3348. SYSTEMTIME stCurrentTime;
  3349. FILETIME ftCurrentTime;
  3350. unsigned __int64 CurrentTime;
  3351. unsigned __int64 ExpiryInterval;
  3352. DWORD dwLastError;
  3353. BOOL fSuccess;
  3354. dwLastError = OpenFileInStorageArea(
  3355. pvContext,
  3356. GENERIC_READ,
  3357. szUserStorageArea,
  3358. REGVAL_PREFERRED_MK,
  3359. &hFile
  3360. );
  3361. if(dwLastError != ERROR_SUCCESS)
  3362. {
  3363. return STATUS_NOT_FOUND;
  3364. }
  3365. //
  3366. // read the expiration and GUID from file into buffer.
  3367. //
  3368. fSuccess = ReadFile( hFile, &sMKPreferred, sizeof(sMKPreferred), &dwBytesRead, NULL );
  3369. CloseHandle( hFile );
  3370. if( !fSuccess )
  3371. {
  3372. return STATUS_NOT_FOUND;
  3373. }
  3374. //
  3375. // validate data
  3376. //
  3377. if( dwBytesRead != sizeof(sMKPreferred) )
  3378. {
  3379. return STATUS_NOT_FOUND;
  3380. }
  3381. //
  3382. // Copy the GUID of the preferred master key to the output buffer.
  3383. //
  3384. CopyMemory(pguidMasterKey, &(sMKPreferred.guidPreferredKey), sizeof(GUID));
  3385. //
  3386. // see if the key has expired
  3387. //
  3388. GetSystemTime(&stCurrentTime);
  3389. SystemTimeToFileTime(&stCurrentTime, &ftCurrentTime);
  3390. if(CompareFileTime(&ftCurrentTime, &(sMKPreferred.ftPreferredKeyExpires)) >= 0)
  3391. {
  3392. // key has expired
  3393. return STATUS_PASSWORD_EXPIRED;
  3394. }
  3395. ExpiryInterval = MASTERKEY_EXPIRES_DAYS * 24 * 60 * 60;
  3396. ExpiryInterval *= 10000000;
  3397. CurrentTime = ((__int64)ftCurrentTime.dwHighDateTime << 32) + (__int64)ftCurrentTime.dwLowDateTime;
  3398. CurrentTime += ExpiryInterval;
  3399. ftCurrentTime.dwLowDateTime = (DWORD)(CurrentTime & 0xffffffff);
  3400. ftCurrentTime.dwHighDateTime = (DWORD)(CurrentTime >> 32);
  3401. if(CompareFileTime(&ftCurrentTime, &(sMKPreferred.ftPreferredKeyExpires)) < 0)
  3402. {
  3403. // expiry time is too far in the future
  3404. return STATUS_PASSWORD_EXPIRED;
  3405. }
  3406. //
  3407. // The key is current.
  3408. //
  3409. return STATUS_SUCCESS;
  3410. }
  3411. BOOL
  3412. SetPreferredMasterKeyGuid(
  3413. IN PVOID pvContext,
  3414. IN LPCWSTR szUserStorageArea,
  3415. IN GUID *pguidMasterKey
  3416. )
  3417. {
  3418. MASTERKEY_PREFERRED_INFO sMKPreferred;
  3419. SYSTEMTIME stCurrentTime;
  3420. FILETIME ftCurrentTime;
  3421. unsigned __int64 uTime;
  3422. unsigned __int64 oTime;
  3423. HANDLE hFile;
  3424. DWORD dwBytesWritten;
  3425. DWORD dwLastError;
  3426. BOOL fSuccess;
  3427. CopyMemory(&sMKPreferred.guidPreferredKey, pguidMasterKey, sizeof(GUID));
  3428. //
  3429. // set key expiration time.
  3430. //
  3431. GetSystemTime(&stCurrentTime);
  3432. SystemTimeToFileTime(&stCurrentTime, &(sMKPreferred.ftPreferredKeyExpires));
  3433. uTime = sMKPreferred.ftPreferredKeyExpires.dwLowDateTime;
  3434. uTime += ((unsigned __int64)sMKPreferred.ftPreferredKeyExpires.dwHighDateTime << 32) ;
  3435. //
  3436. // the compiler complains about integer constant overflow
  3437. // if we don't break it up..
  3438. //
  3439. oTime = MASTERKEY_EXPIRES_DAYS * 24 * 60 * 60;
  3440. oTime *= 10000000;
  3441. uTime += oTime;
  3442. sMKPreferred.ftPreferredKeyExpires.dwLowDateTime = (DWORD)(uTime & 0xffffffff);
  3443. sMKPreferred.ftPreferredKeyExpires.dwHighDateTime = (DWORD)(uTime >> 32);
  3444. dwLastError = OpenFileInStorageArea(
  3445. pvContext,
  3446. GENERIC_WRITE,
  3447. szUserStorageArea,
  3448. REGVAL_PREFERRED_MK,
  3449. &hFile
  3450. );
  3451. if(dwLastError != ERROR_SUCCESS) {
  3452. SetLastError(dwLastError);
  3453. return FALSE;
  3454. }
  3455. //
  3456. // write the expiration and GUID from buffer into file.
  3457. //
  3458. fSuccess = WriteFile( hFile, &sMKPreferred, sizeof(sMKPreferred), &dwBytesWritten, NULL );
  3459. CloseHandle( hFile );
  3460. return fSuccess;
  3461. }
  3462. DWORD
  3463. OpenFileInStorageArea(
  3464. IN PVOID pvContext, // if NULL, caller is assumed to be impersonating
  3465. IN DWORD dwDesiredAccess,
  3466. IN LPCWSTR szUserStorageArea,
  3467. IN LPCWSTR szFileName,
  3468. IN OUT HANDLE *phFile
  3469. )
  3470. {
  3471. LPWSTR szFilePath = NULL;
  3472. DWORD cbUserStorageArea;
  3473. DWORD cbFileName;
  3474. DWORD dwShareMode = 0;
  3475. DWORD dwCreationDistribution = OPEN_EXISTING;
  3476. DWORD dwLastError = ERROR_SUCCESS;
  3477. *phFile = INVALID_HANDLE_VALUE;
  3478. if( dwDesiredAccess & GENERIC_READ ) {
  3479. dwShareMode |= FILE_SHARE_READ;
  3480. dwCreationDistribution = OPEN_EXISTING;
  3481. }
  3482. if( dwDesiredAccess & GENERIC_WRITE ) {
  3483. dwShareMode = 0;
  3484. dwCreationDistribution = OPEN_ALWAYS;
  3485. }
  3486. cbUserStorageArea = lstrlenW( szUserStorageArea ) * sizeof(WCHAR);
  3487. cbFileName = lstrlenW( szFileName ) * sizeof(WCHAR);
  3488. szFilePath = (LPWSTR)SSAlloc( cbUserStorageArea + cbFileName + sizeof(WCHAR) );
  3489. if( szFilePath == NULL )
  3490. return ERROR_NOT_ENOUGH_MEMORY;
  3491. CopyMemory(szFilePath, szUserStorageArea, cbUserStorageArea);
  3492. CopyMemory((LPBYTE)szFilePath+cbUserStorageArea, szFileName, cbFileName + sizeof(WCHAR));
  3493. if( pvContext )
  3494. dwLastError = CPSImpersonateClient( pvContext );
  3495. if( dwLastError == ERROR_SUCCESS ) {
  3496. //
  3497. // TODO:
  3498. // apply security descriptor to file.
  3499. //
  3500. *phFile = CreateFileWithRetries(
  3501. szFilePath,
  3502. dwDesiredAccess,
  3503. dwShareMode,
  3504. NULL,
  3505. dwCreationDistribution,
  3506. FILE_ATTRIBUTE_HIDDEN |
  3507. FILE_ATTRIBUTE_SYSTEM |
  3508. FILE_FLAG_SEQUENTIAL_SCAN,
  3509. NULL
  3510. );
  3511. if( *phFile == INVALID_HANDLE_VALUE ) {
  3512. dwLastError = GetLastError();
  3513. }
  3514. if( pvContext )
  3515. CPSRevertToSelf( pvContext );
  3516. }
  3517. if(szFilePath)
  3518. SSFree(szFilePath);
  3519. return dwLastError;
  3520. }
  3521. HANDLE
  3522. CreateFileWithRetries(
  3523. IN LPCWSTR lpFileName,
  3524. IN DWORD dwDesiredAccess,
  3525. IN DWORD dwShareMode,
  3526. IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  3527. IN DWORD dwCreationDisposition,
  3528. IN DWORD dwFlagsAndAttributes,
  3529. IN HANDLE hTemplateFile
  3530. )
  3531. {
  3532. HANDLE hFile = INVALID_HANDLE_VALUE;
  3533. static const DWORD rgReadRetrys[] = { 1, 10, 50, 100, 1000, 0 };
  3534. static const DWORD rgWriteRetrys[] = { 1, 10, 20, 20, 50, 75, 100, 500, 1000, 0 };
  3535. const DWORD *prgRetries;
  3536. DWORD dwRetryIndex;
  3537. DWORD dwLastError = ERROR_SHARING_VIOLATION;
  3538. if( dwDesiredAccess & GENERIC_WRITE ) {
  3539. prgRetries = rgWriteRetrys;
  3540. } else {
  3541. prgRetries = rgReadRetrys;
  3542. }
  3543. for( dwRetryIndex = 0 ; prgRetries[ dwRetryIndex ] ; dwRetryIndex++ ) {
  3544. hFile = CreateFileU(
  3545. lpFileName,
  3546. dwDesiredAccess,
  3547. dwShareMode,
  3548. lpSecurityAttributes,
  3549. dwCreationDisposition,
  3550. dwFlagsAndAttributes,
  3551. hTemplateFile
  3552. );
  3553. if( hFile != INVALID_HANDLE_VALUE )
  3554. break;
  3555. dwLastError = GetLastError();
  3556. if( dwLastError == ERROR_SHARING_VIOLATION )
  3557. {
  3558. //
  3559. // sleep around for the designated period of time...
  3560. //
  3561. Sleep( prgRetries[dwRetryIndex] );
  3562. continue;
  3563. }
  3564. break;
  3565. }
  3566. if( hFile == INVALID_HANDLE_VALUE )
  3567. SetLastError( dwLastError );
  3568. return hFile;
  3569. }
  3570. BOOL
  3571. ReadMasterKey(
  3572. IN PVOID pvContext, // if NULL, caller is assumed to be impersonating
  3573. IN PMASTERKEY_STORED phMasterKey
  3574. )
  3575. /*++
  3576. Read the masterkey specified by phMasterKey->wszguidMasterKey into memory.
  3577. --*/
  3578. {
  3579. HANDLE hFile = INVALID_HANDLE_VALUE;
  3580. HANDLE hMap = NULL;
  3581. DWORD dwFileSizeLow;
  3582. PMASTERKEY_STORED_ON_DISK pMasterKeyRead = NULL;
  3583. DWORD cbguidMasterKey, cbguidMasterKey2;
  3584. PBYTE pbCurrentBlock;
  3585. WCHAR szGuidReadMasterKey[MAX_GUID_SZ_CHARS];
  3586. BOOL fSuccess = FALSE;
  3587. if( OpenFileInStorageArea(
  3588. pvContext,
  3589. GENERIC_READ,
  3590. phMasterKey->szFilePath,
  3591. phMasterKey->wszguidMasterKey,
  3592. &hFile
  3593. ) != ERROR_SUCCESS)
  3594. goto cleanup;
  3595. dwFileSizeLow = GetFileSize( hFile, NULL );
  3596. if(dwFileSizeLow == INVALID_FILE_SIZE )
  3597. goto cleanup;
  3598. if( dwFileSizeLow < sizeof(MASTERKEY_STORED_ON_DISK) )
  3599. goto cleanup;
  3600. __try
  3601. {
  3602. hMap = CreateFileMappingU(
  3603. hFile,
  3604. NULL,
  3605. PAGE_READONLY,
  3606. 0,
  3607. 0,
  3608. NULL
  3609. );
  3610. if( hMap == NULL )
  3611. goto cleanup;
  3612. pMasterKeyRead = (PMASTERKEY_STORED_ON_DISK)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 );
  3613. if(pMasterKeyRead == NULL)
  3614. goto cleanup;
  3615. if(pMasterKeyRead->dwVersion > MASTERKEY_STORED_VERSION)
  3616. goto cleanup;
  3617. //
  3618. // do some size validation
  3619. //
  3620. if((pMasterKeyRead->cbMK + pMasterKeyRead->cbLK +
  3621. pMasterKeyRead->cbBK + pMasterKeyRead->cbBBK) >
  3622. ( dwFileSizeLow - sizeof(MASTERKEY_STORED_ON_DISK) )
  3623. )
  3624. goto cleanup;
  3625. //
  3626. // validate retrieved GUID matches requested GUID.
  3627. //
  3628. CopyMemory(szGuidReadMasterKey, pMasterKeyRead->wszguidMasterKey, MAX_GUID_SZ_CHARS * sizeof(WCHAR));
  3629. szGuidReadMasterKey[MAX_GUID_SZ_CHARS - 1] = L'\0';
  3630. cbguidMasterKey = (lstrlenW( phMasterKey->wszguidMasterKey ) + 1) * sizeof(WCHAR);
  3631. cbguidMasterKey2 = (lstrlenW( szGuidReadMasterKey ) + 1) * sizeof(WCHAR);
  3632. if(cbguidMasterKey != cbguidMasterKey2)
  3633. goto cleanup;
  3634. if(memcmp( phMasterKey->wszguidMasterKey, pMasterKeyRead->wszguidMasterKey, cbguidMasterKey) != 0)
  3635. goto cleanup;
  3636. phMasterKey->dwVersion = pMasterKeyRead->dwVersion;
  3637. //
  3638. // pickup master key policy
  3639. //
  3640. phMasterKey->dwPolicy = pMasterKeyRead->dwPolicy;
  3641. //
  3642. // copy useful components into new block so a single contiguous write
  3643. // can occur.
  3644. //
  3645. pbCurrentBlock = (LPBYTE)(pMasterKeyRead + 1);
  3646. if( pMasterKeyRead->cbMK )
  3647. {
  3648. phMasterKey->pbMK = (LPBYTE)SSAlloc( pMasterKeyRead->cbMK );
  3649. if(phMasterKey->pbMK == NULL)
  3650. goto cleanup;
  3651. phMasterKey->cbMK = pMasterKeyRead->cbMK;
  3652. CopyMemory(phMasterKey->pbMK, pbCurrentBlock, pMasterKeyRead->cbMK);
  3653. pbCurrentBlock += pMasterKeyRead->cbMK;
  3654. }
  3655. if( pMasterKeyRead->cbLK )
  3656. {
  3657. phMasterKey->pbLK = (LPBYTE)SSAlloc( pMasterKeyRead->cbLK );
  3658. if(phMasterKey->pbLK == NULL)
  3659. goto cleanup;
  3660. phMasterKey->cbLK = pMasterKeyRead->cbLK;
  3661. CopyMemory(phMasterKey->pbLK, pbCurrentBlock, pMasterKeyRead->cbLK);
  3662. pbCurrentBlock += pMasterKeyRead->cbLK;
  3663. }
  3664. if( pMasterKeyRead->cbBK )
  3665. {
  3666. phMasterKey->pbBK = (LPBYTE)SSAlloc( pMasterKeyRead->cbBK );
  3667. if(phMasterKey->pbBK == NULL)
  3668. goto cleanup;
  3669. phMasterKey->cbBK = pMasterKeyRead->cbBK;
  3670. CopyMemory(phMasterKey->pbBK, pbCurrentBlock, pMasterKeyRead->cbBK);
  3671. pbCurrentBlock += pMasterKeyRead->cbBK;
  3672. }
  3673. if( pMasterKeyRead->cbBBK )
  3674. {
  3675. phMasterKey->pbBBK = (LPBYTE)SSAlloc( pMasterKeyRead->cbBBK );
  3676. if(phMasterKey->pbBBK == NULL)
  3677. goto cleanup;
  3678. phMasterKey->cbBBK = pMasterKeyRead->cbBBK;
  3679. CopyMemory(phMasterKey->pbBBK, pbCurrentBlock, pMasterKeyRead->cbBBK);
  3680. }
  3681. } __except (EXCEPTION_EXECUTE_HANDLER)
  3682. {
  3683. goto cleanup;
  3684. }
  3685. fSuccess = TRUE;
  3686. cleanup:
  3687. if( pMasterKeyRead )
  3688. UnmapViewOfFile( pMasterKeyRead );
  3689. if( hMap )
  3690. CloseHandle( hMap );
  3691. if( hFile != INVALID_HANDLE_VALUE )
  3692. CloseHandle( hFile );
  3693. if( !fSuccess )
  3694. FreeMasterKey( phMasterKey );
  3695. return fSuccess;
  3696. }
  3697. BOOL
  3698. WriteMasterKey(
  3699. IN PVOID pvContext, // if NULL, caller is assumed to be impersonating
  3700. IN PMASTERKEY_STORED phMasterKey
  3701. )
  3702. /*++
  3703. Persist the specified masterkey to storage.
  3704. if pvContext is NULL, the caller must be impersonating the user associated
  3705. with the masterkey.
  3706. --*/
  3707. {
  3708. PMASTERKEY_STORED_ON_DISK pMasterKeyToWrite;
  3709. DWORD cbMasterKeyToWrite;
  3710. PBYTE pbCurrentBlock;
  3711. HANDLE hFile;
  3712. BOOL fSuccess = FALSE;
  3713. if(phMasterKey->dwVersion > MASTERKEY_STORED_VERSION)
  3714. return FALSE;
  3715. cbMasterKeyToWrite = sizeof(MASTERKEY_STORED_ON_DISK) +
  3716. phMasterKey->cbMK +
  3717. phMasterKey->cbLK +
  3718. phMasterKey->cbBK +
  3719. phMasterKey->cbBBK ;
  3720. pMasterKeyToWrite = (PMASTERKEY_STORED_ON_DISK) SSAlloc( cbMasterKeyToWrite );
  3721. if(pMasterKeyToWrite == NULL)
  3722. return FALSE;
  3723. //
  3724. // copy useful components
  3725. //
  3726. pMasterKeyToWrite->dwVersion = phMasterKey->dwVersion;
  3727. CopyMemory(
  3728. pMasterKeyToWrite->wszguidMasterKey,
  3729. phMasterKey->wszguidMasterKey,
  3730. (MAX_GUID_SZ_CHARS * sizeof(WCHAR))
  3731. );
  3732. pMasterKeyToWrite->dwPolicy = phMasterKey->dwPolicy;
  3733. pMasterKeyToWrite->cbMK = phMasterKey->cbMK;
  3734. pMasterKeyToWrite->cbLK = phMasterKey->cbLK;
  3735. pMasterKeyToWrite->cbBK = phMasterKey->cbBK;
  3736. pMasterKeyToWrite->cbBBK = phMasterKey->cbBBK;
  3737. //
  3738. // overwrite non-useful components
  3739. //
  3740. pMasterKeyToWrite->fModified = FALSE;
  3741. pMasterKeyToWrite->szFilePath = 0;
  3742. pMasterKeyToWrite->pbMK = 0;
  3743. pMasterKeyToWrite->pbLK = 0;
  3744. pMasterKeyToWrite->pbBK = 0;
  3745. pMasterKeyToWrite->pbBBK = 0;
  3746. //
  3747. // copy useful components into new block so a single contiguous write
  3748. // can occur.
  3749. //
  3750. pbCurrentBlock = (LPBYTE)(pMasterKeyToWrite + 1);
  3751. if( phMasterKey->pbMK ) {
  3752. CopyMemory(pbCurrentBlock, phMasterKey->pbMK, phMasterKey->cbMK);
  3753. pbCurrentBlock += phMasterKey->cbMK;
  3754. }
  3755. if( phMasterKey->pbLK ) {
  3756. CopyMemory(pbCurrentBlock, phMasterKey->pbLK, phMasterKey->cbLK);
  3757. pbCurrentBlock += phMasterKey->cbLK;
  3758. }
  3759. if( phMasterKey->pbBK ) {
  3760. CopyMemory(pbCurrentBlock, phMasterKey->pbBK, phMasterKey->cbBK);
  3761. pbCurrentBlock += phMasterKey->cbBK;
  3762. }
  3763. if( phMasterKey->pbBBK ) {
  3764. CopyMemory(pbCurrentBlock, phMasterKey->pbBBK, phMasterKey->cbBBK);
  3765. }
  3766. if( OpenFileInStorageArea(
  3767. pvContext,
  3768. GENERIC_READ | GENERIC_WRITE,
  3769. phMasterKey->szFilePath,
  3770. phMasterKey->wszguidMasterKey,
  3771. &hFile
  3772. ) == ERROR_SUCCESS) {
  3773. BOOL fWriteData;
  3774. DWORD dwBytesWritten;
  3775. CheckToStompMasterKey( pMasterKeyToWrite, hFile, &fWriteData );
  3776. if( fWriteData ) {
  3777. fSuccess = WriteFile(
  3778. hFile,
  3779. pMasterKeyToWrite,
  3780. cbMasterKeyToWrite,
  3781. &dwBytesWritten,
  3782. NULL
  3783. );
  3784. } else {
  3785. fSuccess = TRUE; // nothing to do, success
  3786. }
  3787. CloseHandle( hFile );
  3788. }
  3789. RtlSecureZeroMemory( pMasterKeyToWrite, cbMasterKeyToWrite);
  3790. SSFree( pMasterKeyToWrite );
  3791. return fSuccess;
  3792. }
  3793. BOOL
  3794. CheckToStompMasterKey(
  3795. IN PMASTERKEY_STORED_ON_DISK phMasterKeyCandidate, // masterkey to check if worthy to stomp over existing
  3796. IN HANDLE hFile, // file handle to existing masterkey
  3797. IN OUT BOOL *pfStomp // stomp the existing masterkey?
  3798. )
  3799. {
  3800. HANDLE hMap = NULL;
  3801. PMASTERKEY_STORED_ON_DISK pMasterKeyRead = NULL;
  3802. BOOL fSuccess = FALSE;
  3803. *pfStomp = TRUE;
  3804. if( phMasterKeyCandidate->dwPolicy & POLICY_NO_BACKUP )
  3805. return TRUE;
  3806. if( phMasterKeyCandidate->dwPolicy & POLICY_LOCAL_BACKUP &&
  3807. phMasterKeyCandidate->cbBK )
  3808. return TRUE;
  3809. if( phMasterKeyCandidate->cbBBK )
  3810. return TRUE;
  3811. __try
  3812. {
  3813. hMap = CreateFileMapping(
  3814. hFile,
  3815. NULL,
  3816. PAGE_READONLY,
  3817. 0,
  3818. 0,
  3819. NULL
  3820. );
  3821. if( hMap == NULL )
  3822. goto cleanup;
  3823. pMasterKeyRead = (PMASTERKEY_STORED_ON_DISK)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 );
  3824. if(pMasterKeyRead == NULL)
  3825. goto cleanup;
  3826. if(pMasterKeyRead->dwVersion > MASTERKEY_STORED_VERSION)
  3827. goto cleanup;
  3828. //
  3829. // there's really only two cases where we don't allow stomping:
  3830. // candidate masterkey doesn't contain phase 1 and existing does,
  3831. // candidate masterkey doesn't contain phase 1 and existing one contains phase2.
  3832. // note: we allow stomping over a masterkey that contains a phase 2 with one
  3833. // that only contains a phase 1, because of a race condition that can occur
  3834. // during the backup operation; In this situation, it is better to have
  3835. // a phase 1 and let it get upgraded to phase 2 at a later time.
  3836. //
  3837. if( phMasterKeyCandidate->cbBK == 0 &&
  3838. (pMasterKeyRead->cbBK || pMasterKeyRead->cbBBK))
  3839. {
  3840. *pfStomp = FALSE;
  3841. }
  3842. } __except (EXCEPTION_EXECUTE_HANDLER)
  3843. {
  3844. goto cleanup;
  3845. }
  3846. fSuccess = TRUE;
  3847. cleanup:
  3848. if( pMasterKeyRead )
  3849. UnmapViewOfFile( pMasterKeyRead );
  3850. if( hMap )
  3851. CloseHandle( hMap );
  3852. return fSuccess;
  3853. }
  3854. BOOL
  3855. CloseMasterKey(
  3856. IN PVOID pvContext, // if NULL, caller is assumed to be impersonating
  3857. IN PMASTERKEY_STORED phMasterKey,
  3858. IN BOOL fPersist // persist any changes to storage?
  3859. )
  3860. /*++
  3861. Free the memory an optionally persist any changes associated with a
  3862. master key.
  3863. --*/
  3864. {
  3865. BOOL fSuccess = TRUE;
  3866. //
  3867. // if we were told to persist any changes, and changes were actually made,
  3868. // persist them out.
  3869. //
  3870. if( fPersist && phMasterKey->fModified )
  3871. fSuccess = WriteMasterKey( pvContext, phMasterKey );
  3872. //
  3873. // free memory.
  3874. //
  3875. FreeMasterKey( phMasterKey );
  3876. return fSuccess;
  3877. }
  3878. VOID
  3879. FreeMasterKey(
  3880. IN PMASTERKEY_STORED phMasterKey
  3881. )
  3882. /*++
  3883. Free allocated memory associated with the specified master key.
  3884. --*/
  3885. {
  3886. if( phMasterKey->dwVersion > MASTERKEY_STORED_VERSION )
  3887. return;
  3888. if( phMasterKey->szFilePath )
  3889. SSFree( phMasterKey->szFilePath );
  3890. if( phMasterKey->pbMK ) {
  3891. RtlSecureZeroMemory( phMasterKey->pbMK, phMasterKey->cbMK );
  3892. SSFree( phMasterKey->pbMK );
  3893. }
  3894. if( phMasterKey->pbLK ) {
  3895. RtlSecureZeroMemory( phMasterKey->pbLK, phMasterKey->cbLK );
  3896. SSFree( phMasterKey->pbLK );
  3897. }
  3898. if( phMasterKey->pbBK ) {
  3899. RtlSecureZeroMemory( phMasterKey->pbBK, phMasterKey->cbBK );
  3900. SSFree( phMasterKey->pbBK );
  3901. }
  3902. if( phMasterKey->pbBBK ) {
  3903. RtlSecureZeroMemory( phMasterKey->pbBBK, phMasterKey->cbBBK );
  3904. SSFree( phMasterKey->pbBBK );
  3905. }
  3906. RtlSecureZeroMemory( phMasterKey, sizeof(MASTERKEY_STORED) );
  3907. return;
  3908. }
  3909. BOOL
  3910. DuplicateMasterKey(
  3911. IN PMASTERKEY_STORED phMasterKeyIn,
  3912. IN PMASTERKEY_STORED phMasterKeyOut
  3913. )
  3914. /*++
  3915. Duplicate the input masterkey to a new copy, setting the fModified flag
  3916. on the copy to FALSE.
  3917. This provides a mechanism to allow for deferring operations against a
  3918. master key.
  3919. --*/
  3920. {
  3921. BOOL fSuccess = FALSE;
  3922. if( phMasterKeyIn->dwVersion > MASTERKEY_STORED_VERSION )
  3923. return FALSE;
  3924. ZeroMemory( phMasterKeyOut, sizeof(MASTERKEY_STORED) );
  3925. phMasterKeyOut->dwVersion = phMasterKeyIn->dwVersion;
  3926. phMasterKeyOut->dwPolicy = phMasterKeyIn->dwPolicy;
  3927. phMasterKeyOut->fModified = FALSE;
  3928. if( lstrlenW( phMasterKeyIn->wszguidMasterKey ) > MAX_GUID_SZ_CHARS )
  3929. return FALSE;
  3930. CopyMemory(phMasterKeyOut->wszguidMasterKey, phMasterKeyIn->wszguidMasterKey, MAX_GUID_SZ_CHARS * sizeof(WCHAR));
  3931. if( phMasterKeyIn->szFilePath ) {
  3932. DWORD cbFilePath = (lstrlenW(phMasterKeyIn->szFilePath) + 1) * sizeof(WCHAR);
  3933. phMasterKeyOut->szFilePath = (LPWSTR)SSAlloc( cbFilePath );
  3934. if(phMasterKeyOut->szFilePath == NULL)
  3935. goto cleanup;
  3936. CopyMemory( phMasterKeyOut->szFilePath, phMasterKeyIn->szFilePath, cbFilePath );
  3937. }
  3938. if( phMasterKeyIn->pbMK ) {
  3939. phMasterKeyOut->cbMK = phMasterKeyIn->cbMK;
  3940. phMasterKeyOut->pbMK = (PBYTE)SSAlloc(phMasterKeyIn->cbMK);
  3941. if(phMasterKeyOut->pbMK == NULL)
  3942. goto cleanup;
  3943. CopyMemory( phMasterKeyOut->pbMK, phMasterKeyIn->pbMK, phMasterKeyIn->cbMK );
  3944. }
  3945. if( phMasterKeyIn->pbLK ) {
  3946. phMasterKeyOut->cbLK = phMasterKeyIn->cbLK;
  3947. phMasterKeyOut->pbLK = (PBYTE)SSAlloc(phMasterKeyIn->cbLK);
  3948. if(phMasterKeyOut->pbLK == NULL)
  3949. goto cleanup;
  3950. CopyMemory( phMasterKeyOut->pbLK, phMasterKeyIn->pbLK, phMasterKeyIn->cbLK );
  3951. }
  3952. if( phMasterKeyIn->pbBK ) {
  3953. phMasterKeyOut->cbBK = phMasterKeyIn->cbBK;
  3954. phMasterKeyOut->pbBK = (PBYTE)SSAlloc(phMasterKeyIn->cbBK);
  3955. if(phMasterKeyOut->pbBK == NULL)
  3956. goto cleanup;
  3957. CopyMemory( phMasterKeyOut->pbBK, phMasterKeyIn->pbBK, phMasterKeyIn->cbBK );
  3958. }
  3959. if( phMasterKeyIn->pbBBK ) {
  3960. phMasterKeyOut->cbBBK = phMasterKeyIn->cbBBK;
  3961. phMasterKeyOut->pbBBK = (PBYTE)SSAlloc(phMasterKeyIn->cbBBK);
  3962. if(phMasterKeyOut->pbBBK == NULL)
  3963. goto cleanup;
  3964. CopyMemory( phMasterKeyOut->pbBBK, phMasterKeyIn->pbBBK, phMasterKeyIn->cbBBK );
  3965. }
  3966. fSuccess = TRUE;
  3967. cleanup:
  3968. if( !fSuccess )
  3969. FreeMasterKey( phMasterKeyOut );
  3970. return fSuccess;
  3971. }
  3972. BOOL
  3973. InitializeKeyManagement(
  3974. VOID
  3975. )
  3976. {
  3977. if(!InitializeKeyCache())
  3978. {
  3979. return FALSE;
  3980. }
  3981. return TRUE;
  3982. }
  3983. BOOL
  3984. TeardownKeyManagement(
  3985. VOID
  3986. )
  3987. {
  3988. DeleteKeyCache();
  3989. return TRUE;
  3990. }
  3991. DWORD
  3992. DpapiUpdateLsaSecret(
  3993. IN PVOID pvContext)
  3994. {
  3995. CRYPT_SERVER_CONTEXT SystemContext;
  3996. CRYPT_SERVER_CONTEXT SystemUserContext;
  3997. CRYPT_SERVER_CONTEXT LocalServiceContext;
  3998. CRYPT_SERVER_CONTEXT NetworkServiceContext;
  3999. LPWSTR pszUserStorageArea = NULL;
  4000. BOOL fSystemContextCreated = FALSE;
  4001. BOOL fSystemUserContextCreated = FALSE;
  4002. BOOL fLocalServiceContextCreated = FALSE;
  4003. BOOL fNetworkServiceContextCreated = FALSE;
  4004. BOOL fNewSecretCreated = TRUE;
  4005. GUID guidMasterKey;
  4006. BOOL fOverrideToLocalSystem;
  4007. DWORD dwRet;
  4008. D_DebugLog((DEB_TRACE_API, "DpapiUpdateLsaSecret\n"));
  4009. //
  4010. // TCB privilege must be held by the client in order to
  4011. // make this call. Verify that before doing anything else
  4012. //
  4013. dwRet = CPSImpersonateClient( pvContext );
  4014. if(dwRet == ERROR_SUCCESS)
  4015. {
  4016. HANDLE ClientToken;
  4017. dwRet = NtOpenThreadToken(
  4018. NtCurrentThread(),
  4019. TOKEN_QUERY,
  4020. TRUE,
  4021. &ClientToken
  4022. );
  4023. if ( NT_SUCCESS( dwRet ))
  4024. {
  4025. BOOLEAN Result = FALSE;
  4026. PRIVILEGE_SET RequiredPrivileges;
  4027. LUID_AND_ATTRIBUTES PrivilegeArray[1];
  4028. RequiredPrivileges.PrivilegeCount = 1;
  4029. RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
  4030. RequiredPrivileges.Privilege[0].Luid = RtlConvertLongToLuid( SE_TCB_PRIVILEGE );
  4031. RequiredPrivileges.Privilege[0].Attributes = 0;
  4032. dwRet = NtPrivilegeCheck(
  4033. ClientToken,
  4034. &RequiredPrivileges,
  4035. &Result
  4036. );
  4037. if ( NT_SUCCESS( dwRet ) &&
  4038. Result == FALSE )
  4039. {
  4040. dwRet = STATUS_PRIVILEGE_NOT_HELD;
  4041. }
  4042. NtClose( ClientToken );
  4043. ClientToken = NULL;
  4044. }
  4045. CPSRevertToSelf( pvContext );
  4046. }
  4047. if(!NT_SUCCESS(dwRet))
  4048. {
  4049. D_DebugLog((DEB_ERROR, "DpapiUpdateLsaSecret: TCB privilege required!\n"));
  4050. goto cleanup;
  4051. }
  4052. //
  4053. // Enumerate through all of the master keys in the Protect\S-1-5-18
  4054. // directory, and load them all up in the master key cache.
  4055. //
  4056. D_DebugLog((DEB_TRACE, "Load system master keys into cache\n"));
  4057. dwRet = CPSCreateServerContext(&SystemContext, NULL);
  4058. if(dwRet != ERROR_SUCCESS)
  4059. {
  4060. goto cleanup;
  4061. }
  4062. fSystemContextCreated = TRUE;
  4063. fOverrideToLocalSystem = TRUE;
  4064. CPSOverrideToLocalSystem(&SystemContext, &fOverrideToLocalSystem, NULL);
  4065. dwRet = SynchronizeMasterKeys(&SystemContext, ADD_MASTER_KEY_TO_CACHE);
  4066. if(dwRet != ERROR_SUCCESS)
  4067. {
  4068. goto cleanup;
  4069. }
  4070. //
  4071. // Enumerate through all of the master keys in the Protect\S-1-5-18\User
  4072. // directory, and load them all up in the master key cache.
  4073. //
  4074. dwRet = CPSCreateServerContext(&SystemUserContext, NULL);
  4075. if(dwRet != ERROR_SUCCESS)
  4076. {
  4077. goto cleanup;
  4078. }
  4079. fSystemUserContextCreated = TRUE;
  4080. dwRet = SynchronizeMasterKeys(&SystemUserContext, ADD_MASTER_KEY_TO_CACHE);
  4081. if(dwRet != ERROR_SUCCESS)
  4082. {
  4083. goto cleanup;
  4084. }
  4085. //
  4086. // Enumerate through all of the master keys in the Protect\S-1-5-19
  4087. // directory, and load them all up in the master key cache.
  4088. //
  4089. dwRet = CPSCreateServerContext(&LocalServiceContext, NULL);
  4090. if(dwRet != ERROR_SUCCESS)
  4091. {
  4092. goto cleanup;
  4093. }
  4094. fLocalServiceContextCreated = TRUE;
  4095. CPSSetWellKnownAccount(&LocalServiceContext, DP_ACCOUNT_LOCAL_SERVICE);
  4096. dwRet = SynchronizeMasterKeys(&LocalServiceContext, ADD_MASTER_KEY_TO_CACHE);
  4097. if(dwRet != ERROR_SUCCESS)
  4098. {
  4099. goto cleanup;
  4100. }
  4101. //
  4102. // Enumerate through all of the master keys in the Protect\S-1-5-20
  4103. // directory, and load them all up in the master key cache.
  4104. //
  4105. dwRet = CPSCreateServerContext(&NetworkServiceContext, NULL);
  4106. if(dwRet != ERROR_SUCCESS)
  4107. {
  4108. goto cleanup;
  4109. }
  4110. fNetworkServiceContextCreated = TRUE;
  4111. CPSSetWellKnownAccount(&NetworkServiceContext, DP_ACCOUNT_NETWORK_SERVICE);
  4112. dwRet = SynchronizeMasterKeys(&NetworkServiceContext, ADD_MASTER_KEY_TO_CACHE);
  4113. if(dwRet != ERROR_SUCCESS)
  4114. {
  4115. goto cleanup;
  4116. }
  4117. //
  4118. // Regenerate the DPAPI_SYSTEM value.
  4119. //
  4120. D_DebugLog((DEB_TRACE, "Reset lsa secret\n"));
  4121. if(!UpdateSystemCredentials())
  4122. {
  4123. fNewSecretCreated = FALSE;
  4124. DebugLog((DEB_ERROR, "Unable to reset DPAPI_SYSTEM secret.\n"));
  4125. }
  4126. //
  4127. // Reencrypt and write back all of the master keys that are in the cache.
  4128. // Note that since this routine should only be called on brand-new machines
  4129. // that have just been setup using SYSPREP, the total number of master keys
  4130. // should always be exactly two. Thus, we shouldn't have to worry about
  4131. // overflowing the master key cache or anything like that.
  4132. //
  4133. D_DebugLog((DEB_TRACE, "Reencrypt system master keys\n"));
  4134. if(fNewSecretCreated)
  4135. {
  4136. SynchronizeMasterKeys(&SystemContext, REENCRYPT_MASTER_KEY);
  4137. SynchronizeMasterKeys(&SystemUserContext, REENCRYPT_MASTER_KEY);
  4138. SynchronizeMasterKeys(&LocalServiceContext, REENCRYPT_MASTER_KEY);
  4139. SynchronizeMasterKeys(&NetworkServiceContext, REENCRYPT_MASTER_KEY);
  4140. }
  4141. //
  4142. // Generate two new master keys, and mark them as preferred.
  4143. //
  4144. D_DebugLog((DEB_TRACE, "Generate new system master keys\n"));
  4145. dwRet = CPSGetUserStorageArea( &SystemContext,
  4146. NULL,
  4147. FALSE,
  4148. &pszUserStorageArea );
  4149. if(dwRet == ERROR_SUCCESS)
  4150. {
  4151. dwRet = CreateMasterKey( &SystemContext, pszUserStorageArea, &guidMasterKey, FALSE );
  4152. if(dwRet == ERROR_SUCCESS)
  4153. {
  4154. SetPreferredMasterKeyGuid( &SystemContext, pszUserStorageArea, &guidMasterKey );
  4155. }
  4156. SSFree(pszUserStorageArea);
  4157. pszUserStorageArea = NULL;
  4158. }
  4159. else if(dwRet == ERROR_PATH_NOT_FOUND)
  4160. {
  4161. dwRet = ERROR_SUCCESS;
  4162. }
  4163. dwRet = CPSGetUserStorageArea( &SystemUserContext,
  4164. NULL,
  4165. FALSE,
  4166. &pszUserStorageArea );
  4167. if(dwRet == ERROR_SUCCESS)
  4168. {
  4169. dwRet = CreateMasterKey( &SystemUserContext, pszUserStorageArea, &guidMasterKey, FALSE );
  4170. if(dwRet == ERROR_SUCCESS)
  4171. {
  4172. SetPreferredMasterKeyGuid( &SystemUserContext, pszUserStorageArea, &guidMasterKey );
  4173. }
  4174. SSFree(pszUserStorageArea);
  4175. pszUserStorageArea = NULL;
  4176. }
  4177. else if(dwRet == ERROR_PATH_NOT_FOUND)
  4178. {
  4179. dwRet = ERROR_SUCCESS;
  4180. }
  4181. dwRet = CPSGetUserStorageArea( &LocalServiceContext,
  4182. NULL,
  4183. FALSE,
  4184. &pszUserStorageArea );
  4185. if(dwRet == ERROR_SUCCESS)
  4186. {
  4187. dwRet = CreateMasterKey( &LocalServiceContext, pszUserStorageArea, &guidMasterKey, FALSE );
  4188. if(dwRet == ERROR_SUCCESS)
  4189. {
  4190. SetPreferredMasterKeyGuid( &LocalServiceContext, pszUserStorageArea, &guidMasterKey );
  4191. }
  4192. SSFree(pszUserStorageArea);
  4193. pszUserStorageArea = NULL;
  4194. }
  4195. else if(dwRet == ERROR_PATH_NOT_FOUND)
  4196. {
  4197. dwRet = ERROR_SUCCESS;
  4198. }
  4199. dwRet = CPSGetUserStorageArea( &NetworkServiceContext,
  4200. NULL,
  4201. FALSE,
  4202. &pszUserStorageArea );
  4203. if(dwRet == ERROR_SUCCESS)
  4204. {
  4205. dwRet = CreateMasterKey( &NetworkServiceContext, pszUserStorageArea, &guidMasterKey, FALSE );
  4206. if(dwRet == ERROR_SUCCESS)
  4207. {
  4208. SetPreferredMasterKeyGuid( &NetworkServiceContext, pszUserStorageArea, &guidMasterKey );
  4209. }
  4210. SSFree(pszUserStorageArea);
  4211. pszUserStorageArea = NULL;
  4212. }
  4213. else if(dwRet == ERROR_PATH_NOT_FOUND)
  4214. {
  4215. dwRet = ERROR_SUCCESS;
  4216. }
  4217. //
  4218. // Cleanup.
  4219. //
  4220. cleanup:
  4221. if(fSystemContextCreated)
  4222. {
  4223. CPSDeleteServerContext( &SystemContext );
  4224. }
  4225. if(fSystemUserContextCreated)
  4226. {
  4227. CPSDeleteServerContext( &SystemUserContext );
  4228. }
  4229. if(fLocalServiceContextCreated)
  4230. {
  4231. CPSDeleteServerContext( &LocalServiceContext );
  4232. }
  4233. if(fNetworkServiceContextCreated)
  4234. {
  4235. CPSDeleteServerContext( &NetworkServiceContext );
  4236. }
  4237. D_DebugLog((DEB_TRACE_API, "DpapiUpdateLsaSecret returned 0x%x\n", dwRet));
  4238. return dwRet;
  4239. }