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

6989 lines
172 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. efssrv.cxx
  5. Abstract:
  6. EFS (Encrypting File System) Server
  7. Author:
  8. Robert Reichel (RobertRe)
  9. Robert Gu (RobertG)
  10. Environment:
  11. Revision History:
  12. --*/
  13. #include <lsapch.hxx>
  14. extern "C" {
  15. #include <nt.h>
  16. #include <ntdef.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <efsstruc.h>
  22. #include <lmaccess.h>
  23. #include <lmcons.h>
  24. #include <lmapibuf.h>
  25. #include <userenv.h>
  26. #include <userenvp.h>
  27. #include "lsasrvp.h"
  28. #include "debug.h"
  29. #include "efssrv.hxx"
  30. #include "userkey.h"
  31. }
  32. #define ALGORITHM_ID TEXT("AlgorithmID")
  33. #define KEYCACHEPERIOD TEXT("KeyCacheValidationPeriod")
  34. #define FIPSPOLICY TEXT("FipsAlgorithmPolicy")
  35. #define EFSCONFIG TEXT("EfsConfiguration")
  36. #define EFSLASTGOODCONFIG TEXT("LastGoodEfsConfiguration")
  37. #define TRUSTEDPEOPLE TEXT("TrustedPeople")
  38. //
  39. // The following key GPOSTATUSKEY is a temp solution. GPO should provide an API to tell people
  40. // if the GP propagation succeeded or not.
  41. //
  42. #define GPOSTATUSKEY TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions\\{35378EAC-683F-11D2-A89A-00C04FBBCFA2}")
  43. #define GPSTATUS TEXT("Status")
  44. //
  45. // EFS key
  46. //
  47. #define EFSMACHINEKEY TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\EFS")
  48. #define EFSPOLKEY TEXT("SOFTWARE\\Policies\\Microsoft\\Windows NT\\CurrentVersion\\EFS")
  49. #define POLICYUSEFIPS 1
  50. #define DISABLEEFS 0x00000001
  51. // Default cache length is 3600 seconds
  52. #define MAXCACHELENGTH 86400 * 7 // Max cache period - 7 Days. We only check time valid.
  53. #define MINCACHELENGTH 1800 // Min cache period - 0.5 Hours
  54. #define TIME_UNIT 10000000 // 1 TIME_UNIT == 1 second
  55. extern LONG RecoveryCertIsValidating;
  56. extern HANDLE EfsWaitHandle;
  57. ///////////////////////////////////////////////////////////////////////////////
  58. // /
  59. // Define how long our FEKs can be. An FEK will be allocated into a fixed /
  60. // size buffer, but only a certain number of bits of entropy may be used in /
  61. // the export version. /
  62. // /
  63. ///////////////////////////////////////////////////////////////////////////////
  64. //
  65. // This number affects the FEK generation algorithm. It represents the number
  66. // of bits of entropy in the key.
  67. //
  68. const EXPORT_KEY_STRENGTH = 56;
  69. const DOMESTIC_KEY_STRENGTH = 128;
  70. const EXPORT_DESX_SALT_LENGTH = 9;
  71. const DES3_KEY_STRENGTH = 168;
  72. const AES_KEY_STRENGTH_256 = 256;
  73. const DWORD WAITFORCERTVALIDATE = 10000;
  74. #ifndef LSASRV_EXPORT
  75. const DWORD KeyEntropy = DOMESTIC_KEY_STRENGTH;
  76. #else
  77. const DWORD KeyEntropy = EXPORT_KEY_STRENGTH;
  78. #endif
  79. LONG EFSDebugLevel = 0;
  80. ALG_ID EfsAlgInForce = CALG_AES_256;
  81. extern "C" BOOLEAN EfsDisabled = FALSE;
  82. //
  83. // Current recovery policy
  84. //
  85. RTL_RESOURCE RecoveryPolicyResource;
  86. CURRENT_RECOVERY_POLICY CurrentRecoveryPolicy;
  87. DWORD MissingRecoveryPolicyLogged = 0;
  88. //
  89. // Functions in EFSAPI.CXX
  90. //
  91. BOOLEAN
  92. EncryptFSCTLData(
  93. IN ULONG Fsctl,
  94. IN ULONG Psc,
  95. IN ULONG Csc,
  96. IN PVOID EfsData,
  97. IN ULONG EfsDataLength,
  98. IN OUT PUCHAR Buffer,
  99. IN OUT PULONG BufferLength
  100. );
  101. BOOLEAN
  102. SendHandle(
  103. IN HANDLE Handle,
  104. IN OUT PUCHAR EfsData,
  105. IN OUT PULONG EfsDataLength
  106. );
  107. BOOLEAN
  108. SendEfs(
  109. IN PEFS_KEY Fek,
  110. IN PEFS_DATA_STREAM_HEADER Efs,
  111. OUT PUCHAR EfsData,
  112. OUT PULONG EfsDataLength
  113. );
  114. BOOLEAN
  115. SendHandleAndEfs(
  116. IN HANDLE Handle,
  117. IN PEFS_DATA_STREAM_HEADER Efs,
  118. IN OUT PUCHAR EfsData,
  119. IN OUT PULONG EfsDataLength
  120. );
  121. //
  122. // Function prototypes in this module
  123. //
  124. BOOLEAN
  125. CreatePublicKeyInformationThumbprint(
  126. IN PSID pUserSid,
  127. IN PBYTE pbCertHash,
  128. IN DWORD cbCertHash,
  129. IN LPWSTR lpDisplayInformation OPTIONAL,
  130. IN LPWSTR ContainerName OPTIONAL,
  131. IN LPWSTR ProviderName OPTIONAL,
  132. OUT PEFS_PUBLIC_KEY_INFO * PublicKeyInformation
  133. );
  134. PBYTE
  135. EncryptFEK(
  136. IN PEFS_KEY Fek,
  137. IN HCRYPTKEY hRSAKey,
  138. OUT PDWORD dwEncryptedFEKLength
  139. );
  140. PEFS_KEY
  141. ExtractFek(
  142. IN PEFS_USER_INFO pEfsUserInfo,
  143. IN PENCRYPTED_KEY EncryptedKey,
  144. IN BOOL CheckBits
  145. );
  146. DWORD
  147. ConstructEncryptedKey(
  148. IN PBYTE EncryptedFEK,
  149. IN DWORD dwEncryptedFEKLength,
  150. IN PEFS_PUBLIC_KEY_INFO PublicKeyInformation,
  151. IN PEFS_KEY_SALT pEfsKeySalt,
  152. OUT PENCRYPTED_KEY *EncryptedKey,
  153. IN OUT PDWORD EncryptedKeySize
  154. );
  155. DWORD
  156. ConstructKeyRing(
  157. IN PEFS_KEY Fek,
  158. IN DWORD KeyCount,
  159. IN LPWSTR KeyNames[] OPTIONAL,
  160. IN LPWSTR ProviderNames[] OPTIONAL,
  161. IN PBYTE PublicKeys[],
  162. IN DWORD PublicKeyLengths[],
  163. IN PBYTE pbHashes[],
  164. IN DWORD cbHashes[],
  165. IN LPWSTR lpDisplayInformation[],
  166. IN PSID pSid[],
  167. IN BOOLEAN PublicKeyHandle,
  168. OUT PENCRYPTED_KEYS *KeyRing,
  169. OUT PDWORD KeyRingLength
  170. );
  171. DWORD
  172. ReformatPolicyInformation(
  173. PLSAPR_POLICY_DOMAIN_EFS_INFO PolicyEfsInfo,
  174. PLSAPR_POLICY_DOMAIN_EFS_INFO * NewPolicyEfsInfo,
  175. PBOOLEAN Reformatted
  176. );
  177. DWORD
  178. InitRecoveryPolicy(
  179. VOID
  180. );
  181. DWORD
  182. ParseOldRecoveryData(
  183. IN PLSAPR_POLICY_DOMAIN_EFS_INFO PolicyEfsInfo OPTIONAL,
  184. OUT PCURRENT_RECOVERY_POLICY ParsedRecoveryPolicy
  185. );
  186. VOID
  187. DumpPublicKeyInfo(
  188. PEFS_PUBLIC_KEY_INFO PublicKeyInfo
  189. );
  190. void
  191. DumpRecoveryKey(
  192. PRECOVERY_KEY_1_1 pRecoveryKey
  193. );
  194. PEFS_DATA_STREAM_HEADER
  195. AssembleEfsStream(
  196. IN PENCRYPTED_KEYS pDDF,
  197. IN DWORD cbDDF,
  198. IN PENCRYPTED_KEYS pDRF,
  199. IN DWORD cbDRF,
  200. IN PEFS_KEY Fek
  201. );
  202. PENCRYPTED_KEY
  203. GetEncryptedKeyByIndex(
  204. PENCRYPTED_KEYS pEncryptedKeys,
  205. DWORD KeyIndex
  206. );
  207. BOOL
  208. DeleteEncryptedKeyByIndex(
  209. IN PEFS_DATA_STREAM_HEADER pEfs,
  210. IN DWORD KeyIndex,
  211. IN PEFS_KEY Fek,
  212. OUT PEFS_DATA_STREAM_HEADER * pNewEfs
  213. );
  214. BOOLEAN
  215. EqualEncryptedKeys(
  216. IN PENCRYPTED_KEYS SrcKeys,
  217. IN PENCRYPTED_KEYS DstKeys,
  218. IN DWORD cbDstKeys
  219. );
  220. //
  221. // Server
  222. //
  223. VOID
  224. EfsGetRegSettings(
  225. VOID
  226. )
  227. /*++
  228. Routine Description:
  229. This routine is called during server initialization to set
  230. the EFS encryption algorithm.
  231. Arguments:
  232. None.
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. LONG rc;
  238. HKEY EfsKey;
  239. DWORD AlgId;
  240. DWORD CacheLength;
  241. DWORD EfsConfig;
  242. DWORD SizeInfo;
  243. DWORD Type;
  244. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  245. TEXT("SYSTEM\\CurrentControlSet\\Control\\LSA"),
  246. 0,
  247. GENERIC_READ,
  248. &EfsKey
  249. );
  250. if (rc == ERROR_SUCCESS) {
  251. SizeInfo = sizeof(DWORD);
  252. rc = RegQueryValueEx(
  253. EfsKey,
  254. FIPSPOLICY,
  255. NULL,
  256. &Type,
  257. (PUCHAR) &AlgId,
  258. &SizeInfo
  259. );
  260. if (rc == ERROR_SUCCESS) {
  261. if ( AlgId== POLICYUSEFIPS ) {
  262. EfsAlgInForce = CALG_3DES;
  263. }
  264. }
  265. RegCloseKey( EfsKey );
  266. }
  267. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  268. EFSMACHINEKEY,
  269. 0,
  270. GENERIC_READ,
  271. &EfsKey
  272. );
  273. if (rc == ERROR_SUCCESS) {
  274. if (EfsAlgInForce == CALG_AES_256) {
  275. //
  276. // FIPS Policy does not say we have to use FIPS. Let's check if user says EFS
  277. // should use specific algorithm.
  278. //
  279. SizeInfo = sizeof(DWORD);
  280. rc = RegQueryValueEx(
  281. EfsKey,
  282. ALGORITHM_ID,
  283. NULL,
  284. &Type,
  285. (PUCHAR) &AlgId,
  286. &SizeInfo
  287. );
  288. if (rc == ERROR_SUCCESS) {
  289. switch (AlgId) {
  290. case CALG_3DES:
  291. EfsAlgInForce = CALG_3DES; //0x6603
  292. break;
  293. case CALG_DESX:
  294. EfsAlgInForce = CALG_DESX; //0x6604
  295. break;
  296. case CALG_AES_256:
  297. //
  298. // Fall through intended
  299. //
  300. default:
  301. // EfsAlgInForce = CALG_AES_256;//0x6610
  302. break;
  303. }
  304. }
  305. }
  306. SizeInfo = sizeof(DWORD);
  307. rc = RegQueryValueEx(
  308. EfsKey,
  309. KEYCACHEPERIOD,
  310. NULL,
  311. &Type,
  312. (PUCHAR) &CacheLength,
  313. &SizeInfo
  314. );
  315. if (rc == ERROR_SUCCESS) {
  316. if ((CacheLength >= MINCACHELENGTH) && (CacheLength <= MAXCACHELENGTH)){
  317. CACHE_CERT_VALID_TIME = CacheLength * TIME_UNIT;
  318. }
  319. }
  320. //
  321. // Check if EFS is disabled in Policy
  322. //
  323. SizeInfo = sizeof(DWORD);
  324. rc = RegQueryValueEx(
  325. EfsKey,
  326. EFSCONFIG,
  327. NULL,
  328. &Type,
  329. (PUCHAR) &EfsConfig,
  330. &SizeInfo
  331. );
  332. if (rc == ERROR_SUCCESS) {
  333. if (EfsConfig & DISABLEEFS){
  334. EfsDisabled = TRUE;
  335. }
  336. }
  337. RegCloseKey( EfsKey );
  338. }
  339. }
  340. BOOL
  341. EfsIsGpoGood(
  342. VOID
  343. )
  344. /*++
  345. Routine Description:
  346. This is a temp workaround to check if GP propagation succeeded or not.
  347. GP should provide an API to do this.
  348. Arguments:
  349. Not used.
  350. Return Value:
  351. None.
  352. --*/
  353. {
  354. LONG rc;
  355. HKEY PolKey;
  356. DWORD SizeInfo;
  357. DWORD PolStatus = 0;
  358. DWORD Type;
  359. BOOL GoodPol = TRUE;
  360. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  361. GPOSTATUSKEY,
  362. 0,
  363. GENERIC_READ,
  364. &PolKey
  365. );
  366. if (rc == ERROR_SUCCESS) {
  367. //
  368. // Check if EFS is disabled in Policy
  369. //
  370. SizeInfo = sizeof(DWORD);
  371. rc = RegQueryValueEx(
  372. PolKey,
  373. GPSTATUS,
  374. NULL,
  375. &Type,
  376. (PUCHAR) &PolStatus,
  377. &SizeInfo
  378. );
  379. if (rc == ERROR_SUCCESS) {
  380. if (PolStatus) {
  381. //
  382. //Last policy propagation failed
  383. //
  384. GoodPol = FALSE;
  385. }
  386. } else {
  387. //
  388. // Assuming last propagation failed
  389. //
  390. GoodPol = FALSE;
  391. }
  392. RegCloseKey( PolKey );
  393. } else {
  394. GoodPol = FALSE;
  395. }
  396. return GoodPol;
  397. }
  398. VOID
  399. EfsRemoveKey(
  400. VOID
  401. )
  402. /*++
  403. Routine Description:
  404. This routine removes EFS Last Good Policy Key.
  405. Arguments:
  406. No.
  407. Return Value:
  408. No.
  409. --*/
  410. {
  411. LONG rc;
  412. HKEY EfsKey;
  413. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  414. EFSMACHINEKEY,
  415. 0,
  416. GENERIC_READ | KEY_SET_VALUE,
  417. &EfsKey
  418. );
  419. if (rc == ERROR_SUCCESS) {
  420. //
  421. // Delete the last good key
  422. //
  423. RegDeleteValue(
  424. EfsKey,
  425. EFSLASTGOODCONFIG
  426. );
  427. RegCloseKey( EfsKey );
  428. }
  429. }
  430. BOOL
  431. EfsApplyGoodPolicy(
  432. IN BOOLEAN* pEfsDisabled
  433. )
  434. /*++
  435. Routine Description:
  436. This routine is a common routine to apply good policy data.
  437. Arguments:
  438. pEfsDisabled -- Point to the global EfsDisabled.
  439. Return Value:
  440. TRUE if we applied the data. FALSE if no data available.
  441. --*/
  442. {
  443. LONG rc;
  444. HKEY EfsKey;
  445. HKEY EfsPolKey;
  446. DWORD EfsConfig;
  447. DWORD SizeInfo;
  448. DWORD Type;
  449. BOOL PolicyValueApplied = FALSE;
  450. //
  451. // Open EFS policy key
  452. //
  453. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  454. EFSPOLKEY,
  455. 0,
  456. GENERIC_READ,
  457. &EfsPolKey
  458. );
  459. if (rc == ERROR_SUCCESS) {
  460. //
  461. // Let's try to get the latest value
  462. //
  463. SizeInfo = sizeof(DWORD);
  464. rc = RegQueryValueEx(
  465. EfsPolKey,
  466. EFSCONFIG,
  467. NULL,
  468. &Type,
  469. (PUCHAR) &EfsConfig,
  470. &SizeInfo
  471. );
  472. if (rc == ERROR_SUCCESS) {
  473. PolicyValueApplied = TRUE;
  474. if (EfsConfig & DISABLEEFS){
  475. if (!(*pEfsDisabled)) {
  476. *pEfsDisabled = TRUE;
  477. }
  478. } else {
  479. if (*pEfsDisabled) {
  480. *pEfsDisabled = FALSE;
  481. }
  482. }
  483. //
  484. // We need to update our LAST Good key.
  485. //
  486. DWORD Disposition = 0;
  487. rc = RegCreateKeyEx(
  488. HKEY_LOCAL_MACHINE,
  489. EFSMACHINEKEY,
  490. 0,
  491. TEXT("REG_SZ"),
  492. REG_OPTION_NON_VOLATILE,
  493. KEY_ALL_ACCESS,
  494. NULL,
  495. &EfsKey,
  496. &Disposition // address of disposition value buffer
  497. );
  498. if (rc == ERROR_SUCCESS) {
  499. //
  500. // OK. Let's upadte the value
  501. //
  502. RegSetValueEx(
  503. EfsKey,
  504. EFSLASTGOODCONFIG,
  505. 0,
  506. REG_DWORD,
  507. (CONST BYTE *)&EfsConfig,
  508. sizeof(DWORD)
  509. );
  510. RegCloseKey( EfsKey );
  511. }
  512. }
  513. RegCloseKey( EfsPolKey );
  514. }
  515. return (PolicyValueApplied);
  516. }
  517. VOID
  518. EfsApplyLastPolicy(
  519. IN BOOLEAN *pEfsDisabled
  520. )
  521. /*++
  522. Routine Description:
  523. This routine is called during boot init time.
  524. Arguments:
  525. pEfsDisabled -- Point to the global EfsDisabled. May be changed to a structure pointer later
  526. to support more EFS policy vars.
  527. Return Value:
  528. None.
  529. --*/
  530. {
  531. LONG rc;
  532. HKEY EfsKey;
  533. DWORD EfsConfig;
  534. DWORD SizeInfo;
  535. DWORD Type;
  536. if (EfsIsGpoGood()) {
  537. //
  538. // We got a good policy.
  539. //
  540. BOOL PolicyValueApplied;
  541. PolicyValueApplied = EfsApplyGoodPolicy(
  542. pEfsDisabled
  543. );
  544. if (!PolicyValueApplied) {
  545. //
  546. // Policy key is missing or value removed. We need to delete the last good value.
  547. // The last good value could be non-existing. It does not hurt to try again during
  548. // the boot.
  549. //
  550. EfsRemoveKey();
  551. }
  552. } else {
  553. //
  554. // Last Policy propagation failed. Tried to get the last good one if there is one.
  555. //
  556. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  557. EFSMACHINEKEY,
  558. 0,
  559. GENERIC_READ,
  560. &EfsKey
  561. );
  562. if (rc == ERROR_SUCCESS) {
  563. SizeInfo = sizeof(DWORD);
  564. rc = RegQueryValueEx(
  565. EfsKey,
  566. EFSLASTGOODCONFIG,
  567. NULL,
  568. &Type,
  569. (PUCHAR) &EfsConfig,
  570. &SizeInfo
  571. );
  572. if (rc == ERROR_SUCCESS) {
  573. if (EfsConfig & DISABLEEFS){
  574. if (!(*pEfsDisabled)) {
  575. *pEfsDisabled = TRUE;
  576. }
  577. } else {
  578. if (*pEfsDisabled) {
  579. *pEfsDisabled = FALSE;
  580. }
  581. }
  582. }
  583. RegCloseKey( EfsKey );
  584. }
  585. }
  586. }
  587. VOID
  588. EfsGetPolRegSettings(
  589. IN PVOID pEfsPolCallBack,
  590. IN BOOLEAN timeExpired
  591. )
  592. /*++
  593. Routine Description:
  594. This routine is called during policy propagation.
  595. Arguments:
  596. pEfsDisabled -- Point to a structure EFS_POL_CALLBACK.
  597. timeExpired -- FALSE if trigged by the event.
  598. Return Value:
  599. None.
  600. --*/
  601. {
  602. LONG rc;
  603. HKEY EfsKey;
  604. DWORD EfsConfig;
  605. DWORD SizeInfo;
  606. DWORD Type;
  607. BOOLEAN * CrntEfsDisabled = ((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsDisable;
  608. if (timeExpired) {
  609. //
  610. // May be killed.
  611. //
  612. if (*(((PEFS_POL_CALLBACK)pEfsPolCallBack)->EfsPolicyEventHandle)) {
  613. UnregisterGPNotification(*(((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsPolicyEventHandle));
  614. CloseHandle(*(((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsPolicyEventHandle));
  615. *(((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsPolicyEventHandle) = 0;
  616. }
  617. if (EfsWaitHandle) {
  618. RtlDeregisterWait(EfsWaitHandle);
  619. EfsWaitHandle = 0;
  620. }
  621. return;
  622. }
  623. if (EfsIsGpoGood()) {
  624. //
  625. // We got a good policy.
  626. //
  627. BOOL PolicyValueApplied;
  628. PolicyValueApplied = EfsApplyGoodPolicy(
  629. CrntEfsDisabled
  630. );
  631. if (!PolicyValueApplied) {
  632. //
  633. // Policy key is missing or value removed. We need to delete the last good value.
  634. //
  635. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  636. EFSMACHINEKEY,
  637. 0,
  638. GENERIC_READ | KEY_SET_VALUE,
  639. &EfsKey
  640. );
  641. if (rc == ERROR_SUCCESS) {
  642. //
  643. // Set back the default value first.
  644. //
  645. SizeInfo = sizeof(DWORD);
  646. rc = RegQueryValueEx(
  647. EfsKey,
  648. EFSCONFIG,
  649. NULL,
  650. &Type,
  651. (PUCHAR) &EfsConfig,
  652. &SizeInfo
  653. );
  654. if (rc == ERROR_SUCCESS) {
  655. if (EfsConfig & DISABLEEFS){
  656. if (!(*CrntEfsDisabled)) {
  657. *CrntEfsDisabled = TRUE;
  658. }
  659. } else {
  660. if (*CrntEfsDisabled) {
  661. *CrntEfsDisabled = FALSE;
  662. }
  663. }
  664. } else {
  665. //
  666. // No default value is treated as enable EFS
  667. //
  668. if (*CrntEfsDisabled) {
  669. *CrntEfsDisabled = FALSE;
  670. }
  671. }
  672. //
  673. // Delete the last good key
  674. //
  675. RegDeleteValue(
  676. EfsKey,
  677. EFSLASTGOODCONFIG
  678. );
  679. RegCloseKey( EfsKey );
  680. } else {
  681. //
  682. // No default key value. Enable EFS if not now.
  683. //
  684. if (*CrntEfsDisabled) {
  685. *CrntEfsDisabled = FALSE;
  686. }
  687. }
  688. }
  689. }
  690. if (EfsWaitHandle) {
  691. //
  692. // Unregister the last one
  693. //
  694. RtlDeregisterWait(EfsWaitHandle);
  695. EfsWaitHandle = 0;
  696. //
  697. // Reset the notification event
  698. //
  699. if (*(((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsPolicyEventHandle)) {
  700. ResetEvent(*(((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsPolicyEventHandle));
  701. //
  702. // Reregister for a new one
  703. //
  704. if (!NT_SUCCESS(RtlRegisterWait(
  705. &EfsWaitHandle,
  706. *(((PEFS_POL_CALLBACK)pEfsPolCallBack)->EfsPolicyEventHandle),
  707. EfsGetPolRegSettings,
  708. pEfsPolCallBack,
  709. INFINITE,
  710. WT_EXECUTEONLYONCE))){
  711. //
  712. // We couldn't use the thread pool.
  713. //
  714. UnregisterGPNotification(*(((PEFS_POL_CALLBACK)pEfsPolCallBack)->EfsPolicyEventHandle));
  715. CloseHandle(*(((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsPolicyEventHandle));
  716. *(((PEFS_POL_CALLBACK) pEfsPolCallBack)->EfsPolicyEventHandle) = 0;
  717. }
  718. }
  719. }
  720. }
  721. VOID
  722. RecoveryInformationCallback(
  723. POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  724. )
  725. /*++
  726. Routine Description:
  727. Callback for when EFS Recovery policy information changes
  728. Arguments:
  729. ChangedInfoClass - The info class that changed.
  730. Return Value:
  731. None.
  732. --*/
  733. {
  734. InitRecoveryPolicy();
  735. return;
  736. }
  737. VOID
  738. EfspRoleChangeCallback(
  739. POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass
  740. )
  741. /*++
  742. Routine Description:
  743. Callback for when the role of the machine in a domain changes.
  744. Arguments:
  745. ChangedInfoClass - The info class that changed.
  746. Return Value:
  747. None.
  748. --*/
  749. {
  750. NTSTATUS Status;
  751. PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo;
  752. Status = LsarQueryInformationPolicy(LsapPolicyHandle,
  753. PolicyPrimaryDomainInformation,
  754. (PLSAPR_POLICY_INFORMATION *)&PrimaryDomainInfo
  755. );
  756. if (!NT_SUCCESS(Status)) {
  757. DebugLog((DEB_ERROR, "Failed to query primary domain from Lsa, Status = 0x%lx\n", Status));
  758. } else {
  759. if (PrimaryDomainInfo->Sid != NULL) {
  760. EfspInDomain = TRUE;
  761. } else {
  762. EfspInDomain = FALSE;
  763. }
  764. LsaFreeMemory( PrimaryDomainInfo );
  765. }
  766. return;
  767. }
  768. #if 0
  769. //
  770. // We may revisit this function in inheritance work. Keep it for now.
  771. //
  772. BOOL
  773. GetPublicKey(
  774. HCRYPTKEY hKey,
  775. PBYTE * PublicKeyBlob,
  776. PDWORD KeyLength
  777. )
  778. /*++
  779. Routine Description:
  780. Exports a public key
  781. Arguments:
  782. hKey - Supplies the key handle to be exported
  783. PublicKeyBlob - Returns a buffer containing the exported key
  784. KeyLength - Returns the length of the exported key buffer in bytes.
  785. Return Value:
  786. TRUE on success, FALSE otherwise.
  787. --*/
  788. {
  789. *KeyLength = 0;
  790. *PublicKeyBlob = NULL;
  791. if (hKey == NULL) {
  792. ASSERT( FALSE );
  793. return( FALSE );
  794. }
  795. BOOL b = CryptExportKey( hKey, 0, PUBLICKEYBLOB, 0, NULL, KeyLength );
  796. if (b) {
  797. *PublicKeyBlob = (PBYTE) LsapAllocateLsaHeap( *KeyLength );
  798. if (*PublicKeyBlob != NULL) {
  799. b = CryptExportKey( hKey, 0, PUBLICKEYBLOB, 0, *PublicKeyBlob, KeyLength );
  800. if (!b) {
  801. LsapFreeLsaHeap( *PublicKeyBlob );
  802. *PublicKeyBlob = NULL;
  803. }
  804. } else {
  805. b = FALSE;
  806. }
  807. }
  808. return( b );
  809. }
  810. #endif
  811. inline
  812. VOID
  813. AcquireRecoveryPolicyReadLock()
  814. {
  815. BOOL b = RtlAcquireResourceShared( &RecoveryPolicyResource, TRUE );
  816. ASSERT( b );
  817. }
  818. inline
  819. VOID
  820. ReleaseRecoveryPolicyReadLock()
  821. {
  822. RtlReleaseResource( &RecoveryPolicyResource );
  823. }
  824. inline
  825. VOID
  826. ReleaseRecoveryData()
  827. {
  828. ReleaseRecoveryPolicyReadLock();
  829. }
  830. DWORD
  831. GetRecoveryData(
  832. OUT PDWORD dwKeyCount,
  833. OUT PDWORD dwPolicyStatus,
  834. OUT PBYTE * pbPublicKeys[],
  835. OUT DWORD * cbPublicKeys[],
  836. OUT PBYTE * pbHashes[],
  837. OUT DWORD * cbHashes[],
  838. OUT LPWSTR * lpDisplayInfo[] OPTIONAL,
  839. OUT PSID * pSid[] OPTIONAL
  840. )
  841. /*++
  842. Routine Description:
  843. This routine returns the current recovery data. It takes a read
  844. lock on the recovery data so that it cannot be modified while in use.
  845. This lock must be freed by calling ReleaseRecoveryData().
  846. Arguments:
  847. dwKeyCount - Returns the list of keys in the current recovery data.
  848. dwPolicyStatus - The status of the recovery policy.
  849. pbPublicKeys - Returns an array of pointers to exported public key blobs that will be used
  850. to encrypt the FEK.
  851. cbPublicKeys - Specifies the length (in bytes) of each of the keys returned
  852. in the PublicKeys array.
  853. pbHashes - Returns an array of pointers to the key hashes.
  854. cbHashes - Specifies the length (in bytes) of each of the key hashes.
  855. lpDisplayInfo - Recovery cert display information.
  856. pSid - Sids of the recovery agents
  857. Return Value:
  858. ERROR_SUCCESS for succeed.
  859. --*/
  860. {
  861. AcquireRecoveryPolicyReadLock();
  862. //
  863. // Verify that all of the cert contexts are still valid.
  864. //
  865. // If any of them fail, say that there is no recovery
  866. // policy on the system.
  867. //
  868. DWORD i;
  869. BOOLEAN fResult = TRUE;
  870. LARGE_INTEGER TimeStamp;
  871. if ( (*dwPolicyStatus = CurrentRecoveryPolicy.PolicyStatus) < RECOVERY_POLICY_OK) {
  872. *dwKeyCount = CurrentRecoveryPolicy.dwKeyCount;
  873. *pbPublicKeys = CurrentRecoveryPolicy.pbPublicKeys;
  874. *cbPublicKeys = CurrentRecoveryPolicy.cbPublicKeys;
  875. *pbHashes = CurrentRecoveryPolicy.pbHash;
  876. *cbHashes = CurrentRecoveryPolicy.cbHash;
  877. if (lpDisplayInfo) {
  878. *lpDisplayInfo = CurrentRecoveryPolicy.lpDisplayInfo;
  879. }
  880. if (pSid) {
  881. *pSid = CurrentRecoveryPolicy.pSid;
  882. }
  883. return( ERROR_SUCCESS );
  884. }
  885. TimeStamp.QuadPart = 0;
  886. //
  887. // Check if we need validate the certs again
  888. //
  889. if ((NT_SUCCESS( NtQuerySystemTime(&TimeStamp)) &&
  890. (TimeStamp.QuadPart - CurrentRecoveryPolicy.TimeStamp.QuadPart > CACHE_CERT_VALID_TIME )) ||
  891. (CurrentRecoveryPolicy.CertValidated == CERT_NOT_VALIDATED)){
  892. //
  893. // We only let one thread in here.
  894. //
  895. LONG IsCertBeingValidated;
  896. IsCertBeingValidated = InterlockedExchange(&RecoveryCertIsValidating, 1);
  897. if ((CurrentRecoveryPolicy.CertValidated == CERT_NOT_VALIDATED) && (IsCertBeingValidated == 1)) {
  898. //
  899. // If the recovery cert has not been validated and some other thread is validating,
  900. // let's wait for a 10 seconds.
  901. //
  902. Sleep(WAITFORCERTVALIDATE);
  903. if (CurrentRecoveryPolicy.CertValidated == CERT_NOT_VALIDATED) {
  904. //
  905. // Not validated yet. Let's try to grab the lock. Let other thread to wait.
  906. //
  907. IsCertBeingValidated = InterlockedExchange(&RecoveryCertIsValidating, 1);
  908. }
  909. }
  910. if ( (IsCertBeingValidated != 1) || (CurrentRecoveryPolicy.CertValidated == CERT_NOT_VALIDATED) ) {
  911. //
  912. // No thread is validating the cert, let's do it
  913. //
  914. for (i=0; i<CurrentRecoveryPolicy.dwKeyCount; i++) {
  915. //
  916. // We only check the time in the cert
  917. //
  918. LONG CertTimeValid;
  919. if (CertTimeValid = CertVerifyTimeValidity(
  920. NULL,
  921. CurrentRecoveryPolicy.pCertContext[i]->pCertInfo
  922. )){
  923. if ( CertTimeValid > 0 ) {
  924. DebugLog((DEB_WARN, "Expired certificate in recovery policy\n"));
  925. *dwPolicyStatus = RECOVERY_POLICY_EXPIRED_CERTS;
  926. fResult = FALSE;
  927. break;
  928. } else {
  929. DebugLog((DEB_WARN, "Expired certificate in recovery policy\n"));
  930. *dwPolicyStatus = RECOVERY_POLICY_NOT_EFFECT_CERTS;
  931. fResult = FALSE;
  932. break;
  933. }
  934. }
  935. }
  936. //
  937. // When policy is propagated, the write lock is acquired. When we get here, we are having read lock and no one
  938. // is having the write lock. It is OK for threads stepping each other on writing CertValidated and TimeStamp here.
  939. // We are checking the validation in hours, a fraction of a second window here can be ignored.
  940. //
  941. if (CurrentRecoveryPolicy.dwKeyCount && fResult) {
  942. CurrentRecoveryPolicy.CertValidated = CERT_VALIDATED;
  943. } else if ( CurrentRecoveryPolicy.dwKeyCount ) {
  944. CurrentRecoveryPolicy.CertValidated = CERT_VALIDATION_FAILED;
  945. }
  946. if (CurrentRecoveryPolicy.CertValidated != CERT_NOT_VALIDATED) {
  947. CurrentRecoveryPolicy.TimeStamp.QuadPart = TimeStamp.QuadPart;
  948. }
  949. if (IsCertBeingValidated != 1) {
  950. InterlockedExchange(&RecoveryCertIsValidating, IsCertBeingValidated);
  951. }
  952. }
  953. }
  954. if (CurrentRecoveryPolicy.CertValidated == CERT_VALIDATED) {
  955. *dwKeyCount = CurrentRecoveryPolicy.dwKeyCount;
  956. *pbPublicKeys = CurrentRecoveryPolicy.pbPublicKeys;
  957. *cbPublicKeys = CurrentRecoveryPolicy.cbPublicKeys;
  958. *pbHashes = CurrentRecoveryPolicy.pbHash;
  959. *cbHashes = CurrentRecoveryPolicy.cbHash;
  960. if (lpDisplayInfo) {
  961. *lpDisplayInfo = CurrentRecoveryPolicy.lpDisplayInfo;
  962. }
  963. if (pSid) {
  964. *pSid = CurrentRecoveryPolicy.pSid;
  965. }
  966. } else {
  967. *dwKeyCount = 0;
  968. }
  969. if ( ((RECOVERY_POLICY_EXPIRED_CERTS == *dwPolicyStatus) ||
  970. (RECOVERY_POLICY_NOT_EFFECT_CERTS == *dwPolicyStatus)) &&
  971. ( 0 == MissingRecoveryPolicyLogged) ) {
  972. DWORD eventID = EFS_INVALID_RECOVERY_POLICY_ERROR;
  973. //
  974. // Log the fail to get the recovery policy
  975. //
  976. MissingRecoveryPolicyLogged = 1;
  977. EfsLogEntry(
  978. EVENTLOG_ERROR_TYPE,
  979. 0,
  980. eventID,
  981. 0,
  982. 0,
  983. NULL,
  984. NULL
  985. );
  986. }
  987. return( ERROR_SUCCESS );
  988. }
  989. BOOLEAN
  990. ConstructEFS(
  991. PEFS_USER_INFO pEfsUserInfo,
  992. PEFS_KEY Fek,
  993. PEFS_DATA_STREAM_HEADER ParentEfsStreamHeader,
  994. PEFS_DATA_STREAM_HEADER * EfsStreamHeader
  995. )
  996. /*++
  997. Routine Description:
  998. This routine will construct an EFS stream. It is intended to be used
  999. whenever an entire EFS stream is required, such as when a new file is
  1000. created.
  1001. An EFS stream contains a header, a DDF (which contains current user key
  1002. information), and a DRF (which contains recovery information).
  1003. Arguments:
  1004. Fek - Supplies a pointer to a partially filled in EFS_KEY structure,
  1005. specifying the length of the desired key and the algorithm that
  1006. will be used with the key to encrypt the file.
  1007. It is important that the algorithm field be filled in, since this
  1008. key will be eventually encrypted in its entirety, and all the fields
  1009. must be present for that to work.
  1010. ParentEfsStreamHeader - Supplies the EFS stream from the containing directory,
  1011. if one exists. This parameter is not currently used, because we do
  1012. not support inheritance from directories to files (yet).
  1013. EfsStreamHeader - Returns a pointer to an EFS_DATA_STREAM_HEADER which is
  1014. the head of an EFS stream. This header is followed by variable length
  1015. data containing the actual EFS data.
  1016. Return Value:
  1017. --*/
  1018. {
  1019. LPWSTR ContainerName = NULL;
  1020. HCRYPTPROV hProv = 0;
  1021. HCRYPTKEY hUserKey = 0;
  1022. LPWSTR lpDisplayInformation = NULL;
  1023. LPWSTR ProviderName = NULL;
  1024. DWORD ProviderType = 0;
  1025. PUCHAR PublicKey = NULL;
  1026. HCRYPTKEY hWkUserKey = NULL;
  1027. DWORD rc;
  1028. PEFS_DATA_STREAM_HEADER EFS = NULL;
  1029. DWORD DRFLength = 0;
  1030. DWORD DDFLength = 0;
  1031. PENCRYPTED_KEYS pDRF = NULL;
  1032. PENCRYPTED_KEYS pDDF = NULL;
  1033. PBYTE pbHash;
  1034. DWORD cbHash;
  1035. BOOLEAN b = FALSE;
  1036. //
  1037. // To build the DDF, we need the user's current key from the registry.
  1038. // This routine will get the key information from the registry and open
  1039. // the context containing the key.
  1040. //
  1041. rc = GetCurrentKey(
  1042. pEfsUserInfo,
  1043. &hUserKey,
  1044. &hProv,
  1045. &ContainerName,
  1046. &ProviderName,
  1047. &ProviderType,
  1048. &lpDisplayInformation,
  1049. &pbHash,
  1050. &cbHash
  1051. );
  1052. if (ERROR_SUCCESS == rc) {
  1053. if (hUserKey) {
  1054. hWkUserKey = hUserKey;
  1055. } else {
  1056. //
  1057. // Use the key in the cache
  1058. //
  1059. ASSERT(pEfsUserInfo->pUserCache);
  1060. ASSERT(pEfsUserInfo->pUserCache->hUserKey);
  1061. hWkUserKey = pEfsUserInfo->pUserCache->hUserKey;
  1062. }
  1063. } else {
  1064. SetLastError( rc );
  1065. return( FALSE );
  1066. }
  1067. //
  1068. // Before we exit, make sure to clean up ContainerName, ProviderName, pbHash, hUserKey, hProv
  1069. //
  1070. rc = GenerateDRF( Fek, &pDRF, &DRFLength);
  1071. if (ERROR_SUCCESS == rc) {
  1072. LPWSTR lpWkContainerName;
  1073. LPWSTR lpWkDisplayInformation;
  1074. LPWSTR lpWkProviderName;
  1075. PBYTE pbWkHash;
  1076. DWORD cbWkHash;
  1077. if (hUserKey) {
  1078. //
  1079. // Do not use the cache
  1080. //
  1081. lpWkContainerName = ContainerName;
  1082. lpWkProviderName = ProviderName;
  1083. lpWkDisplayInformation = lpDisplayInformation;
  1084. pbWkHash = pbHash;
  1085. cbWkHash = cbHash;
  1086. } else {
  1087. //
  1088. // Use the cache
  1089. //
  1090. lpWkContainerName = pEfsUserInfo->pUserCache->ContainerName;
  1091. lpWkProviderName = pEfsUserInfo->pUserCache->ProviderName;
  1092. lpWkDisplayInformation = pEfsUserInfo->pUserCache->DisplayInformation;
  1093. pbWkHash = pEfsUserInfo->pUserCache->pbHash;
  1094. cbWkHash = pEfsUserInfo->pUserCache->cbHash;
  1095. }
  1096. rc = ConstructKeyRing(
  1097. Fek,
  1098. 1,
  1099. &lpWkContainerName,
  1100. &lpWkProviderName,
  1101. (PBYTE *)&hWkUserKey,
  1102. NULL,
  1103. &pbWkHash,
  1104. &cbWkHash,
  1105. &lpWkDisplayInformation,
  1106. &(pEfsUserInfo->pTokenUser->User.Sid),
  1107. TRUE,
  1108. &pDDF,
  1109. &DDFLength
  1110. );
  1111. if (ERROR_SUCCESS == rc) {
  1112. DWORD EfsLength = DDFLength + DRFLength + sizeof( EFS_DATA_STREAM_HEADER );
  1113. //
  1114. // Efs has to be a multiple of 8 in length to encrypt properly.
  1115. //
  1116. EfsLength = (EfsLength + 7) & 0xfffffff8;
  1117. EFS = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( EfsLength );
  1118. if (EFS != NULL) {
  1119. memset( EFS, 0, sizeof( EFS_DATA_STREAM_HEADER ));
  1120. EFS->Length = EfsLength;
  1121. EFS->State = 0; // used by the server
  1122. EFS->EfsVersion = EFS_CURRENT_VERSION;
  1123. RPC_STATUS RpcStatus = UuidCreate ( &EFS->EfsId );
  1124. if (RpcStatus == ERROR_SUCCESS || RpcStatus == RPC_S_UUID_LOCAL_ONLY) {
  1125. //
  1126. // A "local-only" UUID is ok in this case
  1127. //
  1128. EFS->DataDecryptionField = (ULONG)sizeof(EFS_DATA_STREAM_HEADER );
  1129. memcpy( (PENCRYPTED_KEYS)((PBYTE)EFS + sizeof( EFS_DATA_STREAM_HEADER )), pDDF, DDFLength );
  1130. if ( 0 == DRFLength) {
  1131. EFS->DataRecoveryField = 0;
  1132. } else {
  1133. EFS->DataRecoveryField = (ULONG)(sizeof(EFS_DATA_STREAM_HEADER ) + DDFLength);
  1134. memcpy( (PENCRYPTED_KEYS)((PBYTE)EFS + sizeof( EFS_DATA_STREAM_HEADER ) + DDFLength ), pDRF, DRFLength );
  1135. }
  1136. /*
  1137. BOOLEAN f = EfspChecksumEfs( EFS, Fek );
  1138. ASSERT( f );
  1139. if (!f) {
  1140. rc = GetLastError();
  1141. ASSERT( rc != ERROR_SUCCESS );
  1142. LsapFreeLsaHeap( EFS );
  1143. *EfsStreamHeader = NULL;
  1144. } else {
  1145. //
  1146. // Everything worked, return success.
  1147. //
  1148. *EfsStreamHeader = EFS;
  1149. b = TRUE;
  1150. }
  1151. */
  1152. *EfsStreamHeader = EFS;
  1153. b = TRUE;
  1154. }
  1155. } else {
  1156. rc = GetLastError();
  1157. }
  1158. }
  1159. }
  1160. ReleaseRecoveryData();
  1161. if (pDDF) {
  1162. LsapFreeLsaHeap(pDDF);
  1163. }
  1164. if (pDRF) {
  1165. LsapFreeLsaHeap(pDRF);
  1166. }
  1167. if (ContainerName) {
  1168. //
  1169. // Defensive checking
  1170. //
  1171. LsapFreeLsaHeap( ContainerName );
  1172. }
  1173. if (ProviderName) {
  1174. LsapFreeLsaHeap( ProviderName );
  1175. }
  1176. if (lpDisplayInformation) {
  1177. LsapFreeLsaHeap( lpDisplayInformation );
  1178. }
  1179. if (PublicKey) {
  1180. LsapFreeLsaHeap( PublicKey );
  1181. }
  1182. if (pbHash) {
  1183. LsapFreeLsaHeap( pbHash );
  1184. }
  1185. if (hUserKey) {
  1186. CryptDestroyKey( hUserKey );
  1187. }
  1188. if (hProv) {
  1189. CryptReleaseContext( hProv, 0 );
  1190. }
  1191. if (EFSDebugLevel > 0) {
  1192. DumpEFS( *EfsStreamHeader );
  1193. }
  1194. SetLastError( rc );
  1195. #if DBG
  1196. if (!b) {
  1197. ASSERT( rc != ERROR_SUCCESS );
  1198. }
  1199. #endif
  1200. return( b );
  1201. }
  1202. DWORD
  1203. CopyEfsStream(
  1204. OUT PEFS_DATA_STREAM_HEADER * Target,
  1205. IN PEFS_DATA_STREAM_HEADER Source
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. Makes a copy of the passed EFS stream. Allocates memory for the target
  1210. which must be freed.
  1211. Arguments:
  1212. Target - Takes a pointer which is filled in with a pointer to the copy
  1213. of the EFS stream. This pointer must be freed.
  1214. Return Value:
  1215. ERROR_SUCCESS, or ERROR_NOT_ENOUGH_MEMORY if we can't allocate memory for the
  1216. target buffer.
  1217. --*/
  1218. {
  1219. *Target = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( Source->Length );
  1220. if (*Target) {
  1221. memcpy( *Target, Source, Source->Length );
  1222. } else {
  1223. return( ERROR_NOT_ENOUGH_MEMORY );
  1224. }
  1225. return( ERROR_SUCCESS );
  1226. }
  1227. BOOLEAN
  1228. ConstructDirectoryEFS(
  1229. IN PEFS_USER_INFO pEfsUserInfo,
  1230. IN PEFS_KEY Fek,
  1231. OUT PEFS_DATA_STREAM_HEADER * EfsStreamHeader
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. This routine constructs the EFS stream for a directory.
  1236. Arguments:
  1237. pEfsUserInfo - Supplies useful information about our caller.
  1238. Fek - Supplies the Fek to put into the EFS stream.
  1239. EfsStreamHeader - Returns a pointer to the new EFS stream.
  1240. Return Value:
  1241. return-value - Description of conditions needed to return value. - or -
  1242. None.
  1243. --*/
  1244. {
  1245. return( ConstructEFS( pEfsUserInfo, Fek, NULL, EfsStreamHeader ) );
  1246. }
  1247. DWORD
  1248. ConstructKeyRing(
  1249. IN PEFS_KEY Fek,
  1250. IN DWORD KeyCount,
  1251. IN LPWSTR KeyNames[] OPTIONAL,
  1252. IN LPWSTR ProviderNames[] OPTIONAL,
  1253. IN PBYTE PublicKeys[],
  1254. IN DWORD PublicKeyLengths[],
  1255. IN PBYTE pbHashes[],
  1256. IN DWORD cbHashes[],
  1257. IN LPWSTR lpDisplayInformation[],
  1258. IN PSID pSid[],
  1259. IN BOOLEAN PublicKeyHandle,
  1260. OUT PENCRYPTED_KEYS *KeyRing,
  1261. OUT PDWORD KeyRingLength
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. This routine will construct a key ring (DDF or DRF) structure. A keyring
  1266. contains one or more ENCRYPTED_KEY structures, each of which represents
  1267. an encoding of the FEK with a different user key.
  1268. The caller is expected to call this routine twice, once to determine the
  1269. length of the structure, and a second time to actually create the key ring
  1270. structure.
  1271. Note that the passed keys do not need to exist in the current context,
  1272. and if we are building a DRF structure, most likely will not exist
  1273. in the current context.
  1274. Arguments:
  1275. Fek - Provides the unencrypted FEK for the file.
  1276. KeyCount - Provides the number of keys that are going to be placed in this
  1277. keyring.
  1278. KeyNames - Provides an array of NULL-terminated WCHAR strings, each naming
  1279. a key.
  1280. ProviderNames - Provides an array of providers that is parallel to the
  1281. KeyNames array.
  1282. PublicKeys - Provides an array of pointers to PUBLICKEYBLOB structures,
  1283. one for each named key.
  1284. PublicKeyLengths - Provides an array of lengths of the PUBLICKEYBLOB
  1285. structures pointed to by the PublicKeys array. It could also points to the key
  1286. handle.
  1287. pSid - Users' SIDs
  1288. PublicKeyHandle - Indicate if PublicKeys point to PUBLICKEYBLOB or key handles.
  1289. KeyRing - Returns a pointer to the constructed keyring. If this parameter
  1290. is NULL, only the length will be computed and returned.
  1291. KeyRingLength - Provides the size of the passed KeyRing buffer, or or if the
  1292. KeyRing pointer is NULL, the size of the buffer that must be passed in to
  1293. return the KeyRing.
  1294. Return Value:
  1295. ERROR_SUCCESS - Returned if successful.
  1296. ERROR_NOT_ENOUGH_MEMORY - Some attempt to allocate memory from the local
  1297. heap failed.
  1298. --*/
  1299. {
  1300. //
  1301. // For each Key passed in, import the public key blob
  1302. // and export the session key encrypted with that blob.
  1303. // The FEK will be encrypted with the same session key
  1304. // in each entry.
  1305. //
  1306. PEFS_KEY_SALT pEfsKeySalt = NULL;
  1307. PENCRYPTED_KEY * EncryptedKey = NULL;
  1308. BOOL GotPublicKey = TRUE;
  1309. EncryptedKey = (PENCRYPTED_KEY *)LsapAllocateLsaHeap( KeyCount * sizeof(PENCRYPTED_KEY) );
  1310. *KeyRing = NULL;
  1311. if (EncryptedKey == NULL) {
  1312. return( ERROR_NOT_ENOUGH_MEMORY );
  1313. }
  1314. PDWORD EncryptedKeySize = (PDWORD)LsapAllocateLsaHeap( KeyCount * sizeof( DWORD ));
  1315. if (EncryptedKeySize == NULL) {
  1316. LsapFreeLsaHeap( EncryptedKey );
  1317. return( ERROR_NOT_ENOUGH_MEMORY );
  1318. }
  1319. DWORD i;
  1320. DWORD rc = ERROR_SUCCESS;
  1321. for (i = 0 ; i<KeyCount ; i++) {
  1322. EncryptedKey[i] = NULL;
  1323. EncryptedKeySize[i] = 0;
  1324. }
  1325. for ( i = 0; i<KeyCount && rc==ERROR_SUCCESS ; i++ ) {
  1326. //
  1327. // Import the passed public key
  1328. //
  1329. HCRYPTKEY hXchgKey = 0;
  1330. if (PublicKeyHandle) {
  1331. GotPublicKey = TRUE;
  1332. hXchgKey = (HCRYPTKEY)PublicKeys[i];
  1333. } else {
  1334. GotPublicKey = CryptImportKey( hProvVerify, PublicKeys[i], PublicKeyLengths[i], 0, CRYPT_EXPORTABLE, &hXchgKey );
  1335. }
  1336. if (GotPublicKey) {
  1337. DWORD dwEncryptedFEKLength = 0;
  1338. PBYTE EncryptedFEK = EncryptFEK( Fek, hXchgKey, &dwEncryptedFEKLength );
  1339. if (EncryptedFEK == NULL) {
  1340. rc = GetLastError();
  1341. ASSERT( rc != ERROR_SUCCESS );
  1342. } else {
  1343. PEFS_PUBLIC_KEY_INFO PublicKeyInformation = NULL;
  1344. LPWSTR KeyName;
  1345. LPWSTR ProviderName;
  1346. if (KeyNames && ProviderNames) {
  1347. KeyName = KeyNames[i];
  1348. ProviderName = ProviderNames[i];
  1349. } else {
  1350. KeyName = NULL;
  1351. ProviderName = NULL;
  1352. }
  1353. if (CreatePublicKeyInformationThumbprint(
  1354. pSid[i],
  1355. pbHashes[i],
  1356. cbHashes[i],
  1357. lpDisplayInformation[i],
  1358. KeyName,
  1359. ProviderName,
  1360. &PublicKeyInformation
  1361. )) {
  1362. if ( Fek->Entropy <= EXPORT_KEY_STRENGTH ){
  1363. DWORD SaltLength;
  1364. DWORD SaltBlockLength;
  1365. if (GetSaltLength(Fek->Algorithm, &SaltLength, &SaltBlockLength)){
  1366. pEfsKeySalt = (PEFS_KEY_SALT)LsapAllocateLsaHeap( sizeof( EFS_KEY_SALT ) + SaltBlockLength );
  1367. if (pEfsKeySalt){
  1368. pEfsKeySalt->Length = sizeof( EFS_KEY_SALT ) + SaltBlockLength;
  1369. pEfsKeySalt->SaltType = Fek->Algorithm;
  1370. RtlCopyMemory( (PBYTE)pEfsKeySalt + sizeof( EFS_KEY_SALT ),
  1371. EFS_KEY_DATA( Fek ),
  1372. SaltLength
  1373. );
  1374. }
  1375. }
  1376. } else {
  1377. pEfsKeySalt = NULL;
  1378. }
  1379. if (pEfsKeySalt || (Fek->Entropy > EXPORT_KEY_STRENGTH)) {
  1380. rc = ConstructEncryptedKey( EncryptedFEK,
  1381. dwEncryptedFEKLength,
  1382. PublicKeyInformation,
  1383. pEfsKeySalt,
  1384. &EncryptedKey[i],
  1385. &EncryptedKeySize[i]
  1386. );
  1387. }
  1388. //
  1389. // Clean up output from CreatePublicKeyInformation
  1390. //
  1391. LsapFreeLsaHeap( PublicKeyInformation );
  1392. if (pEfsKeySalt){
  1393. LsapFreeLsaHeap( pEfsKeySalt );
  1394. }
  1395. } else {
  1396. rc = GetLastError();
  1397. }
  1398. //
  1399. // Clean up output from EncryptFEK
  1400. //
  1401. LsapFreeLsaHeap( EncryptedFEK );
  1402. }
  1403. //
  1404. // If the we imported the key, don't need this key any more, get rid of it.
  1405. //
  1406. if (!PublicKeyHandle) {
  1407. CryptDestroyKey( hXchgKey );
  1408. }
  1409. } else {
  1410. //
  1411. // Couldn't import a public key, pick up error code
  1412. //
  1413. rc = GetLastError();
  1414. }
  1415. if (rc != ERROR_SUCCESS) {
  1416. //
  1417. // Something failed along the way, clean up all previous allocations
  1418. //
  1419. for (DWORD j = 0; j < i ; j++ ) {
  1420. if (EncryptedKey[j]) {
  1421. LsapFreeLsaHeap( EncryptedKey[j] );
  1422. }
  1423. }
  1424. LsapFreeLsaHeap( EncryptedKey );
  1425. LsapFreeLsaHeap( EncryptedKeySize );
  1426. return( rc );
  1427. }
  1428. }
  1429. //
  1430. // We successfully created all of the EncryptedKey structures. Assemble them
  1431. // all into a KeyRing and return the result.
  1432. //
  1433. *KeyRingLength = 0;
  1434. for (i=0 ; i<KeyCount ; i++) {
  1435. *KeyRingLength += EncryptedKeySize[i];
  1436. }
  1437. *KeyRingLength += (sizeof ( ENCRYPTED_KEYS ) - sizeof( ENCRYPTED_KEY ));
  1438. *KeyRing = (PENCRYPTED_KEYS)LsapAllocateLsaHeap( *KeyRingLength );
  1439. if (NULL != *KeyRing) {
  1440. (*KeyRing)->KeyCount = KeyCount;
  1441. PBYTE Base = (PBYTE) &((*KeyRing)->EncryptedKey[0]);
  1442. for (i=0 ; i<KeyCount ; i++) {
  1443. memcpy( Base, EncryptedKey[i], EncryptedKey[i]->Length );
  1444. Base += EncryptedKey[i]->Length;
  1445. }
  1446. } else {
  1447. *KeyRingLength = 0;
  1448. rc = ERROR_NOT_ENOUGH_MEMORY;
  1449. }
  1450. //
  1451. // Clean everything up and return
  1452. //
  1453. for (i = 0; i<KeyCount ; i++ ) {
  1454. LsapFreeLsaHeap( EncryptedKey[i] );
  1455. }
  1456. LsapFreeLsaHeap( EncryptedKey );
  1457. LsapFreeLsaHeap( EncryptedKeySize );
  1458. return( rc );
  1459. }
  1460. PEFS_KEY
  1461. GetFekFromEncryptedKeys(
  1462. IN OUT PEFS_USER_INFO pEfsUserInfo,
  1463. IN PENCRYPTED_KEYS Keys,
  1464. IN BOOL CheckBits,
  1465. OUT PDWORD KeyIndex
  1466. )
  1467. /*++
  1468. Routine Description:
  1469. This routine will attempt to decode the FEK from an ENCRYPTED_KEYS
  1470. structure. It will do this by iterating through all of the fields in the
  1471. DRF and attempting to use each one to decrypt the FEK.
  1472. Arguments:
  1473. pEfsUserInfo - User information.
  1474. Keys - Provides the ENCRYPTED_KEYS to be examined.
  1475. CheckBits - If we need to check international version or not. TRUE will check.
  1476. KeyIndex - Which encrypted key is used.
  1477. Return Value:
  1478. On success, returns a pointer to an FEK, which must be freed when no longer
  1479. needed. Returns NULL on error.
  1480. --*/
  1481. {
  1482. //
  1483. // Walk down the list of key names in the ENCRYTPED_KEYS
  1484. //
  1485. if (Keys != NULL) {
  1486. PENCRYPTED_KEY pEncryptedKey = &Keys->EncryptedKey[0];
  1487. ULONG keyCount = *(ULONG UNALIGNED*)&(Keys->KeyCount);
  1488. for (*KeyIndex=0 ; *KeyIndex<keyCount ; (*KeyIndex)++) {
  1489. PENCRYPTED_KEY pAlignedKey;
  1490. BOOLEAN freeAlignedKey;
  1491. DWORD retCode;
  1492. retCode = EfsAlignBlock(
  1493. pEncryptedKey,
  1494. (PVOID *)&pAlignedKey,
  1495. &freeAlignedKey
  1496. );
  1497. if (!pAlignedKey) {
  1498. //
  1499. // OOM. Treat it as not current.
  1500. //
  1501. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1502. return NULL;
  1503. }
  1504. PEFS_KEY Fek = ExtractFek( pEfsUserInfo, pAlignedKey, CheckBits );
  1505. if (Fek != NULL) {
  1506. //
  1507. // Decryption worked, return the key
  1508. //
  1509. if (freeAlignedKey) {
  1510. LsapFreeLsaHeap( pAlignedKey );
  1511. }
  1512. return( Fek );
  1513. }
  1514. pEncryptedKey = (PENCRYPTED_KEY)( ((PBYTE)pEncryptedKey) + pAlignedKey->Length );
  1515. if (freeAlignedKey) {
  1516. LsapFreeLsaHeap( pAlignedKey );
  1517. }
  1518. }
  1519. }
  1520. return( NULL );
  1521. }
  1522. DWORD
  1523. GetLengthEncryptedKeys(
  1524. IN PENCRYPTED_KEYS pEncryptedKeys
  1525. )
  1526. /*++
  1527. Routine Description:
  1528. Computes the total size in bytes of an ENCRYPTED_KEYS structure.
  1529. Arguments:
  1530. pEncryptedKeys - Supplies a pointer to an ENCRYPTED_KEYS structre.
  1531. Return Value:
  1532. The length in bytes of the passed structure.
  1533. --*/
  1534. {
  1535. DWORD cb=0;
  1536. ULONG keyCount = *((ULONG UNALIGNED *) &(pEncryptedKeys->KeyCount));
  1537. ULONG keyLength;
  1538. PENCRYPTED_KEY pEncryptedKey = &pEncryptedKeys->EncryptedKey[0];
  1539. for (DWORD i=0; i<keyCount ; i++) {
  1540. keyLength = *((ULONG UNALIGNED *) &(pEncryptedKey->Length));
  1541. cb += keyLength;
  1542. pEncryptedKey = (PENCRYPTED_KEY)( ((PBYTE)pEncryptedKey) + keyLength );
  1543. }
  1544. cb += sizeof( ENCRYPTED_KEYS ) - sizeof( ENCRYPTED_KEY );
  1545. return( cb );
  1546. }
  1547. BOOL
  1548. AppendEncryptedKeyToDDF(
  1549. IN PEFS_DATA_STREAM_HEADER EfsStream,
  1550. IN PENCRYPTED_KEY EncryptedKey,
  1551. IN PEFS_KEY Fek,
  1552. OUT PEFS_DATA_STREAM_HEADER * OutputEfs
  1553. )
  1554. /*++
  1555. Routine Description:
  1556. This routine will take an existing EFS stream and append the
  1557. passed encrypted key to the end of the DDF section. It does
  1558. not check to see if the key is already there or not.
  1559. Arguments:
  1560. EfsStream - The existing EFS stream.
  1561. EncryptedKey - The FEK encrypted with the new public key.
  1562. OutputEfs - Receives the new EFS stream to be placed on the
  1563. file.
  1564. Return Value:
  1565. --*/
  1566. {
  1567. BOOL b = FALSE;
  1568. //
  1569. // This is a simple append operation.
  1570. //
  1571. // The new size is the size of the old EFS stream
  1572. // plus the size of the new key. Allocate space for it.
  1573. //
  1574. DWORD EfsLength = EfsStream->Length + EncryptedKey->Length;
  1575. EfsLength = (EfsLength + 7) & 0xfffffff8;
  1576. *OutputEfs = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( EfsLength );
  1577. if (*OutputEfs) {
  1578. memset( *OutputEfs, 0, sizeof( EFS_DATA_STREAM_HEADER ));
  1579. //
  1580. // Copy the header
  1581. //
  1582. PEFS_DATA_STREAM_HEADER Efs = *OutputEfs;
  1583. *Efs = *EfsStream;
  1584. Efs->Length = EfsLength;
  1585. //
  1586. // Start copying the DDF at the base of the EFS
  1587. // structure. Copy the whole thing. Do ourselves a
  1588. // favor and don't assume that the DDF or DRF are in
  1589. // any particular order in the EFS structure.
  1590. //
  1591. PENCRYPTED_KEYS pDDF = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, EfsStream );
  1592. DWORD cbDDF = GetLengthEncryptedKeys( pDDF );
  1593. //
  1594. // Store away the offset to the beginning on the DDF
  1595. //
  1596. Efs->DataDecryptionField = (ULONG)sizeof( EFS_DATA_STREAM_HEADER );
  1597. PBYTE Base = (PBYTE)OFFSET_TO_POINTER( DataDecryptionField, Efs );
  1598. memcpy( Base, pDDF, cbDDF );
  1599. //
  1600. // Point to the new DDF, we need to fix it up a little
  1601. //
  1602. PENCRYPTED_KEYS pNewDDF = (PENCRYPTED_KEYS)Base;
  1603. pNewDDF->KeyCount++;
  1604. Base += cbDDF;
  1605. memcpy( Base, EncryptedKey, EncryptedKey->Length );
  1606. Base += EncryptedKey->Length;
  1607. //
  1608. // Now copy the DRF onto the end and we're done.
  1609. //
  1610. PENCRYPTED_KEYS pDRF = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataRecoveryField, EfsStream );
  1611. if ((PVOID) pDRF == (PVOID) EfsStream) {
  1612. Efs->DataRecoveryField = 0;
  1613. } else {
  1614. DWORD cbDRF = GetLengthEncryptedKeys( pDRF );
  1615. Efs->DataRecoveryField = (ULONG)POINTER_TO_OFFSET( Base, Efs );
  1616. memcpy( Base, pDRF, cbDRF );
  1617. }
  1618. // Base += cbDRF
  1619. b = TRUE;
  1620. // memset( &(Efs->EfsHash), 0, MD5_HASH_SIZE );
  1621. // EfspChecksumEfs( Efs, Fek );
  1622. } else {
  1623. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1624. }
  1625. return( b );
  1626. }
  1627. BOOLEAN
  1628. EfspCertInEFS(
  1629. IN PBYTE pbHash,
  1630. IN DWORD cbHash,
  1631. IN PEFS_DATA_STREAM_HEADER pEfsStream
  1632. )
  1633. /*++
  1634. Routine Description:
  1635. Searches the passed EFS stream for an entry with the same hash as passed.
  1636. Arguments:
  1637. pbHash - Supplies a pointer to the hash being queried
  1638. cbHash - Supplies the length in bytes of the hash being queried
  1639. pEfsStream - Supplies the EFS stream from the file being queried
  1640. Return Value:
  1641. TRUE if the passed hash is found, FALSE otherwise.
  1642. --*/
  1643. {
  1644. BOOLEAN fFound = FALSE;
  1645. DWORD KeyIndex;
  1646. //
  1647. // Check the hash in each entry in the DDF. If
  1648. // we get a match, return success.
  1649. //
  1650. PDDF Keys = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, pEfsStream );
  1651. PENCRYPTED_KEY pEncryptedKey = &Keys->EncryptedKey[0];
  1652. for (KeyIndex=0 ; KeyIndex<Keys->KeyCount ; KeyIndex++) {
  1653. PEFS_PUBLIC_KEY_INFO PublicKeyInfo = (PEFS_PUBLIC_KEY_INFO)( (PUCHAR)pEncryptedKey + *(ULONG UNALIGNED *) &(pEncryptedKey->PublicKeyInfo) );
  1654. PEFS_CERT_HASH_DATA CertHashData = (PEFS_CERT_HASH_DATA)( (PUCHAR) PublicKeyInfo + *(ULONG UNALIGNED *) &(PublicKeyInfo->CertificateThumbprint.CertHashData));
  1655. if (*(DWORD UNALIGNED *)&(CertHashData->cbHash) == cbHash) {
  1656. PBYTE pbSrcHash = (PBYTE)CertHashData + *(ULONG UNALIGNED *) &(CertHashData->pbHash);
  1657. if (memcmp(pbSrcHash, pbHash, cbHash) == 0) {
  1658. fFound = TRUE;
  1659. break;
  1660. }
  1661. }
  1662. pEncryptedKey = NEXT_ENCRYPTED_KEY( pEncryptedKey );
  1663. }
  1664. return( fFound );
  1665. }
  1666. BOOLEAN
  1667. AddUserToEFS(
  1668. IN PEFS_DATA_STREAM_HEADER EfsStream,
  1669. IN PSID NewUserSid OPTIONAL,
  1670. IN PEFS_KEY Fek,
  1671. IN PBYTE pbCert,
  1672. IN DWORD cbCert,
  1673. OUT PEFS_DATA_STREAM_HEADER * NewEfs
  1674. )
  1675. /*++
  1676. Routine Description:
  1677. This routine adds a new encrypted key block to the DDF of the passed
  1678. EFS stream.
  1679. Arguments:
  1680. EfsStream - Takes a pointer to the EFS stream to be modified.
  1681. NewUserSid - Optionally supplies a pointer to the SID of the new user.
  1682. Fek - Supplies the FEK of the file being modified.
  1683. pbCert - Supplies a pointer to the certificate of the new user.
  1684. cbCert - Supplies the lenght in bytes of the certificate.
  1685. NewEfs - Returns a pointer to the new EFS stream.
  1686. Return Value:
  1687. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  1688. --*/
  1689. {
  1690. DWORD rc;
  1691. PEFS_DATA_STREAM_HEADER Efs = NULL;
  1692. BOOLEAN b = FALSE;
  1693. PEFS_KEY_SALT pEfsKeySalt = NULL;
  1694. //
  1695. // Get the key information from the passed cert
  1696. //
  1697. PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(
  1698. X509_ASN_ENCODING,
  1699. pbCert,
  1700. cbCert
  1701. );
  1702. if (pCertContext != NULL) {
  1703. PBYTE pbHash;
  1704. DWORD cbHash;
  1705. pbHash = GetCertHashFromCertContext(
  1706. pCertContext,
  1707. &cbHash
  1708. );
  1709. if (pbHash) {
  1710. //
  1711. // See if this hash is already on the file. If so, return error.
  1712. //
  1713. if (!EfspCertInEFS( pbHash, cbHash, EfsStream )) {
  1714. //
  1715. // Now get the public key out of the cert so we can
  1716. // encrypt the FEK
  1717. //
  1718. PCERT_PUBLIC_KEY_INFO pSubjectPublicKeyInfo = &pCertContext->pCertInfo->SubjectPublicKeyInfo;
  1719. //
  1720. // Import the public key into a context
  1721. //
  1722. HCRYPTKEY hKey;
  1723. if (CryptImportPublicKeyInfo( hProvVerify, X509_ASN_ENCODING, pSubjectPublicKeyInfo, &hKey )) {
  1724. //
  1725. // Use the newly imported key to encrypt the FEK
  1726. //
  1727. DWORD dwEncryptedFEKLength = 0;
  1728. PBYTE EncryptedFEK = EncryptFEK( Fek, hKey, &dwEncryptedFEKLength );
  1729. if (EncryptedFEK != NULL) {
  1730. PEFS_PUBLIC_KEY_INFO PublicKeyInformation = NULL;
  1731. //
  1732. // This may come back NULL, but that's ok.
  1733. //
  1734. LPWSTR lpDisplayName = EfspGetCertDisplayInformation( pCertContext );
  1735. b = CreatePublicKeyInformationThumbprint(
  1736. NewUserSid,
  1737. pbHash,
  1738. cbHash,
  1739. lpDisplayName,
  1740. NULL,
  1741. NULL,
  1742. &PublicKeyInformation
  1743. );
  1744. if (lpDisplayName) {
  1745. LsapFreeLsaHeap( lpDisplayName );
  1746. }
  1747. if (b) {
  1748. if (Fek->Entropy <= EXPORT_KEY_STRENGTH) {
  1749. DWORD SaltLength;
  1750. DWORD SaltBlockLength;
  1751. if (GetSaltLength(Fek->Algorithm, &SaltLength, &SaltBlockLength)) {
  1752. pEfsKeySalt = (PEFS_KEY_SALT)LsapAllocateLsaHeap( sizeof( EFS_KEY_SALT ) + SaltBlockLength );
  1753. if (pEfsKeySalt) {
  1754. pEfsKeySalt->Length = sizeof( EFS_KEY_SALT ) + SaltBlockLength;
  1755. pEfsKeySalt->SaltType = Fek->Algorithm;
  1756. RtlCopyMemory( (PBYTE)pEfsKeySalt + sizeof( EFS_KEY_SALT ),
  1757. EFS_KEY_DATA( Fek ),
  1758. SaltLength
  1759. );
  1760. }
  1761. }
  1762. } else {
  1763. pEfsKeySalt = NULL;
  1764. }
  1765. if (pEfsKeySalt || (Fek->Entropy > EXPORT_KEY_STRENGTH)) {
  1766. DWORD EncryptedKeySize = 0;
  1767. PENCRYPTED_KEY EncryptedKey;
  1768. rc = ConstructEncryptedKey( EncryptedFEK,
  1769. dwEncryptedFEKLength,
  1770. PublicKeyInformation,
  1771. pEfsKeySalt,
  1772. &EncryptedKey,
  1773. &EncryptedKeySize
  1774. );
  1775. //
  1776. // We'll check the return code below
  1777. //
  1778. if (rc == ERROR_SUCCESS) {
  1779. b = AppendEncryptedKeyToDDF(
  1780. EfsStream,
  1781. EncryptedKey,
  1782. Fek,
  1783. NewEfs
  1784. ) != 0;
  1785. LsapFreeLsaHeap( EncryptedKey );
  1786. } else {
  1787. SetLastError( rc );
  1788. }
  1789. if (pEfsKeySalt) {
  1790. LsapFreeLsaHeap( pEfsKeySalt );
  1791. }
  1792. } else {
  1793. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1794. }
  1795. LsapFreeLsaHeap( PublicKeyInformation );
  1796. }
  1797. LsapFreeLsaHeap( EncryptedFEK );
  1798. }
  1799. CryptDestroyKey( hKey );
  1800. }
  1801. } else {
  1802. //
  1803. // Adding duplicate cert considered succeed
  1804. //
  1805. b = TRUE;
  1806. }
  1807. LsapFreeLsaHeap( pbHash );
  1808. }
  1809. CertFreeCertificateContext( pCertContext );
  1810. }
  1811. if (!b) {
  1812. //
  1813. // If we're not going to return success, clean up everything we were
  1814. // planning on returning.
  1815. //
  1816. if (*NewEfs != NULL) {
  1817. LsapFreeLsaHeap( *NewEfs );
  1818. }
  1819. }
  1820. return( b );
  1821. }
  1822. PENCRYPTED_KEY
  1823. GetEncryptedKeyByIndex(
  1824. PENCRYPTED_KEYS pEncryptedKeys,
  1825. DWORD KeyIndex
  1826. )
  1827. {
  1828. ASSERT( KeyIndex < *((ULONG UNALIGNED *)&(pEncryptedKeys->KeyCount)) );
  1829. PENCRYPTED_KEY pEncryptedKey = &pEncryptedKeys->EncryptedKey[0];
  1830. if (KeyIndex == 0) {
  1831. return( pEncryptedKey );
  1832. }
  1833. for (DWORD i=0; i<KeyIndex ; i++, pEncryptedKey = (PENCRYPTED_KEY)(((PBYTE)(pEncryptedKey)) + *(ULONG UNALIGNED *)&((PENCRYPTED_KEY)(pEncryptedKey))->Length)) ;
  1834. return( pEncryptedKey );
  1835. }
  1836. BOOL
  1837. UserKeyCurrent(
  1838. PEFS_USER_INFO pEfsUserInfo,
  1839. PDDF Ddf,
  1840. DWORD KeyIndex
  1841. )
  1842. /*++
  1843. Routine Description:
  1844. This routine checks to see if the key used to decrypt the file
  1845. is the user's current encryption key.
  1846. Arguments:
  1847. Ddf - Supplies the DDF of the file being accessed.
  1848. KeyIndex - Supplies the index of the key in the DDF that was
  1849. used to open the file.
  1850. Return Value:
  1851. TRUE if the key used corresponds to the user's encryption key.
  1852. FALSE otherwise.
  1853. --*/
  1854. {
  1855. BOOL b = TRUE;
  1856. DWORD rc = ERROR_SUCCESS;
  1857. PBYTE pbCurrentKeyHash = NULL;
  1858. DWORD cbCurrentKeyHash;
  1859. PBYTE pbHash;
  1860. DWORD cbHash;
  1861. PBYTE pbWkHash = NULL;
  1862. //
  1863. // Compare the current user key with the contents
  1864. // of the specified key, and see if they're in sync.
  1865. //
  1866. PENCRYPTED_KEY pEncryptedKey = GetEncryptedKeyByIndex( Ddf, KeyIndex );
  1867. PENCRYPTED_KEY pAlignedKey;
  1868. BOOLEAN freeAlignedKey;
  1869. rc = EfsAlignBlock(
  1870. pEncryptedKey,
  1871. (PVOID *)&pAlignedKey,
  1872. &freeAlignedKey
  1873. );
  1874. if (!pAlignedKey) {
  1875. //
  1876. // OOM. Treat it as current.
  1877. //
  1878. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1879. return TRUE;
  1880. }
  1881. PEFS_PUBLIC_KEY_INFO pPublicKeyInfo = (PEFS_PUBLIC_KEY_INFO)OFFSET_TO_POINTER( PublicKeyInfo, pAlignedKey );
  1882. if (pPublicKeyInfo->KeySourceTag != EfsCertificateThumbprint) {
  1883. //
  1884. // The user key may be current, but the key on the file isn't.
  1885. // Return FALSE so as to regenerate the EFS on this file.
  1886. //
  1887. DebugLog((DEB_WARN, "Updating downlevel file\n" ));
  1888. if (freeAlignedKey) {
  1889. LsapFreeLsaHeap( pAlignedKey );
  1890. }
  1891. return( FALSE );
  1892. }
  1893. PEFS_CERT_HASH_DATA CertHashData = (PEFS_CERT_HASH_DATA)OFFSET_TO_POINTER( CertificateThumbprint.CertHashData, pPublicKeyInfo );
  1894. pbHash = (PBYTE)OFFSET_TO_POINTER( pbHash, CertHashData );
  1895. cbHash = CertHashData->cbHash;
  1896. if (pEfsUserInfo->pUserCache) {
  1897. //
  1898. // Check the current against the cache
  1899. //
  1900. pbWkHash = pEfsUserInfo->pUserCache->pbHash;
  1901. cbCurrentKeyHash = pEfsUserInfo->pUserCache->cbHash;
  1902. } else {
  1903. rc = GetCurrentHash(
  1904. pEfsUserInfo,
  1905. &pbCurrentKeyHash,
  1906. &cbCurrentKeyHash
  1907. );
  1908. if (rc == ERROR_SUCCESS) {
  1909. pbWkHash = pbCurrentKeyHash;
  1910. }
  1911. }
  1912. //
  1913. // Compare the hash stored in the current user key
  1914. // with the hash in the specified public key info.
  1915. //
  1916. if (rc == ERROR_SUCCESS) {
  1917. //
  1918. // Compare the thumbprint in the public key info against
  1919. // the user's current.
  1920. //
  1921. if (cbHash == cbCurrentKeyHash) {
  1922. if (memcmp(pbWkHash, pbHash, cbHash) != 0) {
  1923. b = FALSE;
  1924. }
  1925. } else {
  1926. b = FALSE;
  1927. }
  1928. }
  1929. if (pbCurrentKeyHash) {
  1930. LsapFreeLsaHeap( pbCurrentKeyHash );
  1931. }
  1932. if (freeAlignedKey) {
  1933. LsapFreeLsaHeap( pAlignedKey );
  1934. }
  1935. //
  1936. // If we failed to get the current key hash and reach here, this means we also failed to create the hash.
  1937. // This could mean that we could not set the current key. We could not test if the hash could be the current.
  1938. // We could not replace the DDF with a current one anyway. We assume the passed in hash as the current.
  1939. // Could I be wrong here?
  1940. //
  1941. return( b );
  1942. }
  1943. BOOL
  1944. ReplaceUserKey(
  1945. PEFS_USER_INFO pEfsUserInfo,
  1946. PEFS_KEY Fek,
  1947. PEFS_DATA_STREAM_HEADER EfsStream,
  1948. DWORD KeyIndex,
  1949. PEFS_DATA_STREAM_HEADER * UpdatedEfs
  1950. )
  1951. /*++
  1952. Routine Description:
  1953. This routine will replace the user key specified by the passed KeyIndex
  1954. with another one that uses the current user EFS keys.
  1955. It assumes that we are in the context of the caller who owns this key.
  1956. Arguments:
  1957. Fek - Supplies the decrypted FEK for the file.
  1958. EfsStream - Supplies the EFS stream on the file.
  1959. KeyIndex - Supplies the index of the key to be replaced.
  1960. UpdatedEfs - Receives a pointer to the new EFS stream to be
  1961. placed on the file.
  1962. Return Value:
  1963. --*/
  1964. {
  1965. //
  1966. // Query the current user keys. This will give me
  1967. // back a hash and a container and provider name.
  1968. //
  1969. HCRYPTKEY hKey;
  1970. HCRYPTPROV hProv;
  1971. PBYTE pbHash;
  1972. DWORD cbHash;
  1973. PEFS_KEY_SALT pEfsKeySalt = NULL;
  1974. BOOL b = FALSE;
  1975. DWORD rc;
  1976. LPWSTR ContainerName;
  1977. LPWSTR ProviderName;
  1978. LPWSTR DisplayInfo;
  1979. DWORD ProviderType;
  1980. DebugLog((DEB_WARN, "Updating EFS stream\n" ));
  1981. PSID NewUserSid = pEfsUserInfo->pTokenUser->User.Sid;
  1982. rc = GetCurrentKey(
  1983. pEfsUserInfo,
  1984. &hKey,
  1985. &hProv,
  1986. &ContainerName,
  1987. &ProviderName,
  1988. &ProviderType,
  1989. &DisplayInfo,
  1990. &pbHash,
  1991. &cbHash
  1992. );
  1993. //
  1994. // Use this key information to encrypt the FEK
  1995. // and generate an encrypted key structure.
  1996. //
  1997. if (rc == ERROR_SUCCESS) {
  1998. DWORD dwEncryptedFEKLength = 0;
  1999. PBYTE EncryptedFEK;
  2000. HCRYPTKEY hLocalKey;
  2001. HCRYPTPROV hLocalProv;
  2002. PBYTE pbLocalHash;
  2003. DWORD cbLocalHash;
  2004. LPWSTR lpLocalContainerName;
  2005. LPWSTR lpLocalProviderName;
  2006. LPWSTR lpLocalDisplayInfo;
  2007. if (pbHash) {
  2008. pbLocalHash = pbHash;
  2009. cbLocalHash = cbHash;
  2010. hLocalKey = hKey;
  2011. hLocalProv = hProv;
  2012. lpLocalContainerName = ContainerName;
  2013. lpLocalProviderName = ProviderName;
  2014. lpLocalDisplayInfo = DisplayInfo;
  2015. } else {
  2016. ASSERT(pEfsUserInfo->pUserCache);
  2017. pbLocalHash = pEfsUserInfo->pUserCache->pbHash;
  2018. cbLocalHash = pEfsUserInfo->pUserCache->cbHash;
  2019. hLocalKey = pEfsUserInfo->pUserCache->hUserKey;
  2020. hLocalProv = pEfsUserInfo->pUserCache->hProv;
  2021. lpLocalContainerName = pEfsUserInfo->pUserCache->ContainerName;
  2022. lpLocalProviderName = pEfsUserInfo->pUserCache->ProviderName;
  2023. lpLocalDisplayInfo = pEfsUserInfo->pUserCache->DisplayInformation;
  2024. }
  2025. EncryptedFEK = EncryptFEK( Fek, hLocalKey, &dwEncryptedFEKLength );
  2026. if (EncryptedFEK != NULL) {
  2027. PEFS_PUBLIC_KEY_INFO PublicKeyInformation = NULL;
  2028. if (CreatePublicKeyInformationThumbprint(
  2029. NewUserSid,
  2030. pbLocalHash,
  2031. cbLocalHash,
  2032. lpLocalDisplayInfo,
  2033. lpLocalContainerName,
  2034. lpLocalProviderName,
  2035. &PublicKeyInformation
  2036. )) {
  2037. if ( Fek->Entropy <= EXPORT_KEY_STRENGTH ){
  2038. DWORD SaltLength;
  2039. DWORD SaltBlockLength;
  2040. if (GetSaltLength(Fek->Algorithm, &SaltLength, &SaltBlockLength)){
  2041. pEfsKeySalt = (PEFS_KEY_SALT)LsapAllocateLsaHeap( sizeof( EFS_KEY_SALT ) + SaltBlockLength );
  2042. if (pEfsKeySalt){
  2043. pEfsKeySalt->Length = sizeof( EFS_KEY_SALT ) + SaltBlockLength;
  2044. pEfsKeySalt->SaltType = Fek->Algorithm;
  2045. RtlCopyMemory( (PBYTE)pEfsKeySalt + sizeof( EFS_KEY_SALT ),
  2046. EFS_KEY_DATA( Fek ),
  2047. SaltLength
  2048. );
  2049. }
  2050. }
  2051. } else {
  2052. pEfsKeySalt = NULL;
  2053. }
  2054. if (pEfsKeySalt || (Fek->Entropy > EXPORT_KEY_STRENGTH)) {
  2055. //
  2056. // This should return an error
  2057. //
  2058. DWORD EncryptedKeySize = 0;
  2059. PENCRYPTED_KEY EncryptedKey;
  2060. rc = ConstructEncryptedKey( EncryptedFEK,
  2061. dwEncryptedFEKLength,
  2062. PublicKeyInformation,
  2063. pEfsKeySalt,
  2064. &EncryptedKey,
  2065. &EncryptedKeySize
  2066. );
  2067. //
  2068. // We'll check the return code below
  2069. //
  2070. if (rc == ERROR_SUCCESS) {
  2071. PEFS_DATA_STREAM_HEADER NewEfs = NULL;
  2072. if (AppendEncryptedKeyToDDF(
  2073. EfsStream,
  2074. EncryptedKey,
  2075. Fek,
  2076. &NewEfs
  2077. )) {
  2078. PEFS_DATA_STREAM_HEADER pNewEfs2 = NULL;
  2079. if (DeleteEncryptedKeyByIndex(
  2080. NewEfs,
  2081. KeyIndex,
  2082. Fek,
  2083. &pNewEfs2
  2084. )) {
  2085. *UpdatedEfs = pNewEfs2;
  2086. b = TRUE;
  2087. } else {
  2088. *UpdatedEfs = NULL; // paranoia
  2089. }
  2090. LsapFreeLsaHeap( NewEfs );
  2091. }
  2092. LsapFreeLsaHeap( EncryptedKey );
  2093. }
  2094. if (pEfsKeySalt){
  2095. LsapFreeLsaHeap( pEfsKeySalt );
  2096. }
  2097. }
  2098. LsapFreeLsaHeap( PublicKeyInformation );
  2099. }
  2100. LsapFreeLsaHeap( EncryptedFEK );
  2101. } else {
  2102. rc = GetLastError();
  2103. }
  2104. if (ContainerName) {
  2105. LsapFreeLsaHeap( ContainerName );
  2106. }
  2107. if (ProviderName) {
  2108. LsapFreeLsaHeap( ProviderName );
  2109. }
  2110. if (DisplayInfo) {
  2111. LsapFreeLsaHeap( DisplayInfo );
  2112. }
  2113. if (pbHash) {
  2114. LsapFreeLsaHeap( pbHash );
  2115. }
  2116. if (hKey) {
  2117. CryptDestroyKey( hKey );
  2118. }
  2119. if (hProv) {
  2120. CryptReleaseContext( hProv, 0 );
  2121. }
  2122. }
  2123. SetLastError( rc );
  2124. if (!b) {
  2125. DebugLog((DEB_ERROR, "Update failed, error = %x\n" ,GetLastError() ));
  2126. }
  2127. return( b );
  2128. }
  2129. BOOL
  2130. DeleteEncryptedKeyByIndex(
  2131. IN PEFS_DATA_STREAM_HEADER pEfs,
  2132. IN DWORD KeyIndex,
  2133. IN PEFS_KEY Fek,
  2134. OUT PEFS_DATA_STREAM_HEADER * pNewEfs
  2135. )
  2136. /*++
  2137. Routine Description:
  2138. This routine deletes the passed key from the DDF of the passed
  2139. EFS stream, and returns a new EFS stream. It does not deallocate
  2140. the original EFS stream.
  2141. Arguments:
  2142. pEfs - Supplies a pointer to the original EFS stream.
  2143. KeyIndex - Supplies the index of the key to delete.
  2144. pNewEfs - Returns a pointer to the new EFS stream allocated
  2145. out of heap.
  2146. Return Value:
  2147. TRUE on success, FALSE on failure. GetLastError() will return more information.
  2148. --*/
  2149. {
  2150. BOOL b = FALSE;
  2151. //
  2152. // Do this the lazy way: build the new DDF
  2153. // and copy it into the EFS stream.
  2154. //
  2155. PENCRYPTED_KEYS pDDF = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, pEfs );
  2156. //
  2157. // This is an over estimate, but it will do.
  2158. //
  2159. PENCRYPTED_KEYS pNewDDF = (PENCRYPTED_KEYS)LsapAllocateLsaHeap( GetLengthEncryptedKeys( pDDF ) );
  2160. if (pNewDDF) {
  2161. pNewDDF->KeyCount = pDDF->KeyCount - 1;
  2162. DWORD cbNewDDF = sizeof( ENCRYPTED_KEYS ) - sizeof( ENCRYPTED_KEY );
  2163. PBYTE Target = (PBYTE)(&pNewDDF->EncryptedKey[0]);
  2164. PBYTE Source = (PBYTE)(&pDDF->EncryptedKey[0]);
  2165. for (DWORD i=0; i<pDDF->KeyCount ; i++) {
  2166. if (i != KeyIndex) {
  2167. //
  2168. // We want this one. Copy it.
  2169. //
  2170. DWORD KeyLength = *((DWORD UNALIGNED*) &((PENCRYPTED_KEY)Source)->Length);
  2171. cbNewDDF += KeyLength;
  2172. memcpy( Target, Source, KeyLength );
  2173. Target = (PBYTE)NEXT_ENCRYPTED_KEY( Target );
  2174. Source = (PBYTE)NEXT_ENCRYPTED_KEY( Source );
  2175. } else {
  2176. //
  2177. // Skip this one.
  2178. //
  2179. Source = (PBYTE)NEXT_ENCRYPTED_KEY( Source );
  2180. }
  2181. }
  2182. //
  2183. // pNewDDF contains a pointer to our new DDF.
  2184. //
  2185. PENCRYPTED_KEYS pDRF = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataRecoveryField, pEfs );
  2186. DWORD cbDRF;
  2187. if ((PVOID)pDRF == (PVOID)pEfs) {
  2188. //
  2189. // There was no DRF
  2190. //
  2191. cbDRF = 0;
  2192. pDRF = NULL;
  2193. } else {
  2194. cbDRF = GetLengthEncryptedKeys( pDRF );
  2195. }
  2196. *pNewEfs = AssembleEfsStream( pNewDDF, cbNewDDF, pDRF, cbDRF, Fek );
  2197. if (*pNewEfs) {
  2198. b = TRUE;
  2199. } else {
  2200. *pNewEfs = NULL; // paranoia
  2201. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2202. }
  2203. LsapFreeLsaHeap( pNewDDF );
  2204. } else {
  2205. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2206. }
  2207. return( b );
  2208. }
  2209. PEFS_DATA_STREAM_HEADER
  2210. AssembleEfsStream(
  2211. IN PENCRYPTED_KEYS pDDF,
  2212. IN DWORD cbDDF,
  2213. IN PENCRYPTED_KEYS pDRF,
  2214. IN DWORD cbDRF,
  2215. IN PEFS_KEY Fek
  2216. )
  2217. /*++
  2218. Routine Description:
  2219. This routine takes the pieces of an EFS stream and assembles them into
  2220. an EFS stream.
  2221. Arguments:
  2222. pDDF - Supplies a pointer to the DDF for the new EFS stream.
  2223. cbDDF - Supplies the length in bytes of the DDF.
  2224. pDRF - Supplies a pointer to the DRF for the new EFS stream.
  2225. cbDRF - Supplies the length in bytes of the DRF.
  2226. Return Value:
  2227. Returns a pointer to a new EFS stream, or NULL. Caller is responsible
  2228. for freeing the returned memory.
  2229. --*/
  2230. {
  2231. //
  2232. // Compute the total size of the new EFS stream
  2233. //
  2234. DWORD cbNewEFS = sizeof( EFS_DATA_STREAM_HEADER ) + cbDDF + cbDRF;
  2235. cbNewEFS = (cbNewEFS + 7) & 0xfffffff8;
  2236. PEFS_DATA_STREAM_HEADER pNewEFS = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( cbNewEFS );
  2237. if (pNewEFS) {
  2238. memset( pNewEFS, 0, sizeof( EFS_DATA_STREAM_HEADER ) );
  2239. pNewEFS->Length = cbNewEFS;
  2240. pNewEFS->State = 0;
  2241. pNewEFS->EfsVersion = EFS_CURRENT_VERSION;
  2242. RPC_STATUS RpcStatus = UuidCreate( &pNewEFS->EfsId );
  2243. if (RpcStatus == ERROR_SUCCESS || RpcStatus == RPC_S_UUID_LOCAL_ONLY) {
  2244. //
  2245. // Copy in the DDF
  2246. //
  2247. PBYTE Base = (PBYTE)(((PBYTE)pNewEFS) + sizeof( EFS_DATA_STREAM_HEADER ));
  2248. pNewEFS->DataDecryptionField = (ULONG)POINTER_TO_OFFSET( Base, pNewEFS );
  2249. memcpy( Base, pDDF, cbDDF );
  2250. Base += cbDDF;
  2251. //
  2252. // Copy the DRF
  2253. //
  2254. if (pDRF) {
  2255. memcpy( Base, pDRF, cbDRF );
  2256. pNewEFS->DataRecoveryField = (ULONG)POINTER_TO_OFFSET( Base, pNewEFS );
  2257. } else {
  2258. pNewEFS->DataRecoveryField = 0;
  2259. }
  2260. // Base += cbDRF
  2261. // EfspChecksumEfs( pNewEFS, Fek );
  2262. } else {
  2263. //
  2264. // Couldn't get a UUID, fail
  2265. //
  2266. LsapFreeLsaHeap( pNewEFS );
  2267. pNewEFS = NULL;
  2268. }
  2269. }
  2270. return( pNewEFS );
  2271. }
  2272. BOOL
  2273. RecoveryInformationCurrent(
  2274. PEFS_DATA_STREAM_HEADER EfsStream
  2275. )
  2276. /*++
  2277. Routine Description:
  2278. This routine examines the recovery information in an EFS stream and determines if
  2279. the system recovery information has changed since this stream was generated. It
  2280. does this by comparing the certificate hashes stored in the current recovery
  2281. information with the certificate hashes stored in the passed DRF.
  2282. Arguments:
  2283. EfsStream - Supplies a pointer to the EFS stream to be examined.
  2284. Return Value:
  2285. TRUE - Recovery information is up to date.
  2286. FALSE - DRF must be regenerated with new recovery information.
  2287. --*/
  2288. {
  2289. //
  2290. // Assume that the entries in the DRF correspond to entries in the
  2291. // current recovery information array in order. That will simplify
  2292. // this operation considerably.
  2293. //
  2294. //
  2295. // Get a pointer to the DRF
  2296. //
  2297. PDRF pDrf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataRecoveryField, EfsStream );
  2298. //
  2299. // For each entry in the DRF, compare hash to corresponding entry in recovery
  2300. // policy. Fail on first mismatch.
  2301. //
  2302. ULONG KeyCount = 0;
  2303. if ((PVOID)pDrf == (PVOID)EfsStream) {
  2304. //
  2305. // No DRF field.
  2306. //
  2307. pDrf = NULL;
  2308. }
  2309. //
  2310. // pDrf->KeyCount could be unaligned
  2311. //
  2312. if (pDrf) {
  2313. RtlCopyMemory(&KeyCount, &pDrf->KeyCount, sizeof(ULONG));
  2314. }
  2315. /*
  2316. //
  2317. // There may not be a recovery policy on this machine. If that's the case,
  2318. // we're just going to leave this file alone.
  2319. //
  2320. if (CurrentRecoveryPolicy.dwKeyCount == 0) {
  2321. return( TRUE );
  2322. }
  2323. */
  2324. if (!pDrf && CurrentRecoveryPolicy.PolicyStatus < RECOVERY_POLICY_OK) {
  2325. //
  2326. // Current recovery policy has no valid recovery agent and the existing $EFS
  2327. // has no valid agent too.
  2328. //
  2329. return (TRUE);
  2330. }
  2331. if (CurrentRecoveryPolicy.dwKeyCount != KeyCount) {
  2332. return( FALSE );
  2333. }
  2334. ASSERT(pDrf);
  2335. if (!pDrf) {
  2336. //
  2337. // We should never get into this. This is only for the purpose of defensive.
  2338. //
  2339. return (TRUE);
  2340. }
  2341. PENCRYPTED_KEY pEncryptedKey = &pDrf->EncryptedKey[0];
  2342. for (ULONG i=0; i<KeyCount ; i++) {
  2343. PENCRYPTED_KEY pAlignedKey;
  2344. BOOLEAN freeAlignedKey;
  2345. (VOID) EfsAlignBlock(
  2346. pEncryptedKey,
  2347. (PVOID *)&pAlignedKey,
  2348. &freeAlignedKey
  2349. );
  2350. if (!pAlignedKey) {
  2351. //
  2352. // OOM. Treat it as not current.
  2353. //
  2354. return (FALSE);
  2355. }
  2356. PEFS_PUBLIC_KEY_INFO PublicKeyInfo = (PEFS_PUBLIC_KEY_INFO)OFFSET_TO_POINTER( PublicKeyInfo, pAlignedKey );
  2357. ASSERT( PublicKeyInfo->KeySourceTag == EfsCertificateThumbprint );
  2358. PEFS_CERT_HASH_DATA CertHashData = (PEFS_CERT_HASH_DATA)OFFSET_TO_POINTER( CertificateThumbprint.CertHashData, PublicKeyInfo );
  2359. PBYTE pbHash = (PBYTE)OFFSET_TO_POINTER( pbHash, CertHashData );
  2360. DWORD cbHash = CertHashData->cbHash;
  2361. if ((cbHash != CurrentRecoveryPolicy.cbHash[i]) || (memcmp(pbHash, CurrentRecoveryPolicy.pbHash[i], cbHash) != 0)) {
  2362. if (freeAlignedKey) {
  2363. LsapFreeLsaHeap( pAlignedKey );
  2364. }
  2365. return( FALSE );
  2366. } else {
  2367. pEncryptedKey = (PENCRYPTED_KEY)(((PBYTE)(pEncryptedKey)) + pAlignedKey->Length);
  2368. if (freeAlignedKey) {
  2369. LsapFreeLsaHeap( pAlignedKey );
  2370. }
  2371. }
  2372. }
  2373. return( TRUE );
  2374. }
  2375. DWORD
  2376. UpdateRecoveryInformation(
  2377. PEFS_KEY Fek,
  2378. PEFS_DATA_STREAM_HEADER EfsStream,
  2379. PEFS_DATA_STREAM_HEADER * UpdatedEfs
  2380. )
  2381. /*++
  2382. Routine Description:
  2383. This routine will create a new EFS stream based on the passed in one.
  2384. The new EFS stream will contain a DRF based on the current recovery
  2385. policy. It is assumed that someone else has already verified that
  2386. the DRF is this stream is out of date, this routine will not do that.
  2387. Arguments:
  2388. Fek - The FEK for the file being updated.
  2389. EfsStream - Supplies the existing EFS stream for the file.
  2390. UpdatedEfs - Returns an updated EFS stream for the file, allocated out of heap.
  2391. Return Value:
  2392. return-value - Description of conditions needed to return value. - or -
  2393. None.
  2394. --*/
  2395. {
  2396. DWORD rc;
  2397. DWORD cbDDF = 0;
  2398. DWORD cbDRF = 0;
  2399. PENCRYPTED_KEYS pNewDRF;
  2400. *UpdatedEfs = NULL;
  2401. //
  2402. // Simply generate a new DRF and stick it onto the end of the existing EFS
  2403. // stream.
  2404. //
  2405. PDDF pDdf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, EfsStream );
  2406. cbDDF = GetLengthEncryptedKeys( pDdf );
  2407. rc = GenerateDRF( Fek, &pNewDRF, &cbDRF);
  2408. if (rc == ERROR_SUCCESS) {
  2409. *UpdatedEfs = AssembleEfsStream( pDdf, cbDDF, pNewDRF, cbDRF, Fek );
  2410. if (*UpdatedEfs == NULL) {
  2411. rc = ERROR_NOT_ENOUGH_MEMORY;
  2412. }
  2413. LsapFreeLsaHeap( pNewDRF );
  2414. }
  2415. ReleaseRecoveryData();
  2416. return( rc );
  2417. }
  2418. DWORD
  2419. DecryptFek(
  2420. IN PEFS_USER_INFO pEfsUserInfo,
  2421. IN PEFS_DATA_STREAM_HEADER EfsStream,
  2422. OUT PEFS_KEY * Fek,
  2423. OUT PEFS_DATA_STREAM_HEADER * NewEfs,
  2424. IN ULONG OpenType
  2425. )
  2426. /*++
  2427. Routine Description:
  2428. This routine will extract the FEK from the passed Efs stream.
  2429. It will also check to see if the EFS stream is up to date w.r.t.
  2430. current keys and recovery policy, and if not, it will generate
  2431. a new one.
  2432. Arguments:
  2433. EfsStream - Supplies the EFS stream from the file being opened.
  2434. Fek - Returns the decrypted FEK from the EFS stream. This data is
  2435. allocated out of local heap and must be freed by the caller.
  2436. NewEfs - Returns a new EFS stream for the file if necessary, otherwise
  2437. returns NULL. This data is allocated out of local heap and must be
  2438. freed by the caller
  2439. OpenType - Whether this is a normal open or an open for recovery.
  2440. Return Value:
  2441. return-value - Description of conditions needed to return value. - or -
  2442. None.
  2443. --*/
  2444. {
  2445. DWORD rc = ERROR_SUCCESS;
  2446. DWORD KeyIndex;
  2447. PEFS_DATA_STREAM_HEADER UpdatedEfs = NULL;
  2448. BOOLEAN Recovery = FALSE;
  2449. BOOLEAN bEfsInvalid = FALSE;
  2450. BOOLEAN DRFIsCurrent = FALSE;
  2451. BOOLEAN ReqUpdateDRF = FALSE;
  2452. *Fek = NULL;
  2453. *NewEfs = NULL;
  2454. if (EfsStream->EfsVersion > EFS_CURRENT_VERSION) {
  2455. return ERROR_EFS_VERSION_NOT_SUPPORT;
  2456. }
  2457. __try {
  2458. #if DBG
  2459. UUID * EfsUuid = &EfsStream->EfsId;
  2460. WCHAR * StringUuid;
  2461. if (STATUS_SUCCESS == UuidToString ( EfsUuid, &StringUuid )) {
  2462. DebugLog((DEB_TRACE_EFS, "Found $EFS w/ id: %ws\n" ,StringUuid ));
  2463. RpcStringFree( &StringUuid) ;
  2464. }
  2465. #endif
  2466. //
  2467. // First try the DDF, and if we strike out there, the DRF.
  2468. //
  2469. PDDF Ddf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, EfsStream );
  2470. PDRF Drf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataRecoveryField, EfsStream );
  2471. if ((PVOID)Drf == (PVOID)EfsStream) {
  2472. //
  2473. // No DRF field.
  2474. //
  2475. Drf = NULL;
  2476. }
  2477. *Fek = GetFekFromEncryptedKeys( pEfsUserInfo, (PENCRYPTED_KEYS)Ddf, TRUE, &KeyIndex );
  2478. if ((NULL == *Fek) && Drf) {
  2479. *Fek = GetFekFromEncryptedKeys( pEfsUserInfo, (PENCRYPTED_KEYS)Drf, TRUE, &KeyIndex );
  2480. Recovery = TRUE;
  2481. }
  2482. if (*Fek == NULL) {
  2483. //
  2484. // Bad keyset means that none of the keysets in the current
  2485. // context could decrypt this file.
  2486. //
  2487. if (GetLastError() == NTE_BAD_KEYSET) {
  2488. return ( ERROR_DECRYPTION_FAILED );
  2489. } else {
  2490. return ( GetLastError() );
  2491. }
  2492. } else {
  2493. //
  2494. // If we opened the file via the DDF, make sure
  2495. // that the entry we used is current for the current
  2496. // user.
  2497. //
  2498. if (!Recovery) {
  2499. if (!UserKeyCurrent( pEfsUserInfo, Ddf, KeyIndex )) {
  2500. //
  2501. // The index we used to open the file
  2502. // is not current. Replace with the current user
  2503. // key.
  2504. //
  2505. (VOID) ReplaceUserKey( pEfsUserInfo, *Fek, EfsStream, KeyIndex, &UpdatedEfs );
  2506. }
  2507. }
  2508. //
  2509. // Checksum the EFS stream to make sure it has not been tampered with.
  2510. // If it is changed, we will try to see if the DRF has been checnged or not.
  2511. //
  2512. /*
  2513. if (!EfspValidateEfsStream( EfsStream, *Fek )) {
  2514. //
  2515. // Checksum not match. See if the DRF changed
  2516. //
  2517. PENCRYPTED_KEYS pNewDRF;
  2518. DWORD cbDRF;
  2519. rc = GenerateDRF(*Fek, &pNewDRF, &cbDRF);
  2520. if ( ERROR_SUCCESS == rc ) {
  2521. //
  2522. // Let's see if the DRF matches
  2523. //
  2524. if (EqualEncryptedKeys(Drf, pNewDRF, cbDRF)) {
  2525. //
  2526. // DRF is not modified. We can't fix the modification
  2527. // Regenerate the check sum.
  2528. //
  2529. DRFIsCurrent = TRUE;
  2530. if (!UpdatedEfs) {
  2531. //
  2532. // If $EFS is updated above, we don't need to generate the check sum again.
  2533. //
  2534. UpdatedEfs = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( EfsStream->Length );
  2535. if (UpdatedEfs) {
  2536. RtlCopyMemory(UpdatedEfs, EfsStream, EfsStream->Length);
  2537. memset( &UpdatedEfs->EfsHash, 0, MD5_HASH_SIZE );
  2538. EfspChecksumEfs( UpdatedEfs, *Fek );
  2539. }
  2540. }
  2541. //
  2542. // This is the best effort. If we failed to get the memory in the above
  2543. // We will still try to let user open the file. But not fix the check sum
  2544. //
  2545. } else {
  2546. //
  2547. // Either the checksum is modified, or the DRF is modified.
  2548. // Do the check sum with the new DRF
  2549. //
  2550. ReqUpdateDRF = TRUE;
  2551. }
  2552. LsapFreeLsaHeap( pNewDRF );
  2553. }
  2554. ReleaseRecoveryData();
  2555. }
  2556. */
  2557. //
  2558. // Regardless of whether we did a recovery or not,
  2559. // we still need to check to see if the recovery
  2560. // information is up to snuff.
  2561. //
  2562. if ( !RecoveryInformationCurrent( EfsStream ) ) {
  2563. //
  2564. // We may have fixed up the current user key
  2565. // above. If so, modify that EFS stream.
  2566. // Otherwise, use the one that the user
  2567. // passed in.
  2568. //
  2569. if (UpdatedEfs) {
  2570. PEFS_DATA_STREAM_HEADER Tmp;
  2571. rc = UpdateRecoveryInformation( *Fek, UpdatedEfs, &Tmp );
  2572. if (ERROR_SUCCESS == rc) {
  2573. LsapFreeLsaHeap( UpdatedEfs );
  2574. UpdatedEfs = Tmp;
  2575. }
  2576. } else {
  2577. rc = UpdateRecoveryInformation( *Fek, EfsStream, &UpdatedEfs );
  2578. }
  2579. }
  2580. //
  2581. // We successfully decrypted the file, but we may
  2582. // not have been able to update the various parts
  2583. // That's ok, we'll let the file decrypt.
  2584. //
  2585. // Note that, if there have been no updates,
  2586. // UpdatedEfs is NULL, so this is a safe thing to do.
  2587. //
  2588. *NewEfs = UpdatedEfs;
  2589. return ( ERROR_SUCCESS );
  2590. }
  2591. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2592. rc = GetExceptionCode();
  2593. //
  2594. // Clean up
  2595. //
  2596. if (UpdatedEfs) {
  2597. LsapFreeLsaHeap( UpdatedEfs );
  2598. }
  2599. if (*Fek != NULL) {
  2600. LsapFreeLsaHeap( *Fek );
  2601. *Fek = NULL;
  2602. }
  2603. }
  2604. return( rc );
  2605. }
  2606. DWORD
  2607. EfsGetFek(
  2608. IN PEFS_USER_INFO pEfsUserInfo,
  2609. IN PEFS_DATA_STREAM_HEADER EfsStream,
  2610. OUT PEFS_KEY * Fek
  2611. )
  2612. /*++
  2613. Routine Description:
  2614. This routine will extract the FEK from the passed Efs stream.
  2615. Arguments:
  2616. EfsStream - Supplies the EFS stream from the file being opened.
  2617. Fek - Returns the decrypted FEK from the EFS stream. This data is
  2618. allocated out of local heap and must be freed by the caller.
  2619. Return Value:
  2620. return-value - Description of conditions needed to return value. - or -
  2621. None.
  2622. --*/
  2623. {
  2624. DWORD rc = ERROR_SUCCESS;
  2625. DWORD KeyIndex;
  2626. *Fek = NULL;
  2627. __try {
  2628. //
  2629. // First try the DDF, and if we strike out there, the DRF.
  2630. //
  2631. PDDF Ddf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, EfsStream );
  2632. PDRF Drf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataRecoveryField, EfsStream );
  2633. *Fek = GetFekFromEncryptedKeys( pEfsUserInfo, (PENCRYPTED_KEYS)Ddf, FALSE, &KeyIndex );
  2634. if ((NULL == *Fek) && ( (PVOID)Drf != (PVOID)EfsStream) ) {
  2635. *Fek = GetFekFromEncryptedKeys( pEfsUserInfo, (PENCRYPTED_KEYS)Drf, FALSE, &KeyIndex );
  2636. }
  2637. if (*Fek == NULL) {
  2638. return (rc = GetLastError() );
  2639. }
  2640. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2641. rc = GetExceptionCode();
  2642. if (*Fek != NULL) {
  2643. LsapFreeLsaHeap( *Fek );
  2644. *Fek = NULL;
  2645. }
  2646. }
  2647. return( rc );
  2648. }
  2649. PEFS_KEY
  2650. ExtractFek(
  2651. IN PEFS_USER_INFO pEfsUserInfo,
  2652. IN PENCRYPTED_KEY EncryptedKey,
  2653. IN BOOL CheckBits
  2654. )
  2655. /*++
  2656. Routine Description:
  2657. This routine will take the passed EncryptedKey structure and attempt
  2658. to decrypt the FEK encoded in the structure. It will do this by first
  2659. attempting to create context using the Provider and Container names
  2660. contained in the structure. If such a context exists, its key
  2661. exchange key is used to import the encrypted session key from the
  2662. structure.
  2663. Once the session key has been imported, it is used to decrypt the encrypted
  2664. FEK structure. All of the pieces are then used to reconstruct the key
  2665. integrity information structure, and if this verifies, then it is assumed
  2666. that the FEK has been decoded correctly.
  2667. Arguments:
  2668. pEfsUserInfo - User Info.
  2669. EncryptedKey - Supplies a pointer to an EncryptedKey from the file being opened.
  2670. CheckBits - TRUE will check the encryption bits against current version.
  2671. Return Value:
  2672. On success, returns a pointer to a decrypted FEK. On failure, returns NULL.
  2673. The returned pointer is allocated out of heap and must be freed.
  2674. --*/
  2675. {
  2676. //
  2677. // Obtain a context to the user's RSA key
  2678. //
  2679. DWORD LastError = ERROR_SUCCESS;
  2680. PEFS_KEY DecryptedFEK = NULL;
  2681. PEFS_PUBLIC_KEY_INFO PublicKeyInfo = (PEFS_PUBLIC_KEY_INFO) OFFSET_TO_POINTER(PublicKeyInfo, EncryptedKey);
  2682. HCRYPTPROV hProv = 0;
  2683. HCRYPTKEY hKey;
  2684. HCRYPTPROV hWkProv;
  2685. HCRYPTKEY hWkKey;
  2686. switch (PublicKeyInfo->KeySourceTag) {
  2687. case EfsCertificateThumbprint:
  2688. {
  2689. //
  2690. // See if there is a cert in the current context
  2691. // that corresponds to this thumbprint. If so,
  2692. // we're in business.
  2693. // The KeySourceTag has been changed a couple of times
  2694. // during the development. Now this is the only valid tag.
  2695. //
  2696. PBYTE pbHash;
  2697. DWORD cbHash;
  2698. PEFS_CERT_HASH_DATA CertHashData = (PEFS_CERT_HASH_DATA)OFFSET_TO_POINTER( CertificateThumbprint.CertHashData, PublicKeyInfo );
  2699. pbHash = (PBYTE)OFFSET_TO_POINTER( pbHash, CertHashData );
  2700. cbHash = CertHashData->cbHash;
  2701. LastError = GetKeyInfoFromCertHash(
  2702. pEfsUserInfo,
  2703. pbHash,
  2704. cbHash,
  2705. &hKey,
  2706. &hProv,
  2707. NULL,
  2708. NULL,
  2709. NULL,
  2710. NULL
  2711. );
  2712. if (LastError != ERROR_SUCCESS) {
  2713. SetLastError( LastError );
  2714. return( NULL );
  2715. }
  2716. break;
  2717. }
  2718. default:
  2719. return( NULL );
  2720. break;
  2721. }
  2722. if (hKey) {
  2723. //
  2724. // We are not using the cache.
  2725. //
  2726. hWkKey = hKey;
  2727. } else {
  2728. ASSERT(pEfsUserInfo->pUserCache);
  2729. hWkKey = pEfsUserInfo->pUserCache->hUserKey;
  2730. }
  2731. //
  2732. // Decrypt the FEK field with the session key
  2733. //
  2734. PBYTE EncryptedFEK = (PBYTE)OFFSET_TO_POINTER( EncryptedFEK, EncryptedKey );
  2735. //
  2736. // Copy the FEK into a temporary buffer for decryption
  2737. //
  2738. DWORD cbData = EncryptedKey->EncryptedFEKLength;
  2739. DecryptedFEK = (PEFS_KEY)LsapAllocateLsaHeap( cbData );
  2740. if (DecryptedFEK != NULL) {
  2741. memcpy( DecryptedFEK, EncryptedFEK, cbData );
  2742. BOOL Verified = FALSE;
  2743. if (CryptDecrypt( hWkKey, 0, TRUE, 0, (PBYTE)DecryptedFEK, &cbData )) {
  2744. //
  2745. // First, perform a sanity check: make sure the key we just decrypted has a length field
  2746. // that's reasonable. If not, we got back garbage.
  2747. //
  2748. if (EFS_KEY_SIZE( DecryptedFEK) <= cbData) {
  2749. //
  2750. // Check the Entropy and the salt here
  2751. //
  2752. PEFS_KEY_SALT pEfsKeySalt = (PEFS_KEY_SALT)OFFSET_TO_POINTER( EfsKeySalt, EncryptedKey );
  2753. if ( (KeyEntropy == EXPORT_KEY_STRENGTH) && CheckBits){
  2754. if ( DecryptedFEK->Entropy <= KeyEntropy ){
  2755. //
  2756. // Check the salt
  2757. //
  2758. DWORD SaltLength;
  2759. DWORD SaltBlockLength;
  2760. if (GetSaltLength(DecryptedFEK->Algorithm, &SaltLength,&SaltBlockLength)){
  2761. if ( pEfsKeySalt ){
  2762. Verified = (memcmp( EFS_KEY_DATA(DecryptedFEK), (PBYTE)pEfsKeySalt + sizeof(EFS_KEY_SALT), SaltLength ) == 0);
  2763. } else {
  2764. //
  2765. // This should not happen
  2766. //
  2767. ASSERT(FALSE);
  2768. Verified = FALSE;
  2769. }
  2770. } else {
  2771. //
  2772. // This algorithm has no salt
  2773. //
  2774. Verified = TRUE;
  2775. }
  2776. } else {
  2777. //
  2778. // Export version cannot decrypt files encrypted with longer keys
  2779. //
  2780. Verified = FALSE;
  2781. }
  2782. } else {
  2783. Verified = TRUE;
  2784. }
  2785. //robertg Now you have a pointer to the salt structure to play with. Set Verified == TRUE if
  2786. // everything checks out.
  2787. }
  2788. } else {
  2789. //
  2790. // If we got back a bad length error, that means that the plaintext of
  2791. // FEK was larger than the cyphertext. Assume that this can't happen,
  2792. // since the CryptDecrypt interface doesn't seem to be able to handle
  2793. // this situation.
  2794. //
  2795. ASSERT(GetLastError() != NTE_BAD_LEN);
  2796. LastError = GetLastError();
  2797. }
  2798. if (!Verified) {
  2799. LsapFreeLsaHeap( DecryptedFEK );
  2800. DecryptedFEK = NULL;
  2801. LastError = ERROR_DECRYPTION_FAILED;
  2802. }
  2803. } else {
  2804. LastError = ERROR_NOT_ENOUGH_MEMORY;
  2805. }
  2806. //
  2807. // Clean up what we allocated.
  2808. //
  2809. if (hKey) {
  2810. CryptDestroyKey( hKey );
  2811. CryptReleaseContext( hProv, 0 );
  2812. }
  2813. SetLastError( LastError );
  2814. return( DecryptedFEK );
  2815. }
  2816. BOOLEAN
  2817. GenerateFEK(
  2818. IN OUT PEFS_KEY *Key
  2819. )
  2820. /*++
  2821. Routine Description:
  2822. Generates a new File Encryption Key (FEK).
  2823. Arguments:
  2824. Key - Supplies a pointer to PEFS_KEY.
  2825. Return Value:
  2826. Error if not enough space can be located.
  2827. --*/
  2828. {
  2829. PBYTE KeyData;
  2830. ULONG KeyLength;
  2831. BOOL b = FALSE;
  2832. DWORD LiveKeyEntropy;
  2833. //
  2834. // Allocate the buffer for the EFS_KEY.
  2835. // Set the algorithm and key length here.
  2836. //
  2837. switch (EfsAlgInForce) {
  2838. case CALG_3DES:
  2839. //
  2840. // DES3 has no international version
  2841. //
  2842. KeyLength = DES3_KEYSIZE;
  2843. LiveKeyEntropy = DES3_KEY_STRENGTH;
  2844. break;
  2845. case CALG_DESX:
  2846. KeyLength = DESX_KEYSIZE - 8;
  2847. LiveKeyEntropy = KeyEntropy;
  2848. break;
  2849. case CALG_AES_256:
  2850. default:
  2851. KeyLength = AES_KEYSIZE_256;
  2852. LiveKeyEntropy = AES_KEY_STRENGTH_256;
  2853. break;
  2854. }
  2855. *Key = (PEFS_KEY)LsapAllocateLsaHeap( sizeof( EFS_KEY ) + KeyLength );
  2856. if ( NULL == *Key ){
  2857. SetLastError(ERROR_OUTOFMEMORY);
  2858. return FALSE;
  2859. }
  2860. (*Key)->KeyLength = KeyLength;
  2861. (*Key)->Algorithm = EfsAlgInForce;
  2862. KeyData = (PBYTE)(((PBYTE)*Key) + sizeof( EFS_KEY ));
  2863. if (b = CryptGenRandom( hProvVerify, (*Key)->KeyLength, KeyData )) {
  2864. (*Key)->Entropy = LiveKeyEntropy;
  2865. } else {
  2866. LsapFreeLsaHeap( *Key );
  2867. *Key = NULL;
  2868. }
  2869. return( b != 0);
  2870. }
  2871. DWORD
  2872. CreatePublicKeyInformationCertificate(
  2873. IN PSID pUserSid OPTIONAL,
  2874. PBYTE pbCert,
  2875. DWORD cbCert,
  2876. OUT PEFS_PUBLIC_KEY_INFO * PublicKeyInformation
  2877. )
  2878. {
  2879. DWORD PublicKeyInformationLength = 0;
  2880. DWORD UserSidLength = 0;
  2881. PWCHAR Base;
  2882. if (pUserSid != NULL) {
  2883. UserSidLength = GetLengthSid( pUserSid );
  2884. }
  2885. //
  2886. // Total size is the size of the public key info structure, the size of the
  2887. // cert hash data structure, the length of the thumbprint, and the lengths of the
  2888. // container name and provider name if they were passed.
  2889. //
  2890. PublicKeyInformationLength = sizeof( EFS_PUBLIC_KEY_INFO ) + UserSidLength + cbCert;
  2891. //
  2892. // Allocate and fill in the PublicKeyInformation structure
  2893. //
  2894. *PublicKeyInformation = (PEFS_PUBLIC_KEY_INFO)LsapAllocateLsaHeap( PublicKeyInformationLength );
  2895. if (*PublicKeyInformation == NULL) {
  2896. return( ERROR_NOT_ENOUGH_MEMORY );
  2897. }
  2898. (*PublicKeyInformation)->Length = PublicKeyInformationLength;
  2899. (*PublicKeyInformation)->KeySourceTag = (ULONG)EfsCertificate;
  2900. //
  2901. // Copy the string and SID data to the end of the structure.
  2902. //
  2903. Base = (PWCHAR)(*PublicKeyInformation);
  2904. Base = (PWCHAR)((PBYTE)Base + sizeof( EFS_PUBLIC_KEY_INFO ));
  2905. if (pUserSid != NULL) {
  2906. (*PublicKeyInformation)->PossibleKeyOwner = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
  2907. CopySid( UserSidLength, (PSID)Base, pUserSid );
  2908. } else {
  2909. (*PublicKeyInformation)->PossibleKeyOwner = 0;
  2910. }
  2911. Base = (PWCHAR)((PBYTE)Base + UserSidLength);
  2912. (*PublicKeyInformation)->CertificateInfo.CertificateLength = cbCert;
  2913. (*PublicKeyInformation)->CertificateInfo.Certificate = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
  2914. memcpy( (PBYTE)Base, pbCert, cbCert );
  2915. return( ERROR_SUCCESS );
  2916. }
  2917. BOOLEAN
  2918. CreatePublicKeyInformationThumbprint(
  2919. IN PSID pUserSid OPTIONAL,
  2920. IN PBYTE pbCertHash,
  2921. IN DWORD cbCertHash,
  2922. IN LPWSTR lpDisplayInformation OPTIONAL,
  2923. IN LPWSTR ContainerName OPTIONAL,
  2924. IN LPWSTR ProviderName OPTIONAL,
  2925. OUT PEFS_PUBLIC_KEY_INFO * PublicKeyInformation
  2926. )
  2927. /*++
  2928. Routine Description:
  2929. This routine creates an EFS_PUBLIC_KEY_INFO structure that can be
  2930. placed in an EFS stream.
  2931. Arguments:
  2932. ContainerName - The name of the container containing the public key. This
  2933. parameter is not optional if ProviderName is passed.
  2934. ProviderName - The name of the provider containing the public key. This
  2935. parameter is not optional if ContainerName is passed.
  2936. pbPublicKeyBlob - The actual public key blob exported from CryptAPI
  2937. KeySource - Data for the KeySource field in the public key structure
  2938. cbPublicKeyBlob - The length of the public key blob in bytes
  2939. PublicKeyInformation - Returns the filled in EFS_PUBLIC_KEY_INFO
  2940. structure.
  2941. Return Value:
  2942. ERROR_SUCCESS or ERROR_NOT_ENOUGH_MEMORY as appropriate
  2943. --*/
  2944. {
  2945. DWORD PublicKeyInformationLength = 0;
  2946. DWORD cbThumbprint = 0;
  2947. DWORD UserSidLength = 0;
  2948. PWCHAR Base;
  2949. if (pUserSid != NULL) {
  2950. UserSidLength = GetLengthSid( pUserSid );
  2951. }
  2952. //
  2953. // Total size is the size of the public key info structure, the size of the
  2954. // cert hash data structure, the length of the thumbprint, and the lengths of the
  2955. // container name and provider name if they were passed.
  2956. //
  2957. PublicKeyInformationLength = sizeof( EFS_PUBLIC_KEY_INFO ) + UserSidLength;
  2958. cbThumbprint = sizeof( EFS_CERT_HASH_DATA ) + cbCertHash;
  2959. if (ContainerName != NULL ) {
  2960. cbThumbprint += (wcslen( ContainerName ) + 1) * sizeof( WCHAR );
  2961. }
  2962. if (ProviderName != NULL ) {
  2963. cbThumbprint += (wcslen( ProviderName ) + 1) * sizeof( WCHAR );
  2964. }
  2965. if (lpDisplayInformation != NULL) {
  2966. cbThumbprint += (wcslen( lpDisplayInformation ) + 1) * sizeof( WCHAR );
  2967. }
  2968. PublicKeyInformationLength += cbThumbprint;
  2969. //
  2970. // Allocate and fill in the PublicKeyInformation structure
  2971. //
  2972. *PublicKeyInformation = (PEFS_PUBLIC_KEY_INFO)LsapAllocateLsaHeap( PublicKeyInformationLength );
  2973. if (*PublicKeyInformation == NULL) {
  2974. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2975. return( FALSE );
  2976. }
  2977. (*PublicKeyInformation)->Length = PublicKeyInformationLength;
  2978. //
  2979. // Mark the information as from CryptoAPI, since that's all we support right now.
  2980. //
  2981. (*PublicKeyInformation)->KeySourceTag = (ULONG)EfsCertificateThumbprint;
  2982. //
  2983. // Copy the string and SID data to the end of the structure.
  2984. //
  2985. Base = (PWCHAR)(*PublicKeyInformation);
  2986. Base = (PWCHAR)((PBYTE)Base + sizeof( EFS_PUBLIC_KEY_INFO ));
  2987. if (pUserSid != NULL) {
  2988. (*PublicKeyInformation)->PossibleKeyOwner = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
  2989. CopySid( UserSidLength, (PSID)Base, pUserSid );
  2990. } else {
  2991. (*PublicKeyInformation)->PossibleKeyOwner = (ULONG)0;
  2992. }
  2993. Base = (PWCHAR)((PBYTE)Base + UserSidLength);
  2994. PEFS_CERT_HASH_DATA pCertHashData;
  2995. (*PublicKeyInformation)->CertificateThumbprint.ThumbprintLength = cbThumbprint;
  2996. (*PublicKeyInformation)->CertificateThumbprint.CertHashData = (ULONG)POINTER_TO_OFFSET( Base, *PublicKeyInformation );
  2997. pCertHashData = (PEFS_CERT_HASH_DATA)Base;
  2998. //
  2999. // Zero the header, eliminate the garbage if any of Container, Provide or Display
  3000. // Information is NULL.
  3001. //
  3002. RtlZeroMemory(pCertHashData, sizeof( EFS_CERT_HASH_DATA ));
  3003. Base = (PWCHAR)((PBYTE)Base + sizeof( EFS_CERT_HASH_DATA ));
  3004. //
  3005. // Copy the hash data to the end of the cert hash data block,
  3006. // and set the offset from the *beginning of the cert hash data block
  3007. // (not the beginning of the public key info structure)
  3008. //
  3009. pCertHashData->cbHash = cbCertHash;
  3010. pCertHashData->pbHash = (ULONG)POINTER_TO_OFFSET( Base, pCertHashData );
  3011. memcpy( (PBYTE)Base, pbCertHash, cbCertHash );
  3012. Base = (PWCHAR)((PBYTE)Base + cbCertHash);
  3013. //
  3014. // If we have Container/Provider hint info, copy them in now
  3015. //
  3016. if (ContainerName != NULL) {
  3017. pCertHashData->ContainerName = (ULONG)POINTER_TO_OFFSET( Base, pCertHashData );
  3018. wcscpy( (PWCHAR)Base, ContainerName );
  3019. //
  3020. // wcscpy copies trailing NULL characters, but wcslen doesn't include them in returned lengths,
  3021. // so add 1 to adjust.
  3022. //
  3023. Base += (wcslen( ContainerName ) + 1);
  3024. }
  3025. if (ProviderName != NULL) {
  3026. //
  3027. // Store the offset into the session key structure
  3028. //
  3029. pCertHashData->ProviderName = (ULONG)POINTER_TO_OFFSET( Base, pCertHashData );
  3030. wcscpy( (PWCHAR)Base, ProviderName );
  3031. Base += (wcslen( ProviderName ) + 1);
  3032. }
  3033. if (lpDisplayInformation != NULL) {
  3034. pCertHashData->lpDisplayInformation = (ULONG)POINTER_TO_OFFSET( Base, pCertHashData );
  3035. wcscpy( (PWCHAR)Base, lpDisplayInformation );
  3036. Base += (wcslen( lpDisplayInformation ) + 1);
  3037. }
  3038. return( TRUE );
  3039. }
  3040. DWORD
  3041. ConstructEncryptedKey(
  3042. PBYTE EncryptedFEK,
  3043. DWORD dwEncryptedFEKLength,
  3044. PEFS_PUBLIC_KEY_INFO PublicKeyInformation,
  3045. PEFS_KEY_SALT pEfsKeySalt OPTIONAL,
  3046. OUT PENCRYPTED_KEY *EncryptedKey,
  3047. OUT PDWORD EncryptedKeySize
  3048. )
  3049. /*++
  3050. Routine Description:
  3051. This routine constructs an ENCRYPTED_KEY structure from the passed
  3052. arguments.
  3053. Arguments:
  3054. EncryptedFEK - The encrypted FEK.
  3055. dwEncryptedFEKLength - The length of the encrypted FEK in bytes.
  3056. PublicKeyInformation - The public key information stucture containing
  3057. the public key.
  3058. pEfsKeySalt - Salt block.
  3059. EncryptedKey - Returns the encrypted key structure.
  3060. EncryptedKeySize - Supplies the length of the encrypted
  3061. key structure. Returns the actual length used or required.
  3062. Return Value:
  3063. ERROR_NOT_ENOUGH_MEMORY - Out of memory.
  3064. ERROR_SUCCESS - Success
  3065. --*/
  3066. {
  3067. //
  3068. // We now have all the information we need to construct the EncryptedKeys structure
  3069. // Compute the total size required
  3070. //
  3071. DWORD KeySize = sizeof( ENCRYPTED_KEY ) +
  3072. dwEncryptedFEKLength +
  3073. PublicKeyInformation->Length;
  3074. if (pEfsKeySalt){
  3075. KeySize += pEfsKeySalt->Length;
  3076. }
  3077. *EncryptedKey = (PENCRYPTED_KEY) LsapAllocateLsaHeap( KeySize );
  3078. if ( NULL == *EncryptedKey ) {
  3079. *EncryptedKeySize = 0;
  3080. return ERROR_NOT_ENOUGH_MEMORY;
  3081. }
  3082. *EncryptedKeySize = KeySize;
  3083. PBYTE Base;
  3084. (*EncryptedKey)->Length = *EncryptedKeySize;
  3085. Base = (PBYTE)(((PBYTE)*EncryptedKey) + sizeof( ENCRYPTED_KEY ));
  3086. //
  3087. // Copy in the public key info structure
  3088. //
  3089. memcpy( Base, PublicKeyInformation, PublicKeyInformation->Length );
  3090. //
  3091. // Save offset to what we just copied.
  3092. //
  3093. (*EncryptedKey)->PublicKeyInfo = (ULONG)POINTER_TO_OFFSET(Base, *EncryptedKey);
  3094. Base += PublicKeyInformation->Length;
  3095. //
  3096. // Copy the FEK, which is a completely encrypted structure
  3097. //
  3098. memcpy( Base, EncryptedFEK, dwEncryptedFEKLength );
  3099. (*EncryptedKey)->EncryptedFEK = (ULONG)POINTER_TO_OFFSET(Base, *EncryptedKey);
  3100. (*EncryptedKey)->EncryptedFEKLength = dwEncryptedFEKLength;
  3101. Base += dwEncryptedFEKLength;
  3102. //
  3103. // Copy the Salt Information
  3104. //
  3105. if (pEfsKeySalt){
  3106. memcpy( Base, pEfsKeySalt, pEfsKeySalt->Length );
  3107. (*EncryptedKey)->EfsKeySalt = (ULONG)POINTER_TO_OFFSET(Base, *EncryptedKey);
  3108. } else {
  3109. (*EncryptedKey)->EfsKeySalt = 0;
  3110. }
  3111. return( ERROR_SUCCESS );
  3112. }
  3113. PBYTE
  3114. EncryptFEK(
  3115. IN PEFS_KEY Fek,
  3116. IN HCRYPTKEY hRSAKey,
  3117. OUT PDWORD dwEncryptedFEKLength
  3118. )
  3119. {
  3120. DWORD rc=ERROR_SUCCESS;
  3121. *dwEncryptedFEKLength = EFS_KEY_SIZE( Fek );
  3122. //
  3123. // If CryptoAPI worked properly, we wouldn't need this, but it doesn't,
  3124. // so we do.
  3125. //
  3126. if (CryptEncrypt( hRSAKey, 0, TRUE, 0, NULL, dwEncryptedFEKLength, 0 )) {
  3127. DWORD BufferLength = (*dwEncryptedFEKLength < EFS_KEY_SIZE(Fek)) ? EFS_KEY_SIZE(Fek) : *dwEncryptedFEKLength;
  3128. PBYTE EncryptedFEK = (PBYTE)LsapAllocateLsaHeap( BufferLength );
  3129. if (EncryptedFEK != NULL) {
  3130. //
  3131. // Copy the FEK into our new buffer and encrypt it there.
  3132. //
  3133. memcpy( EncryptedFEK, Fek, EFS_KEY_SIZE( Fek ) );
  3134. //
  3135. // Reset the length of the data to be encrypted
  3136. //
  3137. *dwEncryptedFEKLength = EFS_KEY_SIZE( Fek );
  3138. if (CryptEncrypt( hRSAKey, 0, TRUE, 0, EncryptedFEK, dwEncryptedFEKLength, BufferLength )) {
  3139. return( EncryptedFEK );
  3140. } else {
  3141. rc = GetLastError();
  3142. DebugLog((DEB_ERROR, "EncryptFEK: 2nd CryptEncrypt failed, error = %x\n" , rc ));
  3143. }
  3144. //
  3145. // If we're here, we failed, clean up
  3146. //
  3147. LsapFreeLsaHeap( EncryptedFEK );
  3148. } else {
  3149. rc = ERROR_NOT_ENOUGH_MEMORY;
  3150. }
  3151. } else {
  3152. rc = GetLastError();
  3153. DebugLog((DEB_ERROR, "EncryptFEK: 1st CryptEncrypt failed, error = %x\n" , rc ));
  3154. }
  3155. if (rc != ERROR_SUCCESS) {
  3156. SetLastError(rc);
  3157. }
  3158. return( NULL );
  3159. }
  3160. BOOL
  3161. RemoveUsersFromEfsStream(
  3162. IN PEFS_DATA_STREAM_HEADER pEfsStream,
  3163. IN DWORD nHashes,
  3164. IN PENCRYPTION_CERTIFICATE_HASH * pHashes,
  3165. IN PEFS_KEY Fek,
  3166. OUT PEFS_DATA_STREAM_HEADER * pNewEfsStream
  3167. )
  3168. /*++
  3169. Routine Description:
  3170. This routine removes the passed users from the passed EFS
  3171. stream, and returns a new one to be applied to the file.
  3172. Arguments:
  3173. argument-name - Supplies | Returns description of argument.
  3174. .
  3175. .
  3176. Return Value:
  3177. return-value - Description of conditions needed to return value. - or -
  3178. None.
  3179. --*/
  3180. {
  3181. //
  3182. // First, see how many matches there are so we can compute
  3183. // the final size of the structure we're going to have to
  3184. // allocate.
  3185. //
  3186. DWORD cbSizeToDelete = 0;
  3187. DWORD nKeysToDelete = 0;
  3188. DWORD rc = ERROR_SUCCESS;
  3189. BOOL b = FALSE;
  3190. PENCRYPTED_KEYS pDDF = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, pEfsStream );
  3191. DWORD KeyCount = pDDF->KeyCount;
  3192. PDWORD KeyIndiciesToDelete = (PDWORD)LsapAllocateLsaHeap( KeyCount * sizeof( DWORD ));
  3193. if (KeyIndiciesToDelete) {
  3194. memset( KeyIndiciesToDelete, 0, KeyCount * sizeof( DWORD ));
  3195. //
  3196. // First pass: walk the list of keys in the DDF and compare each one to the
  3197. // keys in the list of hashes passed. Count the matches and keep track of the
  3198. // total size of the resulting structure.
  3199. //
  3200. PENCRYPTED_KEY pEncryptedKey = &pDDF->EncryptedKey[0];
  3201. for (DWORD i=0; i<KeyCount ; i++, pEncryptedKey = NEXT_ENCRYPTED_KEY( pEncryptedKey )) {
  3202. PENCRYPTED_KEY pAlignedKey;
  3203. BOOLEAN freeAlignedKey;
  3204. rc = EfsAlignBlock(
  3205. pEncryptedKey,
  3206. (PVOID *)&pAlignedKey,
  3207. &freeAlignedKey
  3208. );
  3209. if (!pAlignedKey) {
  3210. //
  3211. // OOM. Treat it as not current.
  3212. //
  3213. rc = ERROR_NOT_ENOUGH_MEMORY;
  3214. nKeysToDelete = 0;
  3215. break;
  3216. }
  3217. PEFS_PUBLIC_KEY_INFO pPublicKeyInfo = (PEFS_PUBLIC_KEY_INFO)OFFSET_TO_POINTER( PublicKeyInfo, pAlignedKey );
  3218. ASSERT( pPublicKeyInfo->KeySourceTag == EfsCertificateThumbprint );
  3219. PEFS_CERT_HASH_DATA CertHashData = (PEFS_CERT_HASH_DATA)OFFSET_TO_POINTER( CertificateThumbprint.CertHashData, pPublicKeyInfo );
  3220. DWORD cbHash = CertHashData->cbHash;
  3221. PBYTE pbHash = (PBYTE)OFFSET_TO_POINTER( pbHash, CertHashData );
  3222. //
  3223. // Compare the hash data with all of the data in the array
  3224. //
  3225. __try{
  3226. for (DWORD j=0; j<nHashes ; j++) {
  3227. PENCRYPTION_CERTIFICATE_HASH pHash = pHashes[j];
  3228. PEFS_HASH_BLOB pHashBlob = pHash->pHash;
  3229. if (pHashBlob->cbData == cbHash ) {
  3230. if (memcmp( pHashBlob->pbData, pbHash, cbHash ) == 0) {
  3231. //
  3232. // We have a match. That means that this entry is going to be removed from
  3233. // the DDF when it is rebuilt.
  3234. //
  3235. cbSizeToDelete += pAlignedKey->Length;
  3236. KeyIndiciesToDelete[nKeysToDelete] = i;
  3237. nKeysToDelete++;
  3238. break;
  3239. }
  3240. }
  3241. }
  3242. } __except (EXCEPTION_EXECUTE_HANDLER) {
  3243. //
  3244. // The passed in pHashes is bad
  3245. //
  3246. nKeysToDelete = 0;
  3247. rc = ERROR_INVALID_PARAMETER;
  3248. }
  3249. if (freeAlignedKey) {
  3250. LsapFreeLsaHeap( pAlignedKey );
  3251. }
  3252. if (ERROR_INVALID_PARAMETER == rc) {
  3253. break;
  3254. }
  3255. }
  3256. if (nKeysToDelete != 0) {
  3257. //
  3258. // We made at least one match. The size of the new efs stream is the size of
  3259. // the old one minus the size of the stuff we're deleting.
  3260. //
  3261. DWORD cbNewEfsStream = pEfsStream->Length - cbSizeToDelete;
  3262. cbNewEfsStream = (cbNewEfsStream + 7) & 0xfffffff8;
  3263. *pNewEfsStream = (PEFS_DATA_STREAM_HEADER)LsapAllocateLsaHeap( cbNewEfsStream );
  3264. if (*pNewEfsStream) {
  3265. //
  3266. // Copy the old header to the new structure.
  3267. //
  3268. **pNewEfsStream = *pEfsStream;
  3269. ((PEFS_DATA_STREAM_HEADER)*pNewEfsStream)->Length = cbNewEfsStream;
  3270. //
  3271. // Copy the old DDF to the new DDF, skipping the
  3272. // ones we want to delete
  3273. //
  3274. //
  3275. // Base is our target. Make it point to the end of the header, which
  3276. // is where we're going to start copying the new DDF.
  3277. //
  3278. PBYTE Base = (PBYTE) (((PBYTE)(*pNewEfsStream)) + sizeof( EFS_DATA_STREAM_HEADER ));
  3279. //
  3280. // Set the offset of the new DDF into the header.
  3281. //
  3282. (*pNewEfsStream)->DataDecryptionField = (ULONG)POINTER_TO_OFFSET( Base, *pNewEfsStream );
  3283. //
  3284. // Start to assemble the new DDF
  3285. //
  3286. PENCRYPTED_KEYS pNewDDF = (PENCRYPTED_KEYS)Base;
  3287. pNewDDF->KeyCount = KeyCount - nKeysToDelete;
  3288. Base = (PBYTE)(&pNewDDF->EncryptedKey[0]);
  3289. PBYTE Source = (PBYTE)(&pDDF->EncryptedKey[0]);
  3290. DWORD NextKeyIndexToDelete = 0;
  3291. for (DWORD i=0; i<KeyCount ; i++) {
  3292. if (KeyIndiciesToDelete[NextKeyIndexToDelete] != i) {
  3293. //
  3294. // We're not going to delete this one, copy it.
  3295. //
  3296. DWORD KeyLength = * (DWORD UNALIGNED *) &(((PENCRYPTED_KEY)Source)->Length);
  3297. memcpy( Base, Source, KeyLength );
  3298. Base = (PBYTE)NEXT_ENCRYPTED_KEY( Base );
  3299. Source = (PBYTE)NEXT_ENCRYPTED_KEY( Source );
  3300. } else {
  3301. //
  3302. // We're going to delete this one. Leave Base
  3303. // alone, but bump Source to the next key.
  3304. //
  3305. Source = (PBYTE)NEXT_ENCRYPTED_KEY( Source );
  3306. NextKeyIndexToDelete++;
  3307. }
  3308. }
  3309. //
  3310. // The new DDF is in place. Copy the recovery information
  3311. // from the old EFS stream into the new one.
  3312. //
  3313. // Base points to where the DRF needs to go, and Source
  3314. // points to where the old one is (in theory).
  3315. //
  3316. ASSERT( Source == (PBYTE)OFFSET_TO_POINTER( DataRecoveryField, pEfsStream ));
  3317. PENCRYPTED_KEYS pDRF = (PENCRYPTED_KEYS)Source;
  3318. //
  3319. // Set the offset of the new DRF into the new EFS stream.
  3320. //
  3321. if ((PVOID)pDRF == (PVOID)pEfsStream) {
  3322. //
  3323. // No DRF in the old $EFS
  3324. //
  3325. (*pNewEfsStream)->DataRecoveryField = 0;
  3326. } else {
  3327. (*pNewEfsStream)->DataRecoveryField = (ULONG)POINTER_TO_OFFSET( Base, *pNewEfsStream );
  3328. //
  3329. // We can copy the old DRF directly into the new one, since nothing in
  3330. // it is changing.
  3331. //
  3332. //
  3333. // Base now points to the top of an ENCRYPTED_KEYS structure.
  3334. // Fill in its header.
  3335. //
  3336. PENCRYPTED_KEYS pNewDRF = (PENCRYPTED_KEYS)Base;
  3337. RtlCopyMemory(&(pNewDRF->KeyCount), &(pDRF->KeyCount), sizeof(ULONG));
  3338. RtlCopyMemory(&KeyCount, &(pDRF->KeyCount), sizeof(ULONG));
  3339. //
  3340. // That was the header. Now start copying the
  3341. // encrypted keys themselves.
  3342. //
  3343. Base = (PBYTE)(&pNewDRF->EncryptedKey[0]);
  3344. Source = (PBYTE)(&pDRF->EncryptedKey[0]);
  3345. for (i=0; i<KeyCount ; i++) {
  3346. DWORD KeyLength = * (DWORD UNALIGNED *) &(((PENCRYPTED_KEY)Source)->Length);
  3347. memcpy( Base, Source, KeyLength );
  3348. Base = (PBYTE)NEXT_ENCRYPTED_KEY( Base );
  3349. Source = (PBYTE)NEXT_ENCRYPTED_KEY( Source );
  3350. }
  3351. }
  3352. b = TRUE;
  3353. // memset( &((*pNewEfsStream)->EfsHash), 0, MD5_HASH_SIZE );
  3354. // if (EfspChecksumEfs( *pNewEfsStream, Fek )) {
  3355. // b = TRUE;
  3356. // }
  3357. } else {
  3358. rc = ERROR_NOT_ENOUGH_MEMORY;
  3359. }
  3360. } else {
  3361. if (ERROR_SUCCESS == rc) {
  3362. b = TRUE;
  3363. }
  3364. }
  3365. LsapFreeLsaHeap( KeyIndiciesToDelete );
  3366. } else {
  3367. rc = ERROR_NOT_ENOUGH_MEMORY;
  3368. }
  3369. if (!b) {
  3370. //
  3371. // Something failed, clean up what we were going
  3372. // to return.
  3373. //
  3374. if (*pNewEfsStream) {
  3375. LsapFreeLsaHeap( *pNewEfsStream );
  3376. *pNewEfsStream = NULL; // paranoia
  3377. }
  3378. }
  3379. SetLastError(rc);
  3380. return( b );
  3381. }
  3382. BOOL
  3383. QueryCertsFromEncryptedKeys(
  3384. IN PENCRYPTED_KEYS pEncryptedKeys,
  3385. OUT PDWORD pnUsers,
  3386. OUT PENCRYPTION_CERTIFICATE_HASH ** pHashes
  3387. )
  3388. /*++
  3389. Routine Description:
  3390. This routine takes a set of encrypted keys and returns the data
  3391. that we wish to display about each one.
  3392. Arguments:
  3393. pEncryptedKeys - Supplies the array of encrypted keys.
  3394. pnUsers - Returns the number of users on the file.
  3395. pHashes - Returns the hash information about each user.
  3396. Return Value:
  3397. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  3398. --*/
  3399. {
  3400. DWORD rc = ERROR_SUCCESS;
  3401. PENCRYPTION_CERTIFICATE_HASH pTmp = NULL;
  3402. //
  3403. // Walk the entries in the encrypted keys and return the information we want about each one.
  3404. //
  3405. DWORD KeyCount = * (DWORD UNALIGNED *) &(pEncryptedKeys->KeyCount);
  3406. *pnUsers = KeyCount;
  3407. PENCRYPTED_KEY pEncryptedKey = &pEncryptedKeys->EncryptedKey[0];
  3408. //
  3409. // *pHashes points to an array of pointers to ENCRYPTION_CERTIFICATE_HASH structures.
  3410. // There will be one entry for each Key on the file
  3411. //
  3412. *pHashes = (PENCRYPTION_CERTIFICATE_HASH *)MIDL_user_allocate( sizeof(PENCRYPTION_CERTIFICATE_HASH) * KeyCount );
  3413. if (*pHashes) {
  3414. memset( *pHashes, 0, sizeof(PENCRYPTION_CERTIFICATE_HASH) * KeyCount );
  3415. for (DWORD i=0;
  3416. i < KeyCount;
  3417. i++, pEncryptedKey = NEXT_ENCRYPTED_KEY( pEncryptedKey )
  3418. ) {
  3419. PENCRYPTED_KEY pAlignedKey;
  3420. BOOLEAN freeAlignedKey;
  3421. rc = EfsAlignBlock(
  3422. pEncryptedKey,
  3423. (PVOID *)&pAlignedKey,
  3424. &freeAlignedKey
  3425. );
  3426. if (!pAlignedKey) {
  3427. //
  3428. // OOM. Treat it as not current.
  3429. //
  3430. rc = ERROR_NOT_ENOUGH_MEMORY;
  3431. break;
  3432. }
  3433. PEFS_PUBLIC_KEY_INFO pPublicKeyInfo = (PEFS_PUBLIC_KEY_INFO)OFFSET_TO_POINTER( PublicKeyInfo, pAlignedKey );
  3434. ASSERT( pPublicKeyInfo->KeySourceTag == EfsCertificateThumbprint );
  3435. PENCRYPTION_CERTIFICATE_HASH pTmp = (PENCRYPTION_CERTIFICATE_HASH) MIDL_user_allocate( sizeof(ENCRYPTION_CERTIFICATE_HASH ));
  3436. if (pTmp) {
  3437. memset( pTmp, 0, sizeof( ENCRYPTION_CERTIFICATE_HASH ));
  3438. pTmp->cbTotalLength = sizeof( ENCRYPTION_CERTIFICATE_HASH );
  3439. if (pPublicKeyInfo->PossibleKeyOwner) {
  3440. PSID pUserSid = ( PSID )OFFSET_TO_POINTER( PossibleKeyOwner, pPublicKeyInfo );
  3441. pTmp->pUserSid = (SID *)MIDL_user_allocate( GetLengthSid( pUserSid ));
  3442. if (pTmp->pUserSid) {
  3443. CopySid( GetLengthSid( pUserSid ),
  3444. pTmp->pUserSid,
  3445. pUserSid
  3446. );
  3447. } else {
  3448. rc = ERROR_NOT_ENOUGH_MEMORY;
  3449. }
  3450. } else {
  3451. pTmp->pUserSid = NULL;
  3452. }
  3453. //
  3454. // Copy the hash
  3455. //
  3456. if (rc == ERROR_SUCCESS) {
  3457. pTmp->pHash = (PEFS_HASH_BLOB)MIDL_user_allocate( sizeof( EFS_HASH_BLOB ));
  3458. if (pTmp->pHash) {
  3459. PEFS_CERT_HASH_DATA CertHashData = (PEFS_CERT_HASH_DATA)OFFSET_TO_POINTER( CertificateThumbprint.CertHashData, pPublicKeyInfo );
  3460. pTmp->pHash->cbData = CertHashData->cbHash;
  3461. pTmp->pHash->pbData = (PBYTE)MIDL_user_allocate( pTmp->pHash->cbData );
  3462. if (pTmp->pHash->pbData) {
  3463. memcpy( pTmp->pHash->pbData, OFFSET_TO_POINTER( pbHash, CertHashData ), pTmp->pHash->cbData );
  3464. ASSERT( rc == ERROR_SUCCESS );
  3465. } else {
  3466. rc = ERROR_NOT_ENOUGH_MEMORY;
  3467. }
  3468. if (rc == ERROR_SUCCESS) {
  3469. //
  3470. // Allocate and fill in the display information field.
  3471. //
  3472. if (CertHashData->lpDisplayInformation) {
  3473. LPWSTR lpDisplayInformation = (LPWSTR)OFFSET_TO_POINTER( lpDisplayInformation, CertHashData );
  3474. pTmp->lpDisplayInformation = (LPWSTR)MIDL_user_allocate( (wcslen( lpDisplayInformation ) + 1) * sizeof( WCHAR ));
  3475. if (pTmp->lpDisplayInformation) {
  3476. wcscpy( pTmp->lpDisplayInformation, lpDisplayInformation );
  3477. (pTmp->lpDisplayInformation)[wcslen(lpDisplayInformation)] = UNICODE_NULL;
  3478. ASSERT( rc == ERROR_SUCCESS );
  3479. } else {
  3480. rc = ERROR_NOT_ENOUGH_MEMORY;
  3481. }
  3482. }
  3483. }
  3484. } else {
  3485. rc = ERROR_NOT_ENOUGH_MEMORY;
  3486. }
  3487. }
  3488. } else {
  3489. rc = ERROR_NOT_ENOUGH_MEMORY;
  3490. }
  3491. if (rc != ERROR_SUCCESS) {
  3492. //
  3493. // We couldn't successfully build this structure. Free up
  3494. // all the stuff we were going to return and drop out of the loop.
  3495. //
  3496. if (pTmp) {
  3497. if (pTmp->pHash) {
  3498. if (pTmp->pHash->pbData) {
  3499. MIDL_user_free( pTmp->pHash->pbData );
  3500. }
  3501. MIDL_user_free( pTmp->pHash );
  3502. }
  3503. if (pTmp->lpDisplayInformation) {
  3504. MIDL_user_free( pTmp->lpDisplayInformation );
  3505. }
  3506. if (pTmp->pUserSid) {
  3507. MIDL_user_free( pTmp->pUserSid );
  3508. }
  3509. MIDL_user_free( pTmp );
  3510. }
  3511. if (freeAlignedKey) {
  3512. LsapFreeLsaHeap( pAlignedKey );
  3513. }
  3514. break;
  3515. } else {
  3516. (*pHashes)[i] = pTmp;
  3517. if (freeAlignedKey) {
  3518. LsapFreeLsaHeap( pAlignedKey );
  3519. }
  3520. }
  3521. }
  3522. if (rc != ERROR_SUCCESS) {
  3523. //
  3524. // Something failed along the way, walk down the list of ones
  3525. // we successfully allocated and free them up. Any partially
  3526. // allocated ones will have been cleaned up above.
  3527. //
  3528. DWORD i=0;
  3529. while ( (*pHashes)[i] ) {
  3530. pTmp = (*pHashes)[i];
  3531. ASSERT( pTmp->pHash );
  3532. ASSERT( pTmp->pHash->pbData );
  3533. MIDL_user_free( pTmp->pHash->pbData );
  3534. MIDL_user_free( pTmp->pHash );
  3535. if (pTmp->lpDisplayInformation) {
  3536. MIDL_user_free( pTmp->lpDisplayInformation );
  3537. }
  3538. if (pTmp->pUserSid) {
  3539. MIDL_user_free( pTmp->pUserSid );
  3540. }
  3541. MIDL_user_free( pTmp );
  3542. (*pHashes)[i] = NULL;
  3543. i++;
  3544. }
  3545. MIDL_user_free( *pHashes );
  3546. }
  3547. } else {
  3548. rc = ERROR_NOT_ENOUGH_MEMORY;
  3549. }
  3550. SetLastError( rc );
  3551. return( ERROR_SUCCESS == rc ? TRUE : FALSE );
  3552. }
  3553. BOOL
  3554. EfsErrorToNtStatus(
  3555. IN DWORD WinError,
  3556. OUT PNTSTATUS NtStatus
  3557. )
  3558. {
  3559. switch (WinError) {
  3560. case ERROR_ENCRYPTION_FAILED:
  3561. {
  3562. *NtStatus = STATUS_ENCRYPTION_FAILED;
  3563. break;
  3564. }
  3565. case NTE_BAD_KEYSET:
  3566. case CRYPT_E_NOT_FOUND:
  3567. case ERROR_DECRYPTION_FAILED:
  3568. {
  3569. *NtStatus = STATUS_DECRYPTION_FAILED;
  3570. break;
  3571. }
  3572. case ERROR_FILE_ENCRYPTED:
  3573. {
  3574. *NtStatus = STATUS_FILE_ENCRYPTED;
  3575. break;
  3576. }
  3577. case ERROR_NO_RECOVERY_POLICY:
  3578. {
  3579. *NtStatus = STATUS_NO_RECOVERY_POLICY;
  3580. break;
  3581. }
  3582. case ERROR_NO_EFS:
  3583. {
  3584. *NtStatus = STATUS_NO_EFS;
  3585. break;
  3586. }
  3587. case ERROR_WRONG_EFS:
  3588. {
  3589. *NtStatus = STATUS_WRONG_EFS;
  3590. break;
  3591. }
  3592. case ERROR_NO_USER_KEYS:
  3593. {
  3594. *NtStatus = STATUS_NO_USER_KEYS;
  3595. break;
  3596. }
  3597. case ERROR_FILE_NOT_ENCRYPTED:
  3598. {
  3599. *NtStatus = STATUS_FILE_NOT_ENCRYPTED;
  3600. break;
  3601. }
  3602. case ERROR_NOT_EXPORT_FORMAT:
  3603. {
  3604. *NtStatus = STATUS_NOT_EXPORT_FORMAT;
  3605. break;
  3606. }
  3607. case ERROR_OUTOFMEMORY:
  3608. {
  3609. *NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  3610. break;
  3611. }
  3612. case ERROR_ACCESS_DENIED:
  3613. {
  3614. *NtStatus = STATUS_ACCESS_DENIED;
  3615. break;
  3616. }
  3617. default:
  3618. {
  3619. DebugLog((DEB_WARN, "EfsErrorToNtStatus, unable to translate 0x%x\n" , WinError ));
  3620. return( FALSE );
  3621. break;
  3622. }
  3623. }
  3624. return( TRUE );
  3625. }
  3626. VOID
  3627. DumpBytes(
  3628. PBYTE Blob,
  3629. ULONG Length,
  3630. ULONG IndentLevel
  3631. )
  3632. {
  3633. const UINT Columns = 8;
  3634. UINT Rows = Length / Columns;
  3635. if (Length % Columns != 0) {
  3636. Rows++;
  3637. }
  3638. for (UINT j=0; j<Rows ; j++) {
  3639. for (UINT k=0; k<IndentLevel ; k++) {
  3640. DbgPrint("\t");
  3641. }
  3642. for (UINT i=0; i<Columns ; i++) {
  3643. DbgPrint("%02X ",Blob[ j*Columns + i ]);
  3644. if ((j*Columns + i) == Length) {
  3645. break;
  3646. }
  3647. }
  3648. DbgPrint("\n");
  3649. }
  3650. }
  3651. VOID
  3652. DumpPublicKeyInfo(
  3653. PEFS_PUBLIC_KEY_INFO PublicKeyInfo
  3654. )
  3655. {
  3656. DbgPrint("\t\tPublicKeyInfo:\n");
  3657. DbgPrint("\t\tLength = 0x%x\n",PublicKeyInfo->Length);
  3658. if (PublicKeyInfo->PossibleKeyOwner != NULL) {
  3659. PWCHAR SidString = ConvertSidToWideCharString( OFFSET_TO_POINTER( PossibleKeyOwner, PublicKeyInfo) );
  3660. DbgPrint("\t\tUserSid = %ws\n",SidString);
  3661. LsapFreeLsaHeap( SidString );
  3662. } else {
  3663. DbgPrint("\t\tUserSid = NULL\n");
  3664. }
  3665. switch (PublicKeyInfo->KeySourceTag) {
  3666. case EfsCryptoAPIContainer:
  3667. {
  3668. DbgPrint("\t\tTag = EfsCryptoAPIContainer\n");
  3669. DbgPrint("\t\tContainerName = %ws\n",OFFSET_TO_POINTER( ContainerInfo.ContainerName, PublicKeyInfo ));
  3670. DbgPrint("\t\tProviderName = %ws\n",OFFSET_TO_POINTER( ContainerInfo.ProviderName, PublicKeyInfo ));
  3671. DbgPrint("\t\tPublicKeyBlobLength = 0x%x\n",PublicKeyInfo->ContainerInfo.PublicKeyBlobLength);
  3672. DumpBytes( (PBYTE)OFFSET_TO_POINTER( ContainerInfo.PublicKeyBlob, PublicKeyInfo ), PublicKeyInfo->ContainerInfo.PublicKeyBlobLength, 2 );
  3673. break;
  3674. }
  3675. case EfsCertificateThumbprint:
  3676. {
  3677. DbgPrint("\t\tTag = EfsCertificateThumbprint\n");
  3678. PEFS_CERT_HASH_DATA CertHashData = (PEFS_CERT_HASH_DATA)OFFSET_TO_POINTER( CertificateThumbprint.CertHashData, PublicKeyInfo );
  3679. LPWSTR ContainerName = NULL;
  3680. if (CertHashData->ContainerName) {
  3681. LPWSTR ContainerName = (LPWSTR)OFFSET_TO_POINTER( ContainerName ,CertHashData);
  3682. DbgPrint("\t\tContainerName = %ws\n",ContainerName);
  3683. } else {
  3684. DbgPrint("\t\tContainerName = NULL\n");
  3685. }
  3686. LPWSTR ProviderName = NULL;
  3687. if (CertHashData->ProviderName) {
  3688. LPWSTR ProviderName = (LPWSTR)OFFSET_TO_POINTER( ProviderName ,CertHashData);
  3689. DbgPrint("\t\tProviderName = %ws\n",ProviderName);
  3690. } else {
  3691. DbgPrint("\t\tProviderName = NULL\n");
  3692. }
  3693. LPWSTR lpDisplayInformation = NULL;
  3694. if (CertHashData->lpDisplayInformation) {
  3695. LPWSTR lpDisplayInformation = (LPWSTR)OFFSET_TO_POINTER( lpDisplayInformation ,CertHashData);
  3696. DbgPrint("\t\tlpDisplayInformation = %ws\n",lpDisplayInformation);
  3697. } else {
  3698. DbgPrint("\t\tlpDisplayInformation = NULL\n");
  3699. }
  3700. DbgPrint("\t\tcbHash = 0x%x\n",CertHashData->cbHash );
  3701. DbgPrint("\t\tpbHash = \n");
  3702. PBYTE pbHash = (PBYTE)OFFSET_TO_POINTER( pbHash, CertHashData );
  3703. DumpBytes( pbHash, CertHashData->cbHash, 2);
  3704. break;
  3705. }
  3706. case EfsCertificate:
  3707. {
  3708. DbgPrint("KeySourceTag of EfsCertificate unexpected\n");
  3709. break;
  3710. }
  3711. default:
  3712. {
  3713. DbgPrint("Unknown KeySourceTag value: %d\n",PublicKeyInfo->KeySourceTag );
  3714. break;
  3715. }
  3716. }
  3717. }
  3718. VOID
  3719. DumpEncryptedKey(
  3720. PENCRYPTED_KEY EncryptedKey
  3721. )
  3722. {
  3723. DbgPrint("\tLength = 0x%x\n",EncryptedKey->Length);
  3724. PEFS_PUBLIC_KEY_INFO PublicKeyInfo = (PEFS_PUBLIC_KEY_INFO)OFFSET_TO_POINTER( PublicKeyInfo, EncryptedKey );
  3725. DumpPublicKeyInfo( PublicKeyInfo );
  3726. DbgPrint("\tEncryptedFEKLength = 0x%x\n",EncryptedKey->EncryptedFEKLength);
  3727. DbgPrint("\tEncryptedFEK = \n");
  3728. DumpBytes( (PBYTE)OFFSET_TO_POINTER( EncryptedFEK, EncryptedKey ), EncryptedKey->EncryptedFEKLength, 1 );
  3729. }
  3730. void
  3731. DumpRecoveryKey(
  3732. PRECOVERY_KEY_1_1 pRecoveryKey
  3733. )
  3734. {
  3735. DbgPrint("\nRecovery key @ 0x%x\n",pRecoveryKey);
  3736. DbgPrint("Length = 0x%x\n",pRecoveryKey->TotalLength);
  3737. DbgPrint("PublicKeyInfo:\n");
  3738. DumpPublicKeyInfo( &pRecoveryKey->PublicKeyInfo );
  3739. }
  3740. VOID
  3741. DumpEFS(
  3742. PEFS_DATA_STREAM_HEADER Efs
  3743. )
  3744. {
  3745. DbgPrint("\nEFS @ 0x%x:\n",Efs);
  3746. DbgPrint("Length = \t\t0x%x\n",Efs->Length);
  3747. DbgPrint("State = \t\t%d\n",Efs->State);
  3748. DbgPrint("EfsVersion = \t\t%d\n",Efs->EfsVersion);
  3749. DbgPrint("CryptoApiVersion = \t%d\n",Efs->CryptoApiVersion);
  3750. DbgPrint("Offset to DDF = \t0x%x\n",Efs->DataDecryptionField);
  3751. DbgPrint("Offset to DRF = \t0x%x\n",Efs->DataRecoveryField);
  3752. DbgPrint("Reserved = \t0x%x\n",Efs->Reserved);
  3753. DbgPrint("\nDDF:\n");
  3754. PENCRYPTED_KEYS Ddf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataDecryptionField, Efs );
  3755. DbgPrint("Number of keys = %d\n",Ddf->KeyCount );
  3756. UINT i;
  3757. PENCRYPTED_KEY EncryptedKey = &Ddf->EncryptedKey[0];
  3758. for (i=0; i<Ddf->KeyCount; i++) {
  3759. DbgPrint("\tKey %d:\n",i);
  3760. DumpEncryptedKey( EncryptedKey );
  3761. EncryptedKey = (PENCRYPTED_KEY)(((PBYTE)EncryptedKey) + EncryptedKey->Length);
  3762. }
  3763. DbgPrint("\nDRF:\n");
  3764. PENCRYPTED_KEYS Drf = (PENCRYPTED_KEYS)OFFSET_TO_POINTER( DataRecoveryField, Efs );
  3765. DbgPrint("Number of keys = %d\n",Drf->KeyCount );
  3766. EncryptedKey = &Drf->EncryptedKey[0];
  3767. for (i=0; i<Drf->KeyCount; i++) {
  3768. DbgPrint("\tKey %d:\n",i);
  3769. DumpEncryptedKey( EncryptedKey );
  3770. EncryptedKey = (PENCRYPTED_KEY)(((PBYTE)EncryptedKey) + EncryptedKey->Length);
  3771. }
  3772. }
  3773. #if 0
  3774. BOOLEAN
  3775. EfspChecksumEfs(
  3776. PEFS_DATA_STREAM_HEADER pEFS,
  3777. PEFS_KEY Fek
  3778. )
  3779. /*++
  3780. Routine Description:
  3781. This routine will checksum the passed EFS stream and fill in the checksum
  3782. field in the header. Assumes that the checksum field itself is set to 0.
  3783. Arguments:
  3784. pEFS - Supplies the EFS stream to be checksum'd. Assume that this structure
  3785. has been fully filled in.
  3786. Fek - Supplies a pointer to the FEK for the file.
  3787. Return Value:
  3788. TRUE on success, FALSE on failure. Sets LastErrror.
  3789. --*/
  3790. {
  3791. HCRYPTHASH hHash = 0;
  3792. DWORD dwHashedDataLength = MD5_HASH_SIZE;
  3793. BOOL b = FALSE;
  3794. DWORD rc = ERROR_SUCCESS;
  3795. if (CryptCreateHash( hProvVerify, CALG_MD5, 0, 0, &hHash )) {
  3796. if (CryptHashData( hHash, (PBYTE)pEFS, pEFS->Length, 0 )) {
  3797. if (CryptHashData( hHash, EFS_KEY_DATA( Fek ), Fek->KeyLength, 0 )) {
  3798. if (CryptGetHashParam( hHash, HP_HASHVAL, (PBYTE)(&pEFS->EfsHash), &dwHashedDataLength, 0 )) {
  3799. ASSERT( dwHashedDataLength == MD5_HASH_SIZE );
  3800. b = TRUE;
  3801. } else {
  3802. rc = GetLastError();
  3803. ASSERT( rc != ERROR_SUCCESS );
  3804. }
  3805. } else {
  3806. rc = GetLastError();
  3807. ASSERT( rc != ERROR_SUCCESS );
  3808. }
  3809. } else {
  3810. rc = GetLastError();
  3811. ASSERT( rc != ERROR_SUCCESS );
  3812. }
  3813. CryptDestroyHash( hHash );
  3814. } else {
  3815. rc = GetLastError();
  3816. ASSERT( rc != ERROR_SUCCESS );
  3817. }
  3818. SetLastError( rc );
  3819. return( b != 0);
  3820. }
  3821. BOOLEAN
  3822. EfspValidateEfsStream(
  3823. PEFS_DATA_STREAM_HEADER pEFS,
  3824. PEFS_KEY Fek
  3825. )
  3826. /*++
  3827. Routine Description:
  3828. This routine checks the checksum in an EFS stream.
  3829. Arguments:
  3830. pEFS - Supplies the EFS stream to be validated.
  3831. Fek - Supplies the FEK of the encrypted file.
  3832. Return Value:
  3833. TRUE on success, FALSE on failure.
  3834. --*/
  3835. {
  3836. DWORD dwHashSize = MD5_HASH_SIZE ;
  3837. UCHAR SavedChecksum[ MD5_HASH_SIZE ];
  3838. UCHAR NewCheckSum [ MD5_HASH_SIZE ];
  3839. BOOL b = FALSE;
  3840. HCRYPTHASH hHash = 0;
  3841. HCRYPTPROV hProv;
  3842. DWORD rc = ERROR_SUCCESS;
  3843. //
  3844. // We have to do the checksum with the checksum in the header
  3845. // zero'd out. Save the original in a local.
  3846. //
  3847. memcpy( SavedChecksum, &pEFS->EfsHash, MD5_HASH_SIZE );
  3848. memset( &pEFS->EfsHash, 0, MD5_HASH_SIZE );
  3849. if (CryptCreateHash( hProvVerify, CALG_MD5, 0, 0, &hHash )) {
  3850. if (CryptHashData( hHash, (PBYTE)pEFS, pEFS->Length, 0 )) {
  3851. if (CryptHashData( hHash, EFS_KEY_DATA( Fek ), Fek->KeyLength, 0 )) {
  3852. if (CryptGetHashParam( hHash, HP_HASHVAL, NewCheckSum, &dwHashSize, 0 )) {
  3853. ASSERT( dwHashSize == MD5_HASH_SIZE );
  3854. if (memcmp( NewCheckSum, SavedChecksum, MD5_HASH_SIZE ) == 0) {
  3855. b = TRUE;
  3856. } else {
  3857. rc = ERROR_ACCESS_DENIED;
  3858. }
  3859. } else {
  3860. rc = GetLastError();
  3861. ASSERT( rc != ERROR_SUCCESS );
  3862. }
  3863. } else {
  3864. rc = GetLastError();
  3865. ASSERT( rc != ERROR_SUCCESS );
  3866. }
  3867. } else {
  3868. rc = GetLastError();
  3869. ASSERT( rc != ERROR_SUCCESS );
  3870. }
  3871. CryptDestroyHash( hHash );
  3872. } else {
  3873. rc = GetLastError();
  3874. ASSERT( rc != ERROR_SUCCESS );
  3875. }
  3876. //
  3877. // Copy back the original
  3878. //
  3879. memcpy( &pEFS->EfsHash, SavedChecksum, MD5_HASH_SIZE );
  3880. SetLastError( rc );
  3881. return( b != 0);
  3882. }
  3883. #endif
  3884. BOOL
  3885. GetSaltLength(
  3886. ALG_ID AlgID,
  3887. DWORD *SaltLength,
  3888. DWORD *SaltBlockLength
  3889. )
  3890. /*++
  3891. Routine Description:
  3892. This routine returns the length of key salt
  3893. Arguments:
  3894. AlgID - Encryption Algorithm ID.
  3895. SaltLength - Bytes to be copied from key.
  3896. SaltBlockLength - Bytes of key salt block in $EFS
  3897. Return Value:
  3898. TRUE on success, FALSE on failure.
  3899. --*/
  3900. {
  3901. BOOL b = FALSE;
  3902. switch (AlgID){
  3903. case CALG_DESX:
  3904. *SaltLength = EXPORT_DESX_SALT_LENGTH;
  3905. *SaltBlockLength = (EXPORT_DESX_SALT_LENGTH + 4 ) & 0xfffffffc;
  3906. b = TRUE;
  3907. break;
  3908. default:
  3909. *SaltLength = 0;
  3910. *SaltBlockLength = 0;
  3911. break;
  3912. }
  3913. return b;
  3914. }
  3915. VOID
  3916. EfspUnloadUserProfile(
  3917. IN HANDLE hToken,
  3918. IN HANDLE hProfile
  3919. )
  3920. /*++
  3921. Routine Description:
  3922. Cleans up after a call to EfspLoadUserProfile. Returns impersonating our client.
  3923. Arguments:
  3924. hToken - The token handle returned from EfspLoadUserProfile. This handle will be closed!
  3925. hProfile - The profile handle returned from EfspLoadUserProfile. This handle will not
  3926. be modified.
  3927. Return Value:
  3928. None.
  3929. --*/
  3930. {
  3931. NTSTATUS Status;
  3932. if (!hToken) {
  3933. //
  3934. // SYSTEM context. The profile was not loaded by EFS.
  3935. //
  3936. return;
  3937. }
  3938. RevertToSelf();
  3939. (VOID) UnloadUserProfile (hToken, hProfile);
  3940. //
  3941. // Start impersonating again
  3942. //
  3943. Status = NtSetInformationThread(
  3944. NtCurrentThread(),
  3945. ThreadImpersonationToken,
  3946. (PVOID) &hToken,
  3947. sizeof(HANDLE)
  3948. );
  3949. if (!NT_SUCCESS( Status )) {
  3950. DebugLog((DEB_ERROR, "EfspUnloadUserProfile: NtSetInformationThread returned %x\n" ,Status ));
  3951. }
  3952. NtClose( hToken );
  3953. return;
  3954. }
  3955. VOID
  3956. EfspFreeUserCache(
  3957. IN PUSER_CACHE pUserCache
  3958. )
  3959. {
  3960. if (pUserCache == NULL){
  3961. return;
  3962. }
  3963. if (pUserCache->pbHash) {
  3964. LsapFreeLsaHeap( pUserCache->pbHash );
  3965. }
  3966. if (pUserCache->ContainerName) {
  3967. LsapFreeLsaHeap( pUserCache->ContainerName );
  3968. }
  3969. if (pUserCache->DisplayInformation) {
  3970. LsapFreeLsaHeap( pUserCache->DisplayInformation );
  3971. }
  3972. if (pUserCache->ProviderName) {
  3973. LsapFreeLsaHeap( pUserCache->ProviderName );
  3974. }
  3975. if (pUserCache->pCertContext) {
  3976. CertFreeCertificateContext( pUserCache->pCertContext );
  3977. }
  3978. if (pUserCache->hUserKey) {
  3979. CryptDestroyKey( pUserCache->hUserKey );
  3980. }
  3981. if (pUserCache->hProv) {
  3982. CryptReleaseContext( pUserCache->hProv, 0 );
  3983. }
  3984. LsapFreeLsaHeap( pUserCache );
  3985. }
  3986. VOID
  3987. EfspReleaseUserCache(
  3988. IN PUSER_CACHE pUserCache
  3989. )
  3990. /*++
  3991. Routine Description:
  3992. Decrease the ref count increased by the EfspGetUserCache
  3993. Arguments:
  3994. pUserCache - Cache node
  3995. Return Value:
  3996. --*/
  3997. {
  3998. RtlEnterCriticalSection( &GuardCacheListLock );
  3999. pUserCache->UseRefCount-- ;
  4000. RtlLeaveCriticalSection( &GuardCacheListLock );
  4001. }
  4002. PUSER_CACHE
  4003. EfspGetUserCache(
  4004. IN OUT PEFS_USER_INFO pEfsUserInfo
  4005. )
  4006. /*++
  4007. Routine Description:
  4008. This routine will try to find the user's cert info in the cache list.
  4009. If return not NULL, this call must be balanced with a EfspReleaseUserCache(PUSER_CACHE pUserCache)
  4010. Arguments:
  4011. pEfsUserInfo - User Info
  4012. Return Value:
  4013. User cache list node, if match found in the cache.
  4014. NULL if not found.
  4015. --*/
  4016. {
  4017. PLIST_ENTRY pListHead, pLink;
  4018. PUSER_CACHE pUserCache;
  4019. //
  4020. // Check to see if there is cache available
  4021. //
  4022. pEfsUserInfo->UserCacheStop = FALSE;
  4023. RtlEnterCriticalSection( &GuardCacheListLock );
  4024. if (UserCacheList.Flink == &UserCacheList) {
  4025. //
  4026. // list empty
  4027. //
  4028. RtlLeaveCriticalSection( &GuardCacheListLock );
  4029. return NULL;
  4030. }
  4031. for (pLink = UserCacheList.Flink; pLink != &UserCacheList; pLink = pLink->Flink) {
  4032. pUserCache = CONTAINING_RECORD(pLink, USER_CACHE, CacheChain);
  4033. ASSERT( pLink );
  4034. ASSERT( pLink->Flink );
  4035. if ( (pEfsUserInfo->AuthId.LowPart == pUserCache->AuthId.LowPart) &&
  4036. (pEfsUserInfo->AuthId.HighPart == pUserCache->AuthId.HighPart)) {
  4037. //
  4038. // Find the cache node. Hold it
  4039. //
  4040. if (pUserCache->StopUseCount) {
  4041. //
  4042. // Free cache waiting
  4043. // When cache for a session is stopped, both interactive and non-interactive should be stopped
  4044. //
  4045. pEfsUserInfo->UserCacheStop = TRUE;
  4046. RtlLeaveCriticalSection( &GuardCacheListLock );
  4047. return NULL;
  4048. }
  4049. pUserCache->UseRefCount++;
  4050. RtlLeaveCriticalSection( &GuardCacheListLock );
  4051. return pUserCache;
  4052. }
  4053. }
  4054. RtlLeaveCriticalSection( &GuardCacheListLock );
  4055. return NULL;
  4056. }
  4057. BOOLEAN
  4058. EfspAddUserCache(
  4059. IN PUSER_CACHE pUserCache
  4060. )
  4061. /*++
  4062. Routine Description:
  4063. This routine will try to add the user's cert info in the cache list.
  4064. If return TRUE, this call must be balanced with a EfspReleaseUserCache(PUSER_CACHE pUserCache)
  4065. Arguments:
  4066. pUserCache - User Cache node.
  4067. Return Value:
  4068. TRUE if added successfully
  4069. FALSE if the list is full.
  4070. --*/
  4071. {
  4072. PLIST_ENTRY pListHead, pLink;
  4073. PUSER_CACHE pUserTmpCache;
  4074. RtlEnterCriticalSection( &GuardCacheListLock );
  4075. if (UserCacheListCount >= UserCacheListLimit) {
  4076. //
  4077. // Let's see if we can kick someone out.
  4078. //
  4079. pLink = UserCacheList.Blink;
  4080. while ( pLink != &UserCacheList ){
  4081. pUserTmpCache = CONTAINING_RECORD(pLink, USER_CACHE, CacheChain);
  4082. ASSERT( pLink );
  4083. ASSERT( pLink->Blink );
  4084. pLink = pLink->Blink;
  4085. if ( pUserTmpCache->UseRefCount <= 0 ){
  4086. //
  4087. // No one is using it. Let's remove it.
  4088. //
  4089. RemoveEntryList(&( pUserTmpCache->CacheChain ));
  4090. UserCacheListCount--;
  4091. EfspFreeUserCache( pUserTmpCache );
  4092. break;
  4093. }
  4094. }
  4095. if (UserCacheListCount >= UserCacheListLimit) {
  4096. RtlLeaveCriticalSection( &GuardCacheListLock );
  4097. return FALSE;
  4098. }
  4099. }
  4100. InsertHeadList(&UserCacheList, &( pUserCache->CacheChain ));
  4101. UserCacheListCount++;
  4102. RtlLeaveCriticalSection( &GuardCacheListLock );
  4103. return TRUE;
  4104. }
  4105. BOOLEAN
  4106. EfspGetUserInfo(
  4107. IN OUT PEFS_USER_INFO pEfsUserInfo
  4108. )
  4109. /*++
  4110. Routine Description:
  4111. This routine obtains all the interesting information about the user
  4112. that we're going to need later.
  4113. Arguments:
  4114. pEfsUserInfo - Supplies a pointer to an EfsUserInfo structure which
  4115. will be filled in.
  4116. Return Value:
  4117. return-value - Description of conditions needed to return value. - or -
  4118. None.
  4119. --*/
  4120. {
  4121. NTSTATUS Status;
  4122. BOOLEAN fReturn = FALSE;
  4123. DWORD rc = ERROR_SUCCESS;
  4124. memset( pEfsUserInfo, 0, sizeof( EFS_USER_INFO ));
  4125. Status = EfspGetUserName(pEfsUserInfo);
  4126. if (NT_SUCCESS( Status )) {
  4127. EfspIsDomainUser( pEfsUserInfo->lpDomainName, &pEfsUserInfo->bDomainAccount );
  4128. EfspIsSystem( pEfsUserInfo, &pEfsUserInfo->bIsSystem );
  4129. if (pEfsUserInfo->bIsSystem) {
  4130. pEfsUserInfo->bDomainAccount = FALSE;
  4131. }
  4132. fReturn = TRUE;
  4133. pEfsUserInfo->pUserCache = EfspGetUserCache( pEfsUserInfo );
  4134. } else {
  4135. rc = RtlNtStatusToDosError( Status );
  4136. }
  4137. SetLastError( rc );
  4138. return( fReturn );
  4139. }
  4140. VOID
  4141. EfspFreeUserInfo(
  4142. IN PEFS_USER_INFO pEfsUserInfo
  4143. )
  4144. /*++
  4145. Routine Description:
  4146. Frees the memory allocated by EfspGetUserInfo(). Does
  4147. not free the passed structure.
  4148. Arguments:
  4149. pEfsUserInfo - Supplies a pointer to the structure to be
  4150. de-allocated.
  4151. Return Value:
  4152. None.
  4153. --*/
  4154. {
  4155. if (pEfsUserInfo->lpUserName) {
  4156. LsapFreeLsaHeap( pEfsUserInfo->lpUserName );
  4157. }
  4158. if (pEfsUserInfo->lpDomainName) {
  4159. LsapFreeLsaHeap( pEfsUserInfo->lpDomainName );
  4160. }
  4161. if (pEfsUserInfo->lpProfilePath) {
  4162. LsapFreeLsaHeap( pEfsUserInfo->lpProfilePath );
  4163. }
  4164. if (pEfsUserInfo->pTokenUser) {
  4165. LsapFreeLsaHeap( pEfsUserInfo->pTokenUser );
  4166. }
  4167. if (pEfsUserInfo->lpUserSid) {
  4168. UNICODE_STRING Dummy;
  4169. Dummy.Buffer = pEfsUserInfo->lpUserSid;
  4170. RtlFreeUnicodeString(&Dummy);
  4171. }
  4172. if (pEfsUserInfo->lpKeyPath) {
  4173. LsapFreeLsaHeap( pEfsUserInfo->lpKeyPath );
  4174. }
  4175. if (pEfsUserInfo->pUserCache) {
  4176. /*
  4177. #if DBG
  4178. DbgPrint("Cache Ref Count Before Release = %ld\n",pEfsUserInfo->pUserCache->UseRefCount);
  4179. #endif
  4180. */
  4181. EfspReleaseUserCache(pEfsUserInfo->pUserCache);
  4182. /*
  4183. #if DBG
  4184. DbgPrint("Cache Ref Count After Release = %ld\n",pEfsUserInfo->pUserCache->UseRefCount);
  4185. #endif
  4186. */
  4187. }
  4188. return;
  4189. }
  4190. BOOL
  4191. EfspLoadUserProfile(
  4192. IN PEFS_USER_INFO pEfsUserInfo,
  4193. OUT PHANDLE hToken,
  4194. OUT PHANDLE hProfile
  4195. )
  4196. /*++
  4197. Routine Description:
  4198. This routine attempts to determine if the user's profile is loaded,
  4199. and if it is not, loads it.
  4200. Callers are expected to call EfspUnloadUserProfile() during their cleanup.
  4201. Arguments:
  4202. pEfsUserInfo - Supplies useful information about the current user.
  4203. hToken - Returns a handle to the user's token.
  4204. hProfile - Returns a handle to the user's profile.
  4205. Return Value:
  4206. TRUE if the profile is already loaded or if this routine loads it successfully,
  4207. FALSE otherwise.
  4208. --*/
  4209. {
  4210. DWORD rc = ERROR_SUCCESS;
  4211. BOOLEAN b = FALSE;
  4212. BOOL fReturn = FALSE;
  4213. LPWSTR lpServerName = NULL;
  4214. PUSER_INFO_3 lpUserInfo = NULL;
  4215. LPWSTR lpLocalProfilePath = NULL;
  4216. BOOLEAN DomainUser = pEfsUserInfo->bDomainAccount;
  4217. BOOLEAN IsSystem = pEfsUserInfo->bIsSystem;
  4218. LPWSTR lpDomainName = pEfsUserInfo->lpDomainName;
  4219. LPWSTR lpProfilePath = pEfsUserInfo->lpProfilePath;
  4220. LPWSTR lpUserName = pEfsUserInfo->lpUserName;
  4221. LPWSTR SidString = pEfsUserInfo->lpUserSid;
  4222. NTSTATUS Status;
  4223. PDOMAIN_CONTROLLER_INFO DomainControllerInfo = NULL;
  4224. *hToken = NULL;
  4225. *hProfile = NULL;
  4226. if (IsSystem) {
  4227. return TRUE;
  4228. }
  4229. if (pEfsUserInfo->InterActiveUser == USER_INTERACTIVE) {
  4230. return TRUE;
  4231. }
  4232. Status = NtOpenThreadToken(
  4233. NtCurrentThread(),
  4234. TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
  4235. TRUE, // OpenAsSelf
  4236. hToken
  4237. );
  4238. if (NT_SUCCESS( Status )) {
  4239. LONG lRet;
  4240. HKEY phKeyCurrentUser;
  4241. lRet = RegOpenKeyExW(
  4242. HKEY_USERS,
  4243. SidString,
  4244. 0, // dwOptions
  4245. MAXIMUM_ALLOWED,
  4246. &phKeyCurrentUser
  4247. );
  4248. if (ERROR_SUCCESS == lRet) {
  4249. //
  4250. // The profile is loaded. Ref it so it doesn't disappear.
  4251. //
  4252. PROFILEINFO pi;
  4253. ZeroMemory (&pi, sizeof(pi));
  4254. pi.dwSize = sizeof(pi);
  4255. pi.lpUserName = lpUserName;
  4256. pi.dwFlags = PI_LITELOAD;
  4257. //
  4258. // Cannot be impersonating when loading the profile
  4259. //
  4260. RevertToSelf();
  4261. __try {
  4262. fReturn = LoadUserProfile (*hToken, &pi);
  4263. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  4264. fReturn = FALSE;
  4265. SetLastError( GetExceptionCode() );
  4266. }
  4267. if (!fReturn) {
  4268. rc = GetLastError();
  4269. } else {
  4270. *hProfile = pi.hProfile;
  4271. }
  4272. //
  4273. // Start impersonating again
  4274. //
  4275. Status = NtSetInformationThread(
  4276. NtCurrentThread(),
  4277. ThreadImpersonationToken,
  4278. (PVOID) hToken,
  4279. sizeof(HANDLE)
  4280. );
  4281. if (!NT_SUCCESS( Status )) {
  4282. //
  4283. // Well, if we can't start impersonating again,
  4284. // we're not going to be able to continue the operation.
  4285. // So unload the profile and fail this whole thing.
  4286. //
  4287. if (fReturn) {
  4288. (VOID) UnloadUserProfile (*hToken, *hProfile);
  4289. }
  4290. fReturn = FALSE;
  4291. DebugLog((DEB_ERROR, "EfspLoadUserProfile: Unloading profile, NtSetInformationThread returned %x\n" ,Status ));
  4292. rc = RtlNtStatusToDosError( Status );
  4293. }
  4294. RegCloseKey( phKeyCurrentUser );
  4295. } else {
  4296. //
  4297. // The profile is not loaded. Load it.
  4298. //
  4299. if (IsSystem) {
  4300. lpLocalProfilePath = NULL;
  4301. DebugLog((DEB_TRACE_EFS, "Attempting to open stream from System context\n" ));
  4302. } else {
  4303. if (lpProfilePath != NULL) {
  4304. //
  4305. // We got the profile path from the logon information.
  4306. //
  4307. DebugLog((DEB_TRACE_EFS, "Got profile path %ws from logon information", lpProfilePath ));
  4308. //
  4309. // Do this up here so we can have common code below.
  4310. //
  4311. // RevertToSelf();
  4312. lpLocalProfilePath = lpProfilePath;
  4313. } else {
  4314. //
  4315. // We didn't get a profile path from the logon information,
  4316. // do it the slow way.
  4317. //
  4318. DebugLog((DEB_TRACE_EFS, "Attempting to compute profile information\n" ));
  4319. BOOLEAN fGotServerName = TRUE;
  4320. if (DomainUser) {
  4321. //
  4322. // Determine the name of the DC for this domain
  4323. //
  4324. rc = DsGetDcName(
  4325. NULL,
  4326. lpDomainName,
  4327. NULL,
  4328. NULL,
  4329. NULL,
  4330. &DomainControllerInfo
  4331. );
  4332. if (ERROR_SUCCESS == rc) {
  4333. lpServerName = DomainControllerInfo->DomainControllerName;
  4334. } else {
  4335. DebugLog((DEB_ERROR, "Failed to obtain DC Name from DsGetDcName, error = %d\n" ,rc ));
  4336. fGotServerName = FALSE;
  4337. }
  4338. } else {
  4339. //
  4340. // Local user, query the local machine
  4341. //
  4342. lpServerName = NULL;
  4343. }
  4344. if (fGotServerName) {
  4345. //
  4346. // Need to do this so that NetUserGetInfo will work.
  4347. // If we don't, the server may fail trying to impersonate us,
  4348. // and then the API will fail. If we revert, then it will only
  4349. // fail if the machine has been denied access.
  4350. //
  4351. // RevertToSelf();
  4352. rc = NetUserGetInfo( lpServerName, lpUserName, 3, (LPBYTE *)&lpUserInfo );
  4353. if (ERROR_SUCCESS == rc) {
  4354. lpLocalProfilePath = lpUserInfo->usri3_profile;
  4355. } else {
  4356. DebugLog((DEB_ERROR, "NetUserGetInfo failed, error = %d\n" ,rc ));
  4357. //
  4358. // Start impersonating again
  4359. //
  4360. /* No need to do this. We are still impersonating.
  4361. Status = NtSetInformationThread(
  4362. NtCurrentThread(),
  4363. ThreadImpersonationToken,
  4364. (PVOID) hToken,
  4365. sizeof(HANDLE)
  4366. );
  4367. if (!NT_SUCCESS( Status )) {
  4368. fReturn = FALSE;
  4369. DebugLog((DEB_ERROR, "EfspLoadUserProfile: NtSetInformationThread returned %x\n" ,Status ));
  4370. rc = RtlNtStatusToDosError( Status );
  4371. }
  4372. */
  4373. }
  4374. }
  4375. }
  4376. }
  4377. //
  4378. // Make sure we revert before calling LoadUserProfile
  4379. //
  4380. RevertToSelf();
  4381. //
  4382. // We have a profile path. Note that it may be NULL.
  4383. //
  4384. DebugLog((DEB_TRACE_EFS, "Loading profile path %ws\n" , (lpLocalProfilePath == NULL ? L"NULL" : lpLocalProfilePath)));
  4385. PROFILEINFO pi;
  4386. ZeroMemory (&pi, sizeof(pi));
  4387. pi.dwSize = sizeof(pi);
  4388. pi.lpUserName = lpUserName;
  4389. pi.lpProfilePath = lpLocalProfilePath;
  4390. pi.dwFlags = PI_LITELOAD;
  4391. __try {
  4392. fReturn = LoadUserProfile (*hToken, &pi);
  4393. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  4394. fReturn = FALSE;
  4395. SetLastError( GetExceptionCode() );
  4396. }
  4397. if (!fReturn) {
  4398. rc = GetLastError();
  4399. DebugLog((DEB_ERROR, "LoadUserProfile failed, error = %d\n" ,rc ));
  4400. } else {
  4401. *hProfile = pi.hProfile;
  4402. }
  4403. //
  4404. // Start impersonating again, at least until LoadUserProfile
  4405. // stops turning off impersonation.
  4406. //
  4407. Status = NtSetInformationThread(
  4408. NtCurrentThread(),
  4409. ThreadImpersonationToken,
  4410. (PVOID) hToken,
  4411. sizeof(HANDLE)
  4412. );
  4413. if (!NT_SUCCESS( Status )) {
  4414. fReturn = FALSE;
  4415. DebugLog((DEB_ERROR, "EfspLoadUserProfile: NtSetInformationThread returned %x\n" ,Status ));
  4416. rc = RtlNtStatusToDosError( Status );
  4417. }
  4418. if (lpUserInfo != NULL) {
  4419. NetApiBufferFree( lpUserInfo );
  4420. }
  4421. }
  4422. if (lpServerName) {
  4423. NetApiBufferFree( DomainControllerInfo );
  4424. }
  4425. if (!fReturn) {
  4426. //
  4427. // We did not succeed for some reason.
  4428. // Clean up what we were going to return.
  4429. //
  4430. NtClose( *hToken );
  4431. }
  4432. } else {
  4433. SetLastError( RtlNtStatusToDosError( Status ));
  4434. }
  4435. SetLastError( rc );
  4436. return( fReturn );
  4437. }
  4438. DWORD
  4439. GenerateDRF(
  4440. IN PEFS_KEY Fek,
  4441. OUT PENCRYPTED_KEYS *pNewDRF,
  4442. OUT DWORD *cbDRF
  4443. )
  4444. {
  4445. DWORD rc;
  4446. DWORD DRFKeyCount;
  4447. DWORD DRFStatus;
  4448. PBYTE * DRFPublicKeys;
  4449. DWORD * DRFPublicKeyLengths;
  4450. PBYTE * DRFCertHashes;
  4451. DWORD * DRFCertHashLengths;
  4452. LPWSTR * DRFDisplayInformation;
  4453. PSID * pDRFSid;
  4454. *pNewDRF = NULL;
  4455. *cbDRF = 0;
  4456. rc = GetRecoveryData(
  4457. &DRFKeyCount,
  4458. &DRFStatus,
  4459. &DRFPublicKeys,
  4460. &DRFPublicKeyLengths,
  4461. &DRFCertHashes,
  4462. &DRFCertHashLengths,
  4463. &DRFDisplayInformation,
  4464. &pDRFSid
  4465. );
  4466. if (rc == ERROR_SUCCESS) {
  4467. if (DRFKeyCount > 0) {
  4468. rc = ConstructKeyRing(
  4469. Fek,
  4470. DRFKeyCount,
  4471. NULL, // No key name information for recovery agents
  4472. NULL,
  4473. DRFPublicKeys,
  4474. DRFPublicKeyLengths,
  4475. DRFCertHashes,
  4476. DRFCertHashLengths,
  4477. DRFDisplayInformation,
  4478. pDRFSid,
  4479. FALSE,
  4480. pNewDRF,
  4481. cbDRF
  4482. );
  4483. } else {
  4484. //
  4485. // No DRF will be returned
  4486. //
  4487. if (DRFStatus < RECOVERY_POLICY_OK) {
  4488. //
  4489. // EFS will go ahead with encryption without DRF
  4490. //
  4491. rc = ERROR_SUCCESS;
  4492. } else {
  4493. rc = ERROR_BAD_RECOVERY_POLICY;
  4494. }
  4495. }
  4496. }
  4497. return rc;
  4498. }
  4499. BOOLEAN
  4500. EqualEncryptedKeys(
  4501. IN PENCRYPTED_KEYS SrcKeys,
  4502. IN PENCRYPTED_KEYS DstKeys,
  4503. IN DWORD cbDstKeys
  4504. )
  4505. /*++
  4506. Routine Description:
  4507. This routine compares two encrypted key arrays.
  4508. Arguments:
  4509. SrcKeys - Source key arrays.
  4510. DstKeys - Destination key arrays.
  4511. cbDstKeys - Destination key array size.
  4512. Return Value:
  4513. TRUE if the profile is already loaded or if this routine loads it successfully,
  4514. FALSE otherwise.
  4515. --*/
  4516. {
  4517. DWORD cbSrcKeys = 0;
  4518. ULONG KeyCount = *(ULONG UNALIGNED *) &(SrcKeys->KeyCount);
  4519. PENCRYPTED_KEY pEncryptedKey;
  4520. ULONG keyLength;
  4521. if (KeyCount != DstKeys->KeyCount ) {
  4522. return FALSE;
  4523. }
  4524. pEncryptedKey = &(SrcKeys->EncryptedKey[0]);
  4525. while ( KeyCount > 0 ) {
  4526. keyLength = * (ULONG UNALIGNED *) &(pEncryptedKey->Length);
  4527. cbSrcKeys += keyLength;
  4528. pEncryptedKey = (PENCRYPTED_KEY)( ((PBYTE)pEncryptedKey) + keyLength );
  4529. KeyCount--;
  4530. }
  4531. cbSrcKeys += (sizeof ( ENCRYPTED_KEYS ) - sizeof( ENCRYPTED_KEY ));
  4532. if ( cbSrcKeys != cbDstKeys ) {
  4533. return FALSE;
  4534. }
  4535. return RtlEqualMemory( SrcKeys, DstKeys, cbDstKeys);
  4536. }
  4537. DWORD
  4538. EfsGetCertNameFromCertContext(
  4539. PCCERT_CONTEXT CertContext,
  4540. LPWSTR * UserDispName
  4541. )
  4542. /*++
  4543. Routine Description:
  4544. Get the user name from the certificate
  4545. Arguments:
  4546. CertContext -- Cert Context
  4547. UserCertName -- User Common Name ( Caller is responsible to delete this memory )
  4548. Return Value:
  4549. ERROR_SUCCESS if succeed.
  4550. If No Name found. "USER_UNKNOWN is returned".
  4551. --*/
  4552. {
  4553. DWORD NameLength;
  4554. DWORD UserNameBufLen = 0;
  4555. DWORD BlobLen = 0;
  4556. PCERT_EXTENSION AlterNameExt = NULL;
  4557. BOOL b;
  4558. LPWSTR DNSName = NULL;
  4559. LPWSTR UPNName = NULL;
  4560. LPWSTR CommonName = NULL;
  4561. DWORD rc = ERROR_SUCCESS;
  4562. if ( NULL == UserDispName ){
  4563. return ERROR_SUCCESS;
  4564. }
  4565. *UserDispName = NULL;
  4566. AlterNameExt = CertFindExtension(
  4567. szOID_SUBJECT_ALT_NAME2,
  4568. CertContext->pCertInfo->cExtension,
  4569. CertContext->pCertInfo->rgExtension
  4570. );
  4571. if (AlterNameExt){
  4572. //
  4573. // Find the alternative name
  4574. //
  4575. b = CryptDecodeObject(
  4576. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4577. szOID_SUBJECT_ALT_NAME ,
  4578. AlterNameExt->Value.pbData,
  4579. AlterNameExt->Value.cbData,
  4580. 0,
  4581. NULL,
  4582. &BlobLen
  4583. );
  4584. if (b){
  4585. //
  4586. // Let's decode it
  4587. //
  4588. CERT_ALT_NAME_INFO *AltNameInfo = NULL;
  4589. AltNameInfo = (CERT_ALT_NAME_INFO *) LsapAllocateLsaHeap( BlobLen );
  4590. if (AltNameInfo){
  4591. b = CryptDecodeObject(
  4592. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4593. szOID_SUBJECT_ALT_NAME,
  4594. AlterNameExt->Value.pbData,
  4595. AlterNameExt->Value.cbData,
  4596. 0,
  4597. AltNameInfo,
  4598. &BlobLen
  4599. );
  4600. if (b){
  4601. //
  4602. // Now search for the UPN, SPN, DNS, EFS name
  4603. //
  4604. DWORD cAltEntry = AltNameInfo->cAltEntry;
  4605. DWORD ii = 0;
  4606. while (ii < cAltEntry){
  4607. if ((AltNameInfo->rgAltEntry[ii].dwAltNameChoice == CERT_ALT_NAME_OTHER_NAME ) &&
  4608. !strcmp(szOID_NT_PRINCIPAL_NAME, AltNameInfo->rgAltEntry[ii].pOtherName->pszObjId)
  4609. ){
  4610. //
  4611. // We found the UPN name
  4612. //
  4613. CERT_NAME_VALUE* CertUPNName = NULL;
  4614. b = CryptDecodeObject(
  4615. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4616. X509_UNICODE_ANY_STRING,
  4617. AltNameInfo->rgAltEntry[ii].pOtherName->Value.pbData,
  4618. AltNameInfo->rgAltEntry[ii].pOtherName->Value.cbData,
  4619. 0,
  4620. NULL,
  4621. &BlobLen
  4622. );
  4623. if (b){
  4624. CertUPNName = (CERT_NAME_VALUE *) LsapAllocateLsaHeap(BlobLen);
  4625. if (CertUPNName){
  4626. b = CryptDecodeObject(
  4627. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4628. X509_UNICODE_ANY_STRING,
  4629. AltNameInfo->rgAltEntry[ii].pOtherName->Value.pbData,
  4630. AltNameInfo->rgAltEntry[ii].pOtherName->Value.cbData,
  4631. 0,
  4632. CertUPNName,
  4633. &BlobLen
  4634. );
  4635. if (b){
  4636. UPNName = (LPWSTR)LsapAllocateLsaHeap( CertUPNName->Value.cbData + sizeof(WCHAR) );
  4637. if (UPNName){
  4638. wcscpy(UPNName, (LPCWSTR) CertUPNName->Value.pbData);
  4639. }
  4640. }
  4641. LsapFreeLsaHeap(CertUPNName);
  4642. if (UPNName){
  4643. //
  4644. // Got the UPN name. Stop searching.
  4645. //
  4646. break;
  4647. }
  4648. }
  4649. }
  4650. } else {
  4651. //
  4652. // Check for other alternative name
  4653. //
  4654. if (AltNameInfo->rgAltEntry[ii].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME){
  4655. DNSName = AltNameInfo->rgAltEntry[ii].pwszDNSName;
  4656. }
  4657. }
  4658. ii++;
  4659. }
  4660. if ( NULL == UPNName ){
  4661. //
  4662. // No UPN name, let's get the other option
  4663. //
  4664. if (DNSName){
  4665. UPNName = (LPTSTR) LsapAllocateLsaHeap ( sizeof(WCHAR) * (wcslen( DNSName ) + 1));
  4666. if (UPNName){
  4667. wcscpy(UPNName, DNSName);
  4668. }
  4669. }
  4670. }
  4671. }
  4672. LsapFreeLsaHeap(AltNameInfo);
  4673. }
  4674. }
  4675. }
  4676. NameLength = CertGetNameString(
  4677. CertContext,
  4678. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  4679. 0,
  4680. NULL,
  4681. NULL,
  4682. 0
  4683. );
  4684. if ( NameLength > 1){
  4685. //
  4686. // The display name exist. Go get the display name.
  4687. //
  4688. CommonName = (LPWSTR) LsapAllocateLsaHeap( sizeof(WCHAR) * NameLength);
  4689. if ( NULL == CommonName ){
  4690. if (UPNName){
  4691. LsapFreeLsaHeap( UPNName );
  4692. }
  4693. return ERROR_NOT_ENOUGH_MEMORY;
  4694. }
  4695. UserNameBufLen = NameLength;
  4696. NameLength = CertGetNameString(
  4697. CertContext,
  4698. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  4699. 0,
  4700. NULL,
  4701. CommonName,
  4702. UserNameBufLen
  4703. );
  4704. ASSERT (NameLength == UserNameBufLen);
  4705. }
  4706. if (CommonName || UPNName){
  4707. NameLength = 3;
  4708. if (CommonName){
  4709. NameLength += wcslen(CommonName);
  4710. }
  4711. if (UPNName){
  4712. NameLength += wcslen(UPNName);
  4713. }
  4714. *UserDispName = (LPWSTR)LsapAllocateLsaHeap(sizeof(WCHAR) * NameLength);
  4715. if (*UserDispName) {
  4716. if (CommonName){
  4717. wcscpy(*UserDispName, CommonName);
  4718. if (UPNName){
  4719. wcscat(*UserDispName, L"(");
  4720. wcscat(*UserDispName, UPNName);
  4721. wcscat(*UserDispName, L")");
  4722. }
  4723. } else {
  4724. wcscpy(*UserDispName, UPNName);
  4725. }
  4726. } else {
  4727. rc = ERROR_NOT_ENOUGH_MEMORY;
  4728. }
  4729. if (CommonName){
  4730. LsapFreeLsaHeap( CommonName );
  4731. }
  4732. if (UPNName){
  4733. LsapFreeLsaHeap( UPNName );
  4734. }
  4735. return rc;
  4736. }
  4737. return DISP_E_UNKNOWNNAME;
  4738. }
  4739. DWORD
  4740. EfsAddCertToTrustStoreStore(
  4741. IN PCCERT_CONTEXT pCert,
  4742. OUT DWORD *ImpersonationError
  4743. )
  4744. /*++
  4745. Routine Description:
  4746. This routine adds the cert to the LM Trusted store.
  4747. Arguments:
  4748. pCert -- The cert to be added.
  4749. ImpersonationError -- Error indicate that we could impersonate after revert to self. This should not be the case.
  4750. Return Value:
  4751. Win32 error code
  4752. --*/
  4753. {
  4754. NTSTATUS Status;
  4755. HANDLE hToken;
  4756. DWORD errCode = ERROR_SUCCESS;
  4757. HCERTSTORE localStore;
  4758. *ImpersonationError = 0;
  4759. Status = NtOpenThreadToken(
  4760. NtCurrentThread(),
  4761. TOKEN_QUERY | TOKEN_IMPERSONATE,
  4762. TRUE, // OpenAsSelf
  4763. &hToken
  4764. );
  4765. if (NT_SUCCESS( Status )) {
  4766. RevertToSelf();
  4767. localStore = CertOpenStore(
  4768. CERT_STORE_PROV_SYSTEM_W,
  4769. 0, // dwEncodingType
  4770. 0, // hCryptProv,
  4771. CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  4772. TRUSTEDPEOPLE
  4773. );
  4774. if (localStore) {
  4775. LPWSTR crntUserName;
  4776. LPWSTR userName;
  4777. PCCERT_CONTEXT userCert = NULL;
  4778. CERT_ENHKEY_USAGE certEnhKeyUsage;
  4779. LPSTR lpstr = szOID_EFS_CRYPTO;
  4780. certEnhKeyUsage.cUsageIdentifier = 1;
  4781. certEnhKeyUsage.rgpszUsageIdentifier = &lpstr;
  4782. errCode = EfsGetCertNameFromCertContext(
  4783. pCert,
  4784. &crntUserName
  4785. );
  4786. if (crntUserName) {
  4787. //
  4788. // Let's enumerate the certs in the store to see if we need to remove the old similar
  4789. // EFS cert.
  4790. //
  4791. do {
  4792. userCert = CertFindCertificateInStore(
  4793. localStore,
  4794. X509_ASN_ENCODING,
  4795. 0, //CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  4796. CERT_FIND_ENHKEY_USAGE,
  4797. &certEnhKeyUsage,
  4798. userCert
  4799. );
  4800. if (userCert) {
  4801. EfsGetCertNameFromCertContext(
  4802. userCert,
  4803. &userName
  4804. );
  4805. if (userName) {
  4806. if (!wcscmp(userName, crntUserName) ) {
  4807. //
  4808. // Find the name match. Remove it.
  4809. //
  4810. PCCERT_CONTEXT tmpCert;
  4811. tmpCert = CertDuplicateCertificateContext(userCert);
  4812. if (tmpCert) {
  4813. CertDeleteCertificateFromStore(tmpCert);
  4814. }
  4815. }
  4816. LsapFreeLsaHeap( userName );
  4817. }
  4818. }
  4819. } while (userCert);
  4820. if(!CertAddCertificateContextToStore(
  4821. localStore,
  4822. pCert,
  4823. CERT_STORE_ADD_NEW,
  4824. NULL) ) {
  4825. errCode = GetLastError();
  4826. }
  4827. LsapFreeLsaHeap( crntUserName );
  4828. } else {
  4829. errCode = GetLastError();
  4830. }
  4831. CertCloseStore( localStore, 0 );
  4832. }
  4833. Status = NtSetInformationThread(
  4834. NtCurrentThread(),
  4835. ThreadImpersonationToken,
  4836. (PVOID) &hToken,
  4837. sizeof(HANDLE)
  4838. );
  4839. if (!NT_SUCCESS( Status )) {
  4840. ASSERT(FALSE);
  4841. *ImpersonationError = 1;
  4842. errCode = RtlNtStatusToDosError( Status );
  4843. }
  4844. } else {
  4845. errCode = RtlNtStatusToDosError( Status );
  4846. }
  4847. return errCode;
  4848. }
  4849. DWORD
  4850. EfsAlignBlock(
  4851. IN PVOID InPointer,
  4852. OUT PVOID *OutPointer,
  4853. OUT BOOLEAN *NewMemory
  4854. )
  4855. /*++
  4856. Routine Description:
  4857. This routine will align the structure with the first ULONG as the length of the structure
  4858. so that we don't get alignment faults.
  4859. Arguments:
  4860. InPointer -- Original Block
  4861. OutPointer -- Aligned Block
  4862. NewMemory -- If new memory block allocated
  4863. Return Value:
  4864. Win32 error code
  4865. --*/
  4866. {
  4867. if ( ((INT_PTR) InPointer & 0x03) == 0) {
  4868. *OutPointer = InPointer;
  4869. *NewMemory = FALSE;
  4870. return ERROR_SUCCESS;
  4871. }
  4872. ULONG length;
  4873. DWORD result=ERROR_SUCCESS;
  4874. RtlCopyMemory(&length, InPointer, sizeof (ULONG));
  4875. *OutPointer = (PENCRYPTED_KEY)LsapAllocateLsaHeap(length);
  4876. if (*OutPointer) {
  4877. RtlCopyMemory(*OutPointer, InPointer, length);
  4878. *NewMemory = TRUE;
  4879. } else {
  4880. *NewMemory = FALSE;
  4881. result = ERROR_NOT_ENOUGH_MEMORY;
  4882. }
  4883. return result;
  4884. }