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.

3273 lines
100 KiB

  1. //+-------------------------------------------------------------------------
  2. // Microsoft Windows
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995 - 1999
  5. //
  6. // File: protroot.cpp
  7. //
  8. // Contents: Protect Current User (CU) Root Store APIs
  9. //
  10. // Functions: I_ProtectedRootDllMain
  11. // I_CertProtectFunction
  12. // I_CertSrvProtectFunction
  13. // IPR_EnableSecurityPrivilege
  14. // IPR_IsCurrentUserRootsAllowed
  15. // IPR_IsAuthRootsAllowed
  16. // IPR_IsNTAuthRequiredDisabled
  17. // IPR_IsNotDefinedNameConstraintDisabled
  18. // IPR_IsAuthRootAutoUpdateDisabled
  19. // IPR_InitProtectedRootInfo
  20. // IPR_DeleteUnprotectedRootsFromStore
  21. // IPR_ProtectedRootMessageBox
  22. // IPR_LogCrypt32Event
  23. // IPR_LogCrypt32Error
  24. // IPR_LogCertInformation
  25. // IPR_AddCertInAuthRootAutoUpdateCtl
  26. //
  27. // History: 23-Nov-97 philh created
  28. //--------------------------------------------------------------------------
  29. #include "global.hxx"
  30. #include <chain.h>
  31. #include <dbgdef.h>
  32. #include <wininet.h>
  33. #ifdef STATIC
  34. #undef STATIC
  35. #endif
  36. #define STATIC
  37. // Used for "root" system store's message box
  38. static HMODULE hRegStoreInst;
  39. // # of bytes for a hash. Such as, SHA (20) or MD5 (16)
  40. #define MAX_HASH_LEN 20
  41. #define PROT_ROOT_SUBKEY_NAME L"ProtectedRoots"
  42. #define PROT_ROOT_CERT_VALUE_NAME L"Certificates"
  43. #define PROT_ROOT_MAX_CNT 1000000
  44. #define SYSTEM_STORE_REGPATH L"Software\\Microsoft\\SystemCertificates"
  45. #define PROT_ROOT_REGPATH \
  46. SYSTEM_STORE_REGPATH L"\\Root\\" PROT_ROOT_SUBKEY_NAME
  47. //+-------------------------------------------------------------------------
  48. // Protected root information data structure and defines
  49. //
  50. // The protected root information is stored in the "Certificates" value of
  51. // the "root" store's "ProtectedRoots" SubKey.
  52. //--------------------------------------------------------------------------
  53. // In V1, all hashes are SHA1 (length of 20 bytes) and are at the end of
  54. // the info. cbInfo = dwRootOffset + cRoot * 20
  55. typedef struct _PROT_ROOT_INFO {
  56. DWORD cbSize; // sizeof(PROT_ROOT_INFO)
  57. DWORD dwVersion;
  58. FILETIME LastUpdate;
  59. DWORD cRoot;
  60. DWORD dwRootOffset;
  61. } PROT_ROOT_INFO, *PPROT_ROOT_INFO;
  62. #define PROT_ROOT_V1 1
  63. // SHA1 hash length
  64. #define PROT_ROOT_HASH_LEN 20
  65. //+-------------------------------------------------------------------------
  66. // Predefined SIDs allocated once by GetPredefinedSids. Freed at
  67. // ProcessDetach.
  68. //--------------------------------------------------------------------------
  69. static CRITICAL_SECTION ProtRootCriticalSection;
  70. static BOOL fInitializedPredefinedSids = FALSE;
  71. static PSID psidLocalSystem = NULL;
  72. static PSID psidAdministrators = NULL;
  73. static PSID psidEveryone = NULL;
  74. //+-------------------------------------------------------------------------
  75. // SID definitions used to set security on the "ProtectedRoots" SubKey.
  76. //--------------------------------------------------------------------------
  77. // Only enable the following if you want to do special testing without
  78. // going through the LocalSystem service.
  79. // #define TESTING_NO_PROT_ROOT_RPC 1
  80. #define PSID_PROT_OWNER psidAdministrators
  81. #ifdef TESTING_NO_PROT_ROOT_RPC
  82. #define PSID_PROT_SYSTEM psidAdministrators
  83. #else
  84. #define PSID_PROT_SYSTEM psidLocalSystem
  85. #endif
  86. #define PSID_PROT_EVERYONE psidEveryone
  87. //+-------------------------------------------------------------------------
  88. // ACL definitions used to set security on the "ProtectedRoots" SubKey.
  89. //--------------------------------------------------------------------------
  90. #define PROT_SYSTEM_ACE_MASK KEY_ALL_ACCESS
  91. #define PROT_EVERYONE_ACE_MASK KEY_READ
  92. #define PROT_ACE_FLAGS CONTAINER_INHERIT_ACE
  93. #define PROT_ACE_COUNT 2
  94. #define PROT_SYSTEM_ACE_INDEX 0
  95. #define PROT_EVERYONE_ACE_INDEX 1
  96. //+-------------------------------------------------------------------------
  97. // Critical Section to Serialize Access to Crypt32 Event Log Data Structures
  98. //--------------------------------------------------------------------------
  99. CRITICAL_SECTION Crypt32EventLogCriticalSection;
  100. //+-------------------------------------------------------------------------
  101. // Allocate/free predefined SIDs
  102. //--------------------------------------------------------------------------
  103. static BOOL GetPredefinedSids()
  104. {
  105. if (fInitializedPredefinedSids)
  106. return TRUE;
  107. BOOL fResult;
  108. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  109. SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority =
  110. SECURITY_WORLD_SID_AUTHORITY;
  111. EnterCriticalSection(&ProtRootCriticalSection);
  112. if (!fInitializedPredefinedSids) {
  113. if (!AllocateAndInitializeSid(
  114. &siaNtAuthority,
  115. 1,
  116. SECURITY_LOCAL_SYSTEM_RID,
  117. 0, 0, 0, 0, 0, 0, 0,
  118. &psidLocalSystem
  119. ))
  120. goto AllocateAndInitializeSidError;
  121. if (!AllocateAndInitializeSid(
  122. &siaNtAuthority,
  123. 2,
  124. SECURITY_BUILTIN_DOMAIN_RID,
  125. DOMAIN_ALIAS_RID_ADMINS,
  126. 0, 0, 0, 0, 0, 0,
  127. &psidAdministrators
  128. ))
  129. goto AllocateAndInitializeSidError;
  130. if (!AllocateAndInitializeSid(
  131. &siaWorldSidAuthority,
  132. 1,
  133. SECURITY_WORLD_RID,
  134. 0, 0, 0, 0, 0, 0, 0,
  135. &psidEveryone
  136. ))
  137. goto AllocateAndInitializeSidError;
  138. fInitializedPredefinedSids = TRUE;
  139. }
  140. fResult = TRUE;
  141. CommonReturn:
  142. LeaveCriticalSection(&ProtRootCriticalSection);
  143. return fResult;
  144. ErrorReturn:
  145. fResult = FALSE;
  146. goto CommonReturn;
  147. TRACE_ERROR(AllocateAndInitializeSidError)
  148. }
  149. static void FreePredefinedSids()
  150. {
  151. if (fInitializedPredefinedSids) {
  152. FreeSid(psidLocalSystem);
  153. FreeSid(psidAdministrators);
  154. FreeSid(psidEveryone);
  155. }
  156. }
  157. //+-------------------------------------------------------------------------
  158. // Dll initialization
  159. //--------------------------------------------------------------------------
  160. BOOL
  161. WINAPI
  162. I_ProtectedRootDllMain(
  163. HMODULE hInst,
  164. ULONG ulReason,
  165. LPVOID lpReserved)
  166. {
  167. BOOL fRet = TRUE;
  168. switch (ulReason) {
  169. case DLL_PROCESS_ATTACH:
  170. // Used for "root" system store's message box
  171. hRegStoreInst = hInst;
  172. fRet = Pki_InitializeCriticalSection(&ProtRootCriticalSection);
  173. if (fRet) {
  174. fRet = Pki_InitializeCriticalSection(
  175. &Crypt32EventLogCriticalSection);
  176. if (!fRet)
  177. DeleteCriticalSection(&ProtRootCriticalSection);
  178. }
  179. I_DBLogAttach();
  180. break;
  181. case DLL_PROCESS_DETACH:
  182. I_DBLogDetach();
  183. FreePredefinedSids();
  184. DeleteCriticalSection(&ProtRootCriticalSection);
  185. DeleteCriticalSection(&Crypt32EventLogCriticalSection);
  186. break;
  187. case DLL_THREAD_DETACH:
  188. default:
  189. break;
  190. }
  191. return fRet;
  192. }
  193. //+=========================================================================
  194. // Protected root registry flags support function
  195. //==========================================================================
  196. //+-------------------------------------------------------------------------
  197. // Get the ProtectedRoots Flags DWORD registry value stored in HKLM.
  198. //--------------------------------------------------------------------------
  199. STATIC DWORD GetProtectedRootFlags()
  200. {
  201. HKEY hKey = NULL;
  202. LONG err;
  203. DWORD dwProtRootFlags = 0;
  204. if (ERROR_SUCCESS != (err = RegOpenKeyExU(
  205. HKEY_LOCAL_MACHINE,
  206. CERT_PROT_ROOT_FLAGS_REGPATH,
  207. 0, // dwReserved
  208. KEY_READ,
  209. &hKey
  210. ))) goto RegOpenKeyError;
  211. if (!ILS_ReadDWORDValueFromRegistry(
  212. hKey,
  213. CERT_PROT_ROOT_FLAGS_VALUE_NAME,
  214. &dwProtRootFlags
  215. )) goto ReadValueError;
  216. CommonReturn:
  217. ILS_CloseRegistryKey(hKey);
  218. return dwProtRootFlags;
  219. ErrorReturn:
  220. dwProtRootFlags = 0;
  221. goto CommonReturn;
  222. SET_ERROR_VAR(RegOpenKeyError, err)
  223. TRACE_ERROR(ReadValueError)
  224. }
  225. //+=========================================================================
  226. // Protected root information support functions
  227. //==========================================================================
  228. //+-------------------------------------------------------------------------
  229. // Open the SubKey containing the protected root information.
  230. //--------------------------------------------------------------------------
  231. STATIC HKEY OpenProtectedRootSubKey(
  232. IN HKEY hKeyCU,
  233. IN REGSAM samDesired
  234. )
  235. {
  236. LONG err;
  237. HKEY hKeyProtRoot;
  238. if (ERROR_SUCCESS != (err = RegOpenKeyExU(
  239. hKeyCU,
  240. PROT_ROOT_REGPATH,
  241. 0, // dwReserved
  242. samDesired,
  243. &hKeyProtRoot)))
  244. goto RegOpenKeyError;
  245. CommonReturn:
  246. return hKeyProtRoot;
  247. ErrorReturn:
  248. hKeyProtRoot = NULL;
  249. goto CommonReturn;
  250. SET_ERROR_VAR(RegOpenKeyError, err)
  251. }
  252. //+-------------------------------------------------------------------------
  253. // Create the SubKey containing the protected root information.
  254. //--------------------------------------------------------------------------
  255. STATIC HKEY CreateProtectedRootSubKey(
  256. IN HKEY hKeyCU,
  257. IN REGSAM samDesired
  258. )
  259. {
  260. LONG err;
  261. HKEY hKeyProtRoot;
  262. DWORD dwDisposition;
  263. if (ERROR_SUCCESS != (err = RegCreateKeyExU(
  264. hKeyCU,
  265. PROT_ROOT_REGPATH,
  266. 0, // dwReserved
  267. NULL, // lpClass
  268. REG_OPTION_NON_VOLATILE,
  269. samDesired,
  270. NULL, // lpSecurityAttributes
  271. &hKeyProtRoot,
  272. &dwDisposition)))
  273. goto RegCreateKeyError;
  274. CommonReturn:
  275. return hKeyProtRoot;
  276. ErrorReturn:
  277. hKeyProtRoot = NULL;
  278. goto CommonReturn;
  279. SET_ERROR_VAR(RegCreateKeyError, err)
  280. }
  281. //+-------------------------------------------------------------------------
  282. // Allocate, read from registry and verify the protected root info.
  283. //
  284. // The root hashes are at the end of the info.
  285. //--------------------------------------------------------------------------
  286. STATIC PPROT_ROOT_INFO ReadProtectedRootInfo(
  287. IN HKEY hKeyProtRoot
  288. )
  289. {
  290. PPROT_ROOT_INFO pInfo = NULL;
  291. DWORD cbInfo;
  292. DWORD cRoot;
  293. DWORD dwRootOffset;
  294. if (!ILS_ReadBINARYValueFromRegistry(
  295. hKeyProtRoot,
  296. PROT_ROOT_CERT_VALUE_NAME,
  297. (BYTE **) &pInfo,
  298. &cbInfo
  299. )) goto ReadCertificatesProtInfoValueError;
  300. if (sizeof(PROT_ROOT_INFO) > cbInfo ||
  301. sizeof(PROT_ROOT_INFO) > pInfo->cbSize ||
  302. pInfo->cbSize > cbInfo ||
  303. PROT_ROOT_V1 != pInfo->dwVersion
  304. ) goto InvalidProtectedRootInfo;
  305. // The root hashes must be at the end of the info
  306. cRoot = pInfo->cRoot;
  307. dwRootOffset = pInfo->dwRootOffset;
  308. if (dwRootOffset < pInfo->cbSize || dwRootOffset > cbInfo ||
  309. PROT_ROOT_MAX_CNT < cRoot ||
  310. cRoot * PROT_ROOT_HASH_LEN != cbInfo - dwRootOffset
  311. ) goto InvalidProtectedRootInfo;
  312. CommonReturn:
  313. return pInfo;
  314. ErrorReturn:
  315. PkiFree(pInfo);
  316. pInfo = NULL;
  317. goto CommonReturn;
  318. TRACE_ERROR(ReadCertificatesProtInfoValueError)
  319. SET_ERROR(InvalidProtectedRootInfo, ERROR_INVALID_DATA)
  320. }
  321. //+-------------------------------------------------------------------------
  322. // Write the protected root info to the registry.
  323. //
  324. // The root hashes are at the end of the info. Updates the info's
  325. // LastUpdate time.
  326. //--------------------------------------------------------------------------
  327. STATIC BOOL WriteProtectedRootInfo(
  328. IN HKEY hKeyProtRoot,
  329. IN OUT PPROT_ROOT_INFO pInfo
  330. )
  331. {
  332. BOOL fResult;
  333. LONG err;
  334. DWORD cbInfo;
  335. SYSTEMTIME SystemTime;
  336. FILETIME FileTime;
  337. cbInfo = pInfo->dwRootOffset + pInfo->cRoot * PROT_ROOT_HASH_LEN;
  338. GetSystemTime(&SystemTime);
  339. SystemTimeToFileTime(&SystemTime, &FileTime);
  340. pInfo->LastUpdate = FileTime;
  341. if (ERROR_SUCCESS != (err = RegSetValueExU(
  342. hKeyProtRoot,
  343. PROT_ROOT_CERT_VALUE_NAME,
  344. NULL,
  345. REG_BINARY,
  346. (BYTE *) pInfo,
  347. cbInfo
  348. ))) goto RegSetValueError;
  349. fResult = TRUE;
  350. CommonReturn:
  351. return fResult;
  352. ErrorReturn:
  353. fResult = FALSE;
  354. goto CommonReturn;
  355. SET_ERROR_VAR(RegSetValueError, err)
  356. }
  357. // In the debugger I saw 0x58
  358. #define PROT_ROOT_SD_LEN 0x100
  359. //+-------------------------------------------------------------------------
  360. // Allocate and get the security descriptor information for the specified
  361. // registry key.
  362. //--------------------------------------------------------------------------
  363. static PSECURITY_DESCRIPTOR AllocAndGetSecurityDescriptor(
  364. IN HKEY hKey,
  365. SECURITY_INFORMATION SecInf
  366. )
  367. {
  368. LONG err;
  369. PSECURITY_DESCRIPTOR psd = NULL;
  370. DWORD cbsd;
  371. cbsd = PROT_ROOT_SD_LEN;
  372. if (NULL == (psd = (PSECURITY_DESCRIPTOR) PkiNonzeroAlloc(cbsd)))
  373. goto OutOfMemory;
  374. err = RegGetKeySecurity(
  375. hKey,
  376. SecInf,
  377. psd,
  378. &cbsd
  379. );
  380. if (ERROR_SUCCESS == err)
  381. goto CommonReturn;
  382. if (ERROR_INSUFFICIENT_BUFFER != err)
  383. goto RegGetKeySecurityError;
  384. if (0 == cbsd)
  385. goto NoSecurityDescriptor;
  386. PkiFree(psd);
  387. psd = NULL;
  388. if (NULL == (psd = (PSECURITY_DESCRIPTOR) PkiNonzeroAlloc(cbsd)))
  389. goto OutOfMemory;
  390. if (ERROR_SUCCESS != (err = RegGetKeySecurity(
  391. hKey,
  392. SecInf,
  393. psd,
  394. &cbsd
  395. ))) goto RegGetKeySecurityError;
  396. CommonReturn:
  397. return psd;
  398. ErrorReturn:
  399. PkiFree(psd);
  400. psd = NULL;
  401. goto CommonReturn;
  402. TRACE_ERROR(OutOfMemory)
  403. SET_ERROR_VAR(RegGetKeySecurityError, err)
  404. SET_ERROR(NoSecurityDescriptor, ERROR_INVALID_SECURITY_DESCR)
  405. }
  406. //+-------------------------------------------------------------------------
  407. // Opens the "ProtectedRoots" registry key and verifies its security owner,
  408. // group, DACLs and SACLs. Must match the security set by
  409. // SrvGetProtectedRootInfo().
  410. //
  411. // If the "ProtectedRoots" SubKey has the proper security. Allocates, reads
  412. // and verifies the "Certificates" value to get the protected root info.
  413. //--------------------------------------------------------------------------
  414. STATIC BOOL GetProtectedRootInfo(
  415. IN HKEY hKeyCU,
  416. IN REGSAM samDesired,
  417. OUT OPTIONAL HKEY *phKeyProtRoot,
  418. OUT OPTIONAL PPROT_ROOT_INFO *ppInfo
  419. )
  420. {
  421. BOOL fResult;
  422. HKEY hKeyProtRoot = NULL;
  423. PSECURITY_DESCRIPTOR psd = NULL;
  424. PPROT_ROOT_INFO pInfo = NULL;
  425. PSID psidOwner; // not allocated
  426. BOOL fOwnerDefaulted;
  427. BOOL fDaclPresent;
  428. PACL pAcl; // not allocated
  429. BOOL fDaclDefaulted;
  430. DWORD dwAceIndex;
  431. PACCESS_ALLOWED_ACE rgpAce[PROT_ACE_COUNT];
  432. if (NULL == (hKeyProtRoot = OpenProtectedRootSubKey(hKeyCU, samDesired)))
  433. goto OpenProtectedRootSubKeyError;
  434. if (NULL == (psd = AllocAndGetSecurityDescriptor(
  435. hKeyProtRoot,
  436. OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
  437. ))) goto GetSecurityDescriptorError;
  438. if (!GetPredefinedSids())
  439. goto GetPredefinedSidsError;
  440. // Verify owner
  441. if (!GetSecurityDescriptorOwner(psd, &psidOwner, &fOwnerDefaulted))
  442. goto GetSecurityDescriptorOwnerError;
  443. if (NULL == psidOwner || !EqualSid(psidOwner, PSID_PROT_OWNER))
  444. goto InvalidProtectedRootOwner;
  445. // Verify DACL
  446. if (!GetSecurityDescriptorDacl(psd, &fDaclPresent, &pAcl,
  447. &fDaclDefaulted))
  448. goto GetSecurityDescriptorDaclError;
  449. if (!fDaclPresent || NULL == pAcl)
  450. goto MissingProtectedRootDaclError;
  451. if (PROT_ACE_COUNT != pAcl->AceCount)
  452. goto InvalidProtectedRootDacl;
  453. for (dwAceIndex = 0; dwAceIndex < PROT_ACE_COUNT; dwAceIndex++) {
  454. PACCESS_ALLOWED_ACE pAce;
  455. if (!GetAce(pAcl, dwAceIndex, (void **) &pAce))
  456. goto InvalidProtectedRootDacl;
  457. rgpAce[dwAceIndex] = pAce;
  458. if (ACCESS_ALLOWED_ACE_TYPE != pAce->Header.AceType ||
  459. PROT_ACE_FLAGS != pAce->Header.AceFlags)
  460. goto InvalidProtectedRootDacl;
  461. }
  462. if (PROT_SYSTEM_ACE_MASK != rgpAce[PROT_SYSTEM_ACE_INDEX]->Mask ||
  463. !EqualSid(PSID_PROT_SYSTEM,
  464. (PSID) &rgpAce[PROT_SYSTEM_ACE_INDEX]->SidStart) ||
  465. PROT_EVERYONE_ACE_MASK != rgpAce[PROT_EVERYONE_ACE_INDEX]->Mask ||
  466. !EqualSid(PSID_PROT_EVERYONE,
  467. (PSID) &rgpAce[PROT_EVERYONE_ACE_INDEX]->SidStart))
  468. goto InvalidProtectedRootDacl;
  469. // Get verified protected root info
  470. if (NULL == (pInfo = ReadProtectedRootInfo(hKeyProtRoot)))
  471. goto ReadProtectedRootInfoError;
  472. fResult = TRUE;
  473. CommonReturn:
  474. PkiFree(psd);
  475. if (phKeyProtRoot)
  476. *phKeyProtRoot = hKeyProtRoot;
  477. else
  478. ILS_CloseRegistryKey(hKeyProtRoot);
  479. if (ppInfo)
  480. *ppInfo = pInfo;
  481. else
  482. PkiFree(pInfo);
  483. return fResult;
  484. ErrorReturn:
  485. ILS_CloseRegistryKey(hKeyProtRoot);
  486. hKeyProtRoot = NULL;
  487. PkiFree(pInfo);
  488. pInfo = NULL;
  489. fResult = FALSE;
  490. goto CommonReturn;
  491. TRACE_ERROR(OpenProtectedRootSubKeyError)
  492. TRACE_ERROR(GetSecurityDescriptorError)
  493. TRACE_ERROR(GetPredefinedSidsError)
  494. TRACE_ERROR(GetSecurityDescriptorOwnerError)
  495. TRACE_ERROR(GetSecurityDescriptorDaclError)
  496. SET_ERROR(InvalidProtectedRootOwner, ERROR_INVALID_OWNER)
  497. SET_ERROR(MissingProtectedRootDaclError, ERROR_INVALID_ACL)
  498. SET_ERROR(InvalidProtectedRootDacl, ERROR_INVALID_ACL)
  499. TRACE_ERROR(ReadProtectedRootInfoError)
  500. }
  501. //+=========================================================================
  502. // Functions to find, add or delete a root hash from the protected root
  503. // info.
  504. //==========================================================================
  505. STATIC BOOL FindProtectedRoot(
  506. IN PPROT_ROOT_INFO pInfo,
  507. IN BYTE rgbFindRootHash[PROT_ROOT_HASH_LEN],
  508. OUT OPTIONAL DWORD *pdwRootIndex = NULL
  509. )
  510. {
  511. BYTE *pbRoot = (BYTE *) pInfo + pInfo->dwRootOffset;
  512. DWORD cRoot = pInfo->cRoot;
  513. DWORD dwRootIndex = 0;
  514. BYTE bFirst = rgbFindRootHash[0];
  515. for ( ; dwRootIndex < cRoot; dwRootIndex++, pbRoot += PROT_ROOT_HASH_LEN) {
  516. if (bFirst == *pbRoot &&
  517. 0 == memcmp(rgbFindRootHash, pbRoot, PROT_ROOT_HASH_LEN)) {
  518. if (pdwRootIndex)
  519. *pdwRootIndex = dwRootIndex;
  520. return TRUE;
  521. }
  522. }
  523. if (pdwRootIndex)
  524. *pdwRootIndex = 0;
  525. return FALSE;
  526. }
  527. // Root hash is appended to the end of the list
  528. STATIC BOOL AddProtectedRoot(
  529. IN OUT PPROT_ROOT_INFO *ppInfo,
  530. IN BYTE rgbAddRootHash[PROT_ROOT_HASH_LEN]
  531. )
  532. {
  533. PPROT_ROOT_INFO pInfo = *ppInfo;
  534. DWORD cRoot = pInfo->cRoot;
  535. DWORD dwRootOffset = pInfo->dwRootOffset;
  536. DWORD cbInfo;
  537. if (PROT_ROOT_MAX_CNT <= cRoot) {
  538. SetLastError(ERROR_OUTOFMEMORY);
  539. return FALSE;
  540. }
  541. cbInfo = dwRootOffset + (cRoot + 1) * PROT_ROOT_HASH_LEN;
  542. if (NULL == (pInfo = (PPROT_ROOT_INFO) PkiRealloc(pInfo, cbInfo)))
  543. return FALSE;
  544. memcpy((BYTE *) pInfo + (dwRootOffset + cRoot * PROT_ROOT_HASH_LEN),
  545. rgbAddRootHash, PROT_ROOT_HASH_LEN);
  546. pInfo->cRoot = cRoot + 1;
  547. *ppInfo = pInfo;
  548. return TRUE;
  549. }
  550. STATIC void DeleteProtectedRoot(
  551. IN PPROT_ROOT_INFO pInfo,
  552. IN DWORD dwDeleteRootIndex
  553. )
  554. {
  555. DWORD cRoot = pInfo->cRoot;
  556. BYTE *pbRoot = (BYTE *) pInfo + pInfo->dwRootOffset;
  557. assert(0 < cRoot);
  558. assert(dwDeleteRootIndex < cRoot);
  559. cRoot--;
  560. if (cRoot > dwDeleteRootIndex) {
  561. // Move following roots down
  562. BYTE *pbDst = pbRoot + dwDeleteRootIndex * PROT_ROOT_HASH_LEN;
  563. BYTE *pbSrc = pbDst + PROT_ROOT_HASH_LEN;
  564. DWORD cbMove = (cRoot - dwDeleteRootIndex) * PROT_ROOT_HASH_LEN;
  565. while (cbMove--)
  566. *pbDst++ = *pbSrc++;
  567. }
  568. // else
  569. // last root in list
  570. pInfo->cRoot = cRoot;
  571. }
  572. //+=========================================================================
  573. // Certificate store support functions
  574. //==========================================================================
  575. //+-------------------------------------------------------------------------
  576. // Opens the SystemRegistry "Root" store unprotected and relative to the
  577. // specifed base SubKey.
  578. //--------------------------------------------------------------------------
  579. STATIC HCERTSTORE OpenUnprotectedRootStore(
  580. IN HKEY hKeyCU,
  581. IN DWORD dwOpenFlags = 0
  582. )
  583. {
  584. CERT_SYSTEM_STORE_RELOCATE_PARA RelocatePara;
  585. RelocatePara.hKeyBase = hKeyCU;
  586. RelocatePara.pwszSystemStore = L"Root";
  587. return CertOpenStore(
  588. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  589. 0, // dwEncodingType
  590. NULL, // hCryptProv
  591. CERT_SYSTEM_STORE_RELOCATE_FLAG |
  592. CERT_SYSTEM_STORE_UNPROTECTED_FLAG |
  593. CERT_SYSTEM_STORE_CURRENT_USER |
  594. dwOpenFlags,
  595. (const void *) &RelocatePara
  596. );
  597. }
  598. //+-------------------------------------------------------------------------
  599. // Gets the certificate's SHA1 hash property. Rehashes the encoded
  600. // certificate. Returns TRUE if the property matches the regenerated hash.
  601. //--------------------------------------------------------------------------
  602. static BOOL GetVerifiedCertHashProperty(
  603. IN PCCERT_CONTEXT pCert,
  604. OUT BYTE rgbHash[PROT_ROOT_HASH_LEN]
  605. )
  606. {
  607. BYTE rgbProp[PROT_ROOT_HASH_LEN];
  608. DWORD cbData;
  609. cbData = PROT_ROOT_HASH_LEN;
  610. if (!CertGetCertificateContextProperty(
  611. pCert,
  612. CERT_SHA1_HASH_PROP_ID,
  613. rgbProp,
  614. &cbData
  615. ) || PROT_ROOT_HASH_LEN != cbData)
  616. return FALSE;
  617. // Verify the property
  618. cbData = PROT_ROOT_HASH_LEN;
  619. if (!CryptHashCertificate(
  620. 0, // hProv
  621. CALG_SHA1,
  622. 0, //dwFlags
  623. pCert->pbCertEncoded,
  624. pCert->cbCertEncoded,
  625. rgbHash,
  626. &cbData
  627. ) || PROT_ROOT_HASH_LEN != cbData)
  628. return FALSE;
  629. return (0 == memcmp(rgbHash, rgbProp, PROT_ROOT_HASH_LEN));
  630. }
  631. //+=========================================================================
  632. // FormatMsgBox support functions
  633. //==========================================================================
  634. //+-------------------------------------------------------------------------
  635. // Formats multi bytes into WCHAR hex. Includes a space after every 4 bytes.
  636. //
  637. // Needs (cb * 2 + cb/4 + 1) characters in wsz
  638. //--------------------------------------------------------------------------
  639. static void FormatMsgBoxMultiBytes(DWORD cb, BYTE *pb, LPWSTR wsz)
  640. {
  641. for (DWORD i = 0; i<cb; i++) {
  642. int b;
  643. if (i && 0 == (i & 3))
  644. *wsz++ = L' ';
  645. b = (*pb & 0xF0) >> 4;
  646. *wsz++ = (WCHAR)( (b <= 9) ? b + L'0' : (b - 10) + L'A');
  647. b = *pb & 0x0F;
  648. *wsz++ = (WCHAR) ((b <= 9) ? b + L'0' : (b - 10) + L'A');
  649. pb++;
  650. }
  651. *wsz++ = 0;
  652. }
  653. //+-------------------------------------------------------------------------
  654. // Format and allocate a single message box item
  655. //
  656. // The formatted item needs to be LocalFree'ed.
  657. //--------------------------------------------------------------------------
  658. static void FormatMsgBoxItem(
  659. OUT LPWSTR *ppwszMsg,
  660. OUT DWORD *pcchMsg,
  661. IN UINT nFormatID,
  662. ...
  663. )
  664. {
  665. // get format string from resources
  666. WCHAR wszFormat[256];
  667. wszFormat[0] = '\0';
  668. LoadStringU(hRegStoreInst, nFormatID, wszFormat,
  669. sizeof(wszFormat)/sizeof(wszFormat[0]));
  670. // format message into requested buffer
  671. va_list argList;
  672. va_start(argList, nFormatID);
  673. *ppwszMsg = NULL;
  674. *pcchMsg = FormatMessageU(
  675. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  676. wszFormat,
  677. 0, // dwMessageId
  678. 0, // dwLanguageId
  679. (LPWSTR) ppwszMsg,
  680. 0, // minimum size to allocate
  681. &argList);
  682. va_end(argList);
  683. }
  684. //+=========================================================================
  685. // Protected root functions called from the services process
  686. //==========================================================================
  687. //+-------------------------------------------------------------------------
  688. // Enable the specified security privilege for the current process.
  689. //
  690. // Also, called from logstor.cpp to enable SE_BACKUP_NAME and
  691. // SE_RESTORE_NAME for CERT_STORE_BACKUP_RESTORE_FLAG.
  692. //--------------------------------------------------------------------------
  693. BOOL
  694. IPR_EnableSecurityPrivilege(
  695. LPCSTR pszPrivilege
  696. )
  697. {
  698. BOOL fResult;
  699. HANDLE hToken = NULL;
  700. TOKEN_PRIVILEGES tp;
  701. LUID luid;
  702. TOKEN_PRIVILEGES tpPrevious;
  703. DWORD cbPrevious;
  704. if (!OpenProcessToken(
  705. GetCurrentProcess(),
  706. TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
  707. &hToken
  708. ))
  709. goto OpenProcessTokenError;
  710. if (!LookupPrivilegeValueA(NULL, pszPrivilege, &luid))
  711. goto LookupPrivilegeValueError;
  712. //
  713. // first pass. get current privilege setting
  714. //
  715. tp.PrivilegeCount = 1;
  716. tp.Privileges[0].Luid = luid;
  717. tp.Privileges[0].Attributes = 0;
  718. cbPrevious = sizeof(TOKEN_PRIVILEGES);
  719. memset(&tpPrevious, 0, sizeof(TOKEN_PRIVILEGES));
  720. AdjustTokenPrivileges(
  721. hToken,
  722. FALSE,
  723. &tp,
  724. sizeof(TOKEN_PRIVILEGES),
  725. &tpPrevious,
  726. &cbPrevious
  727. );
  728. if (ERROR_SUCCESS != GetLastError())
  729. goto AdjustTokenPrivilegesError;
  730. //
  731. // second pass. enable privilege
  732. //
  733. if (0 == tpPrevious.PrivilegeCount)
  734. tpPrevious.Privileges[0].Attributes = 0;
  735. tpPrevious.PrivilegeCount = 1;
  736. tpPrevious.Privileges[0].Luid = luid;
  737. tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  738. AdjustTokenPrivileges(
  739. hToken,
  740. FALSE,
  741. &tpPrevious,
  742. cbPrevious,
  743. NULL,
  744. NULL
  745. );
  746. if (ERROR_SUCCESS != GetLastError())
  747. goto AdjustTokenPrivilegesError;
  748. fResult = TRUE;
  749. CommonReturn:
  750. if (hToken)
  751. CloseHandle(hToken);
  752. return fResult;
  753. ErrorReturn:
  754. fResult = FALSE;
  755. goto CommonReturn;
  756. TRACE_ERROR(OpenProcessTokenError)
  757. TRACE_ERROR(LookupPrivilegeValueError)
  758. TRACE_ERROR(AdjustTokenPrivilegesError)
  759. }
  760. //+-------------------------------------------------------------------------
  761. // Take ownership of the "ProtectedRoots" SubKey
  762. //--------------------------------------------------------------------------
  763. STATIC BOOL SetProtectedRootOwner(
  764. IN HKEY hKeyCU,
  765. OUT BOOL *pfNew
  766. )
  767. {
  768. BOOL fResult;
  769. LONG err;
  770. BOOL fNew = FALSE;
  771. HKEY hKeyProtRoot = NULL;
  772. SECURITY_DESCRIPTOR sd;
  773. if (!IPR_EnableSecurityPrivilege(SE_TAKE_OWNERSHIP_NAME))
  774. goto EnableTakeOwnershipPrivilegeError;
  775. if (hKeyProtRoot = OpenProtectedRootSubKey(hKeyCU, WRITE_OWNER))
  776. fNew = FALSE;
  777. else {
  778. if (ERROR_FILE_NOT_FOUND == GetLastError())
  779. hKeyProtRoot = CreateProtectedRootSubKey(hKeyCU, WRITE_OWNER);
  780. if (NULL == hKeyProtRoot)
  781. goto OpenProtectedRootSubKeyError;
  782. fNew = TRUE;
  783. }
  784. if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
  785. goto InitializeSecurityDescriptorError;
  786. if (!SetSecurityDescriptorOwner(&sd, PSID_PROT_OWNER, FALSE))
  787. goto SetSecurityDescriptorOwnerError;
  788. if (ERROR_SUCCESS != (err = RegSetKeySecurity(
  789. hKeyProtRoot,
  790. OWNER_SECURITY_INFORMATION,
  791. &sd
  792. )))
  793. goto RegSetKeySecurityError;
  794. fResult = TRUE;
  795. CommonReturn:
  796. ILS_CloseRegistryKey(hKeyProtRoot);
  797. *pfNew = fNew;
  798. return fResult;
  799. ErrorReturn:
  800. fResult = FALSE;
  801. goto CommonReturn;
  802. TRACE_ERROR(EnableTakeOwnershipPrivilegeError)
  803. TRACE_ERROR(OpenProtectedRootSubKeyError)
  804. TRACE_ERROR(InitializeSecurityDescriptorError)
  805. TRACE_ERROR(SetSecurityDescriptorOwnerError)
  806. SET_ERROR_VAR(RegSetKeySecurityError, err)
  807. }
  808. //+-------------------------------------------------------------------------
  809. // Allocate and get the specified token info.
  810. //--------------------------------------------------------------------------
  811. static void * AllocAndGetTokenInfo(
  812. IN HANDLE hToken,
  813. IN TOKEN_INFORMATION_CLASS tic
  814. )
  815. {
  816. void *pvInfo = NULL;
  817. DWORD cbInfo = 0;
  818. DWORD cbInfo2;
  819. if (!GetTokenInformation(
  820. hToken,
  821. tic,
  822. pvInfo,
  823. 0, // cbInfo
  824. &cbInfo
  825. )) {
  826. if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
  827. goto GetTokenInfoError;
  828. }
  829. if (0 == cbInfo)
  830. goto NoTokenInfoError;
  831. if (NULL == (pvInfo = PkiNonzeroAlloc(cbInfo)))
  832. goto OutOfMemory;
  833. cbInfo2 = cbInfo;
  834. if (!GetTokenInformation(
  835. hToken,
  836. tic,
  837. pvInfo,
  838. cbInfo,
  839. &cbInfo2
  840. ))
  841. goto GetTokenInfoError;
  842. CommonReturn:
  843. return pvInfo;
  844. ErrorReturn:
  845. PkiFree(pvInfo);
  846. pvInfo = NULL;
  847. goto CommonReturn;
  848. TRACE_ERROR(GetTokenInfoError)
  849. SET_ERROR(NoTokenInfoError, ERROR_NO_TOKEN)
  850. TRACE_ERROR(OutOfMemory)
  851. }
  852. //+-------------------------------------------------------------------------
  853. // Set the security group, DACLs and SACLs for the "ProtectedRoots" SubKey
  854. //--------------------------------------------------------------------------
  855. STATIC BOOL SetProtectedRootGroupDaclSacl(
  856. IN HKEY hKeyCU
  857. )
  858. {
  859. BOOL fResult;
  860. LONG err;
  861. HKEY hKeyProtRoot = NULL;
  862. SECURITY_DESCRIPTOR sd;
  863. HANDLE hToken = NULL;
  864. void *pvTokenInfo = NULL;
  865. PACL pDacl = NULL;
  866. PACCESS_ALLOWED_ACE pAce;
  867. DWORD dwAclSize;
  868. DWORD i;
  869. if (!IPR_EnableSecurityPrivilege(SE_SECURITY_NAME))
  870. goto EnableSecurityNamePrivilegeError;
  871. if (NULL == (hKeyProtRoot = OpenProtectedRootSubKey(
  872. hKeyCU,
  873. WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY
  874. )))
  875. goto OpenProtectedRootSubKeyError;
  876. if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
  877. goto InitializeSecurityDescriptorError;
  878. // Set group SID using current process token's primary group SID
  879. if (!OpenProcessToken(
  880. GetCurrentProcess(),
  881. TOKEN_QUERY,
  882. &hToken
  883. ))
  884. goto OpenProcessTokenError;
  885. if (NULL == (pvTokenInfo = AllocAndGetTokenInfo(hToken, TokenPrimaryGroup)))
  886. goto GetTokenInfoError;
  887. else {
  888. PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup =
  889. (PTOKEN_PRIMARY_GROUP) pvTokenInfo;
  890. PSID psidGroup = pTokenPrimaryGroup->PrimaryGroup;
  891. if (!SetSecurityDescriptorGroup(&sd, psidGroup, FALSE))
  892. goto SetSecurityDescriptorGroupError;
  893. }
  894. // Set DACL
  895. //
  896. // compute size of ACL
  897. //
  898. dwAclSize = sizeof(ACL) +
  899. PROT_ACE_COUNT * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
  900. GetLengthSid(PSID_PROT_SYSTEM) +
  901. GetLengthSid(PSID_PROT_EVERYONE)
  902. ;
  903. //
  904. // allocate storage for Acl
  905. //
  906. if (NULL == (pDacl = (PACL) PkiNonzeroAlloc(dwAclSize)))
  907. goto OutOfMemory;
  908. if (!InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
  909. goto InitializeAclError;
  910. if (!AddAccessAllowedAce(
  911. pDacl,
  912. ACL_REVISION,
  913. PROT_SYSTEM_ACE_MASK,
  914. PSID_PROT_SYSTEM
  915. ))
  916. goto AddAceError;
  917. if (!AddAccessAllowedAce(
  918. pDacl,
  919. ACL_REVISION,
  920. PROT_EVERYONE_ACE_MASK,
  921. PSID_PROT_EVERYONE
  922. ))
  923. goto AddAceError;
  924. //
  925. // make containers inherit.
  926. //
  927. for (i = 0; i < PROT_ACE_COUNT; i++) {
  928. if(!GetAce(pDacl, i, (void **) &pAce))
  929. goto GetAceError;
  930. pAce->Header.AceFlags = PROT_ACE_FLAGS;
  931. }
  932. if (!SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE))
  933. goto SetSecurityDescriptorDaclError;
  934. // Set SACL
  935. if (!SetSecurityDescriptorSacl(&sd, FALSE, NULL, FALSE))
  936. goto SetSecurityDescriptorSaclError;
  937. if (ERROR_SUCCESS != (err = RegSetKeySecurity(
  938. hKeyProtRoot,
  939. GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION |
  940. SACL_SECURITY_INFORMATION,
  941. &sd
  942. )))
  943. goto RegSetKeySecurityError;
  944. fResult = TRUE;
  945. CommonReturn:
  946. ILS_CloseRegistryKey(hKeyProtRoot);
  947. if (hToken)
  948. CloseHandle(hToken);
  949. PkiFree(pvTokenInfo);
  950. PkiFree(pDacl);
  951. return fResult;
  952. ErrorReturn:
  953. fResult = FALSE;
  954. goto CommonReturn;
  955. TRACE_ERROR(EnableSecurityNamePrivilegeError)
  956. TRACE_ERROR(OpenProtectedRootSubKeyError)
  957. TRACE_ERROR(InitializeSecurityDescriptorError)
  958. TRACE_ERROR(OpenProcessTokenError)
  959. TRACE_ERROR(GetTokenInfoError)
  960. TRACE_ERROR(SetSecurityDescriptorGroupError)
  961. TRACE_ERROR(OutOfMemory)
  962. TRACE_ERROR(InitializeAclError)
  963. TRACE_ERROR(AddAceError)
  964. TRACE_ERROR(GetAceError)
  965. TRACE_ERROR(SetSecurityDescriptorDaclError)
  966. TRACE_ERROR(SetSecurityDescriptorSaclError)
  967. SET_ERROR_VAR(RegSetKeySecurityError, err)
  968. }
  969. //+-------------------------------------------------------------------------
  970. // Create the initial protected root info.
  971. //
  972. // If not inhibited, add all the roots in the unprotected CurrentUser
  973. // "Root" store.
  974. //--------------------------------------------------------------------------
  975. STATIC BOOL InitAndSetProtectedRootInfo(
  976. IN HKEY hKeyCU,
  977. IN BOOL fNew
  978. )
  979. {
  980. BOOL fResult;
  981. HKEY hKeyProtRoot = NULL;
  982. HCERTSTORE hStore = NULL;
  983. PPROT_ROOT_INFO pInfo = NULL;
  984. if (NULL == (pInfo = (PPROT_ROOT_INFO) PkiNonzeroAlloc(
  985. sizeof(PROT_ROOT_INFO))))
  986. goto OutOfMemory;
  987. memset(pInfo, 0, sizeof(PROT_ROOT_INFO));
  988. pInfo->cbSize = sizeof(PROT_ROOT_INFO);
  989. pInfo->dwVersion = PROT_ROOT_V1;
  990. pInfo->dwRootOffset = sizeof(PROT_ROOT_INFO);
  991. if (fNew && 0 == (GetProtectedRootFlags() &
  992. CERT_PROT_ROOT_INHIBIT_ADD_AT_INIT_FLAG)) {
  993. if (hStore = OpenUnprotectedRootStore(hKeyCU,
  994. CERT_STORE_READONLY_FLAG)) {
  995. PCCERT_CONTEXT pCert = NULL;
  996. while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
  997. BYTE rgbHash[PROT_ROOT_HASH_LEN];
  998. if (GetVerifiedCertHashProperty(pCert, rgbHash)) {
  999. if (!AddProtectedRoot(&pInfo, rgbHash))
  1000. goto AddProtectedRootError;
  1001. }
  1002. }
  1003. }
  1004. }
  1005. if (NULL == (hKeyProtRoot = OpenProtectedRootSubKey(
  1006. hKeyCU,
  1007. KEY_ALL_ACCESS
  1008. ))) goto OpenProtectedRootSubKeyError;
  1009. if (!WriteProtectedRootInfo(hKeyProtRoot, pInfo))
  1010. goto WritedProtectedRootInfoError;
  1011. fResult = TRUE;
  1012. CommonReturn:
  1013. PkiFree(pInfo);
  1014. CertCloseStore(hStore, 0);
  1015. ILS_CloseRegistryKey(hKeyProtRoot);
  1016. return fResult;
  1017. ErrorReturn:
  1018. fResult = FALSE;
  1019. goto CommonReturn;
  1020. TRACE_ERROR(OutOfMemory)
  1021. TRACE_ERROR(AddProtectedRootError)
  1022. TRACE_ERROR(OpenProtectedRootSubKeyError)
  1023. TRACE_ERROR(WritedProtectedRootInfoError)
  1024. }
  1025. //+-------------------------------------------------------------------------
  1026. // Open the "ProtectedRoots" SubKey and verify its security. Allocate,
  1027. // read and verify the protected root information.
  1028. //
  1029. // If the "ProtectedRoots" SubKey doesn't exist or is invalid, initialize.
  1030. //--------------------------------------------------------------------------
  1031. STATIC BOOL SrvGetProtectedRootInfo(
  1032. IN HKEY hKeyCU,
  1033. OUT OPTIONAL HKEY *phKeyProtRoot,
  1034. OUT OPTIONAL PPROT_ROOT_INFO *ppProtRootInfo
  1035. )
  1036. {
  1037. BOOL fNew;
  1038. if (GetProtectedRootInfo(
  1039. hKeyCU,
  1040. KEY_ALL_ACCESS,
  1041. phKeyProtRoot,
  1042. ppProtRootInfo
  1043. ))
  1044. return TRUE;
  1045. if (!GetPredefinedSids())
  1046. return FALSE;
  1047. if (!SetProtectedRootOwner(hKeyCU, &fNew))
  1048. return FALSE;
  1049. if (!SetProtectedRootGroupDaclSacl(hKeyCU))
  1050. return FALSE;
  1051. if (!InitAndSetProtectedRootInfo(hKeyCU, fNew))
  1052. return FALSE;
  1053. return GetProtectedRootInfo(
  1054. hKeyCU,
  1055. KEY_ALL_ACCESS,
  1056. phKeyProtRoot,
  1057. ppProtRootInfo
  1058. );
  1059. }
  1060. //+-------------------------------------------------------------------------
  1061. // Initialize the protected list of CurrentUser roots
  1062. //--------------------------------------------------------------------------
  1063. STATIC BOOL SrvInitProtectedRoots(
  1064. IN HKEY hKeyCU
  1065. )
  1066. {
  1067. return SrvGetProtectedRootInfo(
  1068. hKeyCU,
  1069. NULL, // phKeyProtRoot
  1070. NULL // ppProtRootInfo
  1071. );
  1072. }
  1073. //+-------------------------------------------------------------------------
  1074. // Purge all CurrentUser roots from the protected list that also exist
  1075. // in the LocalMachine SystemRegistry "Root" store. Also removes duplicated
  1076. // certificates from the CurrentUser SystemRegistry "Root" store.
  1077. //--------------------------------------------------------------------------
  1078. STATIC BOOL SrvPurgeLocalMachineProtectedRoots(
  1079. IN HKEY hKeyCU,
  1080. IN LPCWSTR pwszRootStoreName
  1081. )
  1082. {
  1083. BOOL fResult;
  1084. HKEY hKeyProtRoot = NULL;
  1085. PPROT_ROOT_INFO pInfo = NULL;
  1086. PCCERT_CONTEXT pCert = NULL;
  1087. HCERTSTORE hCURootStore = NULL;
  1088. HCERTSTORE hLMRootStore = NULL;
  1089. BOOL fProtDeleted;
  1090. BYTE rgbHash[PROT_ROOT_HASH_LEN];
  1091. CRYPT_DATA_BLOB HashBlob;
  1092. DWORD dwRootIndex;
  1093. if (!SrvGetProtectedRootInfo(
  1094. hKeyCU,
  1095. &hKeyProtRoot,
  1096. &pInfo
  1097. )) goto GetProtectedRootInfoError;
  1098. if (GetProtectedRootFlags() & CERT_PROT_ROOT_INHIBIT_PURGE_LM_FLAG)
  1099. goto AccessDenied;
  1100. if (NULL == (hCURootStore = OpenUnprotectedRootStore(hKeyCU)))
  1101. goto OpenCURootStoreError;
  1102. if (NULL == (hLMRootStore = CertOpenStore(
  1103. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  1104. 0, // dwEncodingType
  1105. NULL, // hCryptProv
  1106. CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG,
  1107. (const void *) pwszRootStoreName
  1108. )))
  1109. goto OpenLMRootStoreError;
  1110. HashBlob.pbData = rgbHash;
  1111. HashBlob.cbData = PROT_ROOT_HASH_LEN;
  1112. fProtDeleted = FALSE;
  1113. pCert = NULL;
  1114. while (pCert = CertEnumCertificatesInStore(hCURootStore, pCert)) {
  1115. if (GetVerifiedCertHashProperty(pCert, rgbHash)) {
  1116. PCCERT_CONTEXT pLMCert;
  1117. if (pLMCert = CertFindCertificateInStore(
  1118. hLMRootStore,
  1119. 0, // dwCertEncodingType
  1120. 0, // dwFindFlags
  1121. CERT_FIND_SHA1_HASH,
  1122. (const void *) &HashBlob,
  1123. NULL //pPrevCertContext
  1124. )) {
  1125. // CurrentUser Root also exists in LocalMachine. Delete
  1126. // it from the CurrentUser Root store.
  1127. PCCERT_CONTEXT pDeleteCert =
  1128. CertDuplicateCertificateContext(pCert);
  1129. CertFreeCertificateContext(pLMCert);
  1130. if (!CertDeleteCertificateFromStore(pDeleteCert))
  1131. goto DeleteCertFromRootStoreError;
  1132. if (FindProtectedRoot(pInfo, rgbHash, &dwRootIndex)) {
  1133. // The CurrentUser Root is in the protected list,
  1134. // delete it from there.
  1135. DeleteProtectedRoot(pInfo, dwRootIndex);
  1136. fProtDeleted = TRUE;
  1137. }
  1138. }
  1139. }
  1140. }
  1141. // If a protected root exists in the LocalMachine, then, delete it
  1142. // from the protected list. This step is necessary, if the root
  1143. // was removed from the CurrentUser unprotected store.
  1144. dwRootIndex = pInfo->cRoot;
  1145. HashBlob.pbData = (BYTE *) pInfo + pInfo->dwRootOffset +
  1146. PROT_ROOT_HASH_LEN * dwRootIndex;
  1147. while (dwRootIndex--) {
  1148. PCCERT_CONTEXT pLMCert;
  1149. HashBlob.pbData -= PROT_ROOT_HASH_LEN;
  1150. if (pLMCert = CertFindCertificateInStore(
  1151. hLMRootStore,
  1152. 0, // dwCertEncodingType
  1153. 0, // dwFindFlags
  1154. CERT_FIND_SHA1_HASH,
  1155. (const void *) &HashBlob,
  1156. NULL //pPrevCertContext
  1157. )) {
  1158. CertFreeCertificateContext(pLMCert);
  1159. // Cert exists in the LocalMachine store, delete
  1160. // from protected list.
  1161. DeleteProtectedRoot(pInfo, dwRootIndex);
  1162. fProtDeleted = TRUE;
  1163. }
  1164. }
  1165. if (fProtDeleted) {
  1166. if (!WriteProtectedRootInfo(hKeyProtRoot, pInfo))
  1167. goto WriteProtectedRootInfoError;
  1168. }
  1169. fResult = TRUE;
  1170. CommonReturn:
  1171. ILS_CloseRegistryKey(hKeyProtRoot);
  1172. PkiFree(pInfo);
  1173. CertFreeCertificateContext(pCert);
  1174. CertCloseStore(hCURootStore, 0);
  1175. CertCloseStore(hLMRootStore, 0);
  1176. return fResult;
  1177. ErrorReturn:
  1178. fResult = FALSE;
  1179. goto CommonReturn;
  1180. SET_ERROR(AccessDenied, E_ACCESSDENIED)
  1181. TRACE_ERROR(OpenCURootStoreError)
  1182. TRACE_ERROR(OpenLMRootStoreError)
  1183. TRACE_ERROR(GetProtectedRootInfoError)
  1184. TRACE_ERROR(DeleteCertFromRootStoreError)
  1185. TRACE_ERROR(WriteProtectedRootInfoError)
  1186. }
  1187. //+-------------------------------------------------------------------------
  1188. // Add the specified certificate to the CurrentUser SystemRegistry "Root"
  1189. // store and the protected list of roots. The user is prompted before doing
  1190. // the add.
  1191. //
  1192. // Note, CertAddSerializedElementToStore() has __try/__except around
  1193. // accessing pbSerializedCert.
  1194. //--------------------------------------------------------------------------
  1195. STATIC BOOL SrvAddProtectedRoot(
  1196. IN handle_t hRpc,
  1197. IN HKEY hKeyCU,
  1198. IN BYTE *pbSerializedCert,
  1199. IN DWORD cbSerializedCert
  1200. )
  1201. {
  1202. BOOL fResult;
  1203. HKEY hKeyProtRoot = NULL;
  1204. PPROT_ROOT_INFO pInfo = NULL;
  1205. PCCERT_CONTEXT pCert = NULL;
  1206. BYTE rgbCertHash[PROT_ROOT_HASH_LEN];
  1207. HCERTSTORE hRootStore = NULL;
  1208. BOOL fProtExists;
  1209. if (!SrvGetProtectedRootInfo(
  1210. hKeyCU,
  1211. &hKeyProtRoot,
  1212. &pInfo
  1213. )) goto GetProtectedRootInfoError;
  1214. if (!CertAddSerializedElementToStore(
  1215. NULL, // hCertStore, NULL => create context
  1216. pbSerializedCert,
  1217. cbSerializedCert,
  1218. CERT_STORE_ADD_ALWAYS,
  1219. 0, // dwFlags
  1220. CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
  1221. NULL, // pdwContextType
  1222. (const void **) &pCert
  1223. )) goto CreateCertContextError;
  1224. if (!GetVerifiedCertHashProperty(pCert, rgbCertHash))
  1225. goto VerifyHashPropertyError;
  1226. fProtExists = FindProtectedRoot(pInfo, rgbCertHash);
  1227. if (!fProtExists) {
  1228. if (IDYES != IPR_ProtectedRootMessageBox(
  1229. hRpc,
  1230. pCert,
  1231. IDS_ROOT_MSG_BOX_ADD_ACTION,
  1232. MB_TOPMOST | MB_SERVICE_NOTIFICATION ))
  1233. goto Cancelled;
  1234. }
  1235. if (NULL == (hRootStore = OpenUnprotectedRootStore(hKeyCU)))
  1236. goto OpenRootStoreError;
  1237. if (!CertAddSerializedElementToStore(
  1238. hRootStore,
  1239. pbSerializedCert,
  1240. cbSerializedCert,
  1241. CERT_STORE_ADD_REPLACE_EXISTING,
  1242. 0, // dwFlags
  1243. CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
  1244. NULL, // pdwContextType
  1245. NULL // ppvContext
  1246. )) goto AddCertToRootStoreError;
  1247. if (!fProtExists) {
  1248. if (!AddProtectedRoot(&pInfo, rgbCertHash))
  1249. goto AddProtectedRootError;
  1250. if (!WriteProtectedRootInfo(hKeyProtRoot, pInfo))
  1251. goto WriteProtectedRootInfoError;
  1252. }
  1253. fResult = TRUE;
  1254. CommonReturn:
  1255. ILS_CloseRegistryKey(hKeyProtRoot);
  1256. PkiFree(pInfo);
  1257. CertFreeCertificateContext(pCert);
  1258. CertCloseStore(hRootStore, 0);
  1259. return fResult;
  1260. ErrorReturn:
  1261. fResult = FALSE;
  1262. goto CommonReturn;
  1263. SET_ERROR(Cancelled, ERROR_CANCELLED)
  1264. TRACE_ERROR(CreateCertContextError)
  1265. TRACE_ERROR(VerifyHashPropertyError)
  1266. TRACE_ERROR(GetProtectedRootInfoError)
  1267. TRACE_ERROR(OpenRootStoreError)
  1268. TRACE_ERROR(AddCertToRootStoreError)
  1269. TRACE_ERROR(AddProtectedRootError)
  1270. TRACE_ERROR(WriteProtectedRootInfoError)
  1271. }
  1272. //+-------------------------------------------------------------------------
  1273. // Delete the specified certificate from the CurrentUser SystemRegistry "Root"
  1274. // store and the protected list of roots. The user is prompted before doing
  1275. // the delete.
  1276. //
  1277. // __try/__except around memory access to
  1278. // rgbUntrustedRootHash[PROT_ROOT_HASH_LEN]
  1279. //--------------------------------------------------------------------------
  1280. STATIC BOOL SrvDeleteProtectedRoot(
  1281. IN handle_t hRpc,
  1282. IN HKEY hKeyCU,
  1283. IN BYTE rgbUntrustedRootHash[PROT_ROOT_HASH_LEN]
  1284. )
  1285. {
  1286. BOOL fResult;
  1287. HKEY hKeyProtRoot = NULL;
  1288. PPROT_ROOT_INFO pInfo = NULL;
  1289. PCCERT_CONTEXT pCert = NULL;
  1290. HCERTSTORE hRootStore = NULL;
  1291. BYTE rgbCertHash[PROT_ROOT_HASH_LEN];
  1292. DWORD dwRootIndex;
  1293. BOOL fProtExists;
  1294. BYTE rgbRootHash[PROT_ROOT_HASH_LEN];
  1295. CRYPT_DATA_BLOB RootHashBlob;
  1296. DWORD dwExceptionCode;
  1297. if (!SrvGetProtectedRootInfo(
  1298. hKeyCU,
  1299. &hKeyProtRoot,
  1300. &pInfo
  1301. )) goto GetProtectedRootInfoError;
  1302. if (NULL == (hRootStore = OpenUnprotectedRootStore(hKeyCU)))
  1303. goto OpenRootStoreError;
  1304. __try {
  1305. memcpy(rgbRootHash, rgbUntrustedRootHash, sizeof(rgbRootHash));
  1306. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1307. dwExceptionCode = GetExceptionCode();
  1308. goto ExceptionError;
  1309. }
  1310. RootHashBlob.pbData = rgbRootHash;
  1311. RootHashBlob.cbData = PROT_ROOT_HASH_LEN;
  1312. if (NULL == (pCert = CertFindCertificateInStore(
  1313. hRootStore,
  1314. 0, // dwCertEncodingType
  1315. 0, // dwFindFlags
  1316. CERT_FIND_SHA1_HASH,
  1317. (const void *) &RootHashBlob,
  1318. NULL //pPrevCertContext
  1319. ))) goto FindCertError;
  1320. if (!GetVerifiedCertHashProperty(pCert, rgbCertHash))
  1321. goto VerifyHashPropertyError;
  1322. fProtExists = FindProtectedRoot(pInfo, rgbCertHash, &dwRootIndex);
  1323. if (fProtExists) {
  1324. if (IDYES != IPR_ProtectedRootMessageBox(
  1325. hRpc,
  1326. pCert,
  1327. IDS_ROOT_MSG_BOX_DELETE_ACTION,
  1328. MB_TOPMOST | MB_SERVICE_NOTIFICATION ))
  1329. goto Cancelled;
  1330. }
  1331. fResult = CertDeleteCertificateFromStore(pCert);
  1332. pCert = NULL;
  1333. if (!fResult)
  1334. goto DeleteCertFromRootStoreError;
  1335. if (fProtExists) {
  1336. DeleteProtectedRoot(pInfo, dwRootIndex);
  1337. if (!WriteProtectedRootInfo(hKeyProtRoot, pInfo))
  1338. goto WriteProtectedRootInfoError;
  1339. }
  1340. fResult = TRUE;
  1341. CommonReturn:
  1342. ILS_CloseRegistryKey(hKeyProtRoot);
  1343. PkiFree(pInfo);
  1344. CertFreeCertificateContext(pCert);
  1345. CertCloseStore(hRootStore, 0);
  1346. return fResult;
  1347. ErrorReturn:
  1348. fResult = FALSE;
  1349. goto CommonReturn;
  1350. SET_ERROR(Cancelled, ERROR_CANCELLED)
  1351. TRACE_ERROR(OpenRootStoreError)
  1352. TRACE_ERROR(FindCertError)
  1353. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  1354. TRACE_ERROR(VerifyHashPropertyError)
  1355. TRACE_ERROR(GetProtectedRootInfoError)
  1356. TRACE_ERROR(DeleteCertFromRootStoreError)
  1357. TRACE_ERROR(WriteProtectedRootInfoError)
  1358. }
  1359. //+-------------------------------------------------------------------------
  1360. // Delete all CurrentUser roots from the protected list that don't also
  1361. // exist in the CurrentUser SystemRegistry "Root" store. The user is
  1362. // prompted before doing the delete.
  1363. //--------------------------------------------------------------------------
  1364. STATIC BOOL SrvDeleteUnknownProtectedRoots(
  1365. IN handle_t hRpc,
  1366. IN HKEY hKeyCU
  1367. )
  1368. {
  1369. BOOL fResult;
  1370. HKEY hKeyProtRoot = NULL;
  1371. PPROT_ROOT_INFO pInfo = NULL;
  1372. HCERTSTORE hRootStore = NULL;
  1373. DWORD cOrigRoot;
  1374. CRYPT_DATA_BLOB HashBlob;
  1375. DWORD dwRootIndex;
  1376. if (!SrvGetProtectedRootInfo(
  1377. hKeyCU,
  1378. &hKeyProtRoot,
  1379. &pInfo
  1380. )) goto GetProtectedRootInfoError;
  1381. if (NULL == (hRootStore = OpenUnprotectedRootStore(hKeyCU)))
  1382. goto OpenRootStoreError;
  1383. cOrigRoot = pInfo->cRoot;
  1384. HashBlob.pbData = (BYTE *) pInfo + pInfo->dwRootOffset +
  1385. PROT_ROOT_HASH_LEN * cOrigRoot;
  1386. HashBlob.cbData = PROT_ROOT_HASH_LEN;
  1387. dwRootIndex = cOrigRoot;
  1388. while (dwRootIndex--) {
  1389. PCCERT_CONTEXT pCert;
  1390. HashBlob.pbData -= PROT_ROOT_HASH_LEN;
  1391. if (pCert = CertFindCertificateInStore(
  1392. hRootStore,
  1393. 0, // dwCertEncodingType
  1394. 0, // dwFindFlags
  1395. CERT_FIND_SHA1_HASH,
  1396. (const void *) &HashBlob,
  1397. NULL //pPrevCertContext
  1398. ))
  1399. CertFreeCertificateContext(pCert);
  1400. else
  1401. // Cert doesn't exist in the unprotected store, delete
  1402. // from protected list.
  1403. DeleteProtectedRoot(pInfo, dwRootIndex);
  1404. }
  1405. if (cOrigRoot > pInfo->cRoot) {
  1406. // At least one root was deleted above
  1407. int id;
  1408. LPWSTR pwszTitle;
  1409. LPWSTR pwszText;
  1410. DWORD cchText;
  1411. RPC_STATUS RpcStatus = 0;
  1412. FormatMsgBoxItem(&pwszTitle, &cchText, IDS_ROOT_MSG_BOX_TITLE);
  1413. FormatMsgBoxItem(&pwszText, &cchText,
  1414. IDS_ROOT_MSG_BOX_DELETE_UNKNOWN_PROT_ROOTS,
  1415. cOrigRoot - pInfo->cRoot);
  1416. // Do impersonation for TerminalServer clients
  1417. if (hRpc)
  1418. RpcStatus = RpcImpersonateClient(hRpc);
  1419. id = MessageBoxU(
  1420. NULL, // hwndOwner
  1421. pwszText,
  1422. pwszTitle,
  1423. MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING |
  1424. MB_TOPMOST | MB_SERVICE_NOTIFICATION
  1425. );
  1426. if (hRpc && ERROR_SUCCESS == RpcStatus)
  1427. RpcRevertToSelf();
  1428. LocalFree((HLOCAL) pwszTitle);
  1429. LocalFree((HLOCAL) pwszText);
  1430. if (IDYES != id)
  1431. goto AccessDenied;
  1432. if (!WriteProtectedRootInfo(hKeyProtRoot, pInfo))
  1433. goto WriteProtectedRootInfoError;
  1434. }
  1435. fResult = TRUE;
  1436. CommonReturn:
  1437. ILS_CloseRegistryKey(hKeyProtRoot);
  1438. PkiFree(pInfo);
  1439. CertCloseStore(hRootStore, 0);
  1440. return fResult;
  1441. ErrorReturn:
  1442. fResult = FALSE;
  1443. goto CommonReturn;
  1444. SET_ERROR(AccessDenied, E_ACCESSDENIED)
  1445. TRACE_ERROR(GetProtectedRootInfoError)
  1446. TRACE_ERROR(OpenRootStoreError)
  1447. TRACE_ERROR(WriteProtectedRootInfoError)
  1448. }
  1449. // Forward reference
  1450. STATIC BOOL SrvLogCrypt32Event(
  1451. IN BYTE *pbIn,
  1452. IN DWORD cbIn
  1453. );
  1454. STATIC BOOL SrvAddCertInCtl(
  1455. IN BYTE *pbIn,
  1456. IN DWORD cbIn
  1457. );
  1458. //+-------------------------------------------------------------------------
  1459. // Called from the services process to process a protected certificate
  1460. // function.
  1461. //
  1462. // Returns the error status, ie, not returned in LastError.
  1463. //--------------------------------------------------------------------------
  1464. DWORD
  1465. WINAPI
  1466. I_CertSrvProtectFunction(
  1467. IN handle_t hRpc,
  1468. IN DWORD dwFuncId,
  1469. IN DWORD dwFlags,
  1470. IN LPCWSTR pwszIn,
  1471. IN BYTE *pbIn,
  1472. IN DWORD cbIn,
  1473. OUT BYTE **ppbOut,
  1474. OUT DWORD *pcbOut,
  1475. IN PFN_CERT_PROT_MIDL_USER_ALLOC pfnAlloc,
  1476. IN PFN_CERT_PROT_MIDL_USER_FREE pfnFree
  1477. )
  1478. {
  1479. DWORD dwErr;
  1480. BOOL fResult;
  1481. HKEY hKeyCU = NULL;
  1482. LONG err;
  1483. #ifndef TESTING_NO_PROT_ROOT_RPC
  1484. RPC_STATUS RpcStatus;
  1485. #endif
  1486. #ifdef TESTING_NO_PROT_ROOT_RPC
  1487. // For testing, called from the client's process
  1488. err = RegOpenHKCU(&hKeyCU);
  1489. if (ERROR_SUCCESS != err)
  1490. goto RegOpenHKCUError;
  1491. #else
  1492. if (NULL == hRpc)
  1493. goto InvalidArg;
  1494. // Get the client's HKCU.
  1495. if (ERROR_SUCCESS != (RpcStatus = RpcImpersonateClient(hRpc)))
  1496. goto ImpersonateClientError;
  1497. err = RegOpenHKCUEx(&hKeyCU, REG_HKCU_LOCAL_SYSTEM_ONLY_DEFAULT_FLAG);
  1498. RpcRevertToSelf();
  1499. if (ERROR_SUCCESS != err)
  1500. goto RegOpenHKCUError;
  1501. #endif
  1502. switch (dwFuncId) {
  1503. case CERT_PROT_INIT_ROOTS_FUNC_ID:
  1504. fResult = SrvInitProtectedRoots(hKeyCU);
  1505. break;
  1506. case CERT_PROT_PURGE_LM_ROOTS_FUNC_ID:
  1507. fResult = SrvPurgeLocalMachineProtectedRoots(hKeyCU, L"Root");
  1508. fResult &= SrvPurgeLocalMachineProtectedRoots(hKeyCU, L"AuthRoot");
  1509. break;
  1510. case CERT_PROT_ADD_ROOT_FUNC_ID:
  1511. if (NULL == pbIn || 0 == cbIn)
  1512. goto InvalidArg;
  1513. fResult = SrvAddProtectedRoot(hRpc, hKeyCU, pbIn, cbIn);
  1514. break;
  1515. case CERT_PROT_DELETE_ROOT_FUNC_ID:
  1516. if (NULL == pbIn || PROT_ROOT_HASH_LEN != cbIn)
  1517. goto InvalidArg;
  1518. fResult = SrvDeleteProtectedRoot(hRpc, hKeyCU, pbIn);
  1519. break;
  1520. case CERT_PROT_DELETE_UNKNOWN_ROOTS_FUNC_ID:
  1521. fResult = SrvDeleteUnknownProtectedRoots(hRpc, hKeyCU);
  1522. break;
  1523. case CERT_PROT_ADD_ROOT_IN_CTL_FUNC_ID:
  1524. if (NULL == pbIn || 0 == cbIn)
  1525. goto InvalidArg;
  1526. fResult = SrvAddCertInCtl(pbIn, cbIn);
  1527. break;
  1528. case CERT_PROT_LOG_EVENT_FUNC_ID:
  1529. if (NULL == pbIn || 0 == cbIn)
  1530. goto InvalidArg;
  1531. fResult = SrvLogCrypt32Event(pbIn, cbIn);
  1532. break;
  1533. case CERT_PROT_ROOT_LIST_FUNC_ID:
  1534. // Removed support for XAddRoot control
  1535. default:
  1536. goto InvalidArg;
  1537. }
  1538. if (!fResult)
  1539. goto ErrorReturn;
  1540. dwErr = ERROR_SUCCESS;
  1541. CommonReturn:
  1542. if (hKeyCU)
  1543. RegCloseHKCU(hKeyCU);
  1544. return dwErr;
  1545. ErrorReturn:
  1546. dwErr = GetLastError();
  1547. if (0 == dwErr)
  1548. dwErr = (DWORD) E_UNEXPECTED;
  1549. goto CommonReturn;
  1550. SET_ERROR(InvalidArg, E_INVALIDARG)
  1551. #ifdef TESTING_NO_PROT_ROOT_RPC
  1552. #else
  1553. SET_ERROR_VAR(ImpersonateClientError, RpcStatus)
  1554. #endif
  1555. SET_ERROR_VAR(RegOpenHKCUError, err)
  1556. }
  1557. #ifdef TESTING_NO_PROT_ROOT_RPC
  1558. // For testing: the server stuff resides in the client process
  1559. BOOL
  1560. WINAPI
  1561. I_CertProtectFunction(
  1562. IN DWORD dwFuncId,
  1563. IN DWORD dwFlags,
  1564. IN OPTIONAL LPCWSTR pwszIn,
  1565. IN OPTIONAL BYTE *pbIn,
  1566. IN DWORD cbIn,
  1567. OUT OPTIONAL BYTE **ppbOut,
  1568. OUT OPTIONAL DWORD *pcbOut
  1569. )
  1570. {
  1571. DWORD dwErr;
  1572. dwErr = I_CertSrvProtectFunction(
  1573. NULL, // hRpc
  1574. dwFuncId,
  1575. dwFlags,
  1576. pwszIn,
  1577. pbIn,
  1578. cbIn,
  1579. NULL, // ppbOut
  1580. NULL, // pcbOut
  1581. NULL, // pfnAlloc
  1582. NULL // pfnFree
  1583. );
  1584. if (ERROR_SUCCESS == dwErr)
  1585. return TRUE;
  1586. else {
  1587. SetLastError(dwErr);
  1588. return FALSE;
  1589. }
  1590. }
  1591. #else
  1592. BOOL
  1593. WINAPI
  1594. I_CertProtectFunction(
  1595. IN DWORD dwFuncId,
  1596. IN DWORD dwFlags,
  1597. IN OPTIONAL LPCWSTR pwszIn,
  1598. IN OPTIONAL BYTE *pbIn,
  1599. IN DWORD cbIn,
  1600. OUT OPTIONAL BYTE **ppbOut,
  1601. OUT OPTIONAL DWORD *pcbOut
  1602. )
  1603. {
  1604. return I_CertCltProtectFunction(
  1605. dwFuncId,
  1606. dwFlags,
  1607. pwszIn,
  1608. pbIn,
  1609. cbIn,
  1610. ppbOut,
  1611. pcbOut
  1612. );
  1613. }
  1614. #endif
  1615. //+=========================================================================
  1616. // Protected root functions called from the client process in logstor.cpp
  1617. // or in ..\chain\chain.cpp
  1618. //==========================================================================
  1619. //+-------------------------------------------------------------------------
  1620. // Returns TRUE if the protected root flag wasn't set to disable the opening
  1621. // of the CurrentUser's "root\.Default" physical store.
  1622. //--------------------------------------------------------------------------
  1623. BOOL
  1624. IPR_IsCurrentUserRootsAllowed()
  1625. {
  1626. DWORD dwProtRootFlags;
  1627. dwProtRootFlags = GetProtectedRootFlags();
  1628. return 0 == (dwProtRootFlags & CERT_PROT_ROOT_DISABLE_CURRENT_USER_FLAG);
  1629. }
  1630. //+-------------------------------------------------------------------------
  1631. // Returns TRUE if the protected root flag wasn't set to disable the opening
  1632. // of the LocalMachine's "root\.AuthRoot" physical store.
  1633. //--------------------------------------------------------------------------
  1634. BOOL
  1635. IPR_IsAuthRootsAllowed()
  1636. {
  1637. DWORD dwProtRootFlags;
  1638. dwProtRootFlags = GetProtectedRootFlags();
  1639. return 0 == (dwProtRootFlags & CERT_PROT_ROOT_DISABLE_LM_AUTH_FLAG);
  1640. }
  1641. //+-------------------------------------------------------------------------
  1642. // Returns TRUE if the protected root flag was set to disable the
  1643. // requiring of the issuing CA certificate being in the "NTAuth"
  1644. // Enterprise store.
  1645. //--------------------------------------------------------------------------
  1646. BOOL
  1647. IPR_IsNTAuthRequiredDisabled()
  1648. {
  1649. DWORD dwProtRootFlags;
  1650. dwProtRootFlags = GetProtectedRootFlags();
  1651. return 0 != (dwProtRootFlags &
  1652. CERT_PROT_ROOT_DISABLE_NT_AUTH_REQUIRED_FLAG);
  1653. }
  1654. //+-------------------------------------------------------------------------
  1655. // Returns TRUE if the protected root flag was set to disable checking for
  1656. // not defined name constraints.
  1657. //--------------------------------------------------------------------------
  1658. BOOL
  1659. IPR_IsNotDefinedNameConstraintDisabled()
  1660. {
  1661. DWORD dwProtRootFlags;
  1662. dwProtRootFlags = GetProtectedRootFlags();
  1663. return 0 != (dwProtRootFlags &
  1664. CERT_PROT_ROOT_DISABLE_NOT_DEFINED_NAME_CONSTRAINT_FLAG);
  1665. }
  1666. //+---------------------------------------------------------------------------
  1667. // Returns TRUE if Auto Update has been disabled
  1668. //----------------------------------------------------------------------------
  1669. BOOL
  1670. IPR_IsAuthRootAutoUpdateDisabled()
  1671. {
  1672. HKEY hKey = NULL;
  1673. DWORD dwInstallFlag = 0;
  1674. if (!IPR_IsAuthRootsAllowed())
  1675. return TRUE;
  1676. if (ERROR_SUCCESS != RegOpenKeyExU(
  1677. HKEY_LOCAL_MACHINE,
  1678. CERT_OCM_SUBCOMPONENTS_LOCAL_MACHINE_REGPATH,
  1679. 0, // dwReserved
  1680. KEY_READ,
  1681. &hKey
  1682. ))
  1683. return TRUE;
  1684. ILS_ReadDWORDValueFromRegistry(
  1685. hKey,
  1686. CERT_OCM_SUBCOMPONENTS_ROOT_AUTO_UPDATE_VALUE_NAME,
  1687. &dwInstallFlag
  1688. );
  1689. ILS_CloseRegistryKey(hKey);
  1690. return 0 == dwInstallFlag;
  1691. }
  1692. //+-------------------------------------------------------------------------
  1693. // Gets the protected root information containing the list of protected
  1694. // root stores.
  1695. //
  1696. // If protected root store isn't supported, returns TRUE with
  1697. // *ppProtRootInfo set to NULL.
  1698. //--------------------------------------------------------------------------
  1699. BOOL CltGetProtectedRootInfo(
  1700. OUT PPROT_ROOT_INFO *ppInfo
  1701. )
  1702. {
  1703. BOOL fResult;
  1704. LONG err;
  1705. HKEY hKeyCU = NULL;
  1706. *ppInfo = NULL;
  1707. #ifndef TESTING_NO_PROT_ROOT_RPC
  1708. if (!FIsWinNT5())
  1709. // No protected roots on Win9x or NT4.0
  1710. return TRUE;
  1711. #endif
  1712. if (ERROR_SUCCESS != (err = RegOpenHKCU(&hKeyCU)))
  1713. goto RegOpenHKCUError;
  1714. if (GetProtectedRootInfo(
  1715. hKeyCU,
  1716. KEY_READ,
  1717. NULL, // phKeyProtRoot
  1718. ppInfo
  1719. )) goto SuccessReturn;
  1720. if (!I_CertProtectFunction(
  1721. CERT_PROT_INIT_ROOTS_FUNC_ID,
  1722. 0, // dwFlags
  1723. NULL, // pwszIn
  1724. NULL, // pbIn
  1725. 0, // cbIn
  1726. NULL, // ppbOut
  1727. NULL // pcbOut
  1728. )) {
  1729. DWORD dwErr = GetLastError();
  1730. if (ERROR_CALL_NOT_IMPLEMENTED == dwErr || RPC_S_UNKNOWN_IF == dwErr)
  1731. goto SuccessReturn;
  1732. goto ProtFuncError;
  1733. }
  1734. if (!GetProtectedRootInfo(
  1735. hKeyCU,
  1736. KEY_READ,
  1737. NULL, // phKeyProtRoot
  1738. ppInfo
  1739. ))
  1740. goto GetProtectedRootInfoError;
  1741. SuccessReturn:
  1742. fResult = TRUE;
  1743. CommonReturn:
  1744. if (hKeyCU)
  1745. RegCloseHKCU(hKeyCU);
  1746. return fResult;
  1747. ErrorReturn:
  1748. *ppInfo = NULL;
  1749. fResult = FALSE;
  1750. goto CommonReturn;
  1751. SET_ERROR_VAR(RegOpenHKCUError, err)
  1752. TRACE_ERROR(GetProtectedRootInfoError)
  1753. TRACE_ERROR(ProtFuncError)
  1754. }
  1755. //+-------------------------------------------------------------------------
  1756. // Initializes the protected list of roots.
  1757. //--------------------------------------------------------------------------
  1758. void
  1759. IPR_InitProtectedRootInfo()
  1760. {
  1761. HKEY hKeyCU;
  1762. #ifndef TESTING_NO_PROT_ROOT_RPC
  1763. if (!FIsWinNT5())
  1764. // No protected roots on Win9x or NT4.0
  1765. return;
  1766. #endif
  1767. if (ERROR_SUCCESS == RegOpenHKCU(&hKeyCU)) {
  1768. HKEY hKeyProtRoot;
  1769. if (hKeyProtRoot = OpenProtectedRootSubKey(hKeyCU, KEY_READ))
  1770. // Protected root subkey exists
  1771. ILS_CloseRegistryKey(hKeyProtRoot);
  1772. else {
  1773. I_CertProtectFunction(
  1774. CERT_PROT_INIT_ROOTS_FUNC_ID,
  1775. 0, // dwFlags
  1776. NULL, // pwszIn
  1777. NULL, // pbIn
  1778. 0, // cbIn
  1779. NULL, // ppbOut
  1780. NULL // pcbOut
  1781. );
  1782. }
  1783. RegCloseHKCU(hKeyCU);
  1784. }
  1785. }
  1786. //+-------------------------------------------------------------------------
  1787. // Delete certificates not in the protected store list.
  1788. //--------------------------------------------------------------------------
  1789. BOOL
  1790. IPR_DeleteUnprotectedRootsFromStore(
  1791. IN HCERTSTORE hStore,
  1792. OUT BOOL *pfProtected
  1793. )
  1794. {
  1795. PPROT_ROOT_INFO pInfo;
  1796. PCCERT_CONTEXT pCert;
  1797. if (!CltGetProtectedRootInfo(&pInfo)) {
  1798. *pfProtected = FALSE;
  1799. // Delete all certificates from the store's cache.
  1800. while (pCert = CertEnumCertificatesInStore(hStore, NULL))
  1801. CertDeleteCertificateFromStore(pCert);
  1802. return FALSE;
  1803. }
  1804. if (NULL == pInfo)
  1805. // Root store isn't protected.
  1806. *pfProtected = FALSE;
  1807. else {
  1808. *pfProtected = TRUE;
  1809. pCert = NULL;
  1810. while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
  1811. BYTE rgbHash[PROT_ROOT_HASH_LEN];
  1812. if (!GetVerifiedCertHashProperty(pCert, rgbHash) ||
  1813. !FindProtectedRoot(pInfo, rgbHash)) {
  1814. PCCERT_CONTEXT pDeleteCert =
  1815. CertDuplicateCertificateContext(pCert);
  1816. CertDeleteCertificateFromStore(pDeleteCert);
  1817. }
  1818. }
  1819. PkiFree(pInfo);
  1820. }
  1821. return TRUE;
  1822. }
  1823. // Includes the title
  1824. #define MAX_PROT_ROOT_BOX_ITEMS 10
  1825. typedef struct _PROT_ROOT_BOX_ITEM {
  1826. LPWSTR pwszItem;
  1827. DWORD cchItem;
  1828. } PROT_ROOT_BOX_ITEM;
  1829. // Returns count of items added
  1830. DWORD
  1831. I_FormatRootBoxItems(
  1832. IN PCCERT_CONTEXT pCert,
  1833. IN UINT wActionID,
  1834. IN OUT PROT_ROOT_BOX_ITEM rgItem[MAX_PROT_ROOT_BOX_ITEMS]
  1835. )
  1836. {
  1837. DWORD cItem = 0;
  1838. DWORD cchTmp;
  1839. LPWSTR pwszTmp;
  1840. // ACTION:
  1841. FormatMsgBoxItem(&rgItem[cItem].pwszItem, &rgItem[cItem].cchItem,
  1842. wActionID);
  1843. cItem++;
  1844. // SUBJECT
  1845. cchTmp = CertNameToStrW(
  1846. pCert->dwCertEncodingType,
  1847. &pCert->pCertInfo->Subject,
  1848. CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  1849. NULL, // pwsz
  1850. 0); // cwsz
  1851. pwszTmp = (LPWSTR) PkiNonzeroAlloc(cchTmp * sizeof(WCHAR));
  1852. if (NULL != pwszTmp)
  1853. CertNameToStrW(
  1854. pCert->dwCertEncodingType,
  1855. &pCert->pCertInfo->Subject,
  1856. CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  1857. pwszTmp,
  1858. cchTmp);
  1859. FormatMsgBoxItem(&rgItem[cItem].pwszItem, &rgItem[cItem].cchItem,
  1860. IDS_ROOT_MSG_BOX_SUBJECT, NULL != pwszTmp ? pwszTmp : L"");
  1861. cItem++;
  1862. PkiFree(pwszTmp);
  1863. // ISSUER. May be self issued
  1864. if (CertCompareCertificateName(
  1865. pCert->dwCertEncodingType,
  1866. &pCert->pCertInfo->Subject,
  1867. &pCert->pCertInfo->Issuer
  1868. ))
  1869. // Self issued
  1870. FormatMsgBoxItem(&rgItem[cItem].pwszItem, &rgItem[cItem].cchItem,
  1871. IDS_ROOT_MSG_BOX_SELF_ISSUED);
  1872. else {
  1873. // Format certificate's issuer
  1874. cchTmp = CertNameToStrW(
  1875. pCert->dwCertEncodingType,
  1876. &pCert->pCertInfo->Issuer,
  1877. CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  1878. NULL, // pwsz
  1879. 0); // cwsz
  1880. pwszTmp = (LPWSTR) PkiNonzeroAlloc(cchTmp * sizeof(WCHAR));
  1881. if (NULL != pwszTmp)
  1882. CertNameToStrW(
  1883. pCert->dwCertEncodingType,
  1884. &pCert->pCertInfo->Issuer,
  1885. CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  1886. pwszTmp,
  1887. cchTmp);
  1888. FormatMsgBoxItem(&rgItem[cItem].pwszItem, &rgItem[cItem].cchItem,
  1889. IDS_ROOT_MSG_BOX_ISSUER, NULL != pwszTmp ? pwszTmp : L"");
  1890. PkiFree(pwszTmp);
  1891. }
  1892. cItem++;
  1893. // TIME VALIDITY
  1894. {
  1895. FILETIME ftLocal;
  1896. SYSTEMTIME stLocal;
  1897. WCHAR wszNotBefore[128];
  1898. WCHAR wszNotAfter[128];
  1899. wszNotBefore[0] = '\0';
  1900. wszNotAfter[0] = '\0';
  1901. FileTimeToLocalFileTime(&pCert->pCertInfo->NotBefore, &ftLocal);
  1902. FileTimeToSystemTime(&ftLocal, &stLocal);
  1903. GetDateFormatU(LOCALE_USER_DEFAULT, DATE_LONGDATE, &stLocal,
  1904. NULL, wszNotBefore, 128);
  1905. FileTimeToLocalFileTime(&pCert->pCertInfo->NotAfter, &ftLocal);
  1906. FileTimeToSystemTime(&ftLocal, &stLocal);
  1907. GetDateFormatU(LOCALE_USER_DEFAULT, DATE_LONGDATE, &stLocal,
  1908. NULL, wszNotAfter, 128);
  1909. FormatMsgBoxItem(&rgItem[cItem].pwszItem,
  1910. &rgItem[cItem].cchItem, IDS_ROOT_MSG_BOX_TIME_VALIDITY,
  1911. wszNotBefore, wszNotAfter);
  1912. cItem++;
  1913. }
  1914. // SERIAL NUMBER
  1915. if (pCert->pCertInfo->SerialNumber.cbData) {
  1916. DWORD cb = pCert->pCertInfo->SerialNumber.cbData;
  1917. BYTE *pb;
  1918. if (pb = PkiAsn1AllocAndReverseBytes(
  1919. pCert->pCertInfo->SerialNumber.pbData, cb)) {
  1920. LPWSTR pwsz;
  1921. if (pwsz = (LPWSTR) PkiNonzeroAlloc(
  1922. (cb*2 + cb/4 + 1) * sizeof(WCHAR))) {
  1923. FormatMsgBoxMultiBytes(cb, pb, pwsz);
  1924. FormatMsgBoxItem(&rgItem[cItem].pwszItem,
  1925. &rgItem[cItem].cchItem, IDS_ROOT_MSG_BOX_SERIAL_NUMBER,
  1926. pwsz);
  1927. cItem++;
  1928. PkiFree(pwsz);
  1929. }
  1930. PkiAsn1Free(pb);
  1931. }
  1932. }
  1933. // THUMBPRINTS: sha1 and md5
  1934. {
  1935. BYTE rgbHash[MAX_HASH_LEN];
  1936. DWORD cbHash = MAX_HASH_LEN;
  1937. WCHAR wszTmp[MAX_HASH_LEN * 3 + 1];
  1938. // get the sha1 thumbprint
  1939. if (CertGetCertificateContextProperty(
  1940. pCert,
  1941. CERT_SHA1_HASH_PROP_ID,
  1942. rgbHash,
  1943. &cbHash)) {
  1944. FormatMsgBoxMultiBytes(cbHash, rgbHash, wszTmp);
  1945. FormatMsgBoxItem(&rgItem[cItem].pwszItem,
  1946. &rgItem[cItem].cchItem, IDS_ROOT_MSG_BOX_SHA1_THUMBPRINT,
  1947. wszTmp);
  1948. cItem++;
  1949. }
  1950. // get the md5 thumbprint
  1951. if (CertGetCertificateContextProperty(
  1952. pCert,
  1953. CERT_MD5_HASH_PROP_ID,
  1954. rgbHash,
  1955. &cbHash)) {
  1956. FormatMsgBoxMultiBytes(cbHash, rgbHash, wszTmp);
  1957. FormatMsgBoxItem(&rgItem[cItem].pwszItem,
  1958. &rgItem[cItem].cchItem, IDS_ROOT_MSG_BOX_MD5_THUMBPRINT,
  1959. wszTmp);
  1960. cItem++;
  1961. }
  1962. }
  1963. return cItem;
  1964. }
  1965. // Returns count of items added
  1966. DWORD
  1967. I_FormatAddRootBoxItems(
  1968. IN PCCERT_CONTEXT pCert,
  1969. IN OUT PROT_ROOT_BOX_ITEM rgItem[MAX_PROT_ROOT_BOX_ITEMS]
  1970. )
  1971. {
  1972. WCHAR wszIssuer[100];
  1973. BYTE rgbHash[MAX_HASH_LEN];
  1974. DWORD cbHash = MAX_HASH_LEN;
  1975. WCHAR wszThumbprint[MAX_HASH_LEN * 3 + 1];
  1976. // Issuer Name
  1977. CertGetNameStringW(
  1978. pCert,
  1979. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  1980. 0, // dwFlags
  1981. NULL, // pvTypePara
  1982. wszIssuer,
  1983. sizeof(wszIssuer) / sizeof(wszIssuer[0])
  1984. );
  1985. // sha1 Thumbprint
  1986. if (CertGetCertificateContextProperty(
  1987. pCert,
  1988. CERT_SHA1_HASH_PROP_ID,
  1989. rgbHash,
  1990. &cbHash))
  1991. FormatMsgBoxMultiBytes(cbHash, rgbHash, wszThumbprint);
  1992. else
  1993. wcscpy(wszThumbprint, L"???");
  1994. // Format the intro, body and end lines
  1995. FormatMsgBoxItem(&rgItem[0].pwszItem, &rgItem[0].cchItem,
  1996. IDS_ADD_ROOT_MSG_BOX_INTRO, wszIssuer);
  1997. FormatMsgBoxItem(&rgItem[1].pwszItem, &rgItem[1].cchItem,
  1998. IDS_ADD_ROOT_MSG_BOX_BODY_0, wszIssuer);
  1999. FormatMsgBoxItem(&rgItem[2].pwszItem, &rgItem[2].cchItem,
  2000. IDS_ADD_ROOT_MSG_BOX_BODY_1, wszThumbprint);
  2001. FormatMsgBoxItem(&rgItem[3].pwszItem, &rgItem[3].cchItem,
  2002. IDS_ADD_ROOT_MSG_BOX_END_0);
  2003. FormatMsgBoxItem(&rgItem[4].pwszItem, &rgItem[4].cchItem,
  2004. IDS_ADD_ROOT_MSG_BOX_END_1);
  2005. return 5;
  2006. }
  2007. //+-------------------------------------------------------------------------
  2008. // The add/delete root message box.
  2009. //
  2010. // If protected roots aren't supported, called from the client process.
  2011. // Otherwise, called from the services process.
  2012. //--------------------------------------------------------------------------
  2013. int
  2014. IPR_ProtectedRootMessageBox(
  2015. IN handle_t hRpc,
  2016. IN PCCERT_CONTEXT pCert,
  2017. IN UINT wActionID,
  2018. IN UINT uFlags
  2019. )
  2020. {
  2021. int id;
  2022. PROT_ROOT_BOX_ITEM rgItem[MAX_PROT_ROOT_BOX_ITEMS];
  2023. DWORD cItem;
  2024. LPWSTR pwszText = NULL;
  2025. DWORD cchText = 0;
  2026. DWORD ItemIdx;
  2027. if (wActionID == IDS_ROOT_MSG_BOX_ADD_ACTION)
  2028. cItem = I_FormatAddRootBoxItems(
  2029. pCert,
  2030. rgItem
  2031. );
  2032. else
  2033. cItem = I_FormatRootBoxItems(
  2034. pCert,
  2035. wActionID,
  2036. rgItem
  2037. );
  2038. // Concatenate all the items into a single allocated string
  2039. for (ItemIdx = 0; ItemIdx < cItem; ItemIdx++)
  2040. cchText += rgItem[ItemIdx].cchItem;
  2041. if (NULL != (pwszText = (LPWSTR) PkiNonzeroAlloc(
  2042. (cchText + 1) * sizeof(WCHAR)))) {
  2043. LPWSTR pwsz = pwszText;
  2044. RPC_STATUS RpcStatus = 0;
  2045. for (ItemIdx = 0; ItemIdx < cItem; ItemIdx++) {
  2046. DWORD cch = rgItem[ItemIdx].cchItem;
  2047. if (cch) {
  2048. assert(rgItem[ItemIdx].pwszItem);
  2049. memcpy(pwsz, rgItem[ItemIdx].pwszItem, cch * sizeof(WCHAR));
  2050. pwsz += cch;
  2051. }
  2052. }
  2053. assert (pwsz == pwszText + cchText);
  2054. *pwsz = '\0';
  2055. // TITLE
  2056. FormatMsgBoxItem(&rgItem[cItem].pwszItem, &rgItem[cItem].cchItem,
  2057. (IDS_ROOT_MSG_BOX_ADD_ACTION == wActionID) ?
  2058. IDS_ADD_ROOT_MSG_BOX_TITLE : IDS_ROOT_MSG_BOX_TITLE);
  2059. // Do impersonation for TerminalServer clients
  2060. if (hRpc)
  2061. RpcStatus = RpcImpersonateClient(hRpc);
  2062. id = MessageBoxU(
  2063. NULL, // hwndOwner
  2064. pwszText,
  2065. rgItem[cItem].pwszItem,
  2066. MB_TOPMOST | MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING | uFlags
  2067. );
  2068. if (hRpc && ERROR_SUCCESS == RpcStatus)
  2069. RpcRevertToSelf();
  2070. cItem++;
  2071. PkiFree(pwszText);
  2072. } else
  2073. id = IDNO;
  2074. // Free up all the individually allocated items
  2075. while (cItem--) {
  2076. if (rgItem[cItem].pwszItem)
  2077. LocalFree((HLOCAL) rgItem[cItem].pwszItem);
  2078. }
  2079. return id;
  2080. }
  2081. //+=========================================================================
  2082. // crypt32 Event Logging Functions
  2083. //==========================================================================
  2084. #define MAX_CRYPT32_EVENT_LOG_STRINGS 5
  2085. #define MAX_CRYPT32_EVENT_LOG_COUNT 50
  2086. // 1 hour (in units of seconds)
  2087. #define CRYPT32_EVENT_LOG_THRESHOLD_PERIOD (60*60)
  2088. // Count of logged events. Gets reset whenever the interval between
  2089. // logged events >= CRYPT32_EVENT_LOG_THRESHOLD_PERIOD. If
  2090. // MAX_CRYPT32_EVENT_LOG_COUNT is reached, suspend logging for
  2091. // CRYPT32_EVENT_LOG_THRESHOLD_PERIOD.
  2092. DWORD dwCrypt32EventLogCnt;
  2093. // Time of last logged event.
  2094. FILETIME ftLastCrypt32EventLog;
  2095. // advapi32.dll Event APIs. Not supported on Win9x.
  2096. typedef HANDLE (WINAPI *PFN_REGISTER_EVENT_SOURCE_W)(
  2097. IN LPCWSTR lpUNCServerName,
  2098. IN LPCWSTR lpSourceName
  2099. );
  2100. typedef BOOL (WINAPI *PFN_DEREGISTER_EVENT_SOURCE)(
  2101. IN OUT HANDLE hEventLog
  2102. );
  2103. typedef BOOL (WINAPI *PFN_REPORT_EVENT_W)(
  2104. IN HANDLE hEventLog,
  2105. IN WORD wType,
  2106. IN WORD wCategory,
  2107. IN DWORD dwEventID,
  2108. IN PSID lpUserSid,
  2109. IN WORD wNumStrings,
  2110. IN DWORD dwDataSize,
  2111. IN LPCWSTR *lpStrings,
  2112. IN LPVOID lpRawData
  2113. );
  2114. //+-------------------------------------------------------------------------
  2115. // Logs crypt32 events. Ensures we don't log more than
  2116. // MAX_CRYPT32_EVENT_LOG_COUNT events in any period of
  2117. // CRYPT32_EVENT_LOG_THRESHOLD_PERIOD seconds.
  2118. //
  2119. // Also, dynamically detects if event logging is supported by the version
  2120. // of advapi32.dll on the machine.
  2121. //--------------------------------------------------------------------------
  2122. STATIC BOOL LogCrypt32Event(
  2123. IN WORD wType,
  2124. IN WORD wCategory,
  2125. IN DWORD dwEventID,
  2126. IN WORD wNumStrings,
  2127. IN DWORD dwDataSize,
  2128. IN LPCWSTR *rgpwszStrings,
  2129. IN BYTE *pbData
  2130. )
  2131. {
  2132. BOOL fResult;
  2133. FILETIME ftCurrent;
  2134. FILETIME ftNext;
  2135. LONG lThreshold;
  2136. HMODULE hModule; // No FreeLibary() for GetModuleHandle
  2137. DWORD dwExceptionCode;
  2138. DWORD dwLastErr = 0;
  2139. PFN_REGISTER_EVENT_SOURCE_W pfnRegisterEventSourceW;
  2140. PFN_REPORT_EVENT_W pfnReportEventW;
  2141. PFN_DEREGISTER_EVENT_SOURCE pfnDeregisterEventSource;
  2142. // Check if we have exceeded the crypt32 event log threshold for
  2143. // this time period
  2144. //
  2145. // lThreshold:
  2146. // -1 - haven't reached it,
  2147. // 0 - reached it this time
  2148. // +1 - previously reached, won't log this event
  2149. lThreshold = -1;
  2150. EnterCriticalSection(&Crypt32EventLogCriticalSection);
  2151. I_CryptIncrementFileTimeBySeconds(&ftLastCrypt32EventLog,
  2152. CRYPT32_EVENT_LOG_THRESHOLD_PERIOD, &ftNext);
  2153. GetSystemTimeAsFileTime(&ftCurrent);
  2154. if (0 <= CompareFileTime(&ftCurrent, &ftNext))
  2155. dwCrypt32EventLogCnt = 0;
  2156. else if (MAX_CRYPT32_EVENT_LOG_COUNT <= dwCrypt32EventLogCnt)
  2157. lThreshold = 1;
  2158. if (0 >= lThreshold) {
  2159. ftLastCrypt32EventLog = ftCurrent;
  2160. dwCrypt32EventLogCnt++;
  2161. if (MAX_CRYPT32_EVENT_LOG_COUNT <= dwCrypt32EventLogCnt)
  2162. lThreshold = 0;
  2163. }
  2164. LeaveCriticalSection(&Crypt32EventLogCriticalSection);
  2165. if (0 < lThreshold)
  2166. goto ExceededCrypt32EventLogThreshold;
  2167. // Only supported on systems where the event APIs are exported from
  2168. // advapi32.dll. Note, crypt32.dll has a static link dependency on
  2169. // advapi32.dll.
  2170. if (NULL == (hModule = GetModuleHandleA("advapi32.dll")))
  2171. goto GetAdvapi32ModuleError;
  2172. pfnRegisterEventSourceW = (PFN_REGISTER_EVENT_SOURCE_W)
  2173. GetProcAddress(hModule, "RegisterEventSourceW");
  2174. pfnReportEventW = (PFN_REPORT_EVENT_W)
  2175. GetProcAddress(hModule, "ReportEventW");
  2176. pfnDeregisterEventSource = (PFN_DEREGISTER_EVENT_SOURCE)
  2177. GetProcAddress(hModule, "DeregisterEventSource");
  2178. if (NULL == pfnRegisterEventSourceW ||
  2179. NULL == pfnReportEventW ||
  2180. NULL == pfnDeregisterEventSource)
  2181. goto Advapi32EventAPINotSupported;
  2182. fResult = TRUE;
  2183. __try {
  2184. HANDLE hEventLog;
  2185. hEventLog = pfnRegisterEventSourceW(
  2186. NULL, // lpUNCServerName
  2187. L"crypt32"
  2188. );
  2189. if (hEventLog) {
  2190. if (!pfnReportEventW(
  2191. hEventLog,
  2192. wType,
  2193. wCategory,
  2194. dwEventID,
  2195. NULL, // lpUserSid
  2196. wNumStrings,
  2197. dwDataSize,
  2198. rgpwszStrings,
  2199. pbData
  2200. )) {
  2201. fResult = FALSE;
  2202. dwLastErr = GetLastError();
  2203. }
  2204. I_DBLogCrypt32Event(
  2205. wType,
  2206. dwEventID,
  2207. wNumStrings,
  2208. rgpwszStrings
  2209. );
  2210. if (0 == lThreshold) {
  2211. WCHAR wszCnt[34];
  2212. WCHAR wszPeriod[34];
  2213. LPCWSTR rgpwszThresholdStrings[2] = {wszCnt, wszPeriod};
  2214. _ltow(MAX_CRYPT32_EVENT_LOG_COUNT, wszCnt, 10);
  2215. _ltow(CRYPT32_EVENT_LOG_THRESHOLD_PERIOD / 60, wszPeriod, 10);
  2216. if (!pfnReportEventW(
  2217. hEventLog,
  2218. EVENTLOG_WARNING_TYPE,
  2219. 0, // wCategory
  2220. MSG_CRYPT32_EVENT_LOG_THRESHOLD_WARNING,
  2221. NULL, // lpUserSid
  2222. 2, // wNumStrings
  2223. 0, // dwDataSize
  2224. rgpwszThresholdStrings,
  2225. NULL // pbData
  2226. )) {
  2227. fResult = FALSE;
  2228. dwLastErr = GetLastError();
  2229. }
  2230. I_DBLogCrypt32Event(
  2231. EVENTLOG_WARNING_TYPE,
  2232. MSG_CRYPT32_EVENT_LOG_THRESHOLD_WARNING,
  2233. 2, // wNumStrings
  2234. rgpwszThresholdStrings
  2235. );
  2236. }
  2237. pfnDeregisterEventSource(hEventLog);
  2238. } else {
  2239. fResult = FALSE;
  2240. dwLastErr = GetLastError();
  2241. }
  2242. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2243. dwExceptionCode = GetExceptionCode();
  2244. goto ExceptionError;
  2245. }
  2246. if (!fResult)
  2247. goto ReportEventError;
  2248. CommonReturn:
  2249. return fResult;
  2250. ErrorReturn:
  2251. fResult = FALSE;
  2252. goto CommonReturn;
  2253. SET_ERROR(ExceededCrypt32EventLogThreshold, ERROR_CAN_NOT_COMPLETE)
  2254. TRACE_ERROR(GetAdvapi32ModuleError)
  2255. SET_ERROR(Advapi32EventAPINotSupported, ERROR_PROC_NOT_FOUND)
  2256. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  2257. SET_ERROR_VAR(ReportEventError, dwLastErr)
  2258. }
  2259. //+-------------------------------------------------------------------------
  2260. // Unmarshals the event logging parameter block passed to the service
  2261. // and call's the crypt32 event logging function with the unmarshalled
  2262. // parameters.
  2263. //
  2264. // __try/__except around memory access to pbIn.
  2265. //--------------------------------------------------------------------------
  2266. STATIC BOOL SrvLogCrypt32Event(
  2267. IN BYTE *pbIn,
  2268. IN DWORD cbIn
  2269. )
  2270. {
  2271. BOOL fResult;
  2272. PCERT_PROT_EVENT_LOG_PARA pPara = NULL;
  2273. BYTE *pbExtra;
  2274. DWORD cbExtra;
  2275. LPCWSTR rgpwszStrings[MAX_CRYPT32_EVENT_LOG_STRINGS];
  2276. LPCWSTR pwszStrings;
  2277. DWORD cchStrings;
  2278. WORD i;
  2279. BYTE *pbData;
  2280. DWORD dwExceptionCode;
  2281. if (sizeof(CERT_PROT_EVENT_LOG_PARA) > cbIn)
  2282. goto InvalidArg;
  2283. // Ensure the PARA is aligned.
  2284. pPara = (PCERT_PROT_EVENT_LOG_PARA) PkiNonzeroAlloc(cbIn);
  2285. if (NULL == pPara)
  2286. goto OutOfMemory;
  2287. __try {
  2288. memcpy(pPara, pbIn, cbIn);
  2289. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2290. dwExceptionCode = GetExceptionCode();
  2291. goto ExceptionError;
  2292. }
  2293. pbExtra = (BYTE *) &pPara[1];
  2294. cbExtra = cbIn - sizeof(CERT_PROT_EVENT_LOG_PARA);
  2295. // If present, create an array of pointers to the NULL terminated
  2296. // UNICODE strings that immediately follow the PARA structure.
  2297. if (MAX_CRYPT32_EVENT_LOG_STRINGS < pPara->wNumStrings)
  2298. goto InvalidArg;
  2299. cchStrings = cbExtra / sizeof(WCHAR); // Maximum #, will be less if we
  2300. // also have binary data
  2301. pwszStrings = (LPCWSTR) pbExtra;
  2302. for (i = 0; i < pPara->wNumStrings; i++) {
  2303. rgpwszStrings[i] = pwszStrings;
  2304. for ( ; cchStrings > 0; cchStrings--, pwszStrings++) {
  2305. if (L'\0' == *pwszStrings)
  2306. // Have NULL terminated string
  2307. break;
  2308. }
  2309. if (0 == cchStrings)
  2310. // Reached end without a NULL terminator
  2311. goto InvalidData;
  2312. // Advance past NULL terminator
  2313. cchStrings--;
  2314. pwszStrings++;
  2315. }
  2316. // The optional data immediately follows the above sequence of
  2317. // NULL terminated strings
  2318. pbData = (BYTE *) pwszStrings;
  2319. assert(cbExtra >= (DWORD) (pbData - pbExtra));
  2320. if ((cbExtra - (pbData - pbExtra)) != pPara->dwDataSize)
  2321. goto InvalidData;
  2322. fResult = LogCrypt32Event(
  2323. pPara->wType,
  2324. pPara->wCategory,
  2325. pPara->dwEventID,
  2326. pPara->wNumStrings,
  2327. pPara->dwDataSize,
  2328. 0 == pPara->wNumStrings ? NULL : rgpwszStrings,
  2329. 0 == pPara->dwDataSize ? NULL : pbData
  2330. );
  2331. CommonReturn:
  2332. PkiFree(pPara);
  2333. return fResult;
  2334. ErrorReturn:
  2335. fResult = FALSE;
  2336. goto CommonReturn;
  2337. SET_ERROR(InvalidData, ERROR_INVALID_DATA)
  2338. TRACE_ERROR(OutOfMemory)
  2339. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  2340. SET_ERROR(InvalidArg, E_INVALIDARG)
  2341. }
  2342. //+-------------------------------------------------------------------------
  2343. // Marshals the event logging parameters and does an LRPC to the
  2344. // crypt32 service to do the event logging.
  2345. //
  2346. // Should only be called in the client.
  2347. //--------------------------------------------------------------------------
  2348. void
  2349. IPR_LogCrypt32Event(
  2350. IN WORD wType,
  2351. IN DWORD dwEventID,
  2352. IN WORD wNumStrings,
  2353. IN LPCWSTR *rgpwszStrings
  2354. )
  2355. {
  2356. DWORD rgcchStrings[MAX_CRYPT32_EVENT_LOG_STRINGS];
  2357. LPWSTR pwszStrings;
  2358. DWORD cchStrings;
  2359. WORD i;
  2360. PCERT_PROT_EVENT_LOG_PARA pPara = NULL;
  2361. DWORD cbPara;
  2362. // Get Strings character count
  2363. if (MAX_CRYPT32_EVENT_LOG_STRINGS < wNumStrings)
  2364. goto InvalidArg;
  2365. cchStrings = 0;
  2366. for (i = 0; i < wNumStrings; i++) {
  2367. rgcchStrings[i] = wcslen(rgpwszStrings[i]) + 1;
  2368. cchStrings += rgcchStrings[i];
  2369. }
  2370. // Create one serialized blob to be passed to the service. This will
  2371. // consist of the event log para struct followed immediately by the
  2372. // NULL terminated UNICODE strings
  2373. cbPara = sizeof(CERT_PROT_EVENT_LOG_PARA) + cchStrings * sizeof(WCHAR);
  2374. if (NULL == (pPara = (PCERT_PROT_EVENT_LOG_PARA) PkiZeroAlloc(cbPara)))
  2375. goto OutOfMemory;
  2376. pPara->wType = wType;
  2377. // pPara->wCategory = 0;
  2378. pPara->dwEventID = dwEventID;
  2379. pPara->wNumStrings = wNumStrings;
  2380. // pPara->wPad1 = 0;
  2381. // pPara->dwDataSize = 0;
  2382. pwszStrings = (LPWSTR) &pPara[1];
  2383. for (i = 0; i < wNumStrings; i++) {
  2384. memcpy(pwszStrings, rgpwszStrings[i], rgcchStrings[i] * sizeof(WCHAR));
  2385. pwszStrings += rgcchStrings[i];
  2386. }
  2387. if (!I_CertProtectFunction(
  2388. CERT_PROT_LOG_EVENT_FUNC_ID,
  2389. 0, // dwFlags
  2390. NULL, // pwszIn
  2391. (BYTE *) pPara,
  2392. cbPara,
  2393. NULL, // ppbOut
  2394. NULL // pcbOut
  2395. ))
  2396. goto ProtFuncError;
  2397. CommonReturn:
  2398. PkiFree(pPara);
  2399. return;
  2400. ErrorReturn:
  2401. goto CommonReturn;
  2402. SET_ERROR(InvalidArg, E_INVALIDARG)
  2403. TRACE_ERROR(OutOfMemory)
  2404. TRACE_ERROR(ProtFuncError)
  2405. }
  2406. //+-------------------------------------------------------------------------
  2407. // Log a crypt32 error event
  2408. //
  2409. // Should only be called in the client.
  2410. //--------------------------------------------------------------------------
  2411. void
  2412. IPR_LogCrypt32Error(
  2413. IN DWORD dwEventID,
  2414. IN LPCWSTR pwszString, // %1
  2415. IN DWORD dwErr // %2
  2416. )
  2417. {
  2418. WCHAR wszErr[80];
  2419. const DWORD cchErr = sizeof(wszErr) / sizeof(wszErr[0]);
  2420. LPCWSTR rgpwszStrings[2];
  2421. DWORD cchFormatErr;
  2422. LPWSTR pwszFormatErr = NULL;
  2423. cchFormatErr = FormatMessageU (
  2424. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  2425. NULL,
  2426. dwErr,
  2427. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  2428. (LPWSTR) &pwszFormatErr,
  2429. 0,
  2430. NULL);
  2431. if (0 == cchFormatErr &&
  2432. INTERNET_ERROR_BASE <= dwErr && INTERNET_ERROR_LAST >= dwErr) {
  2433. HMODULE hWininet;
  2434. hWininet = LoadLibraryEx(
  2435. "wininet.dll",
  2436. NULL, // reserved, must be NULL
  2437. LOAD_LIBRARY_AS_DATAFILE
  2438. );
  2439. if (hWininet) {
  2440. cchFormatErr = FormatMessageU (
  2441. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  2442. hWininet,
  2443. dwErr,
  2444. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  2445. (LPWSTR) &pwszFormatErr,
  2446. 0,
  2447. NULL);
  2448. FreeLibrary(hWininet);
  2449. }
  2450. }
  2451. if (0 != cchFormatErr)
  2452. rgpwszStrings[1] = pwszFormatErr;
  2453. else {
  2454. int cch = 0;
  2455. if (HTTP_STATUS_FIRST <= dwErr && HTTP_STATUS_LAST >= dwErr) {
  2456. WCHAR wszFormat[64];
  2457. wszFormat[0] = '\0';
  2458. if (0 < LoadStringU(hRegStoreInst, IDS_HTTP_RESPONSE_STATUS,
  2459. wszFormat, sizeof(wszFormat) / sizeof(wszFormat[0]))) {
  2460. cch = _snwprintf(wszErr, cchErr - 1, L"%d (%s)", dwErr,
  2461. wszFormat);
  2462. }
  2463. }
  2464. if (0 >= cch)
  2465. cch = _snwprintf(wszErr, cchErr - 1, L"%d (0x%x)", dwErr, dwErr);
  2466. if (0 < cch) {
  2467. wszErr[cchErr - 1] = L'\0';
  2468. rgpwszStrings[1] = wszErr;
  2469. } else
  2470. rgpwszStrings[1] = L"???";
  2471. }
  2472. rgpwszStrings[0] = pwszString;
  2473. IPR_LogCrypt32Event(
  2474. EVENTLOG_ERROR_TYPE,
  2475. dwEventID,
  2476. 2, // wNumStrings
  2477. rgpwszStrings
  2478. );
  2479. if (pwszFormatErr)
  2480. LocalFree(pwszFormatErr);
  2481. }
  2482. //+-------------------------------------------------------------------------
  2483. // Formats the cert's subject or issuer name string and SHA1 thumbprint.
  2484. //--------------------------------------------------------------------------
  2485. STATIC BOOL FormatLogCertInformation(
  2486. IN PCCERT_CONTEXT pCert,
  2487. IN BOOL fFormatIssuerName,
  2488. OUT WCHAR wszSha1Hash[SHA1_HASH_LEN * 2 + 1],
  2489. OUT LPWSTR *ppwszName
  2490. )
  2491. {
  2492. BOOL fResult;
  2493. DWORD cchName;
  2494. LPWSTR pwszName = NULL;
  2495. DWORD cbData;
  2496. BYTE rgbSha1Hash[SHA1_HASH_LEN];
  2497. PCERT_NAME_BLOB pNameBlob;
  2498. if (fFormatIssuerName)
  2499. pNameBlob = &pCert->pCertInfo->Issuer;
  2500. else
  2501. pNameBlob = &pCert->pCertInfo->Subject;
  2502. cchName = CertNameToStrW(
  2503. pCert->dwCertEncodingType,
  2504. pNameBlob,
  2505. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2506. NULL, // pwsz
  2507. 0 // cwsz
  2508. );
  2509. if (NULL == (pwszName = (LPWSTR) PkiNonzeroAlloc(cchName * sizeof(WCHAR))))
  2510. goto OutOfMemory;
  2511. CertNameToStrW(
  2512. pCert->dwCertEncodingType,
  2513. pNameBlob,
  2514. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2515. pwszName,
  2516. cchName
  2517. );
  2518. cbData = SHA1_HASH_LEN;
  2519. if (CertGetCertificateContextProperty(
  2520. pCert,
  2521. CERT_SHA1_HASH_PROP_ID,
  2522. rgbSha1Hash,
  2523. &cbData
  2524. ) && SHA1_HASH_LEN == cbData)
  2525. ILS_BytesToWStr(SHA1_HASH_LEN, rgbSha1Hash, wszSha1Hash);
  2526. else
  2527. wcscpy(wszSha1Hash, L"???");
  2528. fResult = TRUE;
  2529. CommonReturn:
  2530. *ppwszName = pwszName;
  2531. return fResult;
  2532. ErrorReturn:
  2533. if (pwszName) {
  2534. PkiFree(pwszName);
  2535. pwszName = NULL;
  2536. }
  2537. fResult = FALSE;
  2538. goto CommonReturn;
  2539. TRACE_ERROR(OutOfMemory)
  2540. }
  2541. //+-------------------------------------------------------------------------
  2542. // Get the cert's subject or issuer name string and SHA1 thumbprint. Logs the
  2543. // specified crypt32 event.
  2544. //
  2545. // This function is called from the client.
  2546. //--------------------------------------------------------------------------
  2547. void
  2548. IPR_LogCertInformation(
  2549. IN DWORD dwEventID,
  2550. IN PCCERT_CONTEXT pCert,
  2551. IN BOOL fFormatIssuerName
  2552. )
  2553. {
  2554. LPWSTR pwszName = NULL;
  2555. WCHAR wszSha1Hash[SHA1_HASH_LEN * 2 + 1];
  2556. LPCWSTR rgpwszStrings[2];
  2557. if (!FormatLogCertInformation(
  2558. pCert,
  2559. fFormatIssuerName,
  2560. wszSha1Hash,
  2561. &pwszName
  2562. ))
  2563. return;
  2564. rgpwszStrings[0] = pwszName;
  2565. rgpwszStrings[1] = wszSha1Hash;
  2566. IPR_LogCrypt32Event(
  2567. EVENTLOG_INFORMATION_TYPE,
  2568. dwEventID,
  2569. 2, // wNumStrings
  2570. rgpwszStrings
  2571. );
  2572. PkiFree(pwszName);
  2573. }
  2574. //+-------------------------------------------------------------------------
  2575. // Get the cert's subject name string and SHA1 thumbprint. Log the
  2576. // MSG_ROOT_AUTO_UPDATE_INFORMATIONAL crypt32 event.
  2577. //
  2578. // This function is called from the service.
  2579. //--------------------------------------------------------------------------
  2580. STATIC void LogAddAuthRootEvent(
  2581. IN PCCERT_CONTEXT pCert
  2582. )
  2583. {
  2584. LPWSTR pwszName = NULL;
  2585. WCHAR wszSha1Hash[SHA1_HASH_LEN * 2 + 1];
  2586. LPCWSTR rgpwszStrings[2];
  2587. if (!FormatLogCertInformation(
  2588. pCert,
  2589. FALSE, // fFormatIssuerName
  2590. wszSha1Hash,
  2591. &pwszName
  2592. ))
  2593. return;
  2594. rgpwszStrings[0] = pwszName;
  2595. rgpwszStrings[1] = wszSha1Hash;
  2596. LogCrypt32Event(
  2597. EVENTLOG_INFORMATION_TYPE,
  2598. 0, // wCategory
  2599. MSG_ROOT_AUTO_UPDATE_INFORMATIONAL,
  2600. 2, // wNumStrings
  2601. 0, // dwDataSize
  2602. rgpwszStrings,
  2603. NULL // pbData
  2604. );
  2605. PkiFree(pwszName);
  2606. }
  2607. //+=========================================================================
  2608. // Install Cert into AuthRoot Auto Update CTL Functions
  2609. //==========================================================================
  2610. //+-------------------------------------------------------------------------
  2611. // Function that can be called from either the client or service to
  2612. // add the certificate to the specified store.
  2613. //
  2614. // First validates the CTL. The certificate must
  2615. // have an entry in the CTL before it will be added. The CTL entry's
  2616. // property attributes are set on the certificate context to be added.
  2617. //--------------------------------------------------------------------------
  2618. STATIC
  2619. BOOL
  2620. AddCertInCtlToStore(
  2621. IN PCCERT_CONTEXT pCert,
  2622. IN PCCTL_CONTEXT pCtl,
  2623. IN OUT HCERTSTORE hStore
  2624. )
  2625. {
  2626. BOOL fResult;
  2627. PCTL_ENTRY pCtlEntry;
  2628. if (!IRL_VerifyAuthRootAutoUpdateCtl(pCtl))
  2629. goto InvalidCtl;
  2630. if (NULL == (pCtlEntry = CertFindSubjectInCTL(
  2631. pCert->dwCertEncodingType,
  2632. CTL_CERT_SUBJECT_TYPE,
  2633. (void *) pCert,
  2634. pCtl,
  2635. 0 // dwFlags
  2636. )))
  2637. goto CertNotInCtl;
  2638. // Check if a remove entry
  2639. if (CertFindAttribute(
  2640. szOID_REMOVE_CERTIFICATE,
  2641. pCtlEntry->cAttribute,
  2642. pCtlEntry->rgAttribute
  2643. ))
  2644. goto RemoveCertEntry;
  2645. // Set Ctl Entry Attribute properties
  2646. if (!CertSetCertificateContextPropertiesFromCTLEntry(
  2647. pCert,
  2648. pCtlEntry,
  2649. CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG
  2650. ))
  2651. goto AddCtlEntryAttibutePropertiesError;
  2652. if (!CertAddCertificateContextToStore(
  2653. hStore,
  2654. pCert,
  2655. CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
  2656. NULL // ppStoreContext
  2657. ))
  2658. goto AddCertToStoreError;
  2659. LogAddAuthRootEvent(pCert);
  2660. fResult = TRUE;
  2661. CommonReturn:
  2662. return fResult;
  2663. ErrorReturn:
  2664. fResult = FALSE;
  2665. goto CommonReturn;
  2666. TRACE_ERROR(InvalidCtl)
  2667. SET_ERROR(CertNotInCtl, CRYPT_E_NOT_FOUND)
  2668. SET_ERROR(RemoveCertEntry, CRYPT_E_NOT_FOUND)
  2669. TRACE_ERROR(AddCtlEntryAttibutePropertiesError)
  2670. TRACE_ERROR(AddCertToStoreError)
  2671. }
  2672. //+-------------------------------------------------------------------------
  2673. // Unmarshals the ASN.1 encoded X.509 certificate immediately followed by the
  2674. // ASN.1 encoded CTL.
  2675. //
  2676. // If the certificate has an entry in a valid CTL, its added to the
  2677. // HKLM "AuthRoot" store.
  2678. // __try/__except around memory access to pbIn.
  2679. //--------------------------------------------------------------------------
  2680. STATIC
  2681. BOOL
  2682. SrvAddCertInCtl(
  2683. IN BYTE *pbIn,
  2684. IN DWORD cbIn
  2685. )
  2686. {
  2687. BOOL fResult;
  2688. DWORD cbCert;
  2689. PCCERT_CONTEXT pCert = NULL;
  2690. PCCTL_CONTEXT pCtl = NULL;
  2691. HCERTSTORE hAuthRootStore = NULL;
  2692. DWORD dwExceptionCode;
  2693. if (IPR_IsAuthRootAutoUpdateDisabled())
  2694. goto AuthRootAutoUpdateDisabledError;
  2695. __try {
  2696. // The input consists of the encoded certificate immediately followed
  2697. // by the encoded CTL. Extract and create both components.
  2698. cbCert = Asn1UtilAdjustEncodedLength(pbIn, cbIn);
  2699. assert(cbCert <= cbIn);
  2700. if (NULL == (pCert = CertCreateCertificateContext(
  2701. X509_ASN_ENCODING,
  2702. pbIn,
  2703. cbCert
  2704. )))
  2705. goto CreateCertificateContextError;
  2706. if (NULL == (pCtl = CertCreateCTLContext(
  2707. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  2708. pbIn + cbCert,
  2709. cbIn - cbCert
  2710. )))
  2711. goto CreateCtlContextError;
  2712. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2713. dwExceptionCode = GetExceptionCode();
  2714. goto ExceptionError;
  2715. }
  2716. if (NULL == (hAuthRootStore = CertOpenStore(
  2717. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2718. 0, // dwEncodingType
  2719. NULL, // hCryptProv
  2720. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2721. (const void *) L"AuthRoot"
  2722. )))
  2723. goto OpenAuthRootStoreError;
  2724. fResult = AddCertInCtlToStore(
  2725. pCert,
  2726. pCtl,
  2727. hAuthRootStore
  2728. );
  2729. CommonReturn:
  2730. if (pCert)
  2731. CertFreeCertificateContext(pCert);
  2732. if (pCtl)
  2733. CertFreeCTLContext(pCtl);
  2734. if (hAuthRootStore)
  2735. CertCloseStore(hAuthRootStore, 0);
  2736. return fResult;
  2737. ErrorReturn:
  2738. fResult = FALSE;
  2739. goto CommonReturn;
  2740. SET_ERROR(AuthRootAutoUpdateDisabledError, E_INVALIDARG)
  2741. TRACE_ERROR(CreateCertificateContextError)
  2742. TRACE_ERROR(CreateCtlContextError)
  2743. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  2744. TRACE_ERROR(OpenAuthRootStoreError)
  2745. }
  2746. //+-------------------------------------------------------------------------
  2747. // For Pre W2K OS's that don't have a crypt32 service, do the add in
  2748. // client process.
  2749. //--------------------------------------------------------------------------
  2750. STATIC
  2751. BOOL
  2752. PreW2KAddCertInCtl(
  2753. IN PCCERT_CONTEXT pCert,
  2754. IN PCCTL_CONTEXT pCtl
  2755. )
  2756. {
  2757. BOOL fResult;
  2758. HCERTSTORE hRootStore = NULL;
  2759. // Try opening the HKLM AuthRoot store. If that fails, fall back to
  2760. // adding to the HKCU Root (Unprotected) store
  2761. if (NULL == (hRootStore = CertOpenStore(
  2762. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2763. 0, // dwEncodingType
  2764. NULL, // hCryptProv
  2765. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2766. (const void *) L"AuthRoot"
  2767. ))) {
  2768. if (NULL == (hRootStore = CertOpenStore(
  2769. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2770. 0, // dwEncodingType
  2771. NULL, // hCryptProv
  2772. CERT_SYSTEM_STORE_CURRENT_USER |
  2773. CERT_SYSTEM_STORE_UNPROTECTED_FLAG,
  2774. (const void *) L"Root"
  2775. )))
  2776. goto OpenRootStoreError;
  2777. }
  2778. fResult = AddCertInCtlToStore(
  2779. pCert,
  2780. pCtl,
  2781. hRootStore
  2782. );
  2783. CommonReturn:
  2784. if (hRootStore)
  2785. CertCloseStore(hRootStore, 0);
  2786. return fResult;
  2787. ErrorReturn:
  2788. fResult = FALSE;
  2789. goto CommonReturn;
  2790. TRACE_ERROR(OpenRootStoreError)
  2791. }
  2792. //+-------------------------------------------------------------------------
  2793. // If the certificate has an entry in a valid CTL, its added to the
  2794. // HKLM "AuthRoot" store.
  2795. //--------------------------------------------------------------------------
  2796. BOOL
  2797. IPR_AddCertInAuthRootAutoUpdateCtl(
  2798. IN PCCERT_CONTEXT pCert,
  2799. IN PCCTL_CONTEXT pCtl
  2800. )
  2801. {
  2802. BOOL fResult;
  2803. DWORD cbIn;
  2804. BYTE *pbIn = NULL;
  2805. // Create one serialized blob to be passed to the service. This will
  2806. // consist of the encoded certificate followed immediately by the
  2807. // encoded CTL.
  2808. cbIn = pCert->cbCertEncoded + pCtl->cbCtlEncoded;
  2809. if (NULL == (pbIn = (BYTE *) PkiNonzeroAlloc(cbIn)))
  2810. goto OutOfMemory;
  2811. memcpy(pbIn, pCert->pbCertEncoded, pCert->cbCertEncoded);
  2812. memcpy(pbIn + pCert->cbCertEncoded, pCtl->pbCtlEncoded,
  2813. pCtl->cbCtlEncoded);
  2814. if (!I_CertProtectFunction(
  2815. CERT_PROT_ADD_ROOT_IN_CTL_FUNC_ID,
  2816. 0, // dwFlags
  2817. NULL, // pwszIn
  2818. pbIn,
  2819. cbIn,
  2820. NULL, // ppbOut
  2821. NULL // pcbOut
  2822. )) {
  2823. DWORD dwErr = GetLastError();
  2824. if (ERROR_CALL_NOT_IMPLEMENTED == dwErr || RPC_S_UNKNOWN_IF == dwErr) {
  2825. if (!PreW2KAddCertInCtl(
  2826. pCert,
  2827. pCtl
  2828. ))
  2829. goto PreW2KAddCertInCtlError;
  2830. } else
  2831. goto ProtFuncError;
  2832. }
  2833. fResult = TRUE;
  2834. CommonReturn:
  2835. PkiFree(pbIn);
  2836. return fResult;
  2837. ErrorReturn:
  2838. fResult = FALSE;
  2839. goto CommonReturn;
  2840. TRACE_ERROR(OutOfMemory)
  2841. TRACE_ERROR(PreW2KAddCertInCtlError)
  2842. TRACE_ERROR(ProtFuncError)
  2843. }