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.

4270 lines
136 KiB

  1. /*++
  2. Copyright (c) 1997 - 1999 Microsoft Corporation
  3. Module Name:
  4. userkey.cxx
  5. Abstract:
  6. EFS (Encrypting File System) Server
  7. Author:
  8. Robert Reichel (RobertRe) July 4, 1997
  9. Robert Gu (RobertG) January 23, 1998
  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 <wincrypt.h>
  21. #include <cryptui.h>
  22. #include <stdio.h>
  23. #include <malloc.h>
  24. #include <certca.h>
  25. #include "lsasrvp.h"
  26. #include "efssrv.hxx"
  27. #include "userkey.h"
  28. #include "lsaitf.h" // LOGONSES_FLAG_* flags
  29. }
  30. #define PROVIDER TEXT("Provider")
  31. #define CONTAINER TEXT("Container")
  32. #define PROVIDER_TYPE TEXT("Type")
  33. #define CERT_HASH TEXT("CertificateHash")
  34. #define CERT_FLAG TEXT("Flag")
  35. #define KEYPATH TEXT("%ws\\Software\\Microsoft\\Windows NT\\CurrentVersion\\EFS\\CurrentKeys")
  36. #define KEYPATHROOT HKEY_USERS
  37. #define YEARCOUNT (LONGLONG) 10000000*3600*24*365 // One Year's tick count
  38. #define AutoEnrollChainLevel 5 // This should be well enough for the EFS cert.
  39. #ifndef wszCERTTYPE_EFS
  40. #define wszCERTTYPE_EFS L"EFS"
  41. #endif
  42. #ifndef wszCERTTYPE_EFS_RECOVERY
  43. #define wszCERTTYPE_EFS_RECOVERY L"EFSRecovery"
  44. #endif
  45. extern DWORD RsaKeyLength;
  46. LONG UserCertIsValidating = 0;
  47. //
  48. // Forward references
  49. //
  50. BOOL
  51. EfspCreateSelfSignedCert(
  52. OUT HCRYPTKEY * hKey,
  53. OUT HCRYPTPROV * hProv,
  54. OUT LPWSTR * lpContainerName,
  55. OUT LPWSTR * lpProviderName,
  56. IN PEFS_USER_INFO pEfsUserInfo,
  57. OUT PBYTE * pbHash,
  58. OUT PDWORD cbHash,
  59. OUT LPWSTR * lpDisplayInfo,
  60. OUT PCCERT_CONTEXT *pCertContext
  61. );
  62. DWORD
  63. GenerateUserKey (
  64. IN PEFS_USER_INFO pEfsUserInfo,
  65. OUT HCRYPTKEY * hKey OPTIONAL,
  66. OUT HCRYPTPROV * hProv OPTIONAL,
  67. OUT LPWSTR * ContainerName,
  68. OUT LPWSTR * ProviderName,
  69. OUT PDWORD ProviderType,
  70. OUT LPWSTR * DisplayInfo,
  71. OUT PBYTE * pbHash,
  72. OUT PDWORD cbHash
  73. );
  74. PWCHAR
  75. ConstructKeyPath(
  76. PWCHAR SidString
  77. )
  78. /*++
  79. Routine Description:
  80. This routine constructs the path to the current user key, in the form
  81. <user-sid>\Software\Microsoft\Windows NT\CurrentVersion\EFS\CurrentKeys
  82. Arguments:
  83. None.
  84. Return Value:
  85. Returns the path the the current user keyset
  86. --*/
  87. {
  88. PWCHAR KeyPath = NULL;
  89. if (SidString) {
  90. DWORD KeyPathLength = wcslen( KEYPATH );
  91. //
  92. // Subtract 3 for %ws and add 1 for NULL
  93. //
  94. DWORD StringLength = ( KeyPathLength - 3 + wcslen( SidString ) + 1) * sizeof( WCHAR );
  95. KeyPath = (PWCHAR)LsapAllocateLsaHeap( StringLength );
  96. if (KeyPath) {
  97. swprintf( KeyPath, KEYPATH, SidString );
  98. KeyPath[StringLength/sizeof( WCHAR ) - 1] = UNICODE_NULL;
  99. }
  100. }
  101. return( KeyPath );
  102. }
  103. NTSTATUS
  104. EfspGetTokenUser(
  105. IN OUT PEFS_USER_INFO pEfsUserInfo
  106. )
  107. /*++
  108. Routine Description:
  109. This routine returns the TOKEN_USER structure for the
  110. current user, and optionally, the AuthenticationId from his
  111. token.
  112. Arguments:
  113. pEfsUserInfo - User Info.
  114. Return Value:
  115. NtStatus code
  116. --*/
  117. {
  118. NTSTATUS Status;
  119. HANDLE TokenHandle;
  120. ULONG ReturnLength;
  121. TOKEN_STATISTICS TokenStats;
  122. PTOKEN_USER pTokenUser = NULL;
  123. BOOLEAN b = FALSE;
  124. BYTE PefBuffer[1024];
  125. Status = NtOpenThreadToken(
  126. NtCurrentThread(),
  127. TOKEN_QUERY,
  128. TRUE, // OpenAsSelf
  129. &TokenHandle
  130. );
  131. if (NT_SUCCESS( Status )) {
  132. Status = NtQueryInformationToken (
  133. TokenHandle,
  134. TokenUser,
  135. PefBuffer,
  136. sizeof (PefBuffer),
  137. &ReturnLength
  138. );
  139. if ( NT_SUCCESS( Status ) || (Status == STATUS_BUFFER_TOO_SMALL)) {
  140. pEfsUserInfo->pTokenUser = (PTOKEN_USER)LsapAllocateLsaHeap( ReturnLength );
  141. if (pEfsUserInfo->pTokenUser) {
  142. if (NT_SUCCESS( Status )) {
  143. RtlCopyMemory(pEfsUserInfo->pTokenUser, PefBuffer, ReturnLength);
  144. //
  145. // Fix the SID pointer
  146. //
  147. pEfsUserInfo->pTokenUser->User.Sid = (PSID)((PBYTE)(pEfsUserInfo->pTokenUser) + sizeof(SID_AND_ATTRIBUTES));
  148. ASSERT(RtlValidSid(pEfsUserInfo->pTokenUser->User.Sid));
  149. } else {
  150. //
  151. // The stack performance buffer is not bigger enough
  152. //
  153. Status = NtQueryInformationToken (
  154. TokenHandle,
  155. TokenUser,
  156. pEfsUserInfo->pTokenUser,
  157. ReturnLength,
  158. &ReturnLength
  159. );
  160. }
  161. if ( NT_SUCCESS( Status )) {
  162. Status = NtQueryInformationToken (
  163. TokenHandle,
  164. TokenStatistics,
  165. (PVOID)&TokenStats,
  166. sizeof( TOKEN_STATISTICS ),
  167. &ReturnLength
  168. );
  169. if ( NT_SUCCESS( Status )) {
  170. NTSTATUS Status1;
  171. pEfsUserInfo->AuthId = TokenStats.AuthenticationId;
  172. b = TRUE;
  173. //
  174. // If we failed to get the group info, we assume the user is not interactively logged on.
  175. // The fail should not stop us, we could go without cache at the worst.
  176. //
  177. Status1 = NtQueryInformationToken (
  178. TokenHandle,
  179. TokenGroups,
  180. PefBuffer,
  181. sizeof (PefBuffer),
  182. &ReturnLength
  183. );
  184. if (NT_SUCCESS( Status1 ) || (Status1 == STATUS_BUFFER_TOO_SMALL)) {
  185. PTOKEN_GROUPS pGroups = NULL;
  186. PTOKEN_GROUPS pAllocGroups = NULL;
  187. if ( NT_SUCCESS( Status1 ) ) {
  188. pGroups = (PTOKEN_GROUPS) PefBuffer;
  189. } else {
  190. SafeAllocaAllocate(pAllocGroups, ReturnLength);
  191. Status1 = NtQueryInformationToken (
  192. TokenHandle,
  193. TokenGroups,
  194. pAllocGroups,
  195. ReturnLength,
  196. &ReturnLength
  197. );
  198. if ( NT_SUCCESS( Status1 )) {
  199. pGroups = pAllocGroups;
  200. }
  201. }
  202. if (pGroups) {
  203. //
  204. // Search the interactive SID. Looks like this SID tends to appear at the
  205. // end of the list. We search from back to the first.
  206. //
  207. int SidIndex;
  208. for ( SidIndex = (int)(pGroups->GroupCount - 1); SidIndex >= 0; SidIndex--) {
  209. if (RtlEqualSid(LsapInteractiveSid, pGroups->Groups[SidIndex].Sid)) {
  210. pEfsUserInfo->InterActiveUser = USER_INTERACTIVE;
  211. break;
  212. }
  213. }
  214. if (pEfsUserInfo->InterActiveUser != USER_INTERACTIVE) {
  215. pEfsUserInfo->InterActiveUser = USER_REMOTE;
  216. }
  217. }
  218. SafeAllocaFree( pAllocGroups );
  219. }
  220. // LsapInteractiveSid
  221. }
  222. }
  223. if (!b) {
  224. //
  225. // Something failed, clean up what we were going to return
  226. //
  227. LsapFreeLsaHeap( pEfsUserInfo->pTokenUser );
  228. pEfsUserInfo->pTokenUser = NULL;
  229. }
  230. } else {
  231. Status = STATUS_INSUFFICIENT_RESOURCES;
  232. }
  233. }
  234. NtClose( TokenHandle );
  235. }
  236. return( Status );
  237. }
  238. PWCHAR
  239. ConvertSidToWideCharString(
  240. PSID Sid
  241. )
  242. /*++
  243. Routine Description:
  244. This function generates a printable unicode string representation
  245. of a SID.
  246. The resulting string will take one of two forms. If the
  247. IdentifierAuthority value is not greater than 2^32, then
  248. the SID will be in the form:
  249. S-1-281736-12-72-9-110
  250. ^ ^^ ^^ ^ ^^^
  251. | | | | |
  252. +-----+--+-+--+---- Decimal
  253. Otherwise it will take the form:
  254. S-1-0x173495281736-12-72-9-110
  255. ^^^^^^^^^^^^^^ ^^ ^^ ^ ^^^
  256. Hexidecimal | | | |
  257. +--+-+--+---- Decimal
  258. Arguments:
  259. UnicodeString - Returns a unicode string that is equivalent to
  260. the SID. The maximum length field is only set if
  261. AllocateDestinationString is TRUE.
  262. Sid - Supplies the SID that is to be converted to unicode.
  263. AllocateDestinationString - Supplies a flag that controls whether or
  264. not this API allocates the buffer space for the destination
  265. string. If it does, then the buffer must be deallocated using
  266. RtlFreeUnicodeString (note that only storage for
  267. DestinationString->Buffer is allocated by this API).
  268. Return Value:
  269. SUCCESS - The conversion was successful
  270. STATUS_INVALID_SID - The sid provided does not have a valid structure,
  271. or has too many sub-authorities (more than SID_MAX_SUB_AUTHORITIES).
  272. STATUS_NO_MEMORY - There was not sufficient memory to allocate the
  273. target string. This is returned only if AllocateDestinationString
  274. is specified as TRUE.
  275. STATUS_BUFFER_OVERFLOW - This is returned only if
  276. AllocateDestinationString is specified as FALSE.
  277. --*/
  278. {
  279. UNICODE_STRING Result;
  280. if ( STATUS_SUCCESS != RtlConvertSidToUnicodeString( &Result, Sid, TRUE )) {
  281. return NULL;
  282. }
  283. return Result.Buffer;
  284. }
  285. BOOLEAN
  286. EfspIsSystem(
  287. PEFS_USER_INFO pEfsUserInfo,
  288. OUT PBOOLEAN System
  289. )
  290. /*++
  291. Routine Description:
  292. Determines if the current user is running in system context or not.
  293. Arguments:
  294. System - Receives whether or not the current user is system.
  295. Return Value:
  296. TRUE on success, FALSE on failure.
  297. --*/
  298. {
  299. *System = RtlEqualSid(LsapLocalSystemSid, pEfsUserInfo->pTokenUser->User.Sid);
  300. return( TRUE );
  301. }
  302. BOOL
  303. EfspIsDomainUser(
  304. IN LPWSTR lpDomainName,
  305. OUT PBOOLEAN IsDomain
  306. )
  307. /*++
  308. Routine Description:
  309. Determines if the current user is logged on to a domain account
  310. or a local machine account.
  311. Arguments:
  312. lpDomainName - Supplies the domain name.
  313. IsDomain - Returns TRUE if the current user is logged on to a domain
  314. account, FALSE otherwise.
  315. Return Value:
  316. TRUE on success, FALSE on failure.
  317. --*/
  318. {
  319. *IsDomain = (wcscmp( EfsComputerName, lpDomainName ) != 0);
  320. return( TRUE );
  321. }
  322. BOOL
  323. EnrollKeyPair(
  324. IN PEFS_USER_INFO pEfsUserInfo,
  325. OUT HCRYPTKEY * hKey,
  326. OUT HCRYPTPROV * hProv,
  327. OUT LPWSTR * lpContainerName,
  328. OUT LPWSTR * lpProviderName,
  329. IN DWORD dwProviderType,
  330. OUT PBYTE * pbHash,
  331. OUT PDWORD cbHash,
  332. OUT LPWSTR * lpDisplayInfo
  333. )
  334. /*++
  335. Routine Description:
  336. This routine takes a keypair and attempts to enroll it.
  337. Arguments:
  338. hKey - Optionally returns a handle to the user's key.
  339. hProv - Optionally returns a handle to the user's key's provider.
  340. lpContainerName - Returns the name of the user's key container.
  341. lpProviderName - Returns the name of the user's key provider.
  342. ProviderType - Returns the type of the provider.
  343. pbHash - Returns the hash of the user's certificate.
  344. cbHash - Returns the length in bytes of the certificate hash.
  345. DisplayInfo - Returns the display information associated with this
  346. certificate.
  347. Return Value:
  348. TRUE on success, FALSE on failure. Call GetLastError() for details.
  349. --*/
  350. {
  351. BOOL b = FALSE;
  352. BOOL fResult = FALSE;
  353. DWORD rc = ERROR_SUCCESS;
  354. DWORD ImpersonationError;
  355. HCRYPTKEY hLocalKey = NULL;
  356. HCRYPTPROV hLocalProv = NULL;
  357. PCCERT_CONTEXT pCertContext = NULL ;
  358. //
  359. // Initialize OUT parameters
  360. //
  361. *pbHash = NULL;
  362. *lpDisplayInfo = NULL;
  363. *lpContainerName = NULL;
  364. *lpProviderName = NULL;
  365. *cbHash = 0;
  366. *hKey = NULL;
  367. *hProv = NULL;
  368. //
  369. // Initialize output parameters
  370. //
  371. if (pEfsUserInfo->bDomainAccount) {
  372. HRESULT AutoEnrollSuccess = S_OK;
  373. //
  374. // Attempt to create the auto-enroll object so that this cert re-enrolls.
  375. //
  376. // DLL is demand load.
  377. //
  378. __try {
  379. AutoEnrollSuccess = CACreateLocalAutoEnrollmentObject(
  380. wszCERTTYPE_EFS,
  381. NULL,
  382. NULL,
  383. CERT_SYSTEM_STORE_CURRENT_USER
  384. );
  385. } __except (EXCEPTION_EXECUTE_HANDLER) {
  386. rc = GetExceptionCode();
  387. AutoEnrollSuccess = (HRESULT)rc;
  388. }
  389. if (S_OK == AutoEnrollSuccess) {
  390. HCERTTYPE hCertType = 0;
  391. CRYPTUI_WIZ_CERT_REQUEST_INFO CertRequest;
  392. CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW NewKeyInfo;
  393. CRYPT_KEY_PROV_INFO KeyProvInfo;
  394. CRYPTUI_WIZ_CERT_TYPE CertType;
  395. memset( &CertRequest, 0, sizeof( CRYPTUI_WIZ_CERT_REQUEST_INFO ));
  396. KeyProvInfo.pwszContainerName = NULL;
  397. if (RsaKeyLength > RSA1024BIT_KEY) {
  398. //
  399. // Base Provider is no longer good
  400. //
  401. KeyProvInfo.pwszProvName = MS_ENHANCED_PROV;
  402. } else {
  403. KeyProvInfo.pwszProvName = NULL;
  404. }
  405. KeyProvInfo.dwProvType = dwProviderType;
  406. KeyProvInfo.dwFlags = 0;
  407. KeyProvInfo.cProvParam = 0;
  408. KeyProvInfo.rgProvParam = NULL;
  409. KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
  410. memset( &NewKeyInfo, 0, sizeof( CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW ));
  411. NewKeyInfo.dwSize = sizeof( CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW );
  412. NewKeyInfo.pKeyProvInfo = &KeyProvInfo;
  413. NewKeyInfo.dwGenKeyFlags = RsaKeyLength | CRYPT_EXPORTABLE;
  414. LPWSTR lpwstr = wszCERTTYPE_EFS;
  415. CertType.dwSize = sizeof( CRYPTUI_WIZ_CERT_TYPE );
  416. CertType.cCertType = 1;
  417. CertType.rgwszCertType = &lpwstr;
  418. //
  419. // Fill in the fields of the CertRequest structure
  420. //
  421. CertRequest.dwSize = sizeof( CRYPTUI_WIZ_CERT_REQUEST_INFO ); // required
  422. CertRequest.dwPurpose = CRYPTUI_WIZ_CERT_ENROLL; // enroll the certificate
  423. CertRequest.pwszMachineName = NULL;
  424. CertRequest.pwszAccountName = NULL;
  425. CertRequest.pAuthentication = NULL; // must be NULL
  426. CertRequest.pCertRequestString = NULL; // Reserved, must be NULL
  427. CertRequest.pwszDesStore = NULL; // defaults to MY store
  428. CertRequest.pszHashAlg = NULL;
  429. CertRequest.pRenewCertContext = NULL; // We're enrolling, not renewing
  430. CertRequest.dwPvkChoice = CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_NEW; // Create keyset
  431. CertRequest.pPvkNew = &NewKeyInfo;
  432. CertRequest.pwszCALocation = NULL;
  433. CertRequest.pwszCAName = NULL;
  434. CertRequest.dwPostOption = 0;
  435. CertRequest.pCertRequestExtensions = NULL;
  436. CertRequest.dwCertChoice = CRYPTUI_WIZ_CERT_REQUEST_CERT_TYPE;
  437. CertRequest.pCertType = &CertType;
  438. CertRequest.pwszCertDNName = L"CN=EFS";
  439. CertRequest.pwszFriendlyName = NULL; // Optional if CRYPTUI_WIZ_CERT_ENROLL is set in dwPurpose
  440. CertRequest.pwszDescription = NULL; // Optional if CRYPTUI_WIZ_CERT_ENROLL is set in dwPurpose
  441. DWORD CAdwStatus = 0 ;
  442. BOOL CryptUiResult ;
  443. __try {
  444. CryptUiResult = CryptUIWizCertRequest(
  445. CRYPTUI_WIZ_NO_UI,
  446. NULL,
  447. NULL,
  448. &CertRequest,
  449. &pCertContext,
  450. &CAdwStatus
  451. );
  452. }
  453. __except (EXCEPTION_EXECUTE_HANDLER) {
  454. CryptUiResult = FALSE ;
  455. SetLastError( GetExceptionCode() );
  456. }
  457. if (CryptUiResult) {
  458. //
  459. // Got back success, see if we got a cert back
  460. //
  461. if (CAdwStatus == CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED) {
  462. //
  463. // We got back a valid Cert Context.
  464. // Get the hash out of it.
  465. //
  466. *pbHash = GetCertHashFromCertContext(
  467. pCertContext,
  468. cbHash
  469. );
  470. *lpDisplayInfo = EfspGetCertDisplayInformation( pCertContext );
  471. if (*pbHash && *lpDisplayInfo) {
  472. PCRYPT_KEY_PROV_INFO pCryptKeyProvInfo = GetKeyProvInfo( pCertContext );
  473. if (pCryptKeyProvInfo) {
  474. //
  475. // According to Xiaohong, we always get back container name and provider name here.
  476. // There is no need for us to check NULL here.
  477. //
  478. *lpContainerName = (LPWSTR)LsapAllocateLsaHeap( wcslen(pCryptKeyProvInfo->pwszContainerName) * sizeof( WCHAR ) + sizeof( UNICODE_NULL ));
  479. *lpProviderName = (LPWSTR)LsapAllocateLsaHeap( wcslen(pCryptKeyProvInfo->pwszProvName) * sizeof( WCHAR ) + sizeof( UNICODE_NULL ));
  480. if (*lpContainerName && *lpProviderName) {
  481. wcscpy( *lpContainerName, pCryptKeyProvInfo->pwszContainerName );
  482. wcscpy( *lpProviderName, pCryptKeyProvInfo->pwszProvName );
  483. if (CryptAcquireContext( hProv, *lpContainerName, *lpProviderName, PROV_RSA_FULL, CRYPT_SILENT )) {
  484. if (CryptGetUserKey(*hProv, AT_KEYEXCHANGE, hKey)) {
  485. fResult = TRUE;
  486. } else {
  487. rc = GetLastError();
  488. }
  489. } else {
  490. rc = GetLastError();
  491. }
  492. } else {
  493. rc = ERROR_NOT_ENOUGH_MEMORY;
  494. }
  495. LsapFreeLsaHeap( pCryptKeyProvInfo );
  496. } else {
  497. rc = GetLastError();
  498. }
  499. } else {
  500. rc = GetLastError();
  501. }
  502. // CertFreeCertificateContext( pCertContext );
  503. } else {
  504. //
  505. // We failed. Get the error. This error will be overwritten in the following code.
  506. // It only helps debug for now.
  507. //
  508. rc = GetLastError();
  509. }
  510. } else {
  511. rc = GetLastError();
  512. if (pEfsUserInfo->NonKerberos && (ERROR_OUTOFMEMORY != rc)) {
  513. EfsLogEntry(
  514. EVENTLOG_ERROR_TYPE,
  515. 0,
  516. EFS_NTLM_ERROR,
  517. 0,
  518. sizeof(DWORD),
  519. NULL,
  520. &rc
  521. );
  522. }
  523. }
  524. if (!fResult) {
  525. //
  526. // We failed to get one from the CA. Issue a self-signed cert.
  527. //
  528. //
  529. // Free the memory allocated above first
  530. //
  531. if (*pbHash) {
  532. LsapFreeLsaHeap( *pbHash );
  533. *pbHash = NULL;
  534. }
  535. if (*lpDisplayInfo) {
  536. LsapFreeLsaHeap( *lpDisplayInfo );
  537. *lpDisplayInfo = NULL;
  538. }
  539. if (*lpContainerName) {
  540. LsapFreeLsaHeap( *lpContainerName );
  541. *lpContainerName = NULL;
  542. }
  543. if (*lpProviderName) {
  544. LsapFreeLsaHeap( *lpProviderName );
  545. *lpProviderName = NULL;
  546. }
  547. if (pCertContext) {
  548. CertFreeCertificateContext( pCertContext );
  549. }
  550. if ( *hKey) {
  551. CryptDestroyKey( *hKey );
  552. *hKey = NULL;
  553. }
  554. if ( *hProv) {
  555. CryptReleaseContext( *hProv, 0 );
  556. *hProv = NULL;
  557. }
  558. if (EfspCreateSelfSignedCert( hKey,
  559. hProv,
  560. lpContainerName,
  561. lpProviderName,
  562. pEfsUserInfo,
  563. pbHash,
  564. cbHash,
  565. lpDisplayInfo,
  566. &pCertContext
  567. )) {
  568. fResult = TRUE;
  569. } else {
  570. rc = GetLastError();
  571. }
  572. }
  573. } else {
  574. DebugLog((DEB_WARN, "Unable to create auto-enrollment object, error = %x\n" , AutoEnrollSuccess));
  575. rc = AutoEnrollSuccess;
  576. }
  577. } else {
  578. //
  579. // It's not a domain account, which means we can't get to the CA.
  580. // Issue a self-signed cert.
  581. //
  582. if (EfspCreateSelfSignedCert( hKey,
  583. hProv,
  584. lpContainerName,
  585. lpProviderName,
  586. pEfsUserInfo,
  587. pbHash,
  588. cbHash,
  589. lpDisplayInfo,
  590. &pCertContext
  591. )) {
  592. fResult = TRUE;
  593. } else {
  594. rc = GetLastError();
  595. }
  596. }
  597. //
  598. // Let's add this cert to the local store
  599. //
  600. if (fResult) {
  601. rc = EfsAddCertToCertStore(
  602. pCertContext,
  603. TRUSTEDPEOPLE,
  604. &ImpersonationError
  605. );
  606. if ( ERROR_SUCCESS != rc ) {
  607. DebugLog((DEB_ERROR, "Failed to add the cert to LM CA store, error = %x\n" , rc));
  608. if (ImpersonationError) {
  609. //
  610. // We got serious error. We reverted but could not impersonate back.
  611. // Quit the procedure. This should not happen.
  612. //
  613. DebugLog((DEB_ERROR, "Failed to impersonate after revert.\n"));
  614. fResult = FALSE;
  615. } else {
  616. //
  617. // Fail to add the cert to the store should not prevent us continue.
  618. //
  619. rc = ERROR_SUCCESS;
  620. }
  621. } else {
  622. //
  623. // Let's update the registry. This is the best effort. No need to see if succeed or not.
  624. //
  625. EfsMarkCertAddedToStore(pEfsUserInfo, CERTINLMTRUSTEDSTORE);
  626. }
  627. }
  628. //
  629. // Now check if we need create the cache
  630. //
  631. //
  632. // Create the cache node.
  633. // We could have a cache node which is not validated or no cache at all.
  634. // We could also have a valid cache but was not allowed to use since it
  635. // is being freed.
  636. //
  637. if (fResult && !pEfsUserInfo->UserCacheStop) {
  638. //
  639. // Cache is allowed now
  640. //
  641. if (!pEfsUserInfo->pUserCache || (pEfsUserInfo->pUserCache->CertValidated != CERT_VALIDATED)) {
  642. //
  643. // Let's create the cache
  644. //
  645. PUSER_CACHE pCacheNode;
  646. PSID pUserID = NULL;
  647. ULONG SidLength = 0;
  648. pCacheNode = (PUSER_CACHE) LsapAllocateLsaHeap(sizeof(USER_CACHE));
  649. if (pEfsUserInfo->InterActiveUser != USER_INTERACTIVE) {
  650. SidLength = RtlLengthSid(pEfsUserInfo->pTokenUser->User.Sid);
  651. pUserID = (PSID) LsapAllocateLsaHeap(SidLength);
  652. }
  653. if (pCacheNode && ((SidLength == 0) || (pUserID))) {
  654. NTSTATUS Status = STATUS_SUCCESS;
  655. memset( pCacheNode, 0, sizeof( USER_CACHE ));
  656. if (pUserID) {
  657. Status = RtlCopySid(
  658. SidLength,
  659. pUserID,
  660. pEfsUserInfo->pTokenUser->User.Sid
  661. );
  662. }
  663. if ( NT_SUCCESS( Status ) && NT_SUCCESS( NtQuerySystemTime(&(pCacheNode->TimeStamp)))){
  664. if (EfspInitUserCacheNode(
  665. pCacheNode,
  666. pUserID,
  667. *pbHash,
  668. *cbHash,
  669. *lpContainerName,
  670. *lpProviderName,
  671. *lpDisplayInfo,
  672. &(pCertContext->pCertInfo->NotAfter),
  673. *hKey,
  674. *hProv,
  675. pUserID? NULL: &(pEfsUserInfo->AuthId),
  676. CERT_VALIDATED
  677. )){
  678. //
  679. // Cache node created and ready for use. Do not delete or close the info
  680. // we just got.
  681. //
  682. *lpContainerName = NULL;
  683. *lpProviderName = NULL;
  684. *lpDisplayInfo = NULL;
  685. *pbHash = NULL;
  686. *cbHash = NULL;
  687. *hProv = NULL;
  688. *hKey = NULL;
  689. if (pEfsUserInfo->pUserCache) {
  690. //
  691. // We had a not validated cache
  692. //
  693. EfspReleaseUserCache(pEfsUserInfo->pUserCache);
  694. }
  695. pEfsUserInfo->pUserCache = pCacheNode;
  696. } else {
  697. LsapFreeLsaHeap(pCacheNode);
  698. pCacheNode = NULL;
  699. if (pUserID) {
  700. LsapFreeLsaHeap(pUserID);
  701. pUserID = NULL;
  702. }
  703. }
  704. } else {
  705. LsapFreeLsaHeap(pCacheNode);
  706. pCacheNode = NULL;
  707. if (pUserID) {
  708. LsapFreeLsaHeap(pUserID);
  709. pUserID = NULL;
  710. }
  711. }
  712. } else {
  713. if (pCacheNode) {
  714. LsapFreeLsaHeap(pCacheNode);
  715. pCacheNode = NULL;
  716. }
  717. if (pUserID) {
  718. LsapFreeLsaHeap(pUserID);
  719. pUserID = NULL;
  720. }
  721. }
  722. }
  723. //
  724. // Even if cache failed to create, but we can proceed without cache
  725. //
  726. }
  727. if (pCertContext) {
  728. CertFreeCertificateContext( pCertContext );
  729. pCertContext = NULL;
  730. }
  731. if (!fResult) {
  732. //
  733. // Something failed, free all the OUT parameters
  734. // that were allocated.
  735. //
  736. if (*pbHash) {
  737. LsapFreeLsaHeap( *pbHash );
  738. *pbHash = NULL;
  739. }
  740. if (*lpDisplayInfo) {
  741. LsapFreeLsaHeap( *lpDisplayInfo );
  742. *lpDisplayInfo = NULL;
  743. }
  744. if (*lpContainerName) {
  745. LsapFreeLsaHeap( *lpContainerName );
  746. *lpContainerName = NULL;
  747. }
  748. if (*lpProviderName) {
  749. LsapFreeLsaHeap( *lpProviderName );
  750. *lpProviderName = NULL;
  751. }
  752. if ( *hKey) {
  753. CryptDestroyKey( *hKey );
  754. *hKey = NULL;
  755. }
  756. if ( *hProv) {
  757. CryptReleaseContext( *hProv, 0 );
  758. *hProv = NULL;
  759. }
  760. }
  761. SetLastError( rc );
  762. return ( fResult );
  763. }
  764. BOOL
  765. EfspCreateSelfSignedCert(
  766. OUT HCRYPTKEY * hKey,
  767. OUT HCRYPTPROV * hProv,
  768. OUT LPWSTR * lpContainerName,
  769. OUT LPWSTR * lpProviderName,
  770. IN PEFS_USER_INFO pEfsUserInfo,
  771. OUT PBYTE * pbHash,
  772. OUT PDWORD cbHash,
  773. OUT LPWSTR * lpDisplayInfo,
  774. OUT PCCERT_CONTEXT *pCertContext
  775. )
  776. /*++
  777. Routine Description:
  778. This routine sets up and creates a self-signed certificate.
  779. Arguments:
  780. lpContainerName - Returns the container name of the new certificate.
  781. lpProviderName - Returns the provider name of the new certificate.
  782. pbHash - Returns the hash of the new certificate.
  783. cbHash - Returns the length in bytes of the new certificate hash.
  784. lpDisplayInfo - Returns the display string for the new certificate.
  785. Return Value:
  786. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  787. --*/
  788. {
  789. BOOL b = FALSE;
  790. DWORD rc = ERROR_SUCCESS;
  791. //
  792. // Initialize OUT parameters
  793. //
  794. *lpContainerName = NULL;
  795. *lpProviderName = NULL;
  796. *pbHash = NULL;
  797. *lpDisplayInfo = NULL;
  798. *pCertContext = NULL;
  799. *hKey = NULL;
  800. *hProv = NULL;
  801. RPC_STATUS RpcStatus;
  802. //
  803. // Croft up a key pair
  804. //
  805. //
  806. // Container name
  807. //
  808. GUID guidContainerName;
  809. RpcStatus = UuidCreate(&guidContainerName);
  810. if ((RpcStatus != RPC_S_OK) && (RpcStatus != RPC_S_UUID_LOCAL_ONLY)) {
  811. SetLastError(RpcStatus);
  812. return b;
  813. }
  814. LPWSTR TmpContainerName;
  815. DWORD ProviderNameLen;
  816. if (ERROR_SUCCESS == UuidToStringW(&guidContainerName, &TmpContainerName )) {
  817. //
  818. // Copy the container name into LSA heap memory
  819. //
  820. *lpContainerName = (LPWSTR)LsapAllocateLsaHeap( (wcslen( TmpContainerName ) + 1) * sizeof( WCHAR ) );
  821. if (*lpContainerName) {
  822. wcscpy( *lpContainerName, TmpContainerName );
  823. if (RsaKeyLength > RSA1024BIT_KEY) {
  824. //
  825. // Base Provider is no longer good
  826. //
  827. ProviderNameLen = wcslen( MS_ENHANCED_PROV ) + 1;
  828. } else {
  829. ProviderNameLen = wcslen( MS_DEF_PROV ) + 1;
  830. }
  831. *lpProviderName = (PWCHAR)LsapAllocateLsaHeap( ProviderNameLen * sizeof( WCHAR ) );
  832. if (*lpProviderName == NULL) {
  833. rc = ERROR_NOT_ENOUGH_MEMORY;
  834. } else {
  835. if (RsaKeyLength > RSA1024BIT_KEY) {
  836. wcscpy( *lpProviderName, MS_ENHANCED_PROV );
  837. } else {
  838. wcscpy( *lpProviderName, MS_DEF_PROV );
  839. }
  840. //
  841. // Create the key container
  842. //
  843. if (CryptAcquireContext(hProv, *lpContainerName, *lpProviderName, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT )) {
  844. if (CryptGenKey(*hProv, AT_KEYEXCHANGE, RsaKeyLength | CRYPT_EXPORTABLE, hKey)) {
  845. //
  846. // Construct the subject name information
  847. //
  848. LPWSTR UPNName = NULL;
  849. LPWSTR SubName = NULL;
  850. //*lpDisplayInfo = MakeDNName( FALSE, pEfsUserInfo);
  851. rc = EfsMakeCertNames(
  852. pEfsUserInfo,
  853. lpDisplayInfo,
  854. &SubName,
  855. &UPNName
  856. );
  857. if (ERROR_SUCCESS == rc) {
  858. //
  859. // Use this piece of code to create the PCERT_NAME_BLOB going into CertCreateSelfSignCertificate()
  860. //
  861. CERT_NAME_BLOB SubjectName;
  862. SubjectName.cbData = 0;
  863. if(CertStrToNameW(
  864. CRYPT_ASN_ENCODING,
  865. SubName,
  866. 0,
  867. NULL,
  868. NULL,
  869. &SubjectName.cbData,
  870. NULL)) {
  871. SafeAllocaAllocate(SubjectName.pbData, SubjectName.cbData);
  872. if (SubjectName.pbData) {
  873. if (CertStrToNameW(
  874. CRYPT_ASN_ENCODING,
  875. SubName,
  876. 0,
  877. NULL,
  878. SubjectName.pbData,
  879. &SubjectName.cbData,
  880. NULL) ) {
  881. //
  882. // Make the UPN Name
  883. //
  884. PCERT_EXTENSION altNameExt = NULL;
  885. if (EfsGetAltNameExt(&altNameExt, UPNName)) {
  886. //
  887. // Make the basic restrain extension
  888. //
  889. PCERT_EXTENSION basicRestraint = NULL;
  890. if (EfsGetBasicConstraintExt(&basicRestraint)) {
  891. //
  892. // Make the enhanced key usage
  893. //
  894. CERT_ENHKEY_USAGE certEnhKeyUsage;
  895. LPSTR lpstr;
  896. CERT_EXTENSION certExt[3];
  897. lpstr = szOID_EFS_CRYPTO;
  898. certEnhKeyUsage.cUsageIdentifier = 1;
  899. certEnhKeyUsage.rgpszUsageIdentifier = &lpstr;
  900. // now call CryptEncodeObject to encode the enhanced key usage into the extension struct
  901. certExt[0].Value.cbData = 0;
  902. certExt[0].Value.pbData = NULL;
  903. certExt[0].fCritical = FALSE;
  904. certExt[0].pszObjId = szOID_ENHANCED_KEY_USAGE;
  905. //
  906. // Encode it
  907. //
  908. if (EncodeAndAlloc(
  909. CRYPT_ASN_ENCODING,
  910. X509_ENHANCED_KEY_USAGE,
  911. &certEnhKeyUsage,
  912. &certExt[0].Value.pbData,
  913. &certExt[0].Value.cbData
  914. )) {
  915. //
  916. // finally, set up the array of extensions in the certInfo struct
  917. // any further extensions need to be added to this array.
  918. //
  919. CERT_EXTENSIONS certExts;
  920. certExts.cExtension = sizeof(certExt) / sizeof(CERT_EXTENSION);
  921. certExts.rgExtension = &certExt[0];
  922. certExt[1] = *altNameExt;
  923. certExt[2] = *basicRestraint;
  924. CRYPT_KEY_PROV_INFO KeyProvInfo;
  925. memset( &KeyProvInfo, 0, sizeof( CRYPT_KEY_PROV_INFO ));
  926. KeyProvInfo.pwszContainerName = *lpContainerName;
  927. KeyProvInfo.pwszProvName = *lpProviderName;
  928. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  929. KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
  930. //
  931. // Make the expiration time very very long (100 years)
  932. //
  933. SYSTEMTIME StartTime;
  934. FILETIME FileTime;
  935. LARGE_INTEGER TimeData;
  936. SYSTEMTIME EndTime;
  937. GetSystemTime(&StartTime);
  938. SystemTimeToFileTime(&StartTime, &FileTime);
  939. TimeData.LowPart = FileTime.dwLowDateTime;
  940. TimeData.HighPart = (LONG) FileTime.dwHighDateTime;
  941. TimeData.QuadPart += YEARCOUNT * 100;
  942. FileTime.dwLowDateTime = TimeData.LowPart;
  943. FileTime.dwHighDateTime = (DWORD) TimeData.HighPart;
  944. FileTimeToSystemTime(&FileTime, &EndTime);
  945. *pCertContext = CertCreateSelfSignCertificate(
  946. *hProv,
  947. &SubjectName,
  948. 0,
  949. &KeyProvInfo,
  950. NULL,
  951. &StartTime,
  952. &EndTime,
  953. &certExts
  954. );
  955. if (*pCertContext) {
  956. *pbHash = GetCertHashFromCertContext(
  957. *pCertContext,
  958. cbHash
  959. );
  960. if (*pbHash) {
  961. HCERTSTORE hStore;
  962. // hStore = CertOpenSystemStoreW( NULL, L"MY" );
  963. hStore = CertOpenStore(
  964. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  965. 0, // dwEncodingType
  966. 0, // hCryptProv,
  967. CERT_SYSTEM_STORE_CURRENT_USER,
  968. L"My"
  969. );
  970. if (hStore) {
  971. //
  972. // save the temp cert
  973. //
  974. if(CertAddCertificateContextToStore(
  975. hStore,
  976. *pCertContext,
  977. CERT_STORE_ADD_NEW,
  978. NULL) ) {
  979. b = TRUE;
  980. } else {
  981. rc = GetLastError();
  982. }
  983. CertCloseStore( hStore, 0 );
  984. } else {
  985. rc = GetLastError();
  986. }
  987. } else {
  988. rc = GetLastError();
  989. }
  990. } else {
  991. rc = GetLastError();
  992. }
  993. LsapFreeLsaHeap( certExt[0].Value.pbData );
  994. } else {
  995. rc = GetLastError();
  996. }
  997. LsapFreeLsaHeap(basicRestraint->Value.pbData);
  998. LsapFreeLsaHeap(basicRestraint);
  999. } else {
  1000. rc = GetLastError();
  1001. }
  1002. LsapFreeLsaHeap(altNameExt->Value.pbData);
  1003. LsapFreeLsaHeap(altNameExt);
  1004. } else {
  1005. rc = GetLastError();
  1006. }
  1007. } else {
  1008. rc = GetLastError();
  1009. }
  1010. SafeAllocaFree( SubjectName.pbData );
  1011. } else {
  1012. rc = ERROR_NOT_ENOUGH_MEMORY;
  1013. }
  1014. } else {
  1015. rc = GetLastError();
  1016. }
  1017. }
  1018. LsapFreeLsaHeap(UPNName);
  1019. LsapFreeLsaHeap(SubName);
  1020. } else {
  1021. //
  1022. // We create the container but failed to get the keys. We need to
  1023. // clean up the useless container here.
  1024. //
  1025. rc = GetLastError();
  1026. CryptReleaseContext( *hProv, 0 );
  1027. CryptAcquireContext(hProv, *lpContainerName, *lpProviderName, PROV_RSA_FULL, CRYPT_DELETEKEYSET | CRYPT_SILENT );
  1028. //
  1029. // No need to call CryptReleaseContext any more.
  1030. //
  1031. *hProv = NULL;
  1032. }
  1033. } else {
  1034. rc = GetLastError();
  1035. if (pEfsUserInfo->NonKerberos && (ERROR_OUTOFMEMORY != rc)) {
  1036. EfsLogEntry(
  1037. EVENTLOG_ERROR_TYPE,
  1038. 0,
  1039. EFS_NTLM_ERROR,
  1040. 0,
  1041. sizeof(DWORD),
  1042. NULL,
  1043. &rc
  1044. );
  1045. rc = ERROR_BAD_LOGON_SESSION_STATE;
  1046. }
  1047. }
  1048. }
  1049. } else {
  1050. rc = ERROR_NOT_ENOUGH_MEMORY;
  1051. }
  1052. RpcStringFree( &TmpContainerName );
  1053. } else {
  1054. rc = ERROR_NOT_ENOUGH_MEMORY;
  1055. }
  1056. if (!b) {
  1057. //
  1058. // Something failed, clean up whatever we allocated
  1059. //
  1060. if (*pbHash) {
  1061. LsapFreeLsaHeap( *pbHash );
  1062. *pbHash = NULL;
  1063. }
  1064. if (*lpDisplayInfo) {
  1065. LsapFreeLsaHeap( *lpDisplayInfo );
  1066. *lpDisplayInfo = NULL;
  1067. }
  1068. if (*lpContainerName) {
  1069. LsapFreeLsaHeap( *lpContainerName );
  1070. *lpContainerName = NULL;
  1071. }
  1072. if (*lpProviderName) {
  1073. LsapFreeLsaHeap( *lpProviderName );
  1074. *lpProviderName = NULL;
  1075. }
  1076. if ( *pCertContext ) {
  1077. CertFreeCertificateContext( *pCertContext );
  1078. *pCertContext = NULL;
  1079. }
  1080. if (*hKey) {
  1081. CryptDestroyKey( *hKey );
  1082. *hKey = NULL;
  1083. }
  1084. if (*hProv) {
  1085. CryptReleaseContext( *hProv, 0 );
  1086. *hProv = NULL;
  1087. }
  1088. }
  1089. SetLastError( rc );
  1090. return( b );
  1091. }
  1092. DWORD
  1093. GenerateUserKey (
  1094. IN PEFS_USER_INFO pEfsUserInfo,
  1095. OUT HCRYPTKEY * hKey OPTIONAL,
  1096. OUT HCRYPTPROV * hProv OPTIONAL,
  1097. OUT LPWSTR * lpContainerName,
  1098. OUT LPWSTR * lpProviderName,
  1099. OUT PDWORD ProviderType,
  1100. OUT LPWSTR * DisplayInfo,
  1101. OUT PBYTE * pbHash,
  1102. OUT PDWORD cbHash
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. This routine will construct a default user key for the current user
  1107. and install it in the registry. The constructed key takes the form
  1108. <UserName>_<MachineName>_EFS_<i>
  1109. Where i is increased as necessary to construct a valid key name.
  1110. Arguments:
  1111. hKey - Optionally returns a handle to the new key. This key must
  1112. be destroyed by the caller via CryptDestroyKey().
  1113. hProv - Optionally returns a handle to the provider of the new key.
  1114. This handle must be closed by the user via CryptReleaseContext().
  1115. lpContainerName - Returns a pointer to the name of the new key. This
  1116. buffer must be freed via LsapFreeHeap().
  1117. lpProviderName - Returns a pointer to the provider of the new key. This
  1118. buffer must be freed via LsapFreeHeap().
  1119. ProviderType - Returns the type of the provider of the new key.
  1120. pbHash - Returns a pointer to the certificate hash for this key.
  1121. cbHash - Returns the size fo the pbHash buffer.
  1122. Return Value:
  1123. ERROR_SUCCESS for succeed.
  1124. --*/
  1125. {
  1126. BOOL fSuccess = FALSE;
  1127. DWORD Disposition = 0;
  1128. DWORD dwDataLength = 0;
  1129. HCRYPTKEY LocalhKey = 0;
  1130. HCRYPTPROV LocalhProv = 0;
  1131. HKEY KeyHandle = NULL;
  1132. LONG rc = ERROR_SUCCESS;
  1133. //
  1134. // Initialize our output parameters
  1135. //
  1136. *ProviderType = PROV_RSA_FULL;
  1137. *lpProviderName = NULL;
  1138. *lpContainerName = NULL;
  1139. *DisplayInfo = NULL;
  1140. *pbHash = NULL;
  1141. if (ARGUMENT_PRESENT(hKey)) {
  1142. *hKey = NULL;
  1143. }
  1144. if (ARGUMENT_PRESENT(hProv)) {
  1145. *hProv = NULL;
  1146. }
  1147. //
  1148. // Use the user name as a mutex name to synchronize access to the following
  1149. // code. This way we don't hang up every thread to come through here, only
  1150. // ones from this user.
  1151. //
  1152. HANDLE hMutex = CreateMutex( NULL, TRUE, pEfsUserInfo->lpUserName );
  1153. if (hMutex != NULL) {
  1154. if (GetLastError() == ERROR_SUCCESS) {
  1155. //
  1156. // If we're here, we have the mutex, so we can proceed.
  1157. //
  1158. // Note that it is possible for some other thread to have
  1159. // come through here and created keys for the user while
  1160. // we were busy doing all of this. We will attempt to create
  1161. // the registry key where we will store the key information,
  1162. // and if it's already there, we will assume that someone
  1163. // came in and did all this while we were on our way.
  1164. //
  1165. //
  1166. // Create the registry path, if it does not already exist.
  1167. //
  1168. rc = RegCreateKeyEx( KEYPATHROOT,
  1169. pEfsUserInfo->lpKeyPath,
  1170. 0,
  1171. TEXT("REG_SZ"),
  1172. REG_OPTION_NON_VOLATILE,
  1173. KEY_READ | KEY_WRITE,
  1174. NULL,
  1175. &KeyHandle,
  1176. &Disposition
  1177. );
  1178. if (rc == ERROR_SUCCESS) {
  1179. //
  1180. // The key didn't exist. Create a cert
  1181. //
  1182. if (EnrollKeyPair( pEfsUserInfo,
  1183. &LocalhKey,
  1184. &LocalhProv,
  1185. lpContainerName,
  1186. lpProviderName,
  1187. PROV_RSA_FULL,
  1188. pbHash,
  1189. cbHash,
  1190. DisplayInfo
  1191. )) {
  1192. PBYTE pbLocalHash;
  1193. DWORD cbLocalHash;
  1194. //
  1195. // Write the hash value to the registry
  1196. //
  1197. if (*pbHash) {
  1198. pbLocalHash = *pbHash;
  1199. cbLocalHash = *cbHash;
  1200. } else {
  1201. ASSERT(pEfsUserInfo->pUserCache);
  1202. pbLocalHash = pEfsUserInfo->pUserCache->pbHash;
  1203. cbLocalHash = pEfsUserInfo->pUserCache->cbHash;
  1204. }
  1205. rc = RegSetValueEx(
  1206. KeyHandle, // handle of key to set value for
  1207. CERT_HASH,
  1208. 0,
  1209. REG_BINARY,
  1210. pbLocalHash,
  1211. cbLocalHash
  1212. );
  1213. if (rc == ERROR_SUCCESS) {
  1214. //
  1215. // Mark entire operation as successful
  1216. //
  1217. fSuccess = TRUE;
  1218. }
  1219. } else {
  1220. rc = GetLastError();
  1221. }
  1222. RegCloseKey( KeyHandle );
  1223. } else {
  1224. KeyHandle = NULL; // paranoia
  1225. //
  1226. // We couldn't create the registry key for some reason,
  1227. // fail the entire operation.
  1228. //
  1229. }
  1230. } else {
  1231. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  1232. DebugLog((DEB_TRACE_EFS, "KeyGen mutex %ws exists\n", pEfsUserInfo->lpUserName ));
  1233. //
  1234. // Some other thread is in here trying to create the keys.
  1235. // Wait on this mutex, and assume that once we come back,
  1236. // the other thread is done and we can just leave and
  1237. // try to get the keys again.
  1238. //
  1239. WaitForSingleObject( hMutex, INFINITE );
  1240. } else {
  1241. //
  1242. // If we're here, then CreateMutex did not fail, but GetLastError is
  1243. // set to something other than success or ERROR_ALREADY_EXISTS. Is
  1244. // this an error?
  1245. //
  1246. ASSERT(FALSE);
  1247. }
  1248. rc = ERROR_RETRY;
  1249. }
  1250. DebugLog((DEB_TRACE_EFS, "Closing mutex handle\n" ));
  1251. ReleaseMutex( hMutex );
  1252. CloseHandle( hMutex );
  1253. } else {
  1254. DebugLog((DEB_ERROR, "CreateMutex failed, error = %x\n", GetLastError() ));
  1255. rc = GetLastError();
  1256. }
  1257. if (fSuccess) {
  1258. //
  1259. // Return these to the caller
  1260. //
  1261. if (ARGUMENT_PRESENT( hKey ) && ARGUMENT_PRESENT( hProv )) {
  1262. //
  1263. // If the caller passed this in, he wants
  1264. // the key and provider passed back
  1265. //
  1266. *hKey = LocalhKey;
  1267. *hProv = LocalhProv;
  1268. } else {
  1269. if ( LocalhKey ) {
  1270. CryptDestroyKey( LocalhKey );
  1271. }
  1272. if ( LocalhProv ) {
  1273. CryptReleaseContext( LocalhProv, 0 );
  1274. }
  1275. }
  1276. } else {
  1277. //
  1278. // We failed somewhere, free what we were going
  1279. // to return.
  1280. //
  1281. if (*lpProviderName != NULL) {
  1282. LsapFreeLsaHeap( *lpProviderName );
  1283. *lpProviderName = NULL;
  1284. }
  1285. if (*lpContainerName != NULL) {
  1286. LsapFreeLsaHeap( *lpContainerName );
  1287. *lpContainerName = NULL;
  1288. }
  1289. if (*DisplayInfo != NULL) {
  1290. LsapFreeLsaHeap( *DisplayInfo );
  1291. *DisplayInfo = NULL;
  1292. }
  1293. if (*pbHash) {
  1294. LsapFreeLsaHeap( *pbHash );
  1295. *pbHash = NULL;
  1296. }
  1297. if (LocalhKey != 0) {
  1298. CryptDestroyKey( LocalhKey );
  1299. }
  1300. if (LocalhProv != 0) {
  1301. CryptReleaseContext(LocalhProv, 0);
  1302. }
  1303. }
  1304. return( rc );
  1305. }
  1306. BOOL
  1307. EqualCertPublicKeys(
  1308. PCERT_PUBLIC_KEY_INFO pKey1,
  1309. PCERT_PUBLIC_KEY_INFO pKey2
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. Helper routine to compare the public key portions of two certificates.
  1314. Arguments:
  1315. pKey1 - One of the public key info structures.
  1316. pKey2 - The other one.
  1317. Return Value:
  1318. TRUE on match, FALSE on failure.
  1319. --*/
  1320. {
  1321. CRYPT_BIT_BLOB * PublicKey1 = &pKey1->PublicKey;
  1322. CRYPT_BIT_BLOB * PublicKey2 = &pKey2->PublicKey;
  1323. if (PublicKey1->cbData == PublicKey2->cbData) {
  1324. if (memcmp(PublicKey1->pbData, PublicKey2->pbData, PublicKey2->cbData) == 0) {
  1325. return( TRUE );
  1326. }
  1327. }
  1328. return( FALSE );
  1329. }
  1330. LONG
  1331. SearchMyStoreForEFSCert(
  1332. IN PEFS_USER_INFO pEfsUserInfo,
  1333. OUT HCRYPTKEY * hKey OPTIONAL,
  1334. OUT HCRYPTPROV * hProv OPTIONAL,
  1335. OUT LPWSTR * ContainerName,
  1336. OUT LPWSTR * ProviderName,
  1337. OUT LPWSTR * DisplayInfo,
  1338. OUT PBYTE * pbHash,
  1339. OUT PDWORD cbHash
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. description-of-function.
  1344. Arguments:
  1345. argument-name - Supplies | Returns description of argument.
  1346. .
  1347. .
  1348. Return Value:
  1349. return-value - Description of conditions needed to return value. - or -
  1350. None.
  1351. --*/
  1352. {
  1353. DWORD rc = ERROR_NO_USER_KEYS;
  1354. HKEY hRegKey;
  1355. DWORD Disposition = 0;
  1356. HCRYPTPROV hLocalProv = NULL;
  1357. NTSTATUS status;
  1358. DWORD ImpersonationError = 0;
  1359. //
  1360. // Initialize required return values.
  1361. //
  1362. *ProviderName = NULL;
  1363. *ContainerName = NULL;
  1364. *DisplayInfo = NULL;
  1365. *pbHash = NULL;
  1366. *cbHash = 0;
  1367. //
  1368. // Initialize optional return values
  1369. //
  1370. if (ARGUMENT_PRESENT(hKey)) {
  1371. *hKey = NULL;
  1372. }
  1373. if (ARGUMENT_PRESENT(hProv)) {
  1374. *hProv = NULL;
  1375. }
  1376. //
  1377. // Assume that there's no current EFS information
  1378. // for this guy. Create the registry key.
  1379. //
  1380. rc = RegCreateKeyEx(
  1381. KEYPATHROOT,
  1382. pEfsUserInfo->lpKeyPath,
  1383. 0,
  1384. TEXT("REG_SZ"),
  1385. REG_OPTION_NON_VOLATILE,
  1386. KEY_ALL_ACCESS,
  1387. NULL,
  1388. &hRegKey,
  1389. &Disposition // address of disposition value buffer
  1390. );
  1391. //
  1392. // Open up the user's MY store and see if there's an EFS
  1393. // certificate floating around in there somewhere.
  1394. //
  1395. if (rc == ERROR_SUCCESS) {
  1396. CERT_ENHKEY_USAGE certEnhKeyUsage;
  1397. LPSTR lpstr = szOID_EFS_CRYPTO;
  1398. certEnhKeyUsage.cUsageIdentifier = 1;
  1399. certEnhKeyUsage.rgpszUsageIdentifier = &lpstr;
  1400. PCCERT_CONTEXT pCertContext = NULL;
  1401. //
  1402. // If this fails, there's no cert that matches.
  1403. //
  1404. HCERTSTORE hStore = CertOpenStore(
  1405. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  1406. 0, // dwEncodingType
  1407. 0, // hCryptProv,
  1408. CERT_SYSTEM_STORE_CURRENT_USER,
  1409. L"My"
  1410. );
  1411. // hStore = CertOpenSystemStoreW( NULL, L"MY");
  1412. if (hStore) {
  1413. do {
  1414. //
  1415. // This will go to success if everything works...
  1416. //
  1417. rc = ERROR_NO_USER_KEYS;
  1418. pCertContext = CertFindCertificateInStore(
  1419. hStore,
  1420. X509_ASN_ENCODING,
  1421. 0, //CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  1422. CERT_FIND_ENHKEY_USAGE,
  1423. &certEnhKeyUsage,
  1424. pCertContext
  1425. );
  1426. if (pCertContext) {
  1427. DebugLog((DEB_TRACE_EFS, "Found matching cert in MY store\n" ));
  1428. //
  1429. // Do cert validity checking.
  1430. //
  1431. if ( CertVerifyTimeValidity(
  1432. NULL,
  1433. pCertContext->pCertInfo
  1434. )){
  1435. rc = CERT_E_EXPIRED;
  1436. } else {
  1437. //
  1438. // Test the cert usage here.
  1439. // CERT_E_WRONG_USAGE
  1440. //
  1441. BOOL OidFound;
  1442. rc = EfsFindCertOid(
  1443. szOID_KP_EFS,
  1444. pCertContext,
  1445. &OidFound
  1446. );
  1447. if (ERROR_SUCCESS == rc) {
  1448. rc = ERROR_NO_USER_KEYS;
  1449. if (OidFound) {
  1450. *pbHash = GetCertHashFromCertContext(
  1451. pCertContext,
  1452. cbHash
  1453. );
  1454. if (*pbHash) {
  1455. //
  1456. // See if we can get container and provider info.
  1457. //
  1458. // Once we've got them, make sure we can call CryptAcquireContext
  1459. // and have it work. That guarantees there's a private key available.
  1460. //
  1461. PCRYPT_KEY_PROV_INFO pCryptKeyProvInfo = GetKeyProvInfo( pCertContext );
  1462. if (pCryptKeyProvInfo) {
  1463. if (!wcscmp(pCryptKeyProvInfo->pwszProvName, MS_DEF_PROV_W) ||
  1464. !wcscmp(pCryptKeyProvInfo->pwszProvName, MS_ENHANCED_PROV_W) ||
  1465. !wcscmp(pCryptKeyProvInfo->pwszProvName, MS_STRONG_PROV_W)) {
  1466. if (CryptAcquireContext(
  1467. &hLocalProv,
  1468. pCryptKeyProvInfo->pwszContainerName,
  1469. pCryptKeyProvInfo->pwszProvName,
  1470. pCryptKeyProvInfo->dwProvType,
  1471. pCryptKeyProvInfo->dwFlags | CRYPT_SILENT
  1472. )) {
  1473. //
  1474. // Make sure the public key in the cert matches the one
  1475. // that's in this context.
  1476. //
  1477. DWORD cbPubKeyInfo = 0;
  1478. PCERT_PUBLIC_KEY_INFO pPubKeyInfo = ExportPublicKeyInfo(
  1479. hLocalProv,
  1480. pCryptKeyProvInfo->dwKeySpec,
  1481. X509_ASN_ENCODING,
  1482. &cbPubKeyInfo
  1483. );
  1484. if (pPubKeyInfo) {
  1485. //
  1486. // Get the public key from the cert context
  1487. //
  1488. PCERT_INFO pCertInfo = pCertContext->pCertInfo;
  1489. PCERT_PUBLIC_KEY_INFO pSubjectPublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
  1490. if (EqualCertPublicKeys( pPubKeyInfo, pSubjectPublicKeyInfo )) {
  1491. //
  1492. // They match. We want to make sure not to return
  1493. // an error indicating that we didn't find a key.
  1494. // The next call will reset the value of rc
  1495. //
  1496. rc = RegSetValueEx(
  1497. hRegKey, // handle of key to set value for
  1498. CERT_HASH,
  1499. 0,
  1500. REG_BINARY,
  1501. *pbHash,
  1502. *cbHash
  1503. );
  1504. if (rc == ERROR_SUCCESS) {
  1505. if (pCryptKeyProvInfo->pwszProvName) {
  1506. *ProviderName = (LPWSTR)LsapAllocateLsaHeap( wcslen(pCryptKeyProvInfo->pwszProvName) * sizeof( WCHAR ) + sizeof(L'\0') );
  1507. if (*ProviderName) {
  1508. wcscpy( *ProviderName, pCryptKeyProvInfo->pwszProvName );
  1509. } else {
  1510. rc = ERROR_NOT_ENOUGH_MEMORY;
  1511. }
  1512. }
  1513. if (pCryptKeyProvInfo->pwszContainerName) {
  1514. *ContainerName = (LPWSTR)LsapAllocateLsaHeap( wcslen(pCryptKeyProvInfo->pwszContainerName) * sizeof( WCHAR ) + sizeof(L'\0') );
  1515. if (*ContainerName) {
  1516. wcscpy( *ContainerName, pCryptKeyProvInfo->pwszContainerName );
  1517. } else {
  1518. rc = ERROR_NOT_ENOUGH_MEMORY;
  1519. }
  1520. }
  1521. if (rc == ERROR_SUCCESS) {
  1522. if (!(*DisplayInfo = EfspGetCertDisplayInformation( pCertContext ))) {
  1523. //
  1524. // At least for now, we do not accept Cert without display name
  1525. //
  1526. rc = GetLastError();
  1527. }
  1528. }
  1529. //
  1530. // Let's add it to OtherPeople Store
  1531. //
  1532. if (ERROR_SUCCESS == (rc = EfsAddCertToCertStore(pCertContext, OTHERPEOPLE, &ImpersonationError))) {
  1533. DWORD StoreId = CERTINLMOTHERSTORE;
  1534. //
  1535. // Mark it in the store. Fail will not stop us.
  1536. //
  1537. (void) RegSetValueEx(
  1538. hRegKey, // handle of key to set value for
  1539. CERT_FLAG,
  1540. 0,
  1541. REG_DWORD,
  1542. (LPBYTE)&StoreId,
  1543. sizeof (DWORD)
  1544. );
  1545. } else {
  1546. if (!ImpersonationError) {
  1547. //
  1548. // Any error other than impersonation would not stop us here.
  1549. // Put the cert in the OtherPeople store is just a best effort.
  1550. //
  1551. rc = ERROR_SUCCESS;
  1552. }
  1553. }
  1554. //
  1555. // Create the cache node.
  1556. // We could have a cache node which is not validated or no cache at all.
  1557. // We could also have a valid cache but was not allowed to use since it
  1558. // is being freed.
  1559. //
  1560. if ((rc == ERROR_SUCCESS) && !pEfsUserInfo->UserCacheStop) {
  1561. //
  1562. // Cache is allowed now
  1563. //
  1564. if (!pEfsUserInfo->pUserCache || (pEfsUserInfo->pUserCache->CertValidated != CERT_VALIDATED)) {
  1565. //
  1566. // Let's create the cache
  1567. //
  1568. PUSER_CACHE pCacheNode;
  1569. PSID pUserID = NULL;
  1570. ULONG SidLength = 0;
  1571. pCacheNode = (PUSER_CACHE) LsapAllocateLsaHeap(sizeof(USER_CACHE));
  1572. if (pEfsUserInfo->InterActiveUser != USER_INTERACTIVE) {
  1573. SidLength = RtlLengthSid(pEfsUserInfo->pTokenUser->User.Sid);
  1574. pUserID = (PSID) LsapAllocateLsaHeap(SidLength);
  1575. }
  1576. if (pCacheNode && ((SidLength == 0) || (pUserID))) {
  1577. status = STATUS_SUCCESS;
  1578. memset( pCacheNode, 0, sizeof( USER_CACHE ));
  1579. if (pUserID) {
  1580. status = RtlCopySid(
  1581. SidLength,
  1582. pUserID,
  1583. pEfsUserInfo->pTokenUser->User.Sid
  1584. );
  1585. }
  1586. if (NT_SUCCESS( status ) && NT_SUCCESS( status = NtQuerySystemTime(&(pCacheNode->TimeStamp)))){
  1587. HCRYPTKEY hLocalKey;
  1588. if (CryptGetUserKey( hLocalProv, AT_KEYEXCHANGE, &hLocalKey )){
  1589. if (EfspInitUserCacheNode(
  1590. pCacheNode,
  1591. pUserID,
  1592. *pbHash,
  1593. *cbHash,
  1594. *ContainerName,
  1595. *ProviderName,
  1596. *DisplayInfo,
  1597. &(pCertContext->pCertInfo->NotAfter),
  1598. hLocalKey,
  1599. hLocalProv,
  1600. pUserID? NULL: &(pEfsUserInfo->AuthId),
  1601. CERT_VALIDATED
  1602. )){
  1603. //
  1604. // Cache node created and ready for use. Do not delete or close the info
  1605. // we just got.
  1606. //
  1607. *ContainerName = NULL;
  1608. *ProviderName = NULL;
  1609. *DisplayInfo = NULL;
  1610. *pbHash = NULL;
  1611. *cbHash = NULL;
  1612. hLocalProv = NULL;
  1613. if (pEfsUserInfo->pUserCache) {
  1614. //
  1615. // We had a not validated cache
  1616. //
  1617. EfspReleaseUserCache(pEfsUserInfo->pUserCache);
  1618. }
  1619. pEfsUserInfo->pUserCache = pCacheNode;
  1620. } else {
  1621. if (hLocalKey) {
  1622. CryptDestroyKey( hLocalKey );
  1623. }
  1624. LsapFreeLsaHeap(pCacheNode);
  1625. pCacheNode = NULL;
  1626. if (pUserID) {
  1627. LsapFreeLsaHeap(pUserID);
  1628. pUserID = NULL;
  1629. }
  1630. }
  1631. } else {
  1632. rc = GetLastError();
  1633. LsapFreeLsaHeap(pCacheNode);
  1634. pCacheNode = NULL;
  1635. if (pUserID) {
  1636. LsapFreeLsaHeap(pUserID);
  1637. pUserID = NULL;
  1638. }
  1639. }
  1640. } else {
  1641. rc = RtlNtStatusToDosError( status );
  1642. LsapFreeLsaHeap(pCacheNode);
  1643. pCacheNode = NULL;
  1644. if (pUserID) {
  1645. LsapFreeLsaHeap(pUserID);
  1646. pUserID = NULL;
  1647. }
  1648. }
  1649. } else {
  1650. if (pCacheNode) {
  1651. LsapFreeLsaHeap(pCacheNode);
  1652. pCacheNode = NULL;
  1653. }
  1654. if (pUserID) {
  1655. LsapFreeLsaHeap(pUserID);
  1656. pUserID = NULL;
  1657. }
  1658. }
  1659. }
  1660. }
  1661. }
  1662. } else {
  1663. rc = ERROR_NO_USER_KEYS;
  1664. }
  1665. LsapFreeLsaHeap( pPubKeyInfo );
  1666. }
  1667. }
  1668. }
  1669. LsapFreeLsaHeap( pCryptKeyProvInfo );
  1670. }
  1671. if (rc != ERROR_SUCCESS) {
  1672. LsapFreeLsaHeap( *pbHash );
  1673. *pbHash = NULL;
  1674. }
  1675. } else {
  1676. //
  1677. // If we failed for any reason other than running
  1678. // out of memory, assume that there is no key of
  1679. // use to us and return an appropriate error.
  1680. //
  1681. rc = GetLastError();
  1682. }
  1683. }
  1684. }
  1685. }
  1686. }
  1687. //
  1688. // We want to keep trying until we're out of certificates or we get
  1689. // an unexpected error (like out of memory).
  1690. //
  1691. if (rc != ERROR_SUCCESS) {
  1692. //
  1693. // Something failed, clean up anything we allocated that
  1694. // we were going to return.
  1695. //
  1696. if (*ProviderName) {
  1697. LsapFreeLsaHeap( *ProviderName );
  1698. *ProviderName = NULL;
  1699. }
  1700. if (*ContainerName) {
  1701. LsapFreeLsaHeap( *ContainerName );
  1702. *ContainerName = NULL;
  1703. }
  1704. if (*DisplayInfo) {
  1705. LsapFreeLsaHeap( *DisplayInfo );
  1706. *DisplayInfo = NULL;
  1707. }
  1708. if (*pbHash) {
  1709. LsapFreeLsaHeap( *pbHash );
  1710. *pbHash = NULL;
  1711. }
  1712. if (hLocalProv) {
  1713. CryptReleaseContext( hLocalProv, 0 );
  1714. hLocalProv = NULL;
  1715. }
  1716. }
  1717. } while ( pCertContext && rc != ERROR_SUCCESS && !ImpersonationError);
  1718. if (pCertContext) {
  1719. CertFreeCertificateContext( pCertContext );
  1720. }
  1721. CertCloseStore( hStore, 0 );
  1722. if (ARGUMENT_PRESENT(hKey) && ARGUMENT_PRESENT(hProv) && (rc == ERROR_SUCCESS) && (*pbHash)) {
  1723. *hProv = hLocalProv;
  1724. CryptGetUserKey( *hProv, AT_KEYEXCHANGE, hKey );
  1725. } else {
  1726. if (hLocalProv) {
  1727. CryptReleaseContext( hLocalProv, 0 );
  1728. }
  1729. }
  1730. } else {
  1731. //
  1732. // If we couldn't open the store, return
  1733. // no user keys and continue.
  1734. //
  1735. rc = ERROR_NO_USER_KEYS;
  1736. }
  1737. RegCloseKey( hRegKey );
  1738. }
  1739. return( rc );
  1740. }
  1741. LONG
  1742. GetInfoFromCertHash(
  1743. IN PEFS_USER_INFO pEfsUserInfo,
  1744. OUT HCRYPTKEY * hKey OPTIONAL,
  1745. OUT HCRYPTPROV * hProv OPTIONAL,
  1746. OUT LPWSTR * ContainerName,
  1747. OUT LPWSTR * ProviderName,
  1748. OUT LPWSTR * DisplayInfo,
  1749. OUT PBYTE * pbHash,
  1750. OUT PDWORD cbHash
  1751. )
  1752. /*++
  1753. Routine Description:
  1754. This routine will query the cert hash from the registry for this user and
  1755. return the useful information from the corresponding cert.
  1756. Arguments:
  1757. KeyPath - Supplies the fully formed path to the user's EFS key.
  1758. hKey - Optionally returns a handle to a key context.
  1759. hProv - Optionally returns a handle to a provider context.
  1760. ContainerName - Returns the name of the key container for this key.
  1761. ProviderName - Returns the name of the provider for this key.
  1762. DisplayInfo - Returns the display information from this certificate.
  1763. pbHash - Returns the hash found in the registry.
  1764. cbHash - Returns the size of the hash in bytes.
  1765. Return Value:
  1766. return-value - Description of conditions needed to return value. - or -
  1767. None.
  1768. --*/
  1769. {
  1770. DWORD rc;
  1771. HKEY hRegKey = NULL;
  1772. BOOLEAN bIsValid = TRUE;
  1773. //
  1774. // Initialize non-optional parameters
  1775. //
  1776. *ProviderName = NULL;
  1777. *ContainerName = NULL;
  1778. *DisplayInfo = NULL;
  1779. *pbHash = NULL;
  1780. *cbHash = 0;
  1781. //
  1782. // Initialize optional parameters
  1783. //
  1784. if (hKey) {
  1785. *hKey = NULL;
  1786. }
  1787. if (hProv) {
  1788. *hProv = NULL;
  1789. }
  1790. rc = RegOpenKeyEx(
  1791. KEYPATHROOT,
  1792. pEfsUserInfo->lpKeyPath,
  1793. 0,
  1794. GENERIC_READ | KEY_SET_VALUE,
  1795. &hRegKey
  1796. );
  1797. if (rc == ERROR_SUCCESS) {
  1798. //
  1799. // If there's a certificate thumbprint there, get it and use it.
  1800. //
  1801. DWORD Type;
  1802. rc = RegQueryValueEx(
  1803. hRegKey,
  1804. CERT_HASH,
  1805. NULL,
  1806. &Type,
  1807. NULL,
  1808. cbHash
  1809. );
  1810. if (rc == ERROR_SUCCESS) {
  1811. //
  1812. // Query out the thumbprint, find the cert, and return the key information.
  1813. //
  1814. if (*pbHash = (PBYTE)LsapAllocateLsaHeap( *cbHash )) {
  1815. rc = RegQueryValueEx(
  1816. hRegKey,
  1817. CERT_HASH,
  1818. NULL,
  1819. &Type,
  1820. *pbHash,
  1821. cbHash
  1822. );
  1823. if (rc == ERROR_SUCCESS) {
  1824. rc = GetKeyInfoFromCertHash(
  1825. pEfsUserInfo,
  1826. *pbHash,
  1827. *cbHash,
  1828. hKey,
  1829. hProv,
  1830. ContainerName,
  1831. ProviderName,
  1832. DisplayInfo,
  1833. &bIsValid
  1834. );
  1835. if (((*hKey == NULL) && (pEfsUserInfo->pUserCache) && (pEfsUserInfo->pUserCache->CertValidated != CERT_VALIDATED))
  1836. || !bIsValid) {
  1837. rc = ERROR_NO_USER_KEYS;
  1838. }
  1839. if ((rc == ERROR_SUCCESS) && (*hKey == NULL)) {
  1840. //
  1841. // The key in the cache is current. Free the pbHash
  1842. //
  1843. if (*pbHash) {
  1844. LsapFreeLsaHeap( *pbHash );
  1845. *pbHash = NULL;
  1846. }
  1847. }
  1848. }
  1849. } else {
  1850. rc = ERROR_NOT_ENOUGH_MEMORY;
  1851. }
  1852. }
  1853. RegCloseKey( hRegKey );
  1854. }
  1855. if (rc != ERROR_SUCCESS) {
  1856. //
  1857. // Something failed, clean up anything we allocated that
  1858. // we were going to return.
  1859. //
  1860. if (*ProviderName) {
  1861. LsapFreeLsaHeap( *ProviderName );
  1862. *ProviderName = NULL;
  1863. }
  1864. if (*ContainerName) {
  1865. LsapFreeLsaHeap( *ContainerName );
  1866. *ContainerName = NULL;
  1867. }
  1868. if (*DisplayInfo) {
  1869. LsapFreeLsaHeap( *DisplayInfo );
  1870. *DisplayInfo = NULL;
  1871. }
  1872. if (*pbHash) {
  1873. LsapFreeLsaHeap( *pbHash );
  1874. *pbHash = NULL;
  1875. }
  1876. if (hKey && *hKey) {
  1877. CryptDestroyKey( *hKey );
  1878. *hKey = NULL;
  1879. }
  1880. if (hProv && *hProv) {
  1881. CryptReleaseContext( *hProv, 0 );
  1882. *hProv = NULL;
  1883. }
  1884. //
  1885. // If anything other out out of memory failed, assume that there are no keys
  1886. // for this user.
  1887. //
  1888. if (rc != ERROR_NOT_ENOUGH_MEMORY) {
  1889. rc = ERROR_NO_USER_KEYS;
  1890. }
  1891. }
  1892. return( rc );
  1893. }
  1894. LONG
  1895. GetCurrentKey(
  1896. IN PEFS_USER_INFO pEfsUserInfo,
  1897. OUT HCRYPTKEY * hKey OPTIONAL,
  1898. OUT HCRYPTPROV * hProv OPTIONAL,
  1899. OUT LPWSTR * ContainerName,
  1900. OUT LPWSTR * ProviderName,
  1901. OUT PDWORD ProviderType,
  1902. OUT LPWSTR * DisplayInfo,
  1903. OUT PBYTE * pbHash,
  1904. OUT PDWORD cbHash
  1905. )
  1906. /*++
  1907. Routine Description:
  1908. This is the top level routine to get the user's current EFS key.
  1909. It will do the following, in order:
  1910. 1) Open the registry and attempt to find a certificate hash for
  1911. the user. If it finds one, it will attempt to find this hash
  1912. in the user's MY store and obtain all the useful information
  1913. with it.
  1914. 2) If that fails, it will check to see if there's old key data
  1915. (beta 1 and before) in the registry, and if it finds it, it
  1916. will convert that key data into a certificate and return
  1917. all the needed information.
  1918. 3) If that doesn't work, it will search the user's MY store for
  1919. an EFS certificate. If it finds one, it will install this as
  1920. the user's current EFS key.
  1921. 4) If that doesn't work, it will generate a new user key from scratch.
  1922. If that doesn't work, the operation fails.
  1923. Arguments:
  1924. hKey - Optionally returns a handle to the user's key.
  1925. hProv - Optionally returns a handle to the user's key's provider.
  1926. ContainerName - Returns the name of the user's key container.
  1927. ProviderName - Returns the name of the user's key provider.
  1928. ProviderType - Returns the type of the provider.
  1929. DisplayInfo - Returns the display information associated with this
  1930. certificate.
  1931. pbHash - Returns the hash of the user's certificate.
  1932. cbHash - Returns the length in bytes of the certificate hash.
  1933. Return Value:
  1934. ERROR_SUCCESS or Win32 error.
  1935. --*/
  1936. {
  1937. DWORD rc = ERROR_SUCCESS;
  1938. //
  1939. // There are four places we can get key information:
  1940. //
  1941. // 1) There's a hash in the registry. This is the typical
  1942. // case and the one we're going to try first.
  1943. //
  1944. // 2) Previous stuff left over from the last release of the
  1945. // system.
  1946. //
  1947. // 3) There's a cert in the user's MY store.
  1948. //
  1949. // 4) There's nothing.
  1950. //
  1951. //
  1952. // First, look for a hash.
  1953. //
  1954. if (pEfsUserInfo->pUserCache) {
  1955. if (pEfsUserInfo->pUserCache->CertValidated == CERT_VALIDATED){
  1956. //
  1957. // We will use the cache for current key
  1958. //
  1959. *ProviderName = NULL;
  1960. *ContainerName = NULL;
  1961. *DisplayInfo = NULL;
  1962. *pbHash = NULL;
  1963. *cbHash = 0;
  1964. //
  1965. // Initialize optional parameters
  1966. //
  1967. if (hKey) {
  1968. *hKey = NULL;
  1969. }
  1970. if (hProv) {
  1971. *hProv = NULL;
  1972. }
  1973. } else {
  1974. rc = ERROR_NO_USER_KEYS;
  1975. }
  1976. } else {
  1977. rc = ERROR_NO_USER_KEYS;
  1978. }
  1979. if (rc != ERROR_SUCCESS) {
  1980. if (!EfspLoadUserProfile( pEfsUserInfo, TRUE )){
  1981. //
  1982. // Profile Load Failure
  1983. //
  1984. return GetLastError();
  1985. }
  1986. rc = GetInfoFromCertHash(
  1987. pEfsUserInfo,
  1988. hKey,
  1989. hProv,
  1990. ContainerName,
  1991. ProviderName,
  1992. DisplayInfo,
  1993. pbHash,
  1994. cbHash
  1995. );
  1996. }
  1997. if ((ERROR_SUCCESS == rc) && ( NULL == *pbHash)) {
  1998. LARGE_INTEGER TimeStamp;
  1999. //
  2000. // We are using the cache
  2001. //
  2002. ASSERT( pEfsUserInfo->pUserCache );
  2003. //
  2004. // Check if we need to validate the cert again
  2005. //
  2006. if (NT_SUCCESS( NtQuerySystemTime(&TimeStamp)) &&
  2007. (TimeStamp.QuadPart - pEfsUserInfo->pUserCache->TimeStamp.QuadPart > CACHE_CERT_VALID_TIME )){
  2008. //
  2009. // It is due to check the certificate.
  2010. // Do cert validity checking.
  2011. //
  2012. LONG IsCertBeingValidated;
  2013. IsCertBeingValidated = InterlockedExchange(&UserCertIsValidating, 1);
  2014. if (IsCertBeingValidated != 1) {
  2015. if ( EfsTimeExp(&(pEfsUserInfo->pUserCache->CertExpTime))){
  2016. rc = ERROR_NO_USER_KEYS;
  2017. pEfsUserInfo->pUserCache->CertValidated = CERT_NOT_VALIDATED;
  2018. EfspReleaseUserCache(pEfsUserInfo->pUserCache);
  2019. pEfsUserInfo->pUserCache = NULL;
  2020. } else {
  2021. //
  2022. // Reset the time stamp.
  2023. // Do I need the sync object to protect this?
  2024. // Mixing the high word and low word is not a big problem here.
  2025. //
  2026. pEfsUserInfo->pUserCache->TimeStamp = TimeStamp;
  2027. }
  2028. if (IsCertBeingValidated != 1) {
  2029. InterlockedExchange(&UserCertIsValidating, IsCertBeingValidated);
  2030. }
  2031. }
  2032. }
  2033. }
  2034. if (rc == ERROR_NO_USER_KEYS) {
  2035. //
  2036. // That didn't work. Look for a cert in the
  2037. // user's MY store and use it.
  2038. //
  2039. rc = SearchMyStoreForEFSCert(
  2040. pEfsUserInfo,
  2041. hKey,
  2042. hProv,
  2043. ContainerName,
  2044. ProviderName,
  2045. DisplayInfo,
  2046. pbHash,
  2047. cbHash
  2048. );
  2049. if (rc == ERROR_NO_USER_KEYS) {
  2050. //
  2051. // That didn't work. Last resort:
  2052. // generate a new keyset for the user.
  2053. //
  2054. rc = GenerateUserKey(
  2055. pEfsUserInfo,
  2056. hKey,
  2057. hProv,
  2058. ContainerName,
  2059. ProviderName,
  2060. ProviderType,
  2061. DisplayInfo,
  2062. pbHash,
  2063. cbHash
  2064. );
  2065. if (rc == ERROR_RETRY) {
  2066. //
  2067. // There was another thread creating keys.
  2068. // Try one more time to get them.
  2069. // If this fails, fail the entire attempt.
  2070. //
  2071. rc = GetInfoFromCertHash(
  2072. pEfsUserInfo,
  2073. hKey,
  2074. hProv,
  2075. ContainerName,
  2076. ProviderName,
  2077. DisplayInfo,
  2078. pbHash,
  2079. cbHash
  2080. );
  2081. }
  2082. }
  2083. }
  2084. return( rc );
  2085. }
  2086. NTSTATUS
  2087. EfspGetUserName(
  2088. IN OUT PEFS_USER_INFO pEfsUserInfo
  2089. )
  2090. /*++
  2091. Routine Description:
  2092. This routine is the LSA Server worker routine for the LsaGetUserName
  2093. API.
  2094. WARNING: This routine allocates memory for its output. The caller is
  2095. responsible for freeing this memory after use. See description of the
  2096. Names parameter.
  2097. Arguments:
  2098. UserName - Receives name of the current user.
  2099. DomainName - Optionally receives domain name of the current user.
  2100. Return Values:
  2101. NTSTATUS - Standard Nt Result Code
  2102. STATUS_SUCCESS - The call completed successfully and all Sids have
  2103. been translated to names.
  2104. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  2105. such as memory to complete the call.
  2106. --*/
  2107. {
  2108. PUNICODE_STRING AccountName = NULL;
  2109. PUNICODE_STRING AuthorityName = NULL;
  2110. PUNICODE_STRING ProfilePath = NULL;
  2111. PLSAP_LOGON_SESSION LogonSession;
  2112. NTSTATUS Status;
  2113. //
  2114. // Let's see if we're trying to look up the currently logged on
  2115. // user.
  2116. //
  2117. //
  2118. // TokenUserInformation from this call must be freed by calling
  2119. // LsapFreeLsaHeap().
  2120. //
  2121. Status = EfspGetTokenUser( pEfsUserInfo );
  2122. if ( NT_SUCCESS( Status ) ) {
  2123. pEfsUserInfo->lpUserSid = ConvertSidToWideCharString( pEfsUserInfo->pTokenUser->User.Sid );
  2124. if (pEfsUserInfo->lpUserSid) {
  2125. //
  2126. // If the user ID is Anonymous then there is no name and domain in the
  2127. // logon session
  2128. //
  2129. if (RtlEqualSid(
  2130. pEfsUserInfo->pTokenUser->User.Sid,
  2131. LsapAnonymousSid
  2132. )) {
  2133. DebugLog((DEB_WARN, "Current user is Anonymous\n" ));
  2134. AccountName = &WellKnownSids[LsapAnonymousSidIndex].Name;
  2135. AuthorityName = &WellKnownSids[LsapAnonymousSidIndex].DomainName;
  2136. ProfilePath = NULL;
  2137. } else {
  2138. LogonSession = LsapLocateLogonSession ( &(pEfsUserInfo->AuthId) );
  2139. //
  2140. // During setup, we may get NULL returned for the logon session.
  2141. //
  2142. if (LogonSession) {
  2143. if (LogonSession->LogonType == Network){
  2144. if (LogonSession->PackageSpecificAttr & LOGONSES_FLAG_NTLM_DOWNLEVEL) {
  2145. Status = STATUS_BAD_LOGON_SESSION_STATE;
  2146. EfsLogEntry(
  2147. EVENTLOG_ERROR_TYPE,
  2148. 0,
  2149. EFS_NTLM_ERROR,
  2150. 0,
  2151. sizeof(NTSTATUS),
  2152. NULL,
  2153. &Status
  2154. );
  2155. } else {
  2156. if (RPC_C_AUTHN_WINNT == SpmpGetRpcPackageId(LogonSession->CreatingPackage)){
  2157. //
  2158. // This flag is just for error code.
  2159. //
  2160. pEfsUserInfo->NonKerberos = TRUE;
  2161. }
  2162. }
  2163. }
  2164. if (NT_SUCCESS( Status )) {
  2165. //
  2166. // Got a match. Get the username and domain information
  2167. // from the LogonId
  2168. //
  2169. AccountName = &LogonSession->AccountName;
  2170. AuthorityName = &LogonSession->AuthorityName;
  2171. ProfilePath = &LogonSession->ProfilePath;
  2172. }
  2173. LsapReleaseLogonSession( LogonSession );
  2174. } else {
  2175. Status = STATUS_NO_SUCH_LOGON_SESSION;
  2176. }
  2177. }
  2178. if (Status == STATUS_SUCCESS) {
  2179. pEfsUserInfo->lpUserName = (PWSTR)LsapAllocateLsaHeap(AccountName->Length + sizeof(UNICODE_NULL));
  2180. if (pEfsUserInfo->lpUserName != NULL) {
  2181. memcpy( pEfsUserInfo->lpUserName, AccountName->Buffer, AccountName->Length );
  2182. (pEfsUserInfo->lpUserName)[AccountName->Length/sizeof(WCHAR)] = UNICODE_NULL;
  2183. pEfsUserInfo->lpDomainName = (PWSTR)LsapAllocateLsaHeap(AuthorityName->Length + sizeof(UNICODE_NULL));
  2184. if (pEfsUserInfo->lpDomainName != NULL) {
  2185. memcpy( pEfsUserInfo->lpDomainName, AuthorityName->Buffer, AuthorityName->Length );
  2186. (pEfsUserInfo->lpDomainName)[AuthorityName->Length/sizeof(WCHAR)] = UNICODE_NULL;
  2187. } else {
  2188. Status = STATUS_INSUFFICIENT_RESOURCES;
  2189. }
  2190. if ((ProfilePath != NULL) && (ProfilePath->Length != 0)) {
  2191. pEfsUserInfo->lpProfilePath = (PWSTR)LsapAllocateLsaHeap(ProfilePath->Length + sizeof(UNICODE_NULL));
  2192. if (pEfsUserInfo->lpProfilePath != NULL) {
  2193. memcpy( pEfsUserInfo->lpProfilePath, ProfilePath->Buffer, ProfilePath->Length );
  2194. (pEfsUserInfo->lpProfilePath)[ProfilePath->Length/sizeof(WCHAR)] = UNICODE_NULL;
  2195. } else {
  2196. Status = STATUS_INSUFFICIENT_RESOURCES;
  2197. }
  2198. }
  2199. pEfsUserInfo->lpKeyPath = ConstructKeyPath(pEfsUserInfo->lpUserSid);
  2200. if ( pEfsUserInfo->lpKeyPath == NULL ) {
  2201. Status = STATUS_INSUFFICIENT_RESOURCES;
  2202. }
  2203. } else {
  2204. Status = STATUS_INSUFFICIENT_RESOURCES;
  2205. }
  2206. }
  2207. } else {
  2208. Status = STATUS_INSUFFICIENT_RESOURCES;
  2209. }
  2210. }
  2211. if (!NT_SUCCESS( Status )) {
  2212. //
  2213. // Something failed, clean up what we were going to return
  2214. //
  2215. EfspFreeUserInfo( pEfsUserInfo );
  2216. memset( pEfsUserInfo, 0, sizeof( EFS_USER_INFO ));
  2217. }
  2218. return(Status);
  2219. }
  2220. DWORD
  2221. EfspReplaceUserKeyInformation(
  2222. PEFS_USER_INFO pEfsUserInfo
  2223. )
  2224. /*++
  2225. Routine Description:
  2226. Forces the regeneration of the user's EFS key.
  2227. Arguments:
  2228. None.
  2229. Return Value:
  2230. Win32 error or ERROR_SUCCESS
  2231. --*/
  2232. {
  2233. LPWSTR ProviderName;
  2234. LPWSTR ContainerName;
  2235. LPWSTR DisplayInfo;
  2236. DWORD ProviderType;
  2237. DWORD cbHash;
  2238. PBYTE pbHash;
  2239. DWORD rc;
  2240. if (pEfsUserInfo->pUserCache) {
  2241. //
  2242. // We are going to create a new key. The current cache is going away.
  2243. // We will insert a new cache node in the header.
  2244. //
  2245. EfspReleaseUserCache(pEfsUserInfo->pUserCache);
  2246. pEfsUserInfo->pUserCache = NULL;
  2247. }
  2248. rc = RegDeleteKey(
  2249. KEYPATHROOT,
  2250. pEfsUserInfo->lpKeyPath
  2251. );
  2252. if (rc == ERROR_SUCCESS) {
  2253. rc = GenerateUserKey(
  2254. pEfsUserInfo,
  2255. NULL,
  2256. NULL,
  2257. &ContainerName,
  2258. &ProviderName,
  2259. &ProviderType,
  2260. &DisplayInfo,
  2261. &pbHash,
  2262. &cbHash
  2263. );
  2264. if (rc == ERROR_SUCCESS) {
  2265. if (ContainerName) {
  2266. LsapFreeLsaHeap( ContainerName );
  2267. }
  2268. if (ProviderName) {
  2269. LsapFreeLsaHeap( ProviderName );
  2270. }
  2271. if (DisplayInfo) {
  2272. LsapFreeLsaHeap( DisplayInfo );
  2273. }
  2274. if (pbHash) {
  2275. LsapFreeLsaHeap( pbHash );
  2276. }
  2277. }
  2278. }
  2279. return( rc );
  2280. }
  2281. DWORD
  2282. EfspInstallCertAsUserKey(
  2283. PEFS_USER_INFO pEfsUserInfo,
  2284. PENCRYPTION_CERTIFICATE pEncryptionCertificate
  2285. )
  2286. {
  2287. //
  2288. // Find the passed certificate in the user's MY store.
  2289. // If it's not there, we don't use the cert.
  2290. //
  2291. DWORD rc = ERROR_SUCCESS;
  2292. PCCERT_CONTEXT pCertContext = NULL;
  2293. DWORD cbHash = 0;
  2294. PBYTE pbHash = NULL;
  2295. BOOLEAN bIsValid;
  2296. //
  2297. // If this fails, there's no cert that matches.
  2298. //
  2299. __try{
  2300. pCertContext = CertCreateCertificateContext(
  2301. pEncryptionCertificate->pCertBlob->dwCertEncodingType,
  2302. pEncryptionCertificate->pCertBlob->pbData,
  2303. pEncryptionCertificate->pCertBlob->cbData
  2304. );
  2305. if (pCertContext) {
  2306. if (CertGetCertificateContextProperty(
  2307. pCertContext,
  2308. CERT_SHA1_HASH_PROP_ID,
  2309. NULL,
  2310. &cbHash
  2311. )) {
  2312. SafeAllocaAllocate(pbHash, cbHash);
  2313. if (pbHash) {
  2314. if (CertGetCertificateContextProperty(
  2315. pCertContext,
  2316. CERT_SHA1_HASH_PROP_ID,
  2317. pbHash,
  2318. &cbHash
  2319. )) {
  2320. HCRYPTKEY hKey;
  2321. HCRYPTPROV hProv;
  2322. LPWSTR ContainerName;
  2323. LPWSTR ProviderName;
  2324. LPWSTR DisplayInfo;
  2325. if (pEfsUserInfo->pUserCache) {
  2326. //
  2327. // We are going to create a new key. The current cache is going away.
  2328. // We will insert a new cache node in the header.
  2329. //
  2330. EfspReleaseUserCache(pEfsUserInfo->pUserCache);
  2331. pEfsUserInfo->pUserCache = NULL;
  2332. }
  2333. rc = GetKeyInfoFromCertHash(
  2334. pEfsUserInfo,
  2335. pbHash,
  2336. cbHash,
  2337. &hKey,
  2338. &hProv,
  2339. &ContainerName,
  2340. &ProviderName,
  2341. &DisplayInfo,
  2342. &bIsValid
  2343. );
  2344. if (ERROR_SUCCESS == rc) {
  2345. //
  2346. // We don't care about any of the stuff that came back,
  2347. // all we care about is that it was all found, meaning
  2348. // that the key exists and can be used. Now that we know
  2349. // that, we can jam the hash into the registry.
  2350. //
  2351. HKEY KeyHandle;
  2352. DWORD Disposition;
  2353. rc = RegCreateKeyEx(
  2354. KEYPATHROOT,
  2355. pEfsUserInfo->lpKeyPath,
  2356. 0,
  2357. TEXT("REG_SZ"),
  2358. REG_OPTION_NON_VOLATILE,
  2359. KEY_READ | KEY_WRITE,
  2360. NULL,
  2361. &KeyHandle,
  2362. &Disposition // address of disposition value buffer
  2363. );
  2364. if (ERROR_SUCCESS == rc) {
  2365. rc = RegSetValueEx(
  2366. KeyHandle, // handle of key to set value for
  2367. CERT_HASH,
  2368. 0,
  2369. REG_BINARY,
  2370. pbHash,
  2371. cbHash
  2372. );
  2373. RegCloseKey( KeyHandle );
  2374. }
  2375. if (hKey) {
  2376. //
  2377. // hKey not NULL means we have not put the data in the cache.
  2378. //
  2379. CryptDestroyKey( hKey );
  2380. CryptReleaseContext( hProv, 0 );
  2381. LsapFreeLsaHeap( ContainerName );
  2382. LsapFreeLsaHeap( ProviderName );
  2383. LsapFreeLsaHeap( DisplayInfo );
  2384. }
  2385. }
  2386. } else {
  2387. rc = GetLastError();
  2388. }
  2389. SafeAllocaFree( pbHash );
  2390. pbHash = NULL;
  2391. } else {
  2392. rc = ERROR_NOT_ENOUGH_MEMORY;
  2393. }
  2394. } else {
  2395. rc = GetLastError();
  2396. }
  2397. CertFreeCertificateContext( pCertContext );
  2398. } else {
  2399. rc = GetLastError();
  2400. }
  2401. } __except (EXCEPTION_EXECUTE_HANDLER) {
  2402. rc = ERROR_INVALID_PARAMETER;
  2403. if (pCertContext) {
  2404. CertFreeCertificateContext( pCertContext );
  2405. }
  2406. if (pbHash) {
  2407. SafeAllocaFree( pbHash );
  2408. }
  2409. EfspLogAttack(pEfsUserInfo, CORRUPT_DATA_8);
  2410. }
  2411. return( rc );
  2412. }
  2413. BOOLEAN
  2414. CurrentHashOK(
  2415. IN PEFS_USER_INFO pEfsUserInfo,
  2416. IN PBYTE pbHash,
  2417. IN DWORD cbHash,
  2418. OUT DWORD *dFlag
  2419. )
  2420. /*++
  2421. Routine Description:
  2422. See if the value pbHash is already in the user's key. If not, try to see if we can add it back.
  2423. Arguments:
  2424. pEfsUserInfo -- User Info
  2425. pbHash -- Hash value
  2426. cbHash -- Hash length
  2427. dFlag -- Cert Flag to indicate if the cert has been added to the LM intermediate store
  2428. Return Value:
  2429. TRUE if the pbHash found or added successfully
  2430. --*/
  2431. {
  2432. DWORD rc;
  2433. BOOLEAN b = FALSE;
  2434. HKEY hRegKey = NULL;
  2435. PBYTE pbLocalHash;
  2436. DWORD cbLocalHash;
  2437. rc = RegOpenKeyEx(
  2438. KEYPATHROOT,
  2439. pEfsUserInfo->lpKeyPath,
  2440. 0,
  2441. GENERIC_READ,
  2442. &hRegKey
  2443. );
  2444. *dFlag = 0;
  2445. if (rc == ERROR_SUCCESS) {
  2446. //
  2447. // If there's a certificate thumbprint there, get it and use it.
  2448. //
  2449. DWORD Type;
  2450. rc = RegQueryValueEx(
  2451. hRegKey,
  2452. CERT_HASH,
  2453. NULL,
  2454. &Type,
  2455. NULL,
  2456. &cbLocalHash
  2457. );
  2458. if (rc == ERROR_SUCCESS) {
  2459. if (cbLocalHash == cbHash) {
  2460. //
  2461. // Query out the thumbprint, find the cert, and return the key information.
  2462. //
  2463. SafeAllocaAllocate(pbLocalHash, cbLocalHash);
  2464. if (pbLocalHash != NULL) {
  2465. rc = RegQueryValueEx(
  2466. hRegKey,
  2467. CERT_HASH,
  2468. NULL,
  2469. &Type,
  2470. pbLocalHash,
  2471. &cbLocalHash
  2472. );
  2473. if (rc == ERROR_SUCCESS) {
  2474. //
  2475. // Check if the hash value matches
  2476. //
  2477. if (RtlEqualMemory( pbLocalHash, pbHash, cbHash)){
  2478. b = TRUE;
  2479. cbLocalHash = sizeof (DWORD);
  2480. if (RegQueryValueEx(
  2481. hRegKey,
  2482. CERT_FLAG,
  2483. NULL,
  2484. &Type,
  2485. (LPBYTE) dFlag,
  2486. &cbLocalHash
  2487. )){
  2488. //
  2489. // Make sure dFlag set to 0 if error occurs. This may not be needed.
  2490. //
  2491. *dFlag = 0;
  2492. }
  2493. }
  2494. }
  2495. SafeAllocaFree(pbLocalHash);
  2496. }
  2497. }
  2498. }
  2499. RegCloseKey( hRegKey );
  2500. }
  2501. if (rc != ERROR_SUCCESS) {
  2502. //
  2503. // Let's see if we can create one
  2504. //
  2505. DWORD Disposition = 0;
  2506. //
  2507. // Assume that there's no current EFS information
  2508. // for this guy. Create the registry key.
  2509. //
  2510. rc = RegCreateKeyEx(
  2511. KEYPATHROOT,
  2512. pEfsUserInfo->lpKeyPath,
  2513. 0,
  2514. TEXT("REG_SZ"),
  2515. REG_OPTION_NON_VOLATILE,
  2516. KEY_ALL_ACCESS,
  2517. NULL,
  2518. &hRegKey,
  2519. &Disposition // address of disposition value buffer
  2520. );
  2521. if (rc == ERROR_SUCCESS) {
  2522. rc = RegSetValueEx(
  2523. hRegKey, // handle of key to set value for
  2524. CERT_HASH,
  2525. 0,
  2526. REG_BINARY,
  2527. pbHash,
  2528. cbHash
  2529. );
  2530. if (rc == ERROR_SUCCESS) {
  2531. b = TRUE;
  2532. }
  2533. RegCloseKey( hRegKey );
  2534. }
  2535. }
  2536. return b;
  2537. }
  2538. DWORD
  2539. GetCurrentHash(
  2540. IN PEFS_USER_INFO pEfsUserInfo,
  2541. OUT PBYTE *pbHash,
  2542. OUT DWORD *cbHash
  2543. )
  2544. {
  2545. HKEY hRegKey = NULL;
  2546. DWORD rc;
  2547. ASSERT(pbHash);
  2548. ASSERT(cbHash);
  2549. *pbHash = NULL;
  2550. rc = RegOpenKeyEx(
  2551. KEYPATHROOT,
  2552. pEfsUserInfo->lpKeyPath,
  2553. 0,
  2554. GENERIC_READ,
  2555. &hRegKey
  2556. );
  2557. if (rc == ERROR_SUCCESS) {
  2558. DWORD Type;
  2559. rc = RegQueryValueEx(
  2560. hRegKey,
  2561. CERT_HASH,
  2562. NULL,
  2563. &Type,
  2564. NULL,
  2565. cbHash
  2566. );
  2567. if (rc == ERROR_SUCCESS) {
  2568. if (*pbHash = (PBYTE)LsapAllocateLsaHeap( *cbHash )) {
  2569. rc = RegQueryValueEx(
  2570. hRegKey,
  2571. CERT_HASH,
  2572. NULL,
  2573. &Type,
  2574. *pbHash,
  2575. cbHash
  2576. );
  2577. if (rc != ERROR_SUCCESS) {
  2578. LsapFreeLsaHeap(*pbHash);
  2579. *pbHash = NULL;
  2580. }
  2581. } else {
  2582. rc = GetLastError();
  2583. }
  2584. }
  2585. RegCloseKey( hRegKey );
  2586. }
  2587. return rc;
  2588. }
  2589. BOOLEAN
  2590. EfspInitUserCacheNode(
  2591. IN OUT PUSER_CACHE pCacheNode,
  2592. IN PSID pUserID,
  2593. IN PBYTE pbHash,
  2594. IN DWORD cbHash,
  2595. IN LPWSTR ContainerName,
  2596. IN LPWSTR ProviderName,
  2597. IN LPWSTR DisplayInformation,
  2598. IN LPFILETIME CertExpTime,
  2599. IN HCRYPTKEY hKey,
  2600. IN HCRYPTPROV hProv,
  2601. IN LUID *AuthId,
  2602. IN LONG CertValidated
  2603. )
  2604. /*++
  2605. Routine Description:
  2606. Initialize the cache node and insert it into the list.
  2607. Arguments:
  2608. pCacheNode -- Node to be inserted
  2609. pUserID -- User SID
  2610. pbHash -- User Cert Hash
  2611. cbHash -- Length of the hash data
  2612. ContainerName -- Container name
  2613. ProviderName -- Provider name
  2614. DisplayInformation -- Display information
  2615. CertExpTime -- Certificate expiration time
  2616. hKey -- User Key
  2617. hProv -- Provider handle
  2618. AuthId -- Authentication ID
  2619. CertValidated -- Cert validation info
  2620. Return Value:
  2621. TRUE if successful
  2622. --*/
  2623. {
  2624. if (!pCacheNode) {
  2625. SetLastError(ERROR_INVALID_PARAMETER);
  2626. return FALSE;
  2627. }
  2628. pCacheNode->UserId = pUserID;
  2629. pCacheNode->pbHash = pbHash;
  2630. pCacheNode->cbHash = cbHash;
  2631. pCacheNode->ContainerName = ContainerName;
  2632. pCacheNode->ProviderName = ProviderName;
  2633. pCacheNode->DisplayInformation = DisplayInformation;
  2634. pCacheNode->CertExpTime = *CertExpTime;
  2635. pCacheNode->hUserKey = hKey;
  2636. pCacheNode->hProv = hProv;
  2637. pCacheNode->CertValidated = CertValidated;
  2638. pCacheNode->UseRefCount = 1; // The caller's hold on this node
  2639. pCacheNode->StopUseCount = 0;
  2640. if (AuthId) {
  2641. //
  2642. // pCacheNode->AuthId would be 0 if AuthId == NULL. Init in the caller.
  2643. //
  2644. pCacheNode->AuthId = *AuthId;
  2645. }
  2646. return (EfspAddUserCache(pCacheNode));
  2647. }
  2648. BOOL
  2649. EfsGetBasicConstraintExt(
  2650. IN OUT PCERT_EXTENSION *basicRestraint
  2651. )
  2652. {
  2653. BOOL bRet = TRUE;
  2654. CERT_BASIC_CONSTRAINTS2_INFO CertConstraints2;
  2655. DWORD rc = ERROR_SUCCESS;
  2656. RtlZeroMemory( &CertConstraints2, sizeof(CERT_BASIC_CONSTRAINTS2_INFO) );
  2657. *basicRestraint = (PCERT_EXTENSION) LsapAllocateLsaHeap(sizeof(CERT_EXTENSION));
  2658. if (*basicRestraint) {
  2659. bRet = CryptEncodeObject(
  2660. X509_ASN_ENCODING,
  2661. X509_BASIC_CONSTRAINTS2,
  2662. &CertConstraints2,
  2663. NULL,
  2664. &((*basicRestraint)->Value.cbData)
  2665. );
  2666. if (bRet) {
  2667. (*basicRestraint)->Value.pbData = (PBYTE) LsapAllocateLsaHeap( (*basicRestraint)->Value.cbData );
  2668. if ((*basicRestraint)->Value.pbData) {
  2669. bRet = CryptEncodeObject(
  2670. X509_ASN_ENCODING,
  2671. X509_BASIC_CONSTRAINTS2,
  2672. &CertConstraints2,
  2673. (*basicRestraint)->Value.pbData,
  2674. &((*basicRestraint)->Value.cbData)
  2675. );
  2676. if (bRet) {
  2677. (*basicRestraint)->pszObjId = szOID_BASIC_CONSTRAINTS2;
  2678. (*basicRestraint)->fCritical = FALSE;
  2679. } else {
  2680. rc = GetLastError();
  2681. LsapFreeLsaHeap((*basicRestraint)->Value.pbData);
  2682. SetLastError(rc);
  2683. }
  2684. } else {
  2685. bRet = FALSE;
  2686. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2687. }
  2688. }
  2689. if (!bRet) {
  2690. rc = GetLastError();
  2691. LsapFreeLsaHeap(*basicRestraint);
  2692. SetLastError(rc);
  2693. *basicRestraint = NULL;
  2694. }
  2695. } else {
  2696. bRet = FALSE;
  2697. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2698. }
  2699. return bRet;
  2700. }
  2701. BOOL
  2702. EfsGetAltNameExt(
  2703. IN OUT PCERT_EXTENSION *altNameExt,
  2704. IN LPWSTR UPNName
  2705. )
  2706. {
  2707. BOOL bRet = TRUE;
  2708. DWORD cbData = 0;
  2709. DWORD rc = ERROR_SUCCESS;
  2710. CERT_NAME_VALUE prnName;
  2711. CERT_OTHER_NAME certOtherName;
  2712. CERT_ALT_NAME_ENTRY altName;
  2713. CERT_ALT_NAME_INFO nameInfo;
  2714. *altNameExt = (PCERT_EXTENSION) LsapAllocateLsaHeap(sizeof(CERT_EXTENSION));
  2715. if (*altNameExt) {
  2716. prnName.dwValueType = CERT_RDN_UTF8_STRING;
  2717. prnName.Value.cbData = (wcslen(UPNName) + 1) * sizeof(WCHAR);
  2718. prnName.Value.pbData = (BYTE *)UPNName;
  2719. bRet = CryptEncodeObject(
  2720. X509_ASN_ENCODING,
  2721. X509_UNICODE_ANY_STRING,
  2722. &prnName,
  2723. NULL,
  2724. &certOtherName.Value.cbData
  2725. );
  2726. if (bRet) {
  2727. SafeAllocaAllocate(certOtherName.Value.pbData, certOtherName.Value.cbData);
  2728. if (certOtherName.Value.pbData) {
  2729. bRet = CryptEncodeObject(
  2730. X509_ASN_ENCODING,
  2731. X509_UNICODE_ANY_STRING,
  2732. &prnName,
  2733. certOtherName.Value.pbData,
  2734. &certOtherName.Value.cbData
  2735. );
  2736. if (bRet) {
  2737. altName.dwAltNameChoice = CERT_ALT_NAME_OTHER_NAME;
  2738. certOtherName.pszObjId = szOID_NT_PRINCIPAL_NAME;
  2739. altName.pOtherName = &certOtherName;
  2740. nameInfo.cAltEntry = 1;
  2741. nameInfo.rgAltEntry = &altName;
  2742. bRet = CryptEncodeObject(
  2743. X509_ASN_ENCODING,
  2744. szOID_SUBJECT_ALT_NAME,
  2745. &nameInfo,
  2746. NULL,
  2747. &((*altNameExt)->Value.cbData)
  2748. );
  2749. if (bRet) {
  2750. (*altNameExt)->Value.pbData = (PBYTE) LsapAllocateLsaHeap( (*altNameExt)->Value.cbData );
  2751. if ((*altNameExt)->Value.pbData) {
  2752. bRet = CryptEncodeObject(
  2753. X509_ASN_ENCODING,
  2754. szOID_SUBJECT_ALT_NAME,
  2755. &nameInfo,
  2756. (*altNameExt)->Value.pbData,
  2757. &((*altNameExt)->Value.cbData)
  2758. );
  2759. if (bRet) {
  2760. (*altNameExt)->pszObjId = szOID_SUBJECT_ALT_NAME2;
  2761. (*altNameExt)->fCritical = FALSE;
  2762. } else {
  2763. DWORD rc = GetLastError();
  2764. LsapFreeLsaHeap((*altNameExt)->Value.pbData);
  2765. SetLastError(rc);
  2766. }
  2767. } else {
  2768. bRet = FALSE;
  2769. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2770. }
  2771. }
  2772. }
  2773. rc = GetLastError();
  2774. SafeAllocaFree(certOtherName.Value.pbData);
  2775. SetLastError(rc);
  2776. } else {
  2777. bRet = FALSE;
  2778. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2779. }
  2780. }
  2781. if (!bRet) {
  2782. GetLastError();
  2783. LsapFreeLsaHeap(*altNameExt);
  2784. SetLastError(rc);
  2785. *altNameExt = NULL;
  2786. }
  2787. } else {
  2788. bRet = FALSE;
  2789. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2790. }
  2791. return bRet;
  2792. }
  2793. VOID
  2794. EfsMarkCertAddedToStore(
  2795. IN PEFS_USER_INFO pEfsUserInfo,
  2796. IN DWORD StoreId
  2797. )
  2798. /*++
  2799. Routine Description:
  2800. Mark in the registry that we have add the cert to the LM store.
  2801. Arguments:
  2802. pEfsUserInfo -- User Info
  2803. Return Value:
  2804. None.
  2805. --*/
  2806. {
  2807. HKEY hRegKey = NULL;
  2808. DWORD rc;
  2809. rc = RegOpenKeyEx(
  2810. KEYPATHROOT,
  2811. pEfsUserInfo->lpKeyPath,
  2812. 0,
  2813. GENERIC_READ | GENERIC_WRITE,
  2814. &hRegKey
  2815. );
  2816. if (rc == ERROR_SUCCESS) {
  2817. RegSetValueEx(
  2818. hRegKey, // handle of key to set value for
  2819. CERT_FLAG,
  2820. 0,
  2821. REG_DWORD,
  2822. (LPBYTE)&StoreId,
  2823. sizeof (DWORD)
  2824. );
  2825. RegCloseKey( hRegKey );
  2826. }
  2827. return;
  2828. }
  2829. DWORD
  2830. EfsTryRenewCert(
  2831. IN PEFS_USER_INFO pEfsUserInfo,
  2832. IN PCCERT_CONTEXT pCertContext,
  2833. OUT PCCERT_CONTEXT *pNewCertContext
  2834. )
  2835. /*++
  2836. Routine Description:
  2837. This routine takes a cert context. Will try to see if a replacement cert is ready. We will do no more than
  2838. five level chase and does not check to see if the private key is available.
  2839. If YES, it verifies the cert is good for EFS and refresh the EFS current cert hash.
  2840. Arguments:
  2841. pEfsUserInfo - User Information
  2842. pCertContext - Old EFS cert
  2843. CurrentBadCert - If TRUE, current cert hash will be set to a bogus one so that next GetCurrentKey will do
  2844. a research for performance.
  2845. pNewCertContext - *pNewCertContext non-zero if cert is renewed.
  2846. Return Value:
  2847. ERROR_SUCCESS - No Error.
  2848. --*/
  2849. {
  2850. PCCERT_CONTEXT pTmpCertContext = NULL;
  2851. PCCERT_CONTEXT pNewTmpCertContext = NULL;
  2852. DWORD rc = ERROR_SUCCESS;
  2853. PBYTE newCertHash[AutoEnrollChainLevel];
  2854. DWORD cbNewCertHash[AutoEnrollChainLevel];
  2855. DWORD newHashes;
  2856. DWORD goodHashNo = 0;
  2857. DWORD ii;
  2858. BOOL CircleRef = FALSE;
  2859. BOOL HasProperty;
  2860. *pNewCertContext = NULL;
  2861. newHashes = 0;
  2862. RtlZeroMemory(newCertHash, sizeof( newCertHash ));
  2863. RtlZeroMemory(cbNewCertHash, sizeof( cbNewCertHash ));
  2864. pTmpCertContext = pCertContext;
  2865. while (newHashes < AutoEnrollChainLevel) {
  2866. //
  2867. // The hash has a length of 20 bytes. If this changes in the future,
  2868. // the code will not have problem at all. Set init value to 32 is faster than
  2869. // than set to NULL and adjust later.
  2870. //
  2871. cbNewCertHash[newHashes] = 32;
  2872. SafeAllocaAllocate(newCertHash[newHashes], cbNewCertHash[newHashes]);
  2873. HasProperty = FALSE;
  2874. if (newCertHash[newHashes] != NULL) {
  2875. HasProperty = CertGetCertificateContextProperty(
  2876. pTmpCertContext,
  2877. CERT_RENEWAL_PROP_ID,
  2878. newCertHash[newHashes],
  2879. &cbNewCertHash[newHashes]
  2880. );
  2881. if (!HasProperty) {
  2882. if (ERROR_MORE_DATA == (rc = GetLastError())) {
  2883. SafeAllocaFree(newCertHash[newHashes]);
  2884. SafeAllocaAllocate(newCertHash[newHashes], cbNewCertHash[newHashes]);
  2885. if (newCertHash[newHashes] != NULL) {
  2886. HasProperty = CertGetCertificateContextProperty(
  2887. pTmpCertContext,
  2888. CERT_RENEWAL_PROP_ID,
  2889. newCertHash[newHashes],
  2890. &cbNewCertHash[newHashes]
  2891. );
  2892. if (!HasProperty) {
  2893. rc = GetLastError();
  2894. }
  2895. }
  2896. }
  2897. }
  2898. }
  2899. if (HasProperty){
  2900. //
  2901. // Now make sure the new cert is good for EFS.
  2902. //
  2903. pNewTmpCertContext = GetCertContextFromCertHash(
  2904. newCertHash[newHashes],
  2905. cbNewCertHash[newHashes],
  2906. CERT_SYSTEM_STORE_CURRENT_USER,
  2907. 0
  2908. );
  2909. if (pNewTmpCertContext) {
  2910. //
  2911. // We got the cert. Let's see if the cert is good for EFS.
  2912. // EFSOid is already checked in GetCertContextFromCertHash.
  2913. //
  2914. if ( !CertVerifyTimeValidity(
  2915. NULL,
  2916. pNewTmpCertContext->pCertInfo
  2917. )){
  2918. ii = newHashes;
  2919. while (ii > 0) {
  2920. if (cbNewCertHash[ii-1] == cbNewCertHash[newHashes]) {
  2921. if (memcmp(newCertHash[ii-1], newCertHash[newHashes], cbNewCertHash[ii-1]) == 0) {
  2922. //
  2923. // Circular reference. Break to avoid dead lock. This is unlikely.
  2924. // Malicious user could cause this.
  2925. //
  2926. if (*pNewCertContext) {
  2927. CertFreeCertificateContext( *pNewCertContext );
  2928. }
  2929. CertFreeCertificateContext( pNewTmpCertContext );
  2930. if ((pTmpCertContext != pCertContext) && (pTmpCertContext != *pNewCertContext) ) {
  2931. //
  2932. // Free the old cert context.
  2933. //
  2934. CertFreeCertificateContext( pTmpCertContext );
  2935. pTmpCertContext = NULL;
  2936. }
  2937. *pNewCertContext = NULL;
  2938. ii = 0;
  2939. while (ii <= newHashes) {
  2940. if (newCertHash[ii]) {
  2941. SafeAllocaFree(newCertHash[ii]);
  2942. newCertHash[ii] = NULL;
  2943. }
  2944. ii++;
  2945. }
  2946. CircleRef = TRUE;
  2947. newHashes = 0;
  2948. break;
  2949. }
  2950. }
  2951. ii--;
  2952. }
  2953. if (CircleRef) {
  2954. break;
  2955. }
  2956. goodHashNo = newHashes;
  2957. newHashes++;
  2958. if (*pNewCertContext) {
  2959. if (*pNewCertContext == pTmpCertContext) {
  2960. pTmpCertContext = NULL;
  2961. }
  2962. CertFreeCertificateContext( *pNewCertContext );
  2963. }
  2964. *pNewCertContext = pNewTmpCertContext;
  2965. } else {
  2966. newHashes++;
  2967. rc = CERT_E_EXPIRED;
  2968. }
  2969. if (pTmpCertContext && (pTmpCertContext != pCertContext) && (pTmpCertContext != *pNewCertContext)) {
  2970. //
  2971. // Free the old cert context.
  2972. //
  2973. CertFreeCertificateContext( pTmpCertContext );
  2974. }
  2975. pTmpCertContext = pNewTmpCertContext;
  2976. pNewTmpCertContext = NULL;
  2977. } else {
  2978. //
  2979. // The cert pointed is non-existing. Take the last good one.
  2980. //
  2981. rc = GetLastError();
  2982. break;
  2983. }
  2984. } else {
  2985. if (newCertHash[newHashes] == NULL) {
  2986. rc = ERROR_NOT_ENOUGH_MEMORY;
  2987. } else {
  2988. SafeAllocaFree(newCertHash[newHashes]);
  2989. newCertHash[newHashes] = NULL;
  2990. }
  2991. //
  2992. // Chain ends. This could be a normal path.
  2993. //
  2994. break;
  2995. }
  2996. }
  2997. if (pTmpCertContext && (pTmpCertContext != pCertContext) && (pTmpCertContext != *pNewCertContext)) {
  2998. //
  2999. // Free the old cert context.
  3000. //
  3001. CertFreeCertificateContext( pTmpCertContext );
  3002. pTmpCertContext = NULL;
  3003. }
  3004. if (*pNewCertContext) {
  3005. //
  3006. // We got a good cert. Reset the error.
  3007. //
  3008. rc = ERROR_SUCCESS;
  3009. //
  3010. // Now let's update the current EFS cert
  3011. //
  3012. HKEY KeyHandle;
  3013. DWORD Disposition;
  3014. rc = RegCreateKeyEx(
  3015. KEYPATHROOT,
  3016. pEfsUserInfo->lpKeyPath,
  3017. 0,
  3018. TEXT("REG_SZ"),
  3019. REG_OPTION_NON_VOLATILE,
  3020. KEY_READ | KEY_WRITE,
  3021. NULL,
  3022. &KeyHandle,
  3023. &Disposition // address of disposition value buffer
  3024. );
  3025. if (ERROR_SUCCESS == rc) {
  3026. rc = RegSetValueEx(
  3027. KeyHandle, // handle of key to set value for
  3028. CERT_HASH,
  3029. 0,
  3030. REG_BINARY,
  3031. newCertHash[goodHashNo],
  3032. cbNewCertHash[goodHashNo]
  3033. );
  3034. RegCloseKey( KeyHandle );
  3035. }
  3036. }
  3037. if (ERROR_SUCCESS != rc) {
  3038. //
  3039. // Can't write the new hash.
  3040. //
  3041. if (*pNewCertContext) {
  3042. CertFreeCertificateContext( *pNewCertContext );
  3043. *pNewCertContext = NULL;
  3044. }
  3045. }
  3046. ii = 0;
  3047. while (ii < AutoEnrollChainLevel) {
  3048. if (newCertHash[ii]) {
  3049. SafeAllocaFree(newCertHash[ii]);
  3050. }
  3051. ii++;
  3052. }
  3053. return rc;
  3054. }