Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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