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.

16257 lines
518 KiB

  1. //+-------------------------------------------------------------------------
  2. // Microsoft Windows
  3. //
  4. // Copyright (C) Microsoft Corporation, 1995 - 1999
  5. //
  6. // File: newstor.cpp
  7. //
  8. // Contents: Certificate, CRL and CTL Store APIs
  9. //
  10. // Functions: CertStoreDllMain
  11. // CertOpenStore
  12. // CertDuplicateStore
  13. // CertCloseStore
  14. // CertSaveStore
  15. // CertControlStore
  16. // CertAddStoreToCollection
  17. // CertRemoveStoreFromCollection
  18. // CertSetStoreProperty
  19. // CertGetStoreProperty
  20. // CertGetSubjectCertificateFromStore
  21. // CertEnumCertificatesInStore
  22. // CertFindCertificateInStore
  23. // CertGetIssuerCertificateFromStore
  24. // CertVerifySubjectCertificateContext
  25. // CertDuplicateCertificateContext
  26. // CertCreateCertificateContext
  27. // CertFreeCertificateContext
  28. // CertSetCertificateContextProperty
  29. // CertGetCertificateContextProperty
  30. // CertEnumCertificateContextProperties
  31. // CertCreateCTLEntryFromCertificateContextProperties
  32. // CertSetCertificateContextPropertiesFromCTLEntry
  33. // CertGetCRLFromStore
  34. // CertEnumCRLsInStore
  35. // CertFindCRLInStore
  36. // CertDuplicateCRLContext
  37. // CertCreateCRLContext
  38. // CertFreeCRLContext
  39. // CertSetCRLContextProperty
  40. // CertGetCRLContextProperty
  41. // CertEnumCRLContextProperties
  42. // CertFindCertificateInCRL
  43. // CertAddEncodedCertificateToStore
  44. // CertAddCertificateContextToStore
  45. // CertSerializeCertificateStoreElement
  46. // CertDeleteCertificateFromStore
  47. // CertAddEncodedCRLToStore
  48. // CertAddCRLContextToStore
  49. // CertSerializeCRLStoreElement
  50. // CertDeleteCRLFromStore
  51. // CertAddSerializedElementToStore
  52. //
  53. // CertDuplicateCTLContext
  54. // CertCreateCTLContext
  55. // CertFreeCTLContext
  56. // CertSetCTLContextProperty
  57. // CertGetCTLContextProperty
  58. // CertEnumCTLContextProperties
  59. // CertEnumCTLsInStore
  60. // CertFindSubjectInCTL
  61. // CertFindCTLInStore
  62. // CertAddEncodedCTLToStore
  63. // CertAddCTLContextToStore
  64. // CertSerializeCTLStoreElement
  65. // CertDeleteCTLFromStore
  66. //
  67. // CertAddCertificateLinkToStore
  68. // CertAddCRLLinkToStore
  69. // CertAddCTLLinkToStore
  70. //
  71. // CertCreateContext
  72. //
  73. // I_CertAddSerializedStore
  74. // CryptAcquireCertificatePrivateKey
  75. // I_CertSyncStore
  76. // I_CertSyncStoreEx
  77. // I_CertUpdateStore
  78. //
  79. // CryptGetKeyIdentifierProperty
  80. // CryptSetKeyIdentifierProperty
  81. // CryptEnumKeyIdentifierProperties
  82. //
  83. // History: 17-Feb-96 philh created
  84. // 29-Dec-96 philh redo using provider functions
  85. // 01-May-97 philh added CTL functions
  86. // 01-Aug-97 philh NT 5.0 Changes. Support context links,
  87. // collections and external stores.
  88. //--------------------------------------------------------------------------
  89. #include "global.hxx"
  90. #include <dbgdef.h>
  91. #ifdef STATIC
  92. #undef STATIC
  93. #endif
  94. #define STATIC
  95. HMODULE hCertStoreInst;
  96. // Maximum # of verified CRLs allowed per issuer.
  97. // This array of CRLs is passed to CertHelperVerifyRevocation
  98. #define MAX_CRL_LIST 64
  99. //+-------------------------------------------------------------------------
  100. // Store data structure definitions
  101. //--------------------------------------------------------------------------
  102. // Assumes
  103. // 0 - Certificates
  104. // 1 - CRLs
  105. // 2 - CTLs
  106. #define CONTEXT_COUNT 3
  107. typedef struct _CONTEXT_ELEMENT CONTEXT_ELEMENT, *PCONTEXT_ELEMENT;
  108. typedef struct _PROP_ELEMENT PROP_ELEMENT, *PPROP_ELEMENT;
  109. typedef struct _CERT_STORE CERT_STORE, *PCERT_STORE;
  110. typedef struct _SHARE_STORE SHARE_STORE, *PSHARE_STORE;
  111. typedef struct _CERT_STORE_LINK CERT_STORE_LINK, *PCERT_STORE_LINK;
  112. typedef struct _COLLECTION_STACK_ENTRY COLLECTION_STACK_ENTRY,
  113. *PCOLLECTION_STACK_ENTRY;
  114. // Used to maintain collection state across context find next calls.
  115. //
  116. // Ref count on pStoreLink. No ref count on pCollection.
  117. // pStoreLink may be NULL.
  118. struct _COLLECTION_STACK_ENTRY {
  119. PCERT_STORE pCollection;
  120. PCERT_STORE_LINK pStoreLink;
  121. PCOLLECTION_STACK_ENTRY pPrev;
  122. };
  123. typedef struct _CONTEXT_CACHE_INFO {
  124. PPROP_ELEMENT pPropHead;
  125. } CONTEXT_CACHE_INFO;
  126. typedef struct _CONTEXT_EXTERNAL_INFO {
  127. // For ELEMENT_FIND_NEXT_FLAG
  128. void *pvProvInfo;
  129. } CONTEXT_EXTERNAL_INFO;
  130. typedef struct _CONTEXT_COLLECTION_INFO {
  131. // For Find
  132. PCOLLECTION_STACK_ENTRY pCollectionStack;
  133. } CONTEXT_COLLECTION_INFO;
  134. #define ELEMENT_DELETED_FLAG 0x00010000
  135. // Only set for external elements
  136. #define ELEMENT_FIND_NEXT_FLAG 0x00020000
  137. // Set during CertCloseStore if ELEMENT_FIND_NEXT_FLAG was set.
  138. #define ELEMENT_CLOSE_FIND_NEXT_FLAG 0x00040000
  139. // Set if the element has a CERT_ARCHIVED_PROP_ID
  140. #define ELEMENT_ARCHIVED_FLAG 0x00080000
  141. // A cache element is the actual context element. Its the only element,
  142. // where pEle points to itself. All other elements will eventually
  143. // point to a cache element. Cache elements may only reside in a cache
  144. // store. The pProvStore is the same as the pStore. Note, during a
  145. // context add, a cache element may temporarily be in a collection store
  146. // during the call to the provider's add callback.
  147. //
  148. // A link context element is a link to another element, including a link
  149. // to another link context element. Link context elements may only reside
  150. // in a cache store. The pProvStore is the same as the linked to element's
  151. // pProvStore.
  152. //
  153. // An external element is a link to the element returned by a provider
  154. // that stores elements externally. External elements may only reside in
  155. // an external store. The pProvStore is the external store's
  156. // provider. The store doesn't hold a reference on an external element,
  157. // its ELEMENT_DELETED_FLAG is always set.
  158. //
  159. // A collection element is a link to an element in a cache or external store.
  160. // Its returned when finding in or adding to a collection store. The store
  161. // doesn't hold a reference on a collection element, its
  162. // ELEMENT_DELETED_FLAG is always set.
  163. //
  164. #define ELEMENT_TYPE_CACHE 1
  165. #define ELEMENT_TYPE_LINK_CONTEXT 2
  166. #define ELEMENT_TYPE_EXTERNAL 3
  167. #define ELEMENT_TYPE_COLLECTION 4
  168. #define MAX_LINK_DEPTH 100
  169. typedef struct _CONTEXT_NOCOPY_INFO {
  170. PFN_CRYPT_FREE pfnFree;
  171. void *pvFree;
  172. } CONTEXT_NOCOPY_INFO, *PCONTEXT_NOCOPY_INFO;
  173. // Identical contexts (having the same SHA1 hash) can share the same encoded
  174. // byte array and decoded info data structure.
  175. //
  176. // CreateShareElement() creates with dwRefCnt of 1. FindShareElement() finds
  177. // an existing and increments dwRefCnt. ReleaseShareElement() decrements
  178. // dwRefCnt and frees when 0.
  179. typedef struct _SHARE_ELEMENT SHARE_ELEMENT, *PSHARE_ELEMENT;
  180. struct _SHARE_ELEMENT {
  181. BYTE rgbSha1Hash[SHA1_HASH_LEN];
  182. DWORD dwContextType;
  183. BYTE *pbEncoded; // allocated
  184. DWORD cbEncoded;
  185. void *pvInfo; // allocated
  186. DWORD dwRefCnt;
  187. PSHARE_ELEMENT pNext;
  188. PSHARE_ELEMENT pPrev;
  189. };
  190. // The CONTEXT_ELEMENT is inserted before the CERT_CONTEXT, CRL_CONTEXT or
  191. // CTL_CONTEXT. The dwContextType used is 0 based and not 1 based. For
  192. // example, dwContextType = CERT_STORE_CERTIFICATE_CONTEXT - 1.
  193. struct _CONTEXT_ELEMENT {
  194. DWORD dwElementType;
  195. DWORD dwContextType;
  196. DWORD dwFlags;
  197. LONG lRefCnt;
  198. // For ELEMENT_TYPE_CACHE, pEle points to itself. Otherwise, pEle points
  199. // to the element being linked to and the pEle is addRef'ed. The
  200. // cached element is found by iterating through the pEle's until pEle
  201. // points to itself.
  202. PCONTEXT_ELEMENT pEle;
  203. PCERT_STORE pStore;
  204. PCONTEXT_ELEMENT pNext;
  205. PCONTEXT_ELEMENT pPrev;
  206. PCERT_STORE pProvStore;
  207. PCONTEXT_NOCOPY_INFO pNoCopyInfo;
  208. // When nonNULL, the context's pbEncoded and pInfo aren't allocated.
  209. // Instead, use the shared element's pbEncoded and pInfo. When
  210. // context element is freed, the pSharedEle is ReleaseShareElement()'ed.
  211. PSHARE_ELEMENT pShareEle; // RefCnt'ed
  212. union {
  213. CONTEXT_CACHE_INFO Cache; // ELEMENT_TYPE_CACHE
  214. CONTEXT_EXTERNAL_INFO External; // ELEMENT_TYPE_EXTERNAL
  215. CONTEXT_COLLECTION_INFO Collection; // ELEMENT_TYPE_COLLECTION
  216. };
  217. };
  218. // For CRL, follows the above CONTEXT_ELEMENT
  219. typedef struct _CRL_CONTEXT_SUFFIX {
  220. PCRL_ENTRY *ppSortedEntry;
  221. } CRL_CONTEXT_SUFFIX, *PCRL_CONTEXT_SUFFIX;
  222. typedef struct _HASH_BUCKET_ENTRY HASH_BUCKET_ENTRY, *PHASH_BUCKET_ENTRY;
  223. struct _HASH_BUCKET_ENTRY {
  224. union {
  225. DWORD dwEntryIndex;
  226. DWORD dwEntryOffset;
  227. const BYTE *pbEntry;
  228. };
  229. union {
  230. PHASH_BUCKET_ENTRY pNext;
  231. DWORD iNext;
  232. };
  233. };
  234. typedef struct _SORTED_CTL_FIND_INFO {
  235. DWORD cHashBucket;
  236. BOOL fHashedIdentifier;
  237. // Encoded sequence of TrustedSubjects
  238. const BYTE *pbEncodedSubjects; // not allocated
  239. DWORD cbEncodedSubjects;
  240. // Following is NON-NULL for a szOID_SORTED_CTL extension
  241. const BYTE *pbEncodedHashBucket; // not allocated
  242. // Following are NON-NULL when there isn't a szOID_SORTED_CTL extension
  243. DWORD *pdwHashBucketHead; // allocated
  244. PHASH_BUCKET_ENTRY pHashBucketEntry; // allocated
  245. } SORTED_CTL_FIND_INFO, *PSORTED_CTL_FIND_INFO;
  246. // For CTL, follows the above CONTEXT_ELEMENT
  247. typedef struct _CTL_CONTEXT_SUFFIX {
  248. PCTL_ENTRY *ppSortedEntry; // allocated
  249. BOOL fFastCreate;
  250. // Following only applicable for a FastCreateCtlElement
  251. PCTL_ENTRY pCTLEntry; // allocated
  252. PCERT_EXTENSIONS pExtInfo; // allocated
  253. PSORTED_CTL_FIND_INFO pSortedCtlFindInfo; // not allocated
  254. } CTL_CONTEXT_SUFFIX, *PCTL_CONTEXT_SUFFIX;
  255. struct _PROP_ELEMENT {
  256. DWORD dwPropId;
  257. DWORD dwFlags;
  258. BYTE *pbData;
  259. DWORD cbData;
  260. PPROP_ELEMENT pNext;
  261. PPROP_ELEMENT pPrev;
  262. };
  263. #define STORE_LINK_DELETED_FLAG 0x00010000
  264. struct _CERT_STORE_LINK {
  265. DWORD dwFlags;
  266. LONG lRefCnt;
  267. // Whatever is passed to CertAddStoreToCollection
  268. DWORD dwUpdateFlags;
  269. DWORD dwPriority;
  270. PCERT_STORE pCollection;
  271. PCERT_STORE pSibling; // CertStoreDuplicate'd.
  272. PCERT_STORE_LINK pNext;
  273. PCERT_STORE_LINK pPrev;
  274. };
  275. // Store types
  276. #define STORE_TYPE_CACHE 1
  277. #define STORE_TYPE_EXTERNAL 2
  278. #define STORE_TYPE_COLLECTION 3
  279. // CACHE store may have CACHE or LINK_CONTEXT elements. Until deleted,
  280. // the store has a reference count to.
  281. // EXTERNAL store only has EXTERNAL elements. These elements are always
  282. // deleted, wherein, the store doesn't hold a refCnt.
  283. // COLLECTION store has COLLECTION elements. These elements
  284. // are always deleted, wherein, the store doesn't hold a refCnt.
  285. struct _CERT_STORE {
  286. DWORD dwStoreType;
  287. LONG lRefCnt;
  288. HCRYPTPROV hCryptProv;
  289. DWORD dwFlags;
  290. DWORD dwState;
  291. CRITICAL_SECTION CriticalSection;
  292. PCONTEXT_ELEMENT rgpContextListHead[CONTEXT_COUNT];
  293. PCERT_STORE_LINK pStoreListHead; // COLLECTION
  294. PPROP_ELEMENT pPropHead; // properties for entire store
  295. // For CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG
  296. // Incremented for each context duplicated
  297. LONG lDeferCloseRefCnt;
  298. // Event handle set by CertControlStore(CERT_STORE_CTRL_AUTO_RESYNC)
  299. HANDLE hAutoResyncEvent;
  300. // The following is set for a shared store
  301. PSHARE_STORE pShareStore;
  302. // Store provider info
  303. LONG lStoreProvRefCnt;
  304. HANDLE hStoreProvWait;
  305. HCRYPTOIDFUNCADDR hStoreProvFuncAddr;
  306. CERT_STORE_PROV_INFO StoreProvInfo;
  307. };
  308. //+-------------------------------------------------------------------------
  309. // Store states
  310. //--------------------------------------------------------------------------
  311. #define STORE_STATE_DELETED 0
  312. #define STORE_STATE_NULL 1
  313. #define STORE_STATE_OPENING 2
  314. #define STORE_STATE_OPEN 3
  315. #define STORE_STATE_DEFER_CLOSING 4
  316. #define STORE_STATE_CLOSING 5
  317. #define STORE_STATE_CLOSED 6
  318. // LocalMachine System stores opened for SHARE and MAXIMUM_ALLOWED can
  319. // be shared.
  320. struct _SHARE_STORE {
  321. LPWSTR pwszStore; // not a separate allocation, string
  322. // follows struct
  323. PCERT_STORE pStore; // store holds lRefCnt
  324. PSHARE_STORE pNext;
  325. PSHARE_STORE pPrev;
  326. };
  327. //+-------------------------------------------------------------------------
  328. // Share stores.
  329. //
  330. // A shared stored is identified by its UNICODE name. Simply maintain a
  331. // linked list of share stores.
  332. //
  333. // Shared stores are restricted to LocalMachine System Stores opened
  334. // with CERT_STORE_SHARE_STORE_FLAG, CERT_STORE_SHARE_CONTEXT_FLAG and
  335. // CERT_STORE_MAXIMUM_ALLOWED_FLAG.
  336. //--------------------------------------------------------------------------
  337. STATIC PSHARE_STORE pShareStoreHead;
  338. STATIC CRITICAL_SECTION ShareStoreCriticalSection;
  339. //+-------------------------------------------------------------------------
  340. // Key Identifier Element
  341. //--------------------------------------------------------------------------
  342. typedef struct _KEYID_ELEMENT {
  343. CRYPT_HASH_BLOB KeyIdentifier;
  344. PPROP_ELEMENT pPropHead;
  345. } KEYID_ELEMENT, *PKEYID_ELEMENT;
  346. //+-------------------------------------------------------------------------
  347. // The "Find ANY" INFO data structure.
  348. //
  349. // 0 is the ANY dwFindType for all context types.
  350. //--------------------------------------------------------------------------
  351. static CCERT_STORE_PROV_FIND_INFO FindAnyInfo = {
  352. sizeof(CCERT_STORE_PROV_FIND_INFO), // cbSize
  353. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, // dwMsgAndCertEncodingType
  354. 0, // dwFindFlags
  355. 0, // dwFindType
  356. NULL // pvFindPara
  357. };
  358. //+-------------------------------------------------------------------------
  359. // NULL Store.
  360. //
  361. // HANDLE of all CONTEXTs created by CertCreateCertificateContext or
  362. // CertCreateCRLContext. Created CONTEXTs are immediately added to the
  363. // NULL store's free list. (ie, the store doesn't have a RefCnt on the
  364. // CONTEXT.)
  365. //--------------------------------------------------------------------------
  366. static CERT_STORE NullCertStore;
  367. //+-------------------------------------------------------------------------
  368. // Bug in rsabase.dll. Its not thread safe across multiple crypt prov
  369. // handles.
  370. //--------------------------------------------------------------------------
  371. static CRITICAL_SECTION CryptProvCriticalSection;
  372. //+-------------------------------------------------------------------------
  373. // Store file definitions
  374. //
  375. // The file consist of the FILE_HDR followed by 1 or more FILE_ELEMENTs.
  376. // Each FILE_ELEMENT has a FILE_ELEMENT_HDR + its value.
  377. //
  378. // First the CERT elements are written. If a CERT has any properties, then,
  379. // the PROP elements immediately precede the CERT's element. Next the CRL
  380. // elements are written. If a CRL has any properties, then, the PROP elements
  381. // immediately precede the CRL's element. Likewise for CTL elements and its
  382. // properties. Finally, the END element is written.
  383. //--------------------------------------------------------------------------
  384. typedef struct _FILE_HDR {
  385. DWORD dwVersion;
  386. DWORD dwMagic;
  387. } FILE_HDR, *PFILE_HDR;
  388. #define CERT_FILE_VERSION_0 0
  389. #define CERT_MAGIC ((DWORD)'C'+((DWORD)'E'<<8)+((DWORD)'R'<<16)+((DWORD)'T'<<24))
  390. // The element's data follows the HDR
  391. typedef struct _FILE_ELEMENT_HDR {
  392. DWORD dwEleType;
  393. DWORD dwEncodingType;
  394. DWORD dwLen;
  395. } FILE_ELEMENT_HDR, *PFILE_ELEMENT_HDR;
  396. #define FILE_ELEMENT_END_TYPE 0
  397. // FILE_ELEMENT_PROP_TYPEs !(0 | CERT | CRL | CTL | KEYID)
  398. // Note CERT_KEY_CONTEXT_PROP_ID (and CERT_KEY_PROV_HANDLE_PROP_ID)
  399. // isn't written
  400. #define FILE_ELEMENT_CERT_TYPE 32
  401. #define FILE_ELEMENT_CRL_TYPE 33
  402. #define FILE_ELEMENT_CTL_TYPE 34
  403. #define FILE_ELEMENT_KEYID_TYPE 35
  404. //#define MAX_FILE_ELEMENT_DATA_LEN (4096 * 16)
  405. #define MAX_FILE_ELEMENT_DATA_LEN 0xFFFFFFFF
  406. //+-------------------------------------------------------------------------
  407. // Used when reading an element
  408. //--------------------------------------------------------------------------
  409. #define CSError 0
  410. #define CSContinue 1
  411. #define CSEnd 2
  412. //+-------------------------------------------------------------------------
  413. // Share elements.
  414. //
  415. // A share element is identifed by its sha1 hash. It contains the context's
  416. // encoded bytes and decoded info. Multiple contexts can point to the
  417. // same refcounted share element. The share elements are stored in a
  418. // hash bucket array of linked lists. The first byte of the element's sha1
  419. // hash is used as the index into the array.
  420. //
  421. // Note, the actual index is the first byte modulus BUCKET_COUNT.
  422. //--------------------------------------------------------------------------
  423. #define SHARE_ELEMENT_HASH_BUCKET_COUNT 64
  424. static PSHARE_ELEMENT rgpShareElementHashBucket[SHARE_ELEMENT_HASH_BUCKET_COUNT];
  425. static CRITICAL_SECTION ShareElementCriticalSection;
  426. //+-------------------------------------------------------------------------
  427. // Read, Write & Skip to memory/file function definitions
  428. //--------------------------------------------------------------------------
  429. typedef BOOL (* PFNWRITE)(HANDLE h, void * p, DWORD cb);
  430. typedef BOOL (* PFNREAD)(HANDLE h, void * p, DWORD cb);
  431. typedef BOOL (* PFNSKIP)(HANDLE h, DWORD cb);
  432. //+-------------------------------------------------------------------------
  433. // Store Provider Functions
  434. //--------------------------------------------------------------------------
  435. STATIC BOOL WINAPI OpenMsgStoreProv(
  436. IN LPCSTR lpszStoreProvider,
  437. IN DWORD dwEncodingType,
  438. IN HCRYPTPROV hCryptProv,
  439. IN DWORD dwFlags,
  440. IN const void *pvPara,
  441. IN HCERTSTORE hCertStore,
  442. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  443. );
  444. STATIC BOOL WINAPI OpenMemoryStoreProv(
  445. IN LPCSTR lpszStoreProvider,
  446. IN DWORD dwEncodingType,
  447. IN HCRYPTPROV hCryptProv,
  448. IN DWORD dwFlags,
  449. IN const void *pvPara,
  450. IN HCERTSTORE hCertStore,
  451. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  452. )
  453. {
  454. pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_NO_PERSIST_FLAG;
  455. return TRUE;
  456. }
  457. STATIC BOOL WINAPI OpenFileStoreProv(
  458. IN LPCSTR lpszStoreProvider,
  459. IN DWORD dwEncodingType,
  460. IN HCRYPTPROV hCryptProv,
  461. IN DWORD dwFlags,
  462. IN const void *pvPara,
  463. IN HCERTSTORE hCertStore,
  464. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  465. );
  466. STATIC BOOL WINAPI OpenPKCS7StoreProv(
  467. IN LPCSTR lpszStoreProvider,
  468. IN DWORD dwEncodingType,
  469. IN HCRYPTPROV hCryptProv,
  470. IN DWORD dwFlags,
  471. IN const void *pvPara,
  472. IN HCERTSTORE hCertStore,
  473. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  474. );
  475. STATIC BOOL WINAPI OpenSerializedStoreProv(
  476. IN LPCSTR lpszStoreProvider,
  477. IN DWORD dwEncodingType,
  478. IN HCRYPTPROV hCryptProv,
  479. IN DWORD dwFlags,
  480. IN const void *pvPara,
  481. IN HCERTSTORE hCertStore,
  482. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  483. );
  484. STATIC BOOL WINAPI OpenFilenameStoreProvA(
  485. IN LPCSTR lpszStoreProvider,
  486. IN DWORD dwEncodingType,
  487. IN HCRYPTPROV hCryptProv,
  488. IN DWORD dwFlags,
  489. IN const void *pvPara,
  490. IN HCERTSTORE hCertStore,
  491. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  492. );
  493. STATIC BOOL WINAPI OpenFilenameStoreProvW(
  494. IN LPCSTR lpszStoreProvider,
  495. IN DWORD dwEncodingType,
  496. IN HCRYPTPROV hCryptProv,
  497. IN DWORD dwFlags,
  498. IN const void *pvPara,
  499. IN HCERTSTORE hCertStore,
  500. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  501. );
  502. STATIC BOOL WINAPI OpenCollectionStoreProv(
  503. IN LPCSTR lpszStoreProvider,
  504. IN DWORD dwEncodingType,
  505. IN HCRYPTPROV hCryptProv,
  506. IN DWORD dwFlags,
  507. IN const void *pvPara,
  508. IN HCERTSTORE hCertStore,
  509. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  510. )
  511. {
  512. PCERT_STORE pStore = (PCERT_STORE) hCertStore;
  513. pStore->dwStoreType = STORE_TYPE_COLLECTION;
  514. return TRUE;
  515. }
  516. // from regstor.cpp
  517. extern BOOL WINAPI I_CertDllOpenRegStoreProv(
  518. IN LPCSTR lpszStoreProvider,
  519. IN DWORD dwEncodingType,
  520. IN HCRYPTPROV hCryptProv,
  521. IN DWORD dwFlags,
  522. IN const void *pvPara,
  523. IN HCERTSTORE hCertStore,
  524. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  525. );
  526. extern BOOL WINAPI I_CertDllOpenSystemStoreProvA(
  527. IN LPCSTR lpszStoreProvider,
  528. IN DWORD dwEncodingType,
  529. IN HCRYPTPROV hCryptProv,
  530. IN DWORD dwFlags,
  531. IN const void *pvPara,
  532. IN HCERTSTORE hCertStore,
  533. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  534. );
  535. extern BOOL WINAPI I_CertDllOpenSystemStoreProvW(
  536. IN LPCSTR lpszStoreProvider,
  537. IN DWORD dwEncodingType,
  538. IN HCRYPTPROV hCryptProv,
  539. IN DWORD dwFlags,
  540. IN const void *pvPara,
  541. IN HCERTSTORE hCertStore,
  542. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  543. );
  544. extern BOOL WINAPI I_CertDllOpenSystemRegistryStoreProvW(
  545. IN LPCSTR lpszStoreProvider,
  546. IN DWORD dwEncodingType,
  547. IN HCRYPTPROV hCryptProv,
  548. IN DWORD dwFlags,
  549. IN const void *pvPara,
  550. IN HCERTSTORE hCertStore,
  551. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  552. );
  553. extern BOOL WINAPI I_CertDllOpenSystemRegistryStoreProvA(
  554. IN LPCSTR lpszStoreProvider,
  555. IN DWORD dwEncodingType,
  556. IN HCRYPTPROV hCryptProv,
  557. IN DWORD dwFlags,
  558. IN const void *pvPara,
  559. IN HCERTSTORE hCertStore,
  560. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  561. );
  562. extern BOOL WINAPI I_CertDllOpenPhysicalStoreProvW(
  563. IN LPCSTR lpszStoreProvider,
  564. IN DWORD dwEncodingType,
  565. IN HCRYPTPROV hCryptProv,
  566. IN DWORD dwFlags,
  567. IN const void *pvPara,
  568. IN HCERTSTORE hCertStore,
  569. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  570. );
  571. static HCRYPTOIDFUNCSET hOpenStoreProvFuncSet;
  572. static const CRYPT_OID_FUNC_ENTRY OpenStoreProvFuncTable[] = {
  573. CERT_STORE_PROV_MSG, OpenMsgStoreProv,
  574. CERT_STORE_PROV_MEMORY, OpenMemoryStoreProv,
  575. CERT_STORE_PROV_FILE, OpenFileStoreProv,
  576. CERT_STORE_PROV_REG, I_CertDllOpenRegStoreProv,
  577. CERT_STORE_PROV_PKCS7, OpenPKCS7StoreProv,
  578. CERT_STORE_PROV_SERIALIZED, OpenSerializedStoreProv,
  579. CERT_STORE_PROV_FILENAME_A, OpenFilenameStoreProvA,
  580. CERT_STORE_PROV_FILENAME_W, OpenFilenameStoreProvW,
  581. CERT_STORE_PROV_SYSTEM_A, I_CertDllOpenSystemStoreProvA,
  582. CERT_STORE_PROV_SYSTEM_W, I_CertDllOpenSystemStoreProvW,
  583. CERT_STORE_PROV_COLLECTION, OpenCollectionStoreProv,
  584. CERT_STORE_PROV_SYSTEM_REGISTRY_A, I_CertDllOpenSystemRegistryStoreProvA,
  585. CERT_STORE_PROV_SYSTEM_REGISTRY_W, I_CertDllOpenSystemRegistryStoreProvW,
  586. CERT_STORE_PROV_PHYSICAL_W, I_CertDllOpenPhysicalStoreProvW,
  587. CERT_STORE_PROV_SMART_CARD_W, SmartCardProvOpenStore,
  588. sz_CERT_STORE_PROV_MEMORY, OpenMemoryStoreProv,
  589. sz_CERT_STORE_PROV_SYSTEM_W, I_CertDllOpenSystemStoreProvW,
  590. sz_CERT_STORE_PROV_FILENAME_W, OpenFilenameStoreProvW,
  591. sz_CERT_STORE_PROV_PKCS7, OpenPKCS7StoreProv,
  592. sz_CERT_STORE_PROV_SERIALIZED, OpenSerializedStoreProv,
  593. sz_CERT_STORE_PROV_COLLECTION, OpenCollectionStoreProv,
  594. sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W, I_CertDllOpenSystemRegistryStoreProvW,
  595. sz_CERT_STORE_PROV_PHYSICAL_W, I_CertDllOpenPhysicalStoreProvW,
  596. sz_CERT_STORE_PROV_SMART_CARD_W, SmartCardProvOpenStore
  597. };
  598. #define OPEN_STORE_PROV_FUNC_COUNT (sizeof(OpenStoreProvFuncTable) / \
  599. sizeof(OpenStoreProvFuncTable[0]))
  600. //+-------------------------------------------------------------------------
  601. // NULL Store: initialization and free
  602. //--------------------------------------------------------------------------
  603. STATIC BOOL InitNullCertStore()
  604. {
  605. BOOL fRet;
  606. memset(&NullCertStore, 0, sizeof(NullCertStore));
  607. NullCertStore.dwStoreType = STORE_TYPE_CACHE;
  608. NullCertStore.lRefCnt = 1;
  609. NullCertStore.dwState = STORE_STATE_NULL;
  610. fRet = Pki_InitializeCriticalSection(&NullCertStore.CriticalSection);
  611. NullCertStore.StoreProvInfo.dwStoreProvFlags =
  612. CERT_STORE_PROV_NO_PERSIST_FLAG;
  613. return fRet;
  614. }
  615. STATIC void FreeNullCertStore()
  616. {
  617. DeleteCriticalSection(&NullCertStore.CriticalSection);
  618. }
  619. //+-------------------------------------------------------------------------
  620. // CryptProv: initialization and free
  621. //--------------------------------------------------------------------------
  622. STATIC BOOL InitCryptProv()
  623. {
  624. return Pki_InitializeCriticalSection(&CryptProvCriticalSection);
  625. }
  626. STATIC void FreeCryptProv()
  627. {
  628. DeleteCriticalSection(&CryptProvCriticalSection);
  629. }
  630. extern
  631. BOOL
  632. WINAPI
  633. I_RegStoreDllMain(
  634. HMODULE hInst,
  635. ULONG ulReason,
  636. LPVOID lpReserved);
  637. //+-------------------------------------------------------------------------
  638. // Dll initialization
  639. //--------------------------------------------------------------------------
  640. BOOL
  641. WINAPI
  642. CertStoreDllMain(
  643. HMODULE hInst,
  644. ULONG ulReason,
  645. LPVOID lpReserved)
  646. {
  647. BOOL fRet;
  648. if (!I_RegStoreDllMain(hInst, ulReason, lpReserved))
  649. return FALSE;
  650. switch (ulReason) {
  651. case DLL_PROCESS_ATTACH:
  652. // Used for "root" system store's message box
  653. hCertStoreInst = hInst;
  654. if (NULL == (hOpenStoreProvFuncSet = CryptInitOIDFunctionSet(
  655. CRYPT_OID_OPEN_STORE_PROV_FUNC, 0)))
  656. goto CryptInitOIDFunctionSetError;
  657. if (!CryptInstallOIDFunctionAddress(
  658. NULL, // hModule
  659. 0, // dwEncodingType
  660. CRYPT_OID_OPEN_STORE_PROV_FUNC,
  661. OPEN_STORE_PROV_FUNC_COUNT,
  662. OpenStoreProvFuncTable,
  663. 0)) // dwFlags
  664. goto CryptInstallOIDFunctionAddressError;
  665. if (!Pki_InitializeCriticalSection(&ShareElementCriticalSection))
  666. goto InitShareElementCritSectionError;
  667. if (!Pki_InitializeCriticalSection(&ShareStoreCriticalSection))
  668. goto InitShareStoreCritSectionError;
  669. if (!InitNullCertStore())
  670. goto InitNullCertStoreError;
  671. if (!InitCryptProv())
  672. goto InitCryptProvError;
  673. break;
  674. case DLL_PROCESS_DETACH:
  675. FreeCryptProv();
  676. FreeNullCertStore();
  677. DeleteCriticalSection(&ShareElementCriticalSection);
  678. DeleteCriticalSection(&ShareStoreCriticalSection);
  679. break;
  680. case DLL_THREAD_DETACH:
  681. default:
  682. break;
  683. }
  684. fRet = TRUE;
  685. CommonReturn:
  686. return fRet;
  687. InitCryptProvError:
  688. FreeNullCertStore();
  689. InitNullCertStoreError:
  690. DeleteCriticalSection(&ShareStoreCriticalSection);
  691. InitShareStoreCritSectionError:
  692. DeleteCriticalSection(&ShareElementCriticalSection);
  693. InitShareElementCritSectionError:
  694. ErrorReturn:
  695. I_RegStoreDllMain(hInst, DLL_PROCESS_DETACH, NULL);
  696. fRet = FALSE;
  697. goto CommonReturn;
  698. TRACE_ERROR(CryptInitOIDFunctionSetError)
  699. TRACE_ERROR(CryptInstallOIDFunctionAddressError)
  700. }
  701. //+=========================================================================
  702. // Context Type Tables
  703. //==========================================================================
  704. //+-------------------------------------------------------------------------
  705. // Provider callback function indices
  706. //--------------------------------------------------------------------------
  707. static const DWORD rgdwStoreProvFindIndex[CONTEXT_COUNT] = {
  708. CERT_STORE_PROV_FIND_CERT_FUNC,
  709. CERT_STORE_PROV_FIND_CRL_FUNC,
  710. CERT_STORE_PROV_FIND_CTL_FUNC
  711. };
  712. static const DWORD rgdwStoreProvWriteIndex[CONTEXT_COUNT] = {
  713. CERT_STORE_PROV_WRITE_CERT_FUNC,
  714. CERT_STORE_PROV_WRITE_CRL_FUNC,
  715. CERT_STORE_PROV_WRITE_CTL_FUNC
  716. };
  717. static const DWORD rgdwStoreProvDeleteIndex[CONTEXT_COUNT] = {
  718. CERT_STORE_PROV_DELETE_CERT_FUNC,
  719. CERT_STORE_PROV_DELETE_CRL_FUNC,
  720. CERT_STORE_PROV_DELETE_CTL_FUNC
  721. };
  722. static const DWORD rgdwStoreProvFreeFindIndex[CONTEXT_COUNT] = {
  723. CERT_STORE_PROV_FREE_FIND_CERT_FUNC,
  724. CERT_STORE_PROV_FREE_FIND_CRL_FUNC,
  725. CERT_STORE_PROV_FREE_FIND_CTL_FUNC
  726. };
  727. static const DWORD rgdwStoreProvGetPropertyIndex[CONTEXT_COUNT] = {
  728. CERT_STORE_PROV_GET_CERT_PROPERTY_FUNC,
  729. CERT_STORE_PROV_GET_CRL_PROPERTY_FUNC,
  730. CERT_STORE_PROV_GET_CTL_PROPERTY_FUNC
  731. };
  732. static const DWORD rgdwStoreProvSetPropertyIndex[CONTEXT_COUNT] = {
  733. CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC,
  734. CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC,
  735. CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC
  736. };
  737. //+-------------------------------------------------------------------------
  738. // Context data structure length and field offsets
  739. //--------------------------------------------------------------------------
  740. static const DWORD rgcbContext[CONTEXT_COUNT] = {
  741. sizeof(CERT_CONTEXT),
  742. sizeof(CRL_CONTEXT),
  743. sizeof(CTL_CONTEXT)
  744. };
  745. static const DWORD rgOffsetofStoreHandle[CONTEXT_COUNT] = {
  746. offsetof(CERT_CONTEXT, hCertStore),
  747. offsetof(CRL_CONTEXT, hCertStore),
  748. offsetof(CTL_CONTEXT, hCertStore)
  749. };
  750. static const DWORD rgOffsetofEncodingType[CONTEXT_COUNT] = {
  751. offsetof(CERT_CONTEXT, dwCertEncodingType),
  752. offsetof(CRL_CONTEXT, dwCertEncodingType),
  753. offsetof(CTL_CONTEXT, dwMsgAndCertEncodingType)
  754. };
  755. static const DWORD rgOffsetofEncodedPointer[CONTEXT_COUNT] = {
  756. offsetof(CERT_CONTEXT, pbCertEncoded),
  757. offsetof(CRL_CONTEXT, pbCrlEncoded),
  758. offsetof(CTL_CONTEXT, pbCtlEncoded)
  759. };
  760. static const DWORD rgOffsetofEncodedCount[CONTEXT_COUNT] = {
  761. offsetof(CERT_CONTEXT, cbCertEncoded),
  762. offsetof(CRL_CONTEXT, cbCrlEncoded),
  763. offsetof(CTL_CONTEXT, cbCtlEncoded)
  764. };
  765. //+-------------------------------------------------------------------------
  766. // Find Types
  767. //--------------------------------------------------------------------------
  768. static const DWORD rgdwFindTypeToFindExisting[CONTEXT_COUNT] = {
  769. CERT_FIND_EXISTING,
  770. CRL_FIND_EXISTING,
  771. CTL_FIND_EXISTING
  772. };
  773. //+-------------------------------------------------------------------------
  774. // File Element Types
  775. //--------------------------------------------------------------------------
  776. static const DWORD rgdwFileElementType[CONTEXT_COUNT] = {
  777. FILE_ELEMENT_CERT_TYPE,
  778. FILE_ELEMENT_CRL_TYPE,
  779. FILE_ELEMENT_CTL_TYPE
  780. };
  781. //+-------------------------------------------------------------------------
  782. // Share Element Decode Struct Types
  783. //--------------------------------------------------------------------------
  784. static const LPCSTR rgpszShareElementStructType[CONTEXT_COUNT] = {
  785. X509_CERT_TO_BE_SIGNED,
  786. X509_CERT_CRL_TO_BE_SIGNED,
  787. 0
  788. };
  789. //+=========================================================================
  790. // Context Type Specific Functions
  791. //==========================================================================
  792. //+-------------------------------------------------------------------------
  793. // CERT_CONTEXT Element
  794. //--------------------------------------------------------------------------
  795. // pbCertEncoded has already been allocated
  796. STATIC PCONTEXT_ELEMENT CreateCertElement(
  797. IN PCERT_STORE pStore,
  798. IN DWORD dwCertEncodingType,
  799. IN BYTE *pbCertEncoded,
  800. IN DWORD cbCertEncoded,
  801. IN OPTIONAL PSHARE_ELEMENT pShareEle
  802. );
  803. STATIC void FreeCertElement(IN PCONTEXT_ELEMENT pEle);
  804. STATIC BOOL IsSameCert(
  805. IN PCCERT_CONTEXT pCert,
  806. IN PCCERT_CONTEXT pNew
  807. );
  808. STATIC BOOL CompareCertElement(
  809. IN PCONTEXT_ELEMENT pEle,
  810. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  811. IN BOOL fArchived
  812. );
  813. STATIC BOOL IsNewerCertElement(
  814. IN PCONTEXT_ELEMENT pNewEle,
  815. IN PCONTEXT_ELEMENT pExistingEle
  816. );
  817. static inline PCONTEXT_ELEMENT ToContextElement(
  818. IN PCCERT_CONTEXT pCertContext
  819. )
  820. {
  821. if (pCertContext)
  822. return (PCONTEXT_ELEMENT)
  823. (((BYTE *) pCertContext) - sizeof(CONTEXT_ELEMENT));
  824. else
  825. return NULL;
  826. }
  827. static inline PCCERT_CONTEXT ToCertContext(
  828. IN PCONTEXT_ELEMENT pEle
  829. )
  830. {
  831. if (pEle)
  832. return (PCCERT_CONTEXT)
  833. (((BYTE *) pEle) + sizeof(CONTEXT_ELEMENT));
  834. else
  835. return NULL;
  836. }
  837. //+-------------------------------------------------------------------------
  838. // CRL_CONTEXT Element
  839. //--------------------------------------------------------------------------
  840. // pbCrlEncoded has already been allocated
  841. STATIC PCONTEXT_ELEMENT CreateCrlElement(
  842. IN PCERT_STORE pStore,
  843. IN DWORD dwCertEncodingType,
  844. IN BYTE *pbCrlEncoded,
  845. IN DWORD cbCrlEncoded,
  846. IN OPTIONAL PSHARE_ELEMENT pShareEle
  847. );
  848. STATIC void FreeCrlElement(IN PCONTEXT_ELEMENT pEle);
  849. STATIC BOOL CompareCrlElement(
  850. IN PCONTEXT_ELEMENT pEle,
  851. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  852. IN BOOL fArchived
  853. );
  854. STATIC BOOL IsNewerCrlElement(
  855. IN PCONTEXT_ELEMENT pNewEle,
  856. IN PCONTEXT_ELEMENT pExistingEle
  857. );
  858. static inline PCONTEXT_ELEMENT ToContextElement(
  859. IN PCCRL_CONTEXT pCrlContext
  860. )
  861. {
  862. if (pCrlContext)
  863. return (PCONTEXT_ELEMENT)
  864. (((BYTE *) pCrlContext) - sizeof(CONTEXT_ELEMENT));
  865. else
  866. return NULL;
  867. }
  868. static inline PCCRL_CONTEXT ToCrlContext(
  869. IN PCONTEXT_ELEMENT pEle
  870. )
  871. {
  872. if (pEle)
  873. return (PCCRL_CONTEXT)
  874. (((BYTE *) pEle) + sizeof(CONTEXT_ELEMENT));
  875. else
  876. return NULL;
  877. }
  878. static inline PCRL_CONTEXT_SUFFIX ToCrlContextSuffix(
  879. IN PCONTEXT_ELEMENT pEle
  880. )
  881. {
  882. if (pEle)
  883. return (PCRL_CONTEXT_SUFFIX)
  884. (((BYTE *) pEle) + sizeof(CONTEXT_ELEMENT) + sizeof(CRL_CONTEXT));
  885. else
  886. return NULL;
  887. }
  888. //+-------------------------------------------------------------------------
  889. // CTL_CONTEXT Element
  890. //--------------------------------------------------------------------------
  891. // pbCtlEncoded has already been allocated
  892. STATIC PCONTEXT_ELEMENT CreateCtlElement(
  893. IN PCERT_STORE pStore,
  894. IN DWORD dwMsgAndCertEncodingType,
  895. IN BYTE *pbCtlEncoded,
  896. IN DWORD cbCtlEncoded,
  897. IN OPTIONAL PSHARE_ELEMENT pShareEle
  898. );
  899. STATIC void FreeCtlElement(IN PCONTEXT_ELEMENT pEle);
  900. STATIC BOOL CompareCtlElement(
  901. IN PCONTEXT_ELEMENT pEle,
  902. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  903. IN BOOL fArchived
  904. );
  905. STATIC BOOL IsNewerCtlElement(
  906. IN PCONTEXT_ELEMENT pNewEle,
  907. IN PCONTEXT_ELEMENT pExistingEle
  908. );
  909. static inline PCONTEXT_ELEMENT ToContextElement(
  910. IN PCCTL_CONTEXT pCtlContext
  911. )
  912. {
  913. if (pCtlContext)
  914. return (PCONTEXT_ELEMENT)
  915. (((BYTE *) pCtlContext) - sizeof(CONTEXT_ELEMENT));
  916. else
  917. return NULL;
  918. }
  919. static inline PCCTL_CONTEXT ToCtlContext(
  920. IN PCONTEXT_ELEMENT pEle
  921. )
  922. {
  923. if (pEle)
  924. return (PCCTL_CONTEXT)
  925. (((BYTE *) pEle) + sizeof(CONTEXT_ELEMENT));
  926. else
  927. return NULL;
  928. }
  929. static inline PCTL_CONTEXT_SUFFIX ToCtlContextSuffix(
  930. IN PCONTEXT_ELEMENT pEle
  931. )
  932. {
  933. if (pEle)
  934. return (PCTL_CONTEXT_SUFFIX)
  935. (((BYTE *) pEle) + sizeof(CONTEXT_ELEMENT) + sizeof(CTL_CONTEXT));
  936. else
  937. return NULL;
  938. }
  939. //+=========================================================================
  940. // Context Type Function Tables
  941. //==========================================================================
  942. typedef PCONTEXT_ELEMENT (*PFN_CREATE_ELEMENT)(
  943. IN PCERT_STORE pStore,
  944. IN DWORD dwCertEncodingType,
  945. IN BYTE *pbCertEncoded,
  946. IN DWORD cbCertEncoded,
  947. IN OPTIONAL PSHARE_ELEMENT pShareEle
  948. );
  949. static PFN_CREATE_ELEMENT const rgpfnCreateElement[CONTEXT_COUNT] = {
  950. CreateCertElement,
  951. CreateCrlElement,
  952. CreateCtlElement
  953. };
  954. typedef void (*PFN_FREE_ELEMENT)(
  955. IN PCONTEXT_ELEMENT pEle
  956. );
  957. static PFN_FREE_ELEMENT const rgpfnFreeElement[CONTEXT_COUNT] = {
  958. FreeCertElement,
  959. FreeCrlElement,
  960. FreeCtlElement
  961. };
  962. typedef BOOL (*PFN_COMPARE_ELEMENT)(
  963. IN PCONTEXT_ELEMENT pEle,
  964. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  965. IN BOOL fArchived
  966. );
  967. static PFN_COMPARE_ELEMENT const rgpfnCompareElement[CONTEXT_COUNT] = {
  968. CompareCertElement,
  969. CompareCrlElement,
  970. CompareCtlElement
  971. };
  972. typedef BOOL (*PFN_IS_NEWER_ELEMENT)(
  973. IN PCONTEXT_ELEMENT pNewEle,
  974. IN PCONTEXT_ELEMENT pExistingEle
  975. );
  976. static PFN_IS_NEWER_ELEMENT const rgpfnIsNewerElement[CONTEXT_COUNT] = {
  977. IsNewerCertElement,
  978. IsNewerCrlElement,
  979. IsNewerCtlElement
  980. };
  981. //+=========================================================================
  982. // Store Link Functions
  983. //==========================================================================
  984. STATIC PCERT_STORE_LINK CreateStoreLink(
  985. IN PCERT_STORE pCollection,
  986. IN PCERT_STORE pSibling,
  987. IN DWORD dwUpdateFlags,
  988. IN DWORD dwPriority
  989. );
  990. STATIC void FreeStoreLink(
  991. IN PCERT_STORE_LINK pStoreLink
  992. );
  993. STATIC void RemoveStoreLink(
  994. IN PCERT_STORE_LINK pStoreLink
  995. );
  996. STATIC void RemoveAndFreeStoreLink(
  997. IN PCERT_STORE_LINK pStoreLink
  998. );
  999. static inline void AddRefStoreLink(
  1000. IN PCERT_STORE_LINK pStoreLink
  1001. )
  1002. {
  1003. InterlockedIncrement(&pStoreLink->lRefCnt);
  1004. }
  1005. STATIC void ReleaseStoreLink(
  1006. IN PCERT_STORE_LINK pStoreLink
  1007. );
  1008. //+=========================================================================
  1009. // Context Element Functions
  1010. //==========================================================================
  1011. STATIC DWORD GetContextEncodingType(
  1012. IN PCONTEXT_ELEMENT pEle
  1013. );
  1014. STATIC void GetContextEncodedInfo(
  1015. IN PCONTEXT_ELEMENT pEle,
  1016. OUT BYTE **ppbEncoded,
  1017. OUT DWORD *pcbEncoded
  1018. );
  1019. STATIC PCONTEXT_ELEMENT GetCacheElement(
  1020. IN PCONTEXT_ELEMENT pCacheEle
  1021. );
  1022. STATIC void AddContextElement(
  1023. IN PCONTEXT_ELEMENT pEle
  1024. );
  1025. STATIC void RemoveContextElement(
  1026. IN PCONTEXT_ELEMENT pEle
  1027. );
  1028. STATIC void FreeContextElement(
  1029. IN PCONTEXT_ELEMENT pEle
  1030. );
  1031. STATIC void RemoveAndFreeContextElement(
  1032. IN PCONTEXT_ELEMENT pEle
  1033. );
  1034. STATIC void AddRefContextElement(
  1035. IN PCONTEXT_ELEMENT pEle
  1036. );
  1037. STATIC void AddRefDeferClose(
  1038. IN PCONTEXT_ELEMENT pEle
  1039. );
  1040. STATIC void ReleaseContextElement(
  1041. IN PCONTEXT_ELEMENT pEle
  1042. );
  1043. STATIC BOOL DeleteContextElement(
  1044. IN PCONTEXT_ELEMENT pEle
  1045. );
  1046. // Returns TRUE if both elements have identical SHA1 hash.
  1047. STATIC BOOL IsIdenticalContextElement(
  1048. IN PCONTEXT_ELEMENT pEle1,
  1049. IN PCONTEXT_ELEMENT pEle2
  1050. );
  1051. STATIC BOOL SerializeStoreElement(
  1052. IN HANDLE h,
  1053. IN PFNWRITE pfn,
  1054. IN PCONTEXT_ELEMENT pEle
  1055. );
  1056. STATIC BOOL SerializeContextElement(
  1057. IN PCONTEXT_ELEMENT pEle,
  1058. IN DWORD dwFlags,
  1059. OUT BYTE *pbElement,
  1060. IN OUT DWORD *pcbElement
  1061. );
  1062. STATIC PCONTEXT_ELEMENT CreateLinkElement(
  1063. IN DWORD dwContextType
  1064. );
  1065. static inline void FreeLinkElement(
  1066. IN PCONTEXT_ELEMENT pLinkEle
  1067. )
  1068. {
  1069. PkiFree(pLinkEle);
  1070. }
  1071. STATIC void FreeLinkContextElement(
  1072. IN PCONTEXT_ELEMENT pLinkEle
  1073. );
  1074. // Upon entry no locks
  1075. STATIC void RemoveAndFreeLinkElement(
  1076. IN PCONTEXT_ELEMENT pEle
  1077. );
  1078. STATIC PCONTEXT_ELEMENT FindElementInStore(
  1079. IN PCERT_STORE pStore,
  1080. IN DWORD dwContextType,
  1081. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  1082. IN OPTIONAL PCONTEXT_ELEMENT pPrevEle
  1083. );
  1084. STATIC PCONTEXT_ELEMENT CheckAutoResyncAndFindElementInStore(
  1085. IN PCERT_STORE pStore,
  1086. IN DWORD dwContextType,
  1087. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  1088. IN OPTIONAL PCONTEXT_ELEMENT pPrevEle
  1089. );
  1090. STATIC BOOL AddLinkContextToCacheStore(
  1091. IN PCERT_STORE pStore,
  1092. IN PCONTEXT_ELEMENT pEle,
  1093. IN DWORD dwAddDisposition,
  1094. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  1095. );
  1096. // pEle is used or freed for success only, Otherwise, its left alone and
  1097. // will be freed by the caller.
  1098. //
  1099. // This routine may be called recursively
  1100. STATIC BOOL AddElementToStore(
  1101. IN PCERT_STORE pStore,
  1102. IN PCONTEXT_ELEMENT pEle,
  1103. IN DWORD dwAddDisposition,
  1104. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  1105. );
  1106. STATIC BOOL AddEncodedContextToStore(
  1107. IN PCERT_STORE pStore,
  1108. IN DWORD dwContextType,
  1109. IN DWORD dwCertEncodingType,
  1110. IN const BYTE *pbEncoded,
  1111. IN DWORD cbEncoded,
  1112. IN DWORD dwAddDisposition,
  1113. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  1114. );
  1115. STATIC BOOL AddContextToStore(
  1116. IN PCERT_STORE pStore,
  1117. IN PCONTEXT_ELEMENT pSrcEle,
  1118. IN DWORD dwCertEncodingType,
  1119. IN const BYTE *pbEncoded,
  1120. IN DWORD cbEncoded,
  1121. IN DWORD dwAddDisposition,
  1122. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  1123. );
  1124. //+=========================================================================
  1125. // PROP_ELEMENT Functions
  1126. //==========================================================================
  1127. // pbData has already been allocated
  1128. STATIC PPROP_ELEMENT CreatePropElement(
  1129. IN DWORD dwPropId,
  1130. IN DWORD dwFlags,
  1131. IN BYTE *pbData,
  1132. IN DWORD cbData
  1133. );
  1134. STATIC void FreePropElement(IN PPROP_ELEMENT pEle);
  1135. // Upon entry/exit: Store/Element is locked
  1136. STATIC PPROP_ELEMENT FindPropElement(
  1137. IN PPROP_ELEMENT pPropEle,
  1138. IN DWORD dwPropId
  1139. );
  1140. STATIC PPROP_ELEMENT FindPropElement(
  1141. IN PCONTEXT_ELEMENT pCacheEle,
  1142. IN DWORD dwPropId
  1143. );
  1144. // Upon entry/exit: Store/Element is locked
  1145. STATIC void AddPropElement(
  1146. IN OUT PPROP_ELEMENT *ppPropHead,
  1147. IN PPROP_ELEMENT pPropEle
  1148. );
  1149. STATIC void AddPropElement(
  1150. IN OUT PCONTEXT_ELEMENT pCacheEle,
  1151. IN PPROP_ELEMENT pPropEle
  1152. );
  1153. // Upon entry/exit: Store/Element is locked
  1154. STATIC void RemovePropElement(
  1155. IN OUT PPROP_ELEMENT *ppPropHead,
  1156. IN PPROP_ELEMENT pPropEle
  1157. );
  1158. STATIC void RemovePropElement(
  1159. IN OUT PCONTEXT_ELEMENT pCacheEle,
  1160. IN PPROP_ELEMENT pPropEle
  1161. );
  1162. //+=========================================================================
  1163. // Property Functions
  1164. //==========================================================================
  1165. //+-------------------------------------------------------------------------
  1166. // Set the property for the specified element
  1167. //--------------------------------------------------------------------------
  1168. STATIC BOOL SetProperty(
  1169. IN PCONTEXT_ELEMENT pEle,
  1170. IN DWORD dwPropId,
  1171. IN DWORD dwFlags,
  1172. IN const void *pvData,
  1173. IN BOOL fInhibitProvSet = FALSE
  1174. );
  1175. //+-------------------------------------------------------------------------
  1176. // Get the property for the specified element
  1177. //--------------------------------------------------------------------------
  1178. STATIC BOOL GetProperty(
  1179. IN PCONTEXT_ELEMENT pEle,
  1180. IN DWORD dwPropId,
  1181. OUT void *pvData,
  1182. IN OUT DWORD *pcbData
  1183. );
  1184. // Upon entry/exit the store is locked
  1185. STATIC void DeleteProperty(
  1186. IN OUT PPROP_ELEMENT *ppPropHead,
  1187. IN DWORD dwPropId
  1188. );
  1189. STATIC void DeleteProperty(
  1190. IN OUT PCONTEXT_ELEMENT pCacheEle,
  1191. IN DWORD dwPropId
  1192. );
  1193. //+-------------------------------------------------------------------------
  1194. // Serialize a Property
  1195. //--------------------------------------------------------------------------
  1196. STATIC BOOL SerializeProperty(
  1197. IN HANDLE h,
  1198. IN PFNWRITE pfn,
  1199. IN PCONTEXT_ELEMENT pEle
  1200. );
  1201. #define COPY_PROPERTY_USE_EXISTING_FLAG 0x1
  1202. #define COPY_PROPERTY_INHIBIT_PROV_SET_FLAG 0x2
  1203. #define COPY_PROPERTY_SYNC_FLAG 0x4
  1204. STATIC BOOL CopyProperties(
  1205. IN PCONTEXT_ELEMENT pSrcEle,
  1206. IN PCONTEXT_ELEMENT pDstEle,
  1207. IN DWORD dwFlags
  1208. );
  1209. //+-------------------------------------------------------------------------
  1210. // Get the first or next PropId for the specified element
  1211. //
  1212. // Set dwPropId = 0, to get the first. Returns 0, if no more properties.
  1213. //--------------------------------------------------------------------------
  1214. STATIC DWORD EnumProperties(
  1215. IN PCONTEXT_ELEMENT pEle,
  1216. IN DWORD dwPropId
  1217. );
  1218. //+-------------------------------------------------------------------------
  1219. // Get or set the caller properties for a store or KeyId element.
  1220. //--------------------------------------------------------------------------
  1221. STATIC BOOL GetCallerProperty(
  1222. IN PPROP_ELEMENT pPropHead,
  1223. IN DWORD dwPropId,
  1224. BOOL fAlloc,
  1225. OUT void *pvData,
  1226. IN OUT DWORD *pcbData
  1227. );
  1228. BOOL SetCallerProperty(
  1229. IN OUT PPROP_ELEMENT *ppPropHead,
  1230. IN DWORD dwPropId,
  1231. IN DWORD dwFlags,
  1232. IN const void *pvData
  1233. );
  1234. //+-------------------------------------------------------------------------
  1235. // CRYPT_KEY_PROV_INFO: Encode and Decode Functions
  1236. //--------------------------------------------------------------------------
  1237. #define ENCODE_LEN_ALIGN(Len) ((Len + 7) & ~7)
  1238. typedef struct _SERIALIZED_KEY_PROV_PARAM {
  1239. DWORD dwParam;
  1240. DWORD offbData;
  1241. DWORD cbData;
  1242. DWORD dwFlags;
  1243. } SERIALIZED_KEY_PROV_PARAM, *PSERIALIZED_KEY_PROV_PARAM;
  1244. typedef struct _SERIALIZED_KEY_PROV_INFO {
  1245. DWORD offwszContainerName;
  1246. DWORD offwszProvName;
  1247. DWORD dwProvType;
  1248. DWORD dwFlags;
  1249. DWORD cProvParam;
  1250. DWORD offrgProvParam;
  1251. DWORD dwKeySpec;
  1252. } SERIALIZED_KEY_PROV_INFO, *PSERIALIZED_KEY_PROV_INFO;
  1253. #define MAX_PROV_PARAM 0x00000100
  1254. #define MAX_PROV_PARAM_CBDATA 0x00010000
  1255. STATIC BOOL AllocAndEncodeKeyProvInfo(
  1256. IN PCRYPT_KEY_PROV_INFO pKeyProvInfo,
  1257. OUT BYTE **ppbEncoded,
  1258. OUT DWORD *pcbEncoded
  1259. );
  1260. STATIC BOOL DecodeKeyProvInfo(
  1261. IN PSERIALIZED_KEY_PROV_INFO pSerializedInfo,
  1262. IN DWORD cbSerialized,
  1263. OUT PCRYPT_KEY_PROV_INFO pInfo,
  1264. OUT DWORD *pcbInfo
  1265. );
  1266. //+=========================================================================
  1267. // KEYID_ELEMENT Functions
  1268. //==========================================================================
  1269. // pbKeyIdEncoded has already been allocated
  1270. STATIC PKEYID_ELEMENT CreateKeyIdElement(
  1271. IN BYTE *pbKeyIdEncoded,
  1272. IN DWORD cbKeyIdEncoded
  1273. );
  1274. STATIC void FreeKeyIdElement(IN PKEYID_ELEMENT pEle);
  1275. //+=========================================================================
  1276. // Key Identifier Property Functions
  1277. //
  1278. // If dwPropId == 0, check if the element has a KEY_PROV_INFO property
  1279. //==========================================================================
  1280. STATIC void SetCryptKeyIdentifierKeyProvInfoProperty(
  1281. IN PCONTEXT_ELEMENT pEle,
  1282. IN DWORD dwPropId = 0,
  1283. IN const void *pvData = NULL
  1284. );
  1285. STATIC BOOL GetKeyIdProperty(
  1286. IN PCONTEXT_ELEMENT pEle,
  1287. IN DWORD dwPropId,
  1288. OUT void *pvData,
  1289. IN OUT DWORD *pcbData
  1290. );
  1291. //+-------------------------------------------------------------------------
  1292. // Alloc and NOCOPY Decode
  1293. //--------------------------------------------------------------------------
  1294. STATIC void *AllocAndDecodeObject(
  1295. IN DWORD dwCertEncodingType,
  1296. IN LPCSTR lpszStructType,
  1297. IN const BYTE *pbEncoded,
  1298. IN DWORD cbEncoded,
  1299. IN DWORD dwFlags = CRYPT_DECODE_NOCOPY_FLAG
  1300. )
  1301. {
  1302. DWORD cbStructInfo;
  1303. void *pvStructInfo;
  1304. if (!CryptDecodeObjectEx(
  1305. dwCertEncodingType,
  1306. lpszStructType,
  1307. pbEncoded,
  1308. cbEncoded,
  1309. dwFlags |
  1310. CRYPT_DECODE_SHARE_OID_STRING_FLAG | CRYPT_DECODE_ALLOC_FLAG,
  1311. &PkiDecodePara,
  1312. (void *) &pvStructInfo,
  1313. &cbStructInfo
  1314. ))
  1315. goto ErrorReturn;
  1316. CommonReturn:
  1317. return pvStructInfo;
  1318. ErrorReturn:
  1319. pvStructInfo = NULL;
  1320. goto CommonReturn;
  1321. }
  1322. //+-------------------------------------------------------------------------
  1323. // Allocates and returns the specified cryptographic message parameter.
  1324. //--------------------------------------------------------------------------
  1325. STATIC void *AllocAndGetMsgParam(
  1326. IN HCRYPTMSG hMsg,
  1327. IN DWORD dwParamType,
  1328. IN DWORD dwIndex,
  1329. OUT DWORD *pcbData
  1330. )
  1331. {
  1332. void *pvData;
  1333. DWORD cbData;
  1334. if (!CryptMsgGetParam(
  1335. hMsg,
  1336. dwParamType,
  1337. dwIndex,
  1338. NULL, // pvData
  1339. &cbData) || 0 == cbData)
  1340. goto GetParamError;
  1341. if (NULL == (pvData = PkiNonzeroAlloc(cbData)))
  1342. goto OutOfMemory;
  1343. if (!CryptMsgGetParam(
  1344. hMsg,
  1345. dwParamType,
  1346. dwIndex,
  1347. pvData,
  1348. &cbData)) {
  1349. PkiFree(pvData);
  1350. goto GetParamError;
  1351. }
  1352. CommonReturn:
  1353. *pcbData = cbData;
  1354. return pvData;
  1355. ErrorReturn:
  1356. pvData = NULL;
  1357. cbData = 0;
  1358. goto CommonReturn;
  1359. TRACE_ERROR(OutOfMemory)
  1360. TRACE_ERROR(GetParamError)
  1361. }
  1362. //+-------------------------------------------------------------------------
  1363. // First try to get the EncodingType from the lower 16 bits. If 0, get
  1364. // from the upper 16 bits.
  1365. //--------------------------------------------------------------------------
  1366. static inline DWORD GetCertEncodingType(
  1367. IN DWORD dwEncodingType
  1368. )
  1369. {
  1370. if (0 == dwEncodingType)
  1371. return X509_ASN_ENCODING;
  1372. else
  1373. return (dwEncodingType & CERT_ENCODING_TYPE_MASK) ?
  1374. (dwEncodingType & CERT_ENCODING_TYPE_MASK) :
  1375. ((dwEncodingType >> 16) & CERT_ENCODING_TYPE_MASK);
  1376. }
  1377. STATIC DWORD AdjustEncodedLength(
  1378. IN DWORD dwCertEncodingType,
  1379. IN const BYTE *pbDER,
  1380. IN DWORD cbDER
  1381. )
  1382. {
  1383. if (X509_ASN_ENCODING == GET_CERT_ENCODING_TYPE(dwCertEncodingType))
  1384. return Asn1UtilAdjustEncodedLength(pbDER, cbDER);
  1385. else
  1386. return cbDER;
  1387. }
  1388. //+-------------------------------------------------------------------------
  1389. // Read, Write and Skip file functions
  1390. //--------------------------------------------------------------------------
  1391. BOOL WriteToFile(HANDLE h, void * p, DWORD cb) {
  1392. DWORD cbBytesWritten;
  1393. return(WriteFile(h, p, cb, &cbBytesWritten, NULL));
  1394. }
  1395. BOOL ReadFromFile(
  1396. IN HANDLE h,
  1397. IN void * p,
  1398. IN DWORD cb
  1399. )
  1400. {
  1401. DWORD cbBytesRead;
  1402. return(ReadFile(h, p, cb, &cbBytesRead, NULL));
  1403. }
  1404. BOOL SkipInFile(
  1405. IN HANDLE h,
  1406. IN DWORD cb
  1407. )
  1408. {
  1409. DWORD dwLoFilePointer;
  1410. LONG lHiFilePointer;
  1411. LONG lDistanceToMove;
  1412. lDistanceToMove = (LONG) cb;
  1413. lHiFilePointer = 0;
  1414. dwLoFilePointer = SetFilePointer(
  1415. h,
  1416. lDistanceToMove,
  1417. &lHiFilePointer,
  1418. FILE_CURRENT
  1419. );
  1420. if (0xFFFFFFFF == dwLoFilePointer && NO_ERROR != GetLastError())
  1421. return FALSE;
  1422. else
  1423. return TRUE;
  1424. }
  1425. //+-------------------------------------------------------------------------
  1426. // Read, Write and Skip memory fucntions
  1427. //--------------------------------------------------------------------------
  1428. typedef struct _MEMINFO {
  1429. BYTE * pByte;
  1430. DWORD cb;
  1431. DWORD cbSeek;
  1432. } MEMINFO, * PMEMINFO;
  1433. BOOL WriteToMemory(HANDLE h, void * p, DWORD cb)
  1434. {
  1435. PMEMINFO pMemInfo = (PMEMINFO) h;
  1436. // See if we have room. The caller will detect an error after the final
  1437. // write
  1438. if (pMemInfo->cbSeek + cb <= pMemInfo->cb) {
  1439. // Handle MappedFile Exceptions
  1440. __try {
  1441. // copy the bytes
  1442. memcpy(&pMemInfo->pByte[pMemInfo->cbSeek], p, cb);
  1443. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1444. SetLastError(GetExceptionCode());
  1445. return FALSE;
  1446. }
  1447. }
  1448. pMemInfo->cbSeek += cb;
  1449. return(TRUE);
  1450. }
  1451. BOOL ReadFromMemory(
  1452. IN HANDLE h,
  1453. IN void * p,
  1454. IN DWORD cb
  1455. )
  1456. {
  1457. PMEMINFO pMemInfo = (PMEMINFO) h;
  1458. BOOL fResult;
  1459. fResult = !((pMemInfo->cb - pMemInfo->cbSeek) < cb);
  1460. cb = min((pMemInfo->cb - pMemInfo->cbSeek), cb);
  1461. // Handle MappedFile Exceptions
  1462. __try {
  1463. // copy the bytes
  1464. memcpy(p, &pMemInfo->pByte[pMemInfo->cbSeek], cb);
  1465. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1466. SetLastError(GetExceptionCode());
  1467. return FALSE;
  1468. }
  1469. pMemInfo->cbSeek += cb;
  1470. if(!fResult)
  1471. SetLastError(ERROR_END_OF_MEDIA);
  1472. return(fResult);
  1473. }
  1474. BOOL SkipInMemory(
  1475. IN HANDLE h,
  1476. IN DWORD cb
  1477. )
  1478. {
  1479. PMEMINFO pMemInfo = (PMEMINFO) h;
  1480. BOOL fResult;
  1481. fResult = !((pMemInfo->cb - pMemInfo->cbSeek) < cb);
  1482. cb = min((pMemInfo->cb - pMemInfo->cbSeek), cb);
  1483. pMemInfo->cbSeek += cb;
  1484. if(!fResult)
  1485. SetLastError(ERROR_END_OF_MEDIA);
  1486. return(fResult);
  1487. }
  1488. //+-------------------------------------------------------------------------
  1489. // Lock and unlock functions
  1490. //--------------------------------------------------------------------------
  1491. STATIC void LockStore(IN PCERT_STORE pStore)
  1492. {
  1493. EnterCriticalSection(&pStore->CriticalSection);
  1494. }
  1495. STATIC void UnlockStore(IN PCERT_STORE pStore)
  1496. {
  1497. LeaveCriticalSection(&pStore->CriticalSection);
  1498. }
  1499. //+-------------------------------------------------------------------------
  1500. // Reference count calls to provider functions. This is necessary since
  1501. // the store provider functions are called without a lock on the
  1502. // store. CertCloseStore waits until the provider reference count
  1503. // is decremented to zero before completing the close.
  1504. //
  1505. // Also used to reference count use of the store's CryptProv handle when
  1506. // used without a store lock.
  1507. //--------------------------------------------------------------------------
  1508. // Upon entry/exit the store is locked
  1509. static inline void AddRefStoreProv(IN PCERT_STORE pStore)
  1510. {
  1511. pStore->lStoreProvRefCnt++;
  1512. }
  1513. // Upon entry/exit the store is locked
  1514. static inline void ReleaseStoreProv(IN PCERT_STORE pStore)
  1515. {
  1516. if (0 == --pStore->lStoreProvRefCnt && pStore->hStoreProvWait)
  1517. SetEvent(pStore->hStoreProvWait);
  1518. }
  1519. //+-------------------------------------------------------------------------
  1520. // Try to get the store's CryptProv handle.
  1521. // If we get the store's CryptProv handle,
  1522. // then, increment the provider reference count to force another
  1523. // thread's CertCloseStore to wait until we make a call to ReleaseCryptProv.
  1524. //
  1525. // Leave while still in the CryptProvCriticalSection.
  1526. //
  1527. // ReleaseCryptProv() must always be called.
  1528. //
  1529. // Note, if returned hCryptProv is NULL, the called CertHelper functions
  1530. // will acquire and use the appropriate default provider.
  1531. //--------------------------------------------------------------------------
  1532. #define RELEASE_STORE_CRYPT_PROV_FLAG 0x1
  1533. STATIC HCRYPTPROV GetCryptProv(
  1534. IN PCERT_STORE pStore,
  1535. OUT DWORD *pdwFlags
  1536. )
  1537. {
  1538. HCRYPTPROV hCryptProv;
  1539. LockStore(pStore);
  1540. hCryptProv = pStore->hCryptProv;
  1541. if (hCryptProv) {
  1542. AddRefStoreProv(pStore);
  1543. *pdwFlags = RELEASE_STORE_CRYPT_PROV_FLAG;
  1544. } else
  1545. *pdwFlags = 0;
  1546. UnlockStore(pStore);
  1547. EnterCriticalSection(&CryptProvCriticalSection);
  1548. return hCryptProv;
  1549. }
  1550. STATIC void ReleaseCryptProv(
  1551. IN PCERT_STORE pStore,
  1552. IN DWORD dwFlags
  1553. )
  1554. {
  1555. LeaveCriticalSection(&CryptProvCriticalSection);
  1556. if (dwFlags & RELEASE_STORE_CRYPT_PROV_FLAG) {
  1557. LockStore(pStore);
  1558. ReleaseStoreProv(pStore);
  1559. UnlockStore(pStore);
  1560. }
  1561. }
  1562. //+-------------------------------------------------------------------------
  1563. // Forward references
  1564. //--------------------------------------------------------------------------
  1565. STATIC BOOL IsEmptyStore(
  1566. IN PCERT_STORE pStore
  1567. );
  1568. STATIC BOOL CloseStore(
  1569. IN PCERT_STORE pStore,
  1570. DWORD dwFlags
  1571. );
  1572. void ArchiveManifoldCertificatesInStore(
  1573. IN PCERT_STORE pStore
  1574. );
  1575. //+-------------------------------------------------------------------------
  1576. // Share Store Functions
  1577. //--------------------------------------------------------------------------
  1578. // If the sharable LocalMachine store is already open, its returned with its
  1579. // RefCnt bumped
  1580. STATIC PCERT_STORE FindShareStore(
  1581. IN LPCWSTR pwszStore
  1582. )
  1583. {
  1584. PCERT_STORE pStore = NULL;
  1585. PSHARE_STORE pShare;
  1586. EnterCriticalSection(&ShareStoreCriticalSection);
  1587. for (pShare = pShareStoreHead; pShare; pShare = pShare->pNext) {
  1588. if (0 == _wcsicmp(pShare->pwszStore, pwszStore)) {
  1589. pStore = pShare->pStore;
  1590. InterlockedIncrement(&pStore->lRefCnt);
  1591. break;
  1592. }
  1593. }
  1594. LeaveCriticalSection(&ShareStoreCriticalSection);
  1595. return pStore;
  1596. }
  1597. // The LocalMachine store is added to the linked list of opened, sharable
  1598. // stores.
  1599. STATIC void CreateShareStore(
  1600. IN LPCWSTR pwszStore,
  1601. IN PCERT_STORE pStore
  1602. )
  1603. {
  1604. PSHARE_STORE pShare;
  1605. DWORD cbwszStore;
  1606. cbwszStore = (wcslen(pwszStore) + 1) * sizeof(WCHAR);
  1607. if (NULL == (pShare = (PSHARE_STORE) PkiZeroAlloc(
  1608. sizeof(SHARE_STORE) + cbwszStore)))
  1609. return;
  1610. pShare->pwszStore = (LPWSTR) &pShare[1];
  1611. memcpy(pShare->pwszStore, pwszStore, cbwszStore);
  1612. pShare->pStore = pStore;
  1613. pStore->pShareStore = pShare;
  1614. EnterCriticalSection(&ShareStoreCriticalSection);
  1615. if (pShareStoreHead) {
  1616. pShare->pNext = pShareStoreHead;
  1617. assert(NULL == pShareStoreHead->pPrev);
  1618. pShareStoreHead->pPrev = pShare;
  1619. }
  1620. pShareStoreHead = pShare;
  1621. LeaveCriticalSection(&ShareStoreCriticalSection);
  1622. }
  1623. // Upon input/exit, Store is locked.
  1624. // Returns TRUE if share store was closed and freed
  1625. STATIC BOOL CloseShareStore(
  1626. IN PCERT_STORE pStore
  1627. )
  1628. {
  1629. BOOL fClose;
  1630. EnterCriticalSection(&ShareStoreCriticalSection);
  1631. // Check if we had a FindShareStore after the store's lRefCnt
  1632. // was decremented to 0.
  1633. InterlockedIncrement(&pStore->lRefCnt);
  1634. if (0 == InterlockedDecrement(&pStore->lRefCnt)) {
  1635. PSHARE_STORE pShare;
  1636. pShare = pStore->pShareStore;
  1637. assert(pShare);
  1638. if (pShare) {
  1639. if (pShare->pNext)
  1640. pShare->pNext->pPrev = pShare->pPrev;
  1641. if (pShare->pPrev)
  1642. pShare->pPrev->pNext = pShare->pNext;
  1643. else {
  1644. assert(pShareStoreHead == pShare);
  1645. pShareStoreHead = pShare->pNext;
  1646. }
  1647. PkiFree(pShare);
  1648. }
  1649. pStore->pShareStore = NULL;
  1650. fClose = TRUE;
  1651. } else
  1652. fClose = FALSE;
  1653. LeaveCriticalSection(&ShareStoreCriticalSection);
  1654. return fClose;
  1655. }
  1656. //+-------------------------------------------------------------------------
  1657. // Open the cert store using the specified store provider.
  1658. //
  1659. // hCryptProv specifies the crypto provider to use to create the hash
  1660. // properties or verify the signature of a subject certificate or CRL.
  1661. // The store doesn't need to use a private
  1662. // key. If the CERT_STORE_NO_CRYPT_RELEASE_FLAG isn't set, hCryptProv is
  1663. // CryptReleaseContext'ed on the final CertCloseStore.
  1664. //
  1665. // Note, if the open fails, hCryptProv is released if it would have been
  1666. // released when the store was closed.
  1667. //
  1668. // If hCryptProv is zero, then, the default provider and container for the
  1669. // PROV_RSA_FULL provider type is CryptAcquireContext'ed with
  1670. // CRYPT_VERIFYCONTEXT access. The CryptAcquireContext is deferred until
  1671. // the first create hash or verify signature. In addition, once acquired,
  1672. // the default provider isn't released until process exit when crypt32.dll
  1673. // is unloaded. The acquired default provider is shared across all stores
  1674. // and threads.
  1675. //
  1676. // Use of the dwEncodingType parameter is provider dependent. The type
  1677. // definition for pvPara also depends on the provider.
  1678. //--------------------------------------------------------------------------
  1679. HCERTSTORE
  1680. WINAPI
  1681. CertOpenStore(
  1682. IN LPCSTR lpszStoreProvider,
  1683. IN DWORD dwEncodingType,
  1684. IN HCRYPTPROV hCryptProv,
  1685. IN DWORD dwFlags,
  1686. IN const void *pvPara
  1687. )
  1688. {
  1689. PCERT_STORE pStore;
  1690. PFN_CERT_DLL_OPEN_STORE_PROV_FUNC pfnOpenStoreProv;
  1691. BOOL fShareStore = FALSE;
  1692. // LocalMachine System stores opened for SHARE and MAXIMUM_ALLOWED can
  1693. // be shared.
  1694. if ((CERT_SYSTEM_STORE_LOCAL_MACHINE |
  1695. CERT_STORE_SHARE_STORE_FLAG |
  1696. CERT_STORE_SHARE_CONTEXT_FLAG |
  1697. CERT_STORE_MAXIMUM_ALLOWED_FLAG
  1698. ) == dwFlags
  1699. &&
  1700. 0 == hCryptProv
  1701. ) {
  1702. if (0xFFFF < (DWORD_PTR) lpszStoreProvider) {
  1703. if (0 == _stricmp(sz_CERT_STORE_PROV_SYSTEM_W,
  1704. lpszStoreProvider))
  1705. fShareStore = TRUE;
  1706. } else {
  1707. if (CERT_STORE_PROV_SYSTEM_W == lpszStoreProvider)
  1708. fShareStore = TRUE;
  1709. }
  1710. if (fShareStore) {
  1711. if (pStore = FindShareStore((LPCWSTR) pvPara))
  1712. return (HCERTSTORE) pStore;
  1713. }
  1714. }
  1715. pStore = (PCERT_STORE) PkiZeroAlloc(sizeof(*pStore));
  1716. if (pStore) {
  1717. if (!Pki_InitializeCriticalSection(&pStore->CriticalSection)) {
  1718. PkiFree(pStore);
  1719. pStore = NULL;
  1720. }
  1721. }
  1722. if (pStore == NULL) {
  1723. if (hCryptProv && (dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG) == 0)
  1724. CryptReleaseContext(hCryptProv, 0);
  1725. return NULL;
  1726. }
  1727. CertPerfIncrementStoreTotalCount();
  1728. CertPerfIncrementStoreCurrentCount();
  1729. pStore->StoreProvInfo.cbSize = sizeof(CERT_STORE_PROV_INFO);
  1730. pStore->dwStoreType = STORE_TYPE_CACHE;
  1731. pStore->lRefCnt = 1;
  1732. pStore->dwState = STORE_STATE_OPENING;
  1733. pStore->hCryptProv = hCryptProv;
  1734. pStore->dwFlags = dwFlags;
  1735. if (CERT_STORE_PROV_MEMORY == lpszStoreProvider)
  1736. pStore->StoreProvInfo.dwStoreProvFlags |=
  1737. CERT_STORE_PROV_NO_PERSIST_FLAG;
  1738. else {
  1739. if (!CryptGetOIDFunctionAddress(
  1740. hOpenStoreProvFuncSet,
  1741. 0, // dwEncodingType,
  1742. lpszStoreProvider,
  1743. 0, // dwFlags
  1744. (void **) &pfnOpenStoreProv,
  1745. &pStore->hStoreProvFuncAddr))
  1746. goto GetOIDFuncAddrError;
  1747. if (!pfnOpenStoreProv(
  1748. lpszStoreProvider,
  1749. dwEncodingType,
  1750. hCryptProv,
  1751. dwFlags & ~CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  1752. pvPara,
  1753. (HCERTSTORE) pStore,
  1754. &pStore->StoreProvInfo)) {
  1755. if (0 == (dwFlags & CERT_STORE_MAXIMUM_ALLOWED_FLAG))
  1756. goto OpenStoreProvError;
  1757. pStore->hCryptProv = NULL;
  1758. CertCloseStore((HCERTSTORE) pStore, 0);
  1759. return CertOpenStore(
  1760. lpszStoreProvider,
  1761. dwEncodingType,
  1762. hCryptProv,
  1763. (dwFlags & ~CERT_STORE_MAXIMUM_ALLOWED_FLAG) |
  1764. CERT_STORE_READONLY_FLAG,
  1765. pvPara
  1766. );
  1767. }
  1768. if (pStore->StoreProvInfo.dwStoreProvFlags &
  1769. CERT_STORE_PROV_EXTERNAL_FLAG) {
  1770. assert(STORE_TYPE_CACHE == pStore->dwStoreType &&
  1771. IsEmptyStore(pStore));
  1772. pStore->dwStoreType = STORE_TYPE_EXTERNAL;
  1773. }
  1774. if ((dwFlags & CERT_STORE_MANIFOLD_FLAG) &&
  1775. STORE_TYPE_CACHE == pStore->dwStoreType)
  1776. ArchiveManifoldCertificatesInStore(pStore);
  1777. }
  1778. if (dwFlags & CERT_STORE_DELETE_FLAG) {
  1779. if (0 == (pStore->StoreProvInfo.dwStoreProvFlags &
  1780. CERT_STORE_PROV_DELETED_FLAG))
  1781. goto DeleteNotSupported;
  1782. CertCloseStore((HCERTSTORE) pStore, 0);
  1783. pStore = NULL;
  1784. SetLastError(0);
  1785. } else {
  1786. pStore->dwState = STORE_STATE_OPEN;
  1787. if (fShareStore)
  1788. CreateShareStore((LPCWSTR) pvPara, pStore);
  1789. }
  1790. CommonReturn:
  1791. return (HCERTSTORE) pStore;
  1792. ErrorReturn:
  1793. CertCloseStore((HCERTSTORE) pStore, 0);
  1794. pStore = NULL;
  1795. if (dwFlags & CERT_STORE_DELETE_FLAG) {
  1796. if (0 == GetLastError())
  1797. SetLastError((DWORD) E_UNEXPECTED);
  1798. }
  1799. goto CommonReturn;
  1800. TRACE_ERROR(GetOIDFuncAddrError)
  1801. TRACE_ERROR(OpenStoreProvError)
  1802. SET_ERROR(DeleteNotSupported, ERROR_CALL_NOT_IMPLEMENTED)
  1803. }
  1804. //+-------------------------------------------------------------------------
  1805. // Duplicate a cert store handle
  1806. //--------------------------------------------------------------------------
  1807. HCERTSTORE
  1808. WINAPI
  1809. CertDuplicateStore(
  1810. IN HCERTSTORE hCertStore
  1811. )
  1812. {
  1813. PCERT_STORE pStore = (PCERT_STORE) hCertStore;
  1814. assert(pStore->dwState == STORE_STATE_OPEN ||
  1815. pStore->dwState == STORE_STATE_OPENING ||
  1816. pStore->dwState == STORE_STATE_DEFER_CLOSING ||
  1817. pStore->dwState == STORE_STATE_NULL);
  1818. InterlockedIncrement(&pStore->lRefCnt);
  1819. return hCertStore;
  1820. }
  1821. //+-------------------------------------------------------------------------
  1822. // Checks if the store has any Certs, CRLs, CTLs, collection stores or
  1823. // links
  1824. //--------------------------------------------------------------------------
  1825. STATIC BOOL IsEmptyStore(
  1826. IN PCERT_STORE pStore
  1827. )
  1828. {
  1829. DWORD i;
  1830. // Check that all the context lists are empty
  1831. for (i = 0; i < CONTEXT_COUNT; i++) {
  1832. if (pStore->rgpContextListHead[i])
  1833. return FALSE;
  1834. }
  1835. // For collection, check that all stores have been removed
  1836. if (pStore->pStoreListHead)
  1837. return FALSE;
  1838. return TRUE;
  1839. }
  1840. //+-------------------------------------------------------------------------
  1841. // Free the store if empty
  1842. //
  1843. // Store is locked upon input and unlocked or freed upon returning
  1844. //--------------------------------------------------------------------------
  1845. STATIC void FreeStore(
  1846. IN PCERT_STORE pStore)
  1847. {
  1848. if (STORE_STATE_DEFER_CLOSING == pStore->dwState) {
  1849. // Check if duplicated context reference count is zero.
  1850. InterlockedIncrement(&pStore->lDeferCloseRefCnt);
  1851. if (InterlockedDecrement(&pStore->lDeferCloseRefCnt) == 0)
  1852. CloseStore(pStore, 0);
  1853. else
  1854. UnlockStore(pStore);
  1855. } else if (STORE_STATE_CLOSED == pStore->dwState && IsEmptyStore(pStore)) {
  1856. UnlockStore(pStore);
  1857. pStore->dwState = STORE_STATE_DELETED;
  1858. assert(NULL == pStore->pShareStore);
  1859. if (pStore->hAutoResyncEvent)
  1860. CloseHandle(pStore->hAutoResyncEvent);
  1861. DeleteCriticalSection(&pStore->CriticalSection);
  1862. PkiFree(pStore);
  1863. } else
  1864. UnlockStore(pStore);
  1865. }
  1866. // Store is locked upon input and unlocked or freed upon returning
  1867. STATIC BOOL CloseStore(
  1868. IN PCERT_STORE pStore,
  1869. DWORD dwFlags
  1870. )
  1871. {
  1872. DWORD dwFailFlags = 0;
  1873. DWORD i;
  1874. PCONTEXT_ELEMENT pFreeLinkEleHead;
  1875. PCERT_STORE_LINK pStoreLink;
  1876. PCERT_STORE_LINK pFreeStoreLinkHead;
  1877. PPROP_ELEMENT pPropEle;
  1878. DWORD cStoreProvFunc;
  1879. BOOL fFreeFindNext;
  1880. PFN_CERT_STORE_PROV_CLOSE pfnStoreProvClose;
  1881. HCRYPTPROV hCryptProv;
  1882. assert(pStore);
  1883. assert(NULL == pStore->pShareStore);
  1884. CertPerfDecrementStoreCurrentCount();
  1885. // Assert that another thread isn't already waiting for a provider
  1886. // function to complete.
  1887. assert(NULL == pStore->hStoreProvWait);
  1888. // Assert that another thread isn't already waiting for a provider
  1889. // to return from its close callback.
  1890. assert(pStore->dwState != STORE_STATE_CLOSING &&
  1891. pStore->dwState != STORE_STATE_CLOSED);
  1892. if (pStore->hStoreProvWait || pStore->dwState == STORE_STATE_CLOSING ||
  1893. pStore->dwState == STORE_STATE_CLOSED)
  1894. goto UnexpectedError;
  1895. assert(pStore->dwState == STORE_STATE_OPEN ||
  1896. pStore->dwState == STORE_STATE_OPENING ||
  1897. pStore->dwState == STORE_STATE_DEFER_CLOSING);
  1898. pStore->dwState = STORE_STATE_CLOSING;
  1899. cStoreProvFunc = pStore->StoreProvInfo.cStoreProvFunc;
  1900. // By setting the following to 0 inhibits anyone else from calling
  1901. // the provider's functions.
  1902. pStore->StoreProvInfo.cStoreProvFunc = 0;
  1903. if (cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC)
  1904. pfnStoreProvClose = (PFN_CERT_STORE_PROV_CLOSE)
  1905. pStore->StoreProvInfo.rgpvStoreProvFunc[
  1906. CERT_STORE_PROV_CLOSE_FUNC];
  1907. else
  1908. pfnStoreProvClose = NULL;
  1909. hCryptProv = pStore->hCryptProv;
  1910. // By setting the following to 0 inhibits anyone else from using
  1911. // the store's CryptProv handle
  1912. pStore->hCryptProv = 0;
  1913. fFreeFindNext = FALSE;
  1914. if (STORE_TYPE_EXTERNAL == pStore->dwStoreType) {
  1915. // Check if any FIND_NEXT external elements are remaining to be freed
  1916. for (i = 0; i < CONTEXT_COUNT; i++) {
  1917. PCONTEXT_ELEMENT pEle = pStore->rgpContextListHead[i];
  1918. for ( ; pEle; pEle = pEle->pNext) {
  1919. if (pEle->dwFlags & ELEMENT_FIND_NEXT_FLAG) {
  1920. pEle->dwFlags &= ~ELEMENT_FIND_NEXT_FLAG;
  1921. pEle->dwFlags |= ELEMENT_CLOSE_FIND_NEXT_FLAG;
  1922. AddRefContextElement(pEle);
  1923. fFreeFindNext = TRUE;
  1924. }
  1925. }
  1926. }
  1927. }
  1928. if (pStore->lStoreProvRefCnt) {
  1929. // Wait for all the provider functions to complete and all
  1930. // uses of the hCryptProv handle to finish
  1931. if (NULL == (pStore->hStoreProvWait = CreateEvent(
  1932. NULL, // lpsa
  1933. FALSE, // fManualReset
  1934. FALSE, // fInitialState
  1935. NULL))) { // lpszEventName
  1936. assert(pStore->hStoreProvWait);
  1937. goto UnexpectedError;
  1938. }
  1939. while (pStore->lStoreProvRefCnt) {
  1940. UnlockStore(pStore);
  1941. WaitForSingleObject(pStore->hStoreProvWait, INFINITE);
  1942. LockStore(pStore);
  1943. }
  1944. CloseHandle(pStore->hStoreProvWait);
  1945. pStore->hStoreProvWait = NULL;
  1946. }
  1947. if (fFreeFindNext) {
  1948. // Call the provider to free the FIND_NEXT element. Must call
  1949. // without holding a store lock.
  1950. for (i = 0; i < CONTEXT_COUNT; i++) {
  1951. const DWORD dwStoreProvFreeFindIndex =
  1952. rgdwStoreProvFreeFindIndex[i];
  1953. PCONTEXT_ELEMENT pEle = pStore->rgpContextListHead[i];
  1954. while (pEle) {
  1955. if (pEle->dwFlags & ELEMENT_CLOSE_FIND_NEXT_FLAG) {
  1956. PCONTEXT_ELEMENT pEleFree = pEle;
  1957. PFN_CERT_STORE_PROV_FREE_FIND_CERT pfnStoreProvFreeFindCert;
  1958. pEle = pEle->pNext;
  1959. while (pEle && 0 ==
  1960. (pEle->dwFlags & ELEMENT_CLOSE_FIND_NEXT_FLAG))
  1961. pEle = pEle->pNext;
  1962. UnlockStore(pStore);
  1963. if (dwStoreProvFreeFindIndex < cStoreProvFunc &&
  1964. NULL != (pfnStoreProvFreeFindCert =
  1965. (PFN_CERT_STORE_PROV_FREE_FIND_CERT)
  1966. pStore->StoreProvInfo.rgpvStoreProvFunc[
  1967. dwStoreProvFreeFindIndex]))
  1968. pfnStoreProvFreeFindCert(
  1969. pStore->StoreProvInfo.hStoreProv,
  1970. ToCertContext(pEleFree->pEle),
  1971. pEleFree->External.pvProvInfo,
  1972. 0 // dwFlags
  1973. );
  1974. ReleaseContextElement(pEleFree);
  1975. LockStore(pStore);
  1976. } else
  1977. pEle = pEle->pNext;
  1978. }
  1979. }
  1980. }
  1981. if (pfnStoreProvClose) {
  1982. // To prevent any type of deadlock, call the provider functions
  1983. // without a lock on the store.
  1984. //
  1985. // Note our state is CLOSING, not CLOSED. This prevents any other
  1986. // calls to FreeStore() from prematurely deleting the store.
  1987. UnlockStore(pStore);
  1988. pfnStoreProvClose(pStore->StoreProvInfo.hStoreProv, dwFlags);
  1989. LockStore(pStore);
  1990. }
  1991. if (pStore->hStoreProvFuncAddr)
  1992. CryptFreeOIDFunctionAddress(pStore->hStoreProvFuncAddr, 0);
  1993. if (pStore->StoreProvInfo.hStoreProvFuncAddr2)
  1994. CryptFreeOIDFunctionAddress(
  1995. pStore->StoreProvInfo.hStoreProvFuncAddr2, 0);
  1996. // Since hCryptProv was passed to the provider it must be released
  1997. // last!!!
  1998. if (hCryptProv &&
  1999. 0 == (pStore->dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
  2000. CryptReleaseContext(hCryptProv, 0);
  2001. // Iterate through the elements. If the element hasn't already been
  2002. // deleted, remove the store's reference on the element. Remove and
  2003. // free if no other references.
  2004. pFreeLinkEleHead = NULL;
  2005. for (i = 0; i < CONTEXT_COUNT; i++) {
  2006. PCONTEXT_ELEMENT pEle = pStore->rgpContextListHead[i];
  2007. while (pEle) {
  2008. PCONTEXT_ELEMENT pEleNext = pEle->pNext;
  2009. if (0 == (pEle->dwFlags & ELEMENT_DELETED_FLAG)) {
  2010. if (0 == InterlockedDecrement(&pEle->lRefCnt)) {
  2011. if (ELEMENT_TYPE_LINK_CONTEXT == pEle->dwElementType) {
  2012. // The LINK_CONTEXT can't be freed while holding
  2013. // the store lock. Will free later after unlocking.
  2014. RemoveContextElement(pEle);
  2015. pEle->pNext = pFreeLinkEleHead;
  2016. pFreeLinkEleHead = pEle;
  2017. } else {
  2018. assert(ELEMENT_TYPE_CACHE == pEle->dwElementType);
  2019. RemoveAndFreeContextElement(pEle);
  2020. }
  2021. } else
  2022. // Still a reference on the element
  2023. pEle->dwFlags |= ELEMENT_DELETED_FLAG;
  2024. }
  2025. // else
  2026. // A previous delete has already removed the store's reference
  2027. pEle = pEleNext;
  2028. }
  2029. }
  2030. // Iterate through the store links. If the store link hasn't already been
  2031. // deleted, remove the store's reference on the link. Remove and free
  2032. // if no other references.
  2033. pFreeStoreLinkHead = NULL;
  2034. pStoreLink = pStore->pStoreListHead;
  2035. while (pStoreLink) {
  2036. PCERT_STORE_LINK pStoreLinkNext = pStoreLink->pNext;
  2037. if (0 == (pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG)) {
  2038. if (0 == InterlockedDecrement(&pStoreLink->lRefCnt)) {
  2039. // The STORE_LINK can't be freed while holding
  2040. // the store lock. Will free later after unlocking.
  2041. RemoveStoreLink(pStoreLink);
  2042. pStoreLink->pNext = pFreeStoreLinkHead;
  2043. pFreeStoreLinkHead = pStoreLink;
  2044. } else
  2045. // Still a reference on the store link
  2046. pStoreLink->dwFlags |= STORE_LINK_DELETED_FLAG;
  2047. }
  2048. // else
  2049. // A previous delete has already removed the store's reference
  2050. pStoreLink = pStoreLinkNext;
  2051. }
  2052. if (pFreeLinkEleHead || pFreeStoreLinkHead) {
  2053. // Unlock the store before freeing links
  2054. UnlockStore(pStore);
  2055. while (pFreeLinkEleHead) {
  2056. PCONTEXT_ELEMENT pEle = pFreeLinkEleHead;
  2057. pFreeLinkEleHead = pFreeLinkEleHead->pNext;
  2058. FreeLinkContextElement(pEle);
  2059. }
  2060. while (pFreeStoreLinkHead) {
  2061. pStoreLink = pFreeStoreLinkHead;
  2062. pFreeStoreLinkHead = pFreeStoreLinkHead->pNext;
  2063. if (pStore->hAutoResyncEvent) {
  2064. CertControlStore(
  2065. (HCERTSTORE) pStoreLink->pSibling,
  2066. 0, // dwFlags
  2067. CERT_STORE_CTRL_CANCEL_NOTIFY,
  2068. &pStore->hAutoResyncEvent
  2069. );
  2070. }
  2071. FreeStoreLink(pStoreLink);
  2072. }
  2073. LockStore(pStore);
  2074. }
  2075. // Free the store's property elements
  2076. while (pPropEle = pStore->pPropHead) {
  2077. RemovePropElement(&pStore->pPropHead, pPropEle);
  2078. FreePropElement(pPropEle);
  2079. }
  2080. if (dwFlags & CERT_CLOSE_STORE_CHECK_FLAG) {
  2081. if (!IsEmptyStore(pStore))
  2082. dwFailFlags = CERT_CLOSE_STORE_CHECK_FLAG;
  2083. }
  2084. if (dwFlags & CERT_CLOSE_STORE_FORCE_FLAG) {
  2085. UnlockStore(pStore);
  2086. for (i = 0; i < CONTEXT_COUNT; i++) {
  2087. PCONTEXT_ELEMENT pEle;
  2088. while (pEle = pStore->rgpContextListHead[i]) {
  2089. if (ELEMENT_TYPE_CACHE == pEle->dwElementType)
  2090. RemoveAndFreeContextElement(pEle);
  2091. else
  2092. RemoveAndFreeLinkElement(pEle);
  2093. }
  2094. }
  2095. while (pStoreLink = pStore->pStoreListHead)
  2096. RemoveAndFreeStoreLink(pStoreLink);
  2097. LockStore(pStore);
  2098. assert(IsEmptyStore(pStore));
  2099. }
  2100. pStore->dwState = STORE_STATE_CLOSED;
  2101. // Either frees or unlocks the store
  2102. FreeStore(pStore);
  2103. if (dwFlags & dwFailFlags) {
  2104. SetLastError((DWORD) CRYPT_E_PENDING_CLOSE);
  2105. return FALSE;
  2106. } else
  2107. return TRUE;
  2108. UnexpectedError:
  2109. UnlockStore(pStore);
  2110. SetLastError((DWORD) E_UNEXPECTED);
  2111. return FALSE;
  2112. }
  2113. //+-------------------------------------------------------------------------
  2114. // Close a cert store handle.
  2115. //
  2116. // There needs to be a corresponding close for each open and duplicate.
  2117. //
  2118. // Even on the final close, the cert store isn't freed until all of its
  2119. // certificate, CRL and CTL contexts have also been freed.
  2120. //
  2121. // On the final close, the hCryptProv passed to CertOpenStore is
  2122. // CryptReleaseContext'ed.
  2123. //
  2124. // LastError is preserved unless CERT_CLOSE_STORE_CHECK_FLAG is set and FALSE
  2125. // is returned.
  2126. //--------------------------------------------------------------------------
  2127. BOOL
  2128. WINAPI
  2129. CertCloseStore(
  2130. IN HCERTSTORE hCertStore,
  2131. DWORD dwFlags
  2132. )
  2133. {
  2134. BOOL fResult;
  2135. BOOL fClose;
  2136. BOOL fPendingError = FALSE;
  2137. PCERT_STORE pStore = (PCERT_STORE) hCertStore;
  2138. DWORD dwErr = GetLastError(); // For success, don't globber LastError
  2139. if (pStore == NULL)
  2140. return TRUE;
  2141. if (dwFlags & CERT_CLOSE_STORE_FORCE_FLAG) {
  2142. LockStore(pStore);
  2143. if (pStore->lRefCnt != 1) {
  2144. if (dwFlags & CERT_CLOSE_STORE_CHECK_FLAG)
  2145. fPendingError = TRUE;
  2146. }
  2147. pStore->lRefCnt = 0;
  2148. } else if (InterlockedDecrement(&pStore->lRefCnt) == 0) {
  2149. LockStore(pStore);
  2150. if (pStore->dwFlags & CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG) {
  2151. // Check if duplicated context reference count is zero.
  2152. InterlockedIncrement(&pStore->lDeferCloseRefCnt);
  2153. if (InterlockedDecrement(&pStore->lDeferCloseRefCnt) != 0) {
  2154. assert(pStore->dwState == STORE_STATE_OPEN ||
  2155. pStore->dwState == STORE_STATE_OPENING ||
  2156. pStore->dwState == STORE_STATE_DEFER_CLOSING);
  2157. pStore->dwState = STORE_STATE_DEFER_CLOSING;
  2158. UnlockStore(pStore);
  2159. goto PendingCloseReturn;
  2160. }
  2161. }
  2162. } else
  2163. // Still holding a reference count on the store
  2164. goto PendingCloseReturn;
  2165. if (pStore->pShareStore) {
  2166. assert(0 == (dwFlags & CERT_CLOSE_STORE_FORCE_FLAG));
  2167. // There's a window where the shared store's RefCnt can be incremented
  2168. // before being removed from the linked list of share stores.
  2169. fClose = CloseShareStore(pStore);
  2170. } else
  2171. fClose = TRUE;
  2172. // Don't allow the NULL store to be closed
  2173. assert(pStore->dwState != STORE_STATE_NULL);
  2174. if (pStore->dwState == STORE_STATE_NULL) {
  2175. pStore->lRefCnt = 1;
  2176. UnlockStore(pStore);
  2177. SetLastError((DWORD) E_UNEXPECTED);
  2178. return FALSE;
  2179. }
  2180. // CloseStore() unlocks or frees store
  2181. if (fClose)
  2182. fResult = CloseStore(pStore, dwFlags);
  2183. else {
  2184. fResult = TRUE;
  2185. UnlockStore(pStore);
  2186. }
  2187. if (fResult) {
  2188. if (fPendingError) {
  2189. fResult = FALSE;
  2190. SetLastError((DWORD) CRYPT_E_PENDING_CLOSE);
  2191. } else
  2192. SetLastError(dwErr);
  2193. }
  2194. return fResult;
  2195. PendingCloseReturn:
  2196. if (dwFlags & CERT_CLOSE_STORE_CHECK_FLAG) {
  2197. SetLastError((DWORD) CRYPT_E_PENDING_CLOSE);
  2198. fResult = FALSE;
  2199. } else
  2200. fResult = TRUE;
  2201. return fResult;
  2202. }
  2203. //+=========================================================================
  2204. // ArchiveManifoldCertificatesInStore
  2205. //==========================================================================
  2206. #define SORTED_MANIFOLD_ALLOC_COUNT 25
  2207. typedef struct _SORTED_MANIFOLD_ENTRY {
  2208. PCCERT_CONTEXT pCert;
  2209. CRYPT_OBJID_BLOB Value;
  2210. } SORTED_MANIFOLD_ENTRY, *PSORTED_MANIFOLD_ENTRY;
  2211. //+-------------------------------------------------------------------------
  2212. // Called by qsort.
  2213. //
  2214. // The Manifold entries are sorted according to manifold value and
  2215. // the certificate's NotAfter and NotBefore times.
  2216. //--------------------------------------------------------------------------
  2217. STATIC int __cdecl CompareManifoldEntry(
  2218. IN const void *pelem1,
  2219. IN const void *pelem2
  2220. )
  2221. {
  2222. PSORTED_MANIFOLD_ENTRY p1 = (PSORTED_MANIFOLD_ENTRY) pelem1;
  2223. PSORTED_MANIFOLD_ENTRY p2 = (PSORTED_MANIFOLD_ENTRY) pelem2;
  2224. DWORD cb1 = p1->Value.cbData;
  2225. DWORD cb2 = p2->Value.cbData;
  2226. if (cb1 == cb2) {
  2227. int iCmp;
  2228. if (0 == cb1)
  2229. iCmp = 0;
  2230. else
  2231. iCmp = memcmp(p1->Value.pbData, p2->Value.pbData, cb1);
  2232. if (0 != iCmp)
  2233. return iCmp;
  2234. // Same manifold value. Compare the certificate NotAfter and
  2235. // NotBefore times.
  2236. iCmp = CompareFileTime(&p1->pCert->pCertInfo->NotAfter,
  2237. &p2->pCert->pCertInfo->NotAfter);
  2238. if (0 == iCmp)
  2239. iCmp = CompareFileTime(&p1->pCert->pCertInfo->NotBefore,
  2240. &p2->pCert->pCertInfo->NotBefore);
  2241. return iCmp;
  2242. } else if (cb1 < cb2)
  2243. return -1;
  2244. else
  2245. return 1;
  2246. }
  2247. void ArchiveManifoldCertificatesInStore(
  2248. IN PCERT_STORE pStore
  2249. )
  2250. {
  2251. PCONTEXT_ELEMENT pEle;
  2252. DWORD cAlloc = 0;
  2253. DWORD cManifold = 0;
  2254. PSORTED_MANIFOLD_ENTRY pManifold = NULL;
  2255. assert(STORE_TYPE_CACHE == pStore->dwStoreType);
  2256. LockStore(pStore);
  2257. // Create an array of non-archived certificates having the Manifold
  2258. // extension
  2259. pEle = pStore->rgpContextListHead[CERT_STORE_CERTIFICATE_CONTEXT - 1];
  2260. for ( ; pEle; pEle = pEle->pNext) {
  2261. PCCERT_CONTEXT pCert;
  2262. PCERT_INFO pCertInfo;
  2263. PCERT_EXTENSION pExt;
  2264. assert(ELEMENT_TYPE_CACHE == pEle->dwElementType ||
  2265. ELEMENT_TYPE_LINK_CONTEXT == pEle->dwElementType);
  2266. // Skip past deleted or archived elements
  2267. if (pEle->dwFlags & (ELEMENT_DELETED_FLAG | ELEMENT_ARCHIVED_FLAG))
  2268. continue;
  2269. pCert = ToCertContext(pEle);
  2270. pCertInfo = pCert->pCertInfo;
  2271. if (pExt = CertFindExtension(
  2272. szOID_CERT_MANIFOLD,
  2273. pCertInfo->cExtension,
  2274. pCertInfo->rgExtension
  2275. )) {
  2276. if (cManifold >= cAlloc) {
  2277. PSORTED_MANIFOLD_ENTRY pNewManifold;
  2278. if (NULL == (pNewManifold = (PSORTED_MANIFOLD_ENTRY) PkiRealloc(
  2279. pManifold, (cAlloc + SORTED_MANIFOLD_ALLOC_COUNT) *
  2280. sizeof(SORTED_MANIFOLD_ENTRY))))
  2281. continue;
  2282. pManifold = pNewManifold;
  2283. cAlloc += SORTED_MANIFOLD_ALLOC_COUNT;
  2284. }
  2285. pManifold[cManifold].pCert =
  2286. CertDuplicateCertificateContext(pCert);
  2287. pManifold[cManifold].Value = pExt->Value;
  2288. cManifold++;
  2289. }
  2290. }
  2291. UnlockStore(pStore);
  2292. if (cManifold) {
  2293. const CRYPT_DATA_BLOB ManifoldBlob = { 0, NULL };
  2294. // Sort the Manifold entries according to manifold value and
  2295. // the certificate's NotAfter and NotBefore times.
  2296. qsort(pManifold, cManifold, sizeof(SORTED_MANIFOLD_ENTRY),
  2297. CompareManifoldEntry);
  2298. // Set the Archive property for previous entries having the same
  2299. // manifold value.
  2300. for (DWORD i = 0; i < cManifold - 1; i++) {
  2301. if (pManifold[i].Value.cbData == pManifold[i+1].Value.cbData &&
  2302. (0 == pManifold[i].Value.cbData ||
  2303. 0 == memcmp(pManifold[i].Value.pbData,
  2304. pManifold[i+1].Value.pbData,
  2305. pManifold[i].Value.cbData)))
  2306. CertSetCertificateContextProperty(
  2307. pManifold[i].pCert,
  2308. CERT_ARCHIVED_PROP_ID,
  2309. CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG,
  2310. (const void *) &ManifoldBlob
  2311. );
  2312. }
  2313. while (cManifold--)
  2314. CertFreeCertificateContext(pManifold[cManifold].pCert);
  2315. PkiFree(pManifold);
  2316. }
  2317. }
  2318. //+-------------------------------------------------------------------------
  2319. // Write the CERT, CRL, CTL, PROP or END element to the file or memory
  2320. //
  2321. // Upon entry/exit the store is locked.
  2322. //--------------------------------------------------------------------------
  2323. STATIC BOOL WriteStoreElement(
  2324. IN HANDLE h,
  2325. IN PFNWRITE pfnWrite,
  2326. IN DWORD dwEncodingType,
  2327. IN DWORD dwEleType,
  2328. IN BYTE *pbData,
  2329. IN DWORD cbData
  2330. )
  2331. {
  2332. FILE_ELEMENT_HDR EleHdr;
  2333. BOOL fResult;
  2334. EleHdr.dwEleType = dwEleType;
  2335. EleHdr.dwEncodingType = dwEncodingType;
  2336. EleHdr.dwLen = cbData;
  2337. assert(cbData <= MAX_FILE_ELEMENT_DATA_LEN);
  2338. fResult = pfnWrite(
  2339. h,
  2340. &EleHdr,
  2341. sizeof(EleHdr)
  2342. );
  2343. if (fResult && cbData > 0)
  2344. fResult = pfnWrite(
  2345. h,
  2346. pbData,
  2347. cbData
  2348. );
  2349. return fResult;
  2350. }
  2351. //+-------------------------------------------------------------------------
  2352. // Serialize the certs, CRLs, CTLs and properties in the store. Prepend with a
  2353. // file header and append with an end element.
  2354. //--------------------------------------------------------------------------
  2355. STATIC BOOL SerializeStore(
  2356. IN HANDLE h,
  2357. IN PFNWRITE pfnWrite,
  2358. IN PCERT_STORE pStore
  2359. )
  2360. {
  2361. BOOL fResult;
  2362. DWORD i;
  2363. FILE_HDR FileHdr;
  2364. FileHdr.dwVersion = CERT_FILE_VERSION_0;
  2365. FileHdr.dwMagic = CERT_MAGIC;
  2366. if (!pfnWrite(h, &FileHdr, sizeof(FileHdr))) goto WriteError;
  2367. for (i = 0; i < CONTEXT_COUNT; i++) {
  2368. PCONTEXT_ELEMENT pEle = NULL;
  2369. while (pEle = FindElementInStore(pStore, i, &FindAnyInfo, pEle)) {
  2370. if (!SerializeStoreElement(h, pfnWrite, pEle)) {
  2371. ReleaseContextElement(pEle);
  2372. goto SerializeError;
  2373. }
  2374. }
  2375. }
  2376. if (!WriteStoreElement(
  2377. h,
  2378. pfnWrite,
  2379. 0, // dwEncodingType
  2380. FILE_ELEMENT_END_TYPE,
  2381. NULL, // pbData
  2382. 0 // cbData
  2383. )) goto WriteError;
  2384. fResult = TRUE;
  2385. CommonReturn:
  2386. return fResult;
  2387. ErrorReturn:
  2388. fResult = FALSE;
  2389. goto CommonReturn;
  2390. TRACE_ERROR(WriteError)
  2391. TRACE_ERROR(SerializeError)
  2392. }
  2393. //+-------------------------------------------------------------------------
  2394. // Called by CertStoreSaveEx for CERT_STORE_SAVE_AS_STORE
  2395. //--------------------------------------------------------------------------
  2396. STATIC BOOL SaveAsStore(
  2397. IN PCERT_STORE pStore,
  2398. IN DWORD dwSaveTo,
  2399. IN OUT void *pvSaveToPara,
  2400. IN DWORD dwFlags
  2401. )
  2402. {
  2403. BOOL fResult;
  2404. switch (dwSaveTo) {
  2405. case CERT_STORE_SAVE_TO_FILE:
  2406. fResult = SerializeStore(
  2407. (HANDLE) pvSaveToPara,
  2408. WriteToFile,
  2409. pStore);
  2410. break;
  2411. case CERT_STORE_SAVE_TO_MEMORY:
  2412. {
  2413. PCRYPT_DATA_BLOB pData = (PCRYPT_DATA_BLOB) pvSaveToPara;
  2414. MEMINFO MemInfo;
  2415. MemInfo.pByte = pData->pbData;
  2416. if (NULL == pData->pbData)
  2417. MemInfo.cb = 0;
  2418. else
  2419. MemInfo.cb = pData->cbData;
  2420. MemInfo.cbSeek = 0;
  2421. if (fResult = SerializeStore(
  2422. (HANDLE) &MemInfo,
  2423. WriteToMemory,
  2424. pStore)) {
  2425. if (MemInfo.cbSeek > MemInfo.cb && pData->pbData) {
  2426. SetLastError((DWORD) ERROR_MORE_DATA);
  2427. fResult = FALSE;
  2428. }
  2429. pData->cbData = MemInfo.cbSeek;
  2430. } else
  2431. pData->cbData = 0;
  2432. }
  2433. break;
  2434. default:
  2435. SetLastError((DWORD) E_UNEXPECTED);
  2436. fResult = FALSE;
  2437. }
  2438. return fResult;
  2439. }
  2440. //+-------------------------------------------------------------------------
  2441. // Following routines support the SaveAsPKCS7 function
  2442. //--------------------------------------------------------------------------
  2443. STATIC void FreeSaveAsPKCS7Info(
  2444. IN PCMSG_SIGNED_ENCODE_INFO pInfo,
  2445. IN PCCERT_CONTEXT *ppCert,
  2446. IN PCCRL_CONTEXT *ppCrl
  2447. )
  2448. {
  2449. DWORD dwIndex;
  2450. dwIndex = pInfo->cCertEncoded;
  2451. while (dwIndex--)
  2452. CertFreeCertificateContext(ppCert[dwIndex]);
  2453. PkiFree(ppCert);
  2454. PkiFree(pInfo->rgCertEncoded);
  2455. pInfo->cCertEncoded = 0;
  2456. pInfo->rgCertEncoded = NULL;
  2457. dwIndex = pInfo->cCrlEncoded;
  2458. while (dwIndex--)
  2459. CertFreeCRLContext(ppCrl[dwIndex]);
  2460. PkiFree(ppCrl);
  2461. PkiFree(pInfo->rgCrlEncoded);
  2462. pInfo->cCrlEncoded = 0;
  2463. pInfo->rgCrlEncoded = NULL;
  2464. }
  2465. #define SAVE_AS_PKCS7_ALLOC_COUNT 50
  2466. // Upon entry: store is unlocked
  2467. STATIC BOOL InitSaveAsPKCS7Info(
  2468. IN PCERT_STORE pStore,
  2469. IN OUT PCMSG_SIGNED_ENCODE_INFO pInfo,
  2470. OUT PCCERT_CONTEXT **pppCert,
  2471. OUT PCCRL_CONTEXT **pppCrl
  2472. )
  2473. {
  2474. BOOL fResult;
  2475. DWORD cAlloc;
  2476. DWORD dwIndex;
  2477. PCRYPT_DATA_BLOB pBlob;
  2478. PCCERT_CONTEXT pCert = NULL;
  2479. PCCERT_CONTEXT *ppCert = NULL;
  2480. PCCRL_CONTEXT pCrl = NULL;
  2481. PCCRL_CONTEXT *ppCrl = NULL;
  2482. memset(pInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
  2483. pInfo->cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
  2484. dwIndex = 0;
  2485. cAlloc = 0;
  2486. pBlob = NULL;
  2487. while (pCert = CertEnumCertificatesInStore((HCERTSTORE) pStore, pCert)) {
  2488. if (dwIndex >= cAlloc) {
  2489. PCRYPT_DATA_BLOB pNewBlob;
  2490. PCCERT_CONTEXT *ppNewCert;
  2491. if (NULL == (pNewBlob = (PCRYPT_DATA_BLOB) PkiRealloc(
  2492. pBlob, (cAlloc + SAVE_AS_PKCS7_ALLOC_COUNT) *
  2493. sizeof(CRYPT_DATA_BLOB))))
  2494. goto OutOfMemory;
  2495. pBlob = pNewBlob;
  2496. pInfo->rgCertEncoded = pBlob;
  2497. if (NULL == (ppNewCert = (PCCERT_CONTEXT *) PkiRealloc(
  2498. ppCert, (cAlloc + SAVE_AS_PKCS7_ALLOC_COUNT) *
  2499. sizeof(PCCERT_CONTEXT))))
  2500. goto OutOfMemory;
  2501. ppCert = ppNewCert;
  2502. cAlloc += SAVE_AS_PKCS7_ALLOC_COUNT;
  2503. }
  2504. ppCert[dwIndex] = CertDuplicateCertificateContext(pCert);
  2505. pBlob[dwIndex].pbData = pCert->pbCertEncoded;
  2506. pBlob[dwIndex].cbData = pCert->cbCertEncoded;
  2507. pInfo->cCertEncoded = ++dwIndex;
  2508. }
  2509. dwIndex = 0;
  2510. cAlloc = 0;
  2511. pBlob = NULL;
  2512. while (pCrl = CertEnumCRLsInStore((HCERTSTORE) pStore, pCrl)) {
  2513. if (dwIndex >= cAlloc) {
  2514. PCRYPT_DATA_BLOB pNewBlob;
  2515. PCCRL_CONTEXT *ppNewCrl;
  2516. if (NULL == (pNewBlob = (PCRYPT_DATA_BLOB) PkiRealloc(
  2517. pBlob, (cAlloc + SAVE_AS_PKCS7_ALLOC_COUNT) *
  2518. sizeof(CRYPT_DATA_BLOB))))
  2519. goto OutOfMemory;
  2520. pBlob = pNewBlob;
  2521. pInfo->rgCrlEncoded = pBlob;
  2522. if (NULL == (ppNewCrl = (PCCRL_CONTEXT *) PkiRealloc(
  2523. ppCrl, (cAlloc + SAVE_AS_PKCS7_ALLOC_COUNT) *
  2524. sizeof(PCCRL_CONTEXT))))
  2525. goto OutOfMemory;
  2526. ppCrl = ppNewCrl;
  2527. cAlloc += SAVE_AS_PKCS7_ALLOC_COUNT;
  2528. }
  2529. ppCrl[dwIndex] = CertDuplicateCRLContext(pCrl);
  2530. pBlob[dwIndex].pbData = pCrl->pbCrlEncoded;
  2531. pBlob[dwIndex].cbData = pCrl->cbCrlEncoded;
  2532. pInfo->cCrlEncoded = ++dwIndex;
  2533. }
  2534. fResult = TRUE;
  2535. CommonReturn:
  2536. *pppCert = ppCert;
  2537. *pppCrl = ppCrl;
  2538. return fResult;
  2539. ErrorReturn:
  2540. if (pCert)
  2541. CertFreeCertificateContext(pCert);
  2542. if (pCrl)
  2543. CertFreeCRLContext(pCrl);
  2544. FreeSaveAsPKCS7Info(pInfo, ppCert, ppCrl);
  2545. ppCert = NULL;
  2546. ppCrl = NULL;
  2547. fResult = FALSE;
  2548. goto CommonReturn;
  2549. TRACE_ERROR(OutOfMemory)
  2550. }
  2551. STATIC BOOL EncodePKCS7(
  2552. IN DWORD dwEncodingType,
  2553. IN PCMSG_SIGNED_ENCODE_INFO pInfo,
  2554. OUT BYTE *pbEncoded,
  2555. IN OUT DWORD *pcbEncoded
  2556. )
  2557. {
  2558. BOOL fResult = TRUE;
  2559. DWORD cbEncoded;
  2560. if (NULL == pbEncoded)
  2561. cbEncoded = 0;
  2562. else
  2563. cbEncoded = *pcbEncoded;
  2564. if (0 == cbEncoded)
  2565. cbEncoded = CryptMsgCalculateEncodedLength(
  2566. dwEncodingType,
  2567. 0, // dwFlags
  2568. CMSG_SIGNED,
  2569. pInfo,
  2570. NULL, // pszInnerContentObjID
  2571. 0 // cbData
  2572. );
  2573. else {
  2574. HCRYPTMSG hMsg;
  2575. if (NULL == (hMsg = CryptMsgOpenToEncode(
  2576. dwEncodingType,
  2577. 0, // dwFlags
  2578. CMSG_SIGNED,
  2579. pInfo,
  2580. NULL, // pszInnerContentObjID
  2581. NULL // pStreamInfo
  2582. )))
  2583. cbEncoded = 0;
  2584. else {
  2585. if (CryptMsgUpdate(
  2586. hMsg,
  2587. NULL, // pbData
  2588. 0, // cbData
  2589. TRUE // fFinal
  2590. ))
  2591. fResult = CryptMsgGetParam(
  2592. hMsg,
  2593. CMSG_CONTENT_PARAM,
  2594. 0, // dwIndex
  2595. pbEncoded,
  2596. &cbEncoded);
  2597. else
  2598. cbEncoded = 0;
  2599. CryptMsgClose(hMsg);
  2600. }
  2601. }
  2602. if (fResult) {
  2603. if (0 == cbEncoded)
  2604. fResult = FALSE;
  2605. else if (pbEncoded && cbEncoded > *pcbEncoded) {
  2606. SetLastError((DWORD) ERROR_MORE_DATA);
  2607. fResult = FALSE;
  2608. }
  2609. }
  2610. *pcbEncoded = cbEncoded;
  2611. return fResult;
  2612. }
  2613. //+-------------------------------------------------------------------------
  2614. // Called by CertStoreSaveEx for CERT_STORE_SAVE_AS_PKCS7
  2615. //--------------------------------------------------------------------------
  2616. STATIC BOOL SaveAsPKCS7(
  2617. IN PCERT_STORE pStore,
  2618. IN DWORD dwEncodingType,
  2619. IN DWORD dwSaveTo,
  2620. IN OUT void *pvSaveToPara,
  2621. IN DWORD dwFlags
  2622. )
  2623. {
  2624. BOOL fResult;
  2625. CMSG_SIGNED_ENCODE_INFO SignedEncodeInfo;
  2626. PCCERT_CONTEXT *ppCert;
  2627. PCCRL_CONTEXT *ppCrl;
  2628. BYTE *pbEncoded = NULL;
  2629. DWORD cbEncoded;
  2630. if (0 == GET_CERT_ENCODING_TYPE(dwEncodingType) ||
  2631. 0 == GET_CMSG_ENCODING_TYPE(dwEncodingType)) {
  2632. SetLastError((DWORD) E_INVALIDARG);
  2633. return FALSE;
  2634. }
  2635. if (!InitSaveAsPKCS7Info(
  2636. pStore,
  2637. &SignedEncodeInfo,
  2638. &ppCert,
  2639. &ppCrl)) goto InitInfoError;
  2640. switch (dwSaveTo) {
  2641. case CERT_STORE_SAVE_TO_FILE:
  2642. if (!EncodePKCS7(
  2643. dwEncodingType,
  2644. &SignedEncodeInfo,
  2645. NULL, // pbEncoded
  2646. &cbEncoded)) goto EncodePKCS7Error;
  2647. if (NULL == (pbEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  2648. goto OutOfMemory;
  2649. if (!EncodePKCS7(
  2650. dwEncodingType,
  2651. &SignedEncodeInfo,
  2652. pbEncoded,
  2653. &cbEncoded))
  2654. goto EncodePKCS7Error;
  2655. else {
  2656. DWORD cbBytesWritten;
  2657. if (!WriteFile(
  2658. (HANDLE) pvSaveToPara,
  2659. pbEncoded,
  2660. cbEncoded,
  2661. &cbBytesWritten,
  2662. NULL // lpOverlapped
  2663. )) goto WriteError;
  2664. }
  2665. break;
  2666. case CERT_STORE_SAVE_TO_MEMORY:
  2667. {
  2668. PCRYPT_DATA_BLOB pData = (PCRYPT_DATA_BLOB) pvSaveToPara;
  2669. if (!EncodePKCS7(
  2670. dwEncodingType,
  2671. &SignedEncodeInfo,
  2672. pData->pbData,
  2673. &pData->cbData)) goto EncodePKCS7Error;
  2674. }
  2675. break;
  2676. default:
  2677. goto UnexpectedError;
  2678. }
  2679. fResult = TRUE;
  2680. CommonReturn:
  2681. FreeSaveAsPKCS7Info(&SignedEncodeInfo, ppCert, ppCrl);
  2682. PkiFree(pbEncoded);
  2683. return fResult;
  2684. ErrorReturn:
  2685. fResult = FALSE;
  2686. goto CommonReturn;
  2687. TRACE_ERROR(InitInfoError)
  2688. TRACE_ERROR(EncodePKCS7Error)
  2689. TRACE_ERROR(WriteError)
  2690. TRACE_ERROR(OutOfMemory)
  2691. SET_ERROR(UnexpectedError, E_UNEXPECTED)
  2692. }
  2693. //+-------------------------------------------------------------------------
  2694. // Save the cert store. Enhanced version with lots of options.
  2695. //--------------------------------------------------------------------------
  2696. BOOL
  2697. WINAPI
  2698. CertSaveStore(
  2699. IN HCERTSTORE hCertStore,
  2700. IN DWORD dwEncodingType,
  2701. IN DWORD dwSaveAs,
  2702. IN DWORD dwSaveTo,
  2703. IN OUT void *pvSaveToPara,
  2704. IN DWORD dwFlags
  2705. )
  2706. {
  2707. assert(pvSaveToPara);
  2708. switch (dwSaveTo) {
  2709. case CERT_STORE_SAVE_TO_FILENAME_A:
  2710. {
  2711. BOOL fResult;
  2712. LPWSTR pwszFilename;
  2713. if (NULL == (pwszFilename = MkWStr((LPSTR) pvSaveToPara)))
  2714. return FALSE;
  2715. fResult = CertSaveStore(
  2716. hCertStore,
  2717. dwEncodingType,
  2718. dwSaveAs,
  2719. CERT_STORE_SAVE_TO_FILENAME_W,
  2720. (void *) pwszFilename,
  2721. dwFlags);
  2722. FreeWStr(pwszFilename);
  2723. return fResult;
  2724. }
  2725. break;
  2726. case CERT_STORE_SAVE_TO_FILENAME_W:
  2727. {
  2728. BOOL fResult;
  2729. HANDLE hFile;
  2730. if (INVALID_HANDLE_VALUE == (hFile = CreateFileU(
  2731. (LPWSTR) pvSaveToPara,
  2732. GENERIC_WRITE,
  2733. 0, // fdwShareMode
  2734. NULL, // lpsa
  2735. CREATE_ALWAYS,
  2736. FILE_ATTRIBUTE_NORMAL,
  2737. NULL // hTemplateFile
  2738. )))
  2739. return FALSE;
  2740. fResult = CertSaveStore(
  2741. hCertStore,
  2742. dwEncodingType,
  2743. dwSaveAs,
  2744. CERT_STORE_SAVE_TO_FILE,
  2745. (void *) hFile,
  2746. dwFlags);
  2747. CloseHandle(hFile);
  2748. return fResult;
  2749. }
  2750. break;
  2751. case CERT_STORE_SAVE_TO_FILE:
  2752. case CERT_STORE_SAVE_TO_MEMORY:
  2753. break;
  2754. default:
  2755. SetLastError((DWORD) E_INVALIDARG);
  2756. return FALSE;
  2757. }
  2758. switch (dwSaveAs) {
  2759. case CERT_STORE_SAVE_AS_STORE:
  2760. return SaveAsStore(
  2761. (PCERT_STORE) hCertStore,
  2762. dwSaveTo,
  2763. pvSaveToPara,
  2764. dwFlags);
  2765. break;
  2766. case CERT_STORE_SAVE_AS_PKCS7:
  2767. return SaveAsPKCS7(
  2768. (PCERT_STORE) hCertStore,
  2769. dwEncodingType,
  2770. dwSaveTo,
  2771. pvSaveToPara,
  2772. dwFlags);
  2773. break;
  2774. default:
  2775. SetLastError((DWORD) E_INVALIDARG);
  2776. return FALSE;
  2777. }
  2778. }
  2779. //+=========================================================================
  2780. // Share Element Find, Create and Release functions
  2781. //==========================================================================
  2782. static inline DWORD GetShareElementHashBucketIndex(
  2783. IN BYTE *pbSha1Hash
  2784. )
  2785. {
  2786. return pbSha1Hash[0] % SHARE_ELEMENT_HASH_BUCKET_COUNT;
  2787. }
  2788. // Find existing share element identified by its sha1 hash.
  2789. // For a match, the returned share element is AddRef'ed.
  2790. //
  2791. // The dwContextType is a sanity check. Different context types should never
  2792. // match.
  2793. STATIC PSHARE_ELEMENT FindShareElement(
  2794. IN BYTE *pbSha1Hash,
  2795. IN DWORD dwContextType
  2796. )
  2797. {
  2798. PSHARE_ELEMENT pShareEle;
  2799. DWORD dwBucketIndex = GetShareElementHashBucketIndex(pbSha1Hash);
  2800. EnterCriticalSection(&ShareElementCriticalSection);
  2801. for (pShareEle = rgpShareElementHashBucket[dwBucketIndex];
  2802. NULL != pShareEle;
  2803. pShareEle = pShareEle->pNext)
  2804. {
  2805. if (0 == memcmp(pbSha1Hash, pShareEle->rgbSha1Hash, SHA1_HASH_LEN) &&
  2806. dwContextType == pShareEle->dwContextType) {
  2807. pShareEle->dwRefCnt++;
  2808. break;
  2809. }
  2810. }
  2811. LeaveCriticalSection(&ShareElementCriticalSection);
  2812. return pShareEle;
  2813. }
  2814. // Upon input pbEncoded has been allocated. Not freed on a NULL error
  2815. // return.
  2816. //
  2817. // The returned share element has been AddRef'ed
  2818. STATIC PSHARE_ELEMENT CreateShareElement(
  2819. IN BYTE *pbSha1Hash,
  2820. IN DWORD dwContextType,
  2821. IN DWORD dwEncodingType,
  2822. IN BYTE *pbEncoded,
  2823. IN DWORD cbEncoded
  2824. )
  2825. {
  2826. PSHARE_ELEMENT pShareEle = NULL;
  2827. DWORD dwBucketIndex = GetShareElementHashBucketIndex(pbSha1Hash);
  2828. LPCSTR pszStructType;
  2829. if (NULL == (pShareEle = (PSHARE_ELEMENT) PkiZeroAlloc(
  2830. sizeof(SHARE_ELEMENT))))
  2831. goto OutOfMemory;
  2832. memcpy(pShareEle->rgbSha1Hash, pbSha1Hash, SHA1_HASH_LEN);
  2833. pShareEle->dwContextType = dwContextType;
  2834. pShareEle->pbEncoded = pbEncoded;
  2835. pShareEle->cbEncoded = cbEncoded;
  2836. // Decode according to the context type. Note, a CTL share element
  2837. // doesn't have a decoded CTL.
  2838. pszStructType = rgpszShareElementStructType[dwContextType];
  2839. if (pszStructType) {
  2840. if (NULL == (pShareEle->pvInfo = AllocAndDecodeObject(
  2841. dwEncodingType,
  2842. pszStructType,
  2843. pbEncoded,
  2844. cbEncoded
  2845. )))
  2846. goto DecodeError;
  2847. }
  2848. pShareEle->dwRefCnt = 1;
  2849. // Insert at beginning of share element's hash bucket list
  2850. EnterCriticalSection(&ShareElementCriticalSection);
  2851. if (rgpShareElementHashBucket[dwBucketIndex]) {
  2852. assert(NULL == rgpShareElementHashBucket[dwBucketIndex]->pPrev);
  2853. rgpShareElementHashBucket[dwBucketIndex]->pPrev = pShareEle;
  2854. pShareEle->pNext = rgpShareElementHashBucket[dwBucketIndex];
  2855. }
  2856. rgpShareElementHashBucket[dwBucketIndex] = pShareEle;
  2857. LeaveCriticalSection(&ShareElementCriticalSection);
  2858. switch (dwContextType) {
  2859. case CERT_STORE_CERTIFICATE_CONTEXT - 1:
  2860. CertPerfIncrementCertElementCurrentCount();
  2861. CertPerfIncrementCertElementTotalCount();
  2862. break;
  2863. case CERT_STORE_CRL_CONTEXT - 1:
  2864. CertPerfIncrementCrlElementCurrentCount();
  2865. CertPerfIncrementCrlElementTotalCount();
  2866. break;
  2867. case CERT_STORE_CTL_CONTEXT - 1:
  2868. CertPerfIncrementCtlElementCurrentCount();
  2869. CertPerfIncrementCtlElementTotalCount();
  2870. break;
  2871. }
  2872. CommonReturn:
  2873. return pShareEle;
  2874. ErrorReturn:
  2875. if (pShareEle) {
  2876. PkiFree(pShareEle->pvInfo);
  2877. PkiFree(pShareEle);
  2878. pShareEle = NULL;
  2879. }
  2880. goto CommonReturn;
  2881. TRACE_ERROR(OutOfMemory)
  2882. TRACE_ERROR(DecodeError)
  2883. }
  2884. STATIC void ReleaseShareElement(
  2885. IN PSHARE_ELEMENT pShareEle
  2886. )
  2887. {
  2888. EnterCriticalSection(&ShareElementCriticalSection);
  2889. if (0 == --pShareEle->dwRefCnt) {
  2890. if (pShareEle->pNext)
  2891. pShareEle->pNext->pPrev = pShareEle->pPrev;
  2892. if (pShareEle->pPrev)
  2893. pShareEle->pPrev->pNext = pShareEle->pNext;
  2894. else {
  2895. DWORD dwBucketIndex =
  2896. GetShareElementHashBucketIndex(pShareEle->rgbSha1Hash);
  2897. assert(rgpShareElementHashBucket[dwBucketIndex] == pShareEle);
  2898. if (rgpShareElementHashBucket[dwBucketIndex] == pShareEle)
  2899. rgpShareElementHashBucket[dwBucketIndex] = pShareEle->pNext;
  2900. }
  2901. switch (pShareEle->dwContextType) {
  2902. case CERT_STORE_CERTIFICATE_CONTEXT - 1:
  2903. CertPerfDecrementCertElementCurrentCount();
  2904. break;
  2905. case CERT_STORE_CRL_CONTEXT - 1:
  2906. CertPerfDecrementCrlElementCurrentCount();
  2907. break;
  2908. case CERT_STORE_CTL_CONTEXT - 1:
  2909. CertPerfDecrementCtlElementCurrentCount();
  2910. break;
  2911. }
  2912. PkiFree(pShareEle->pbEncoded);
  2913. PkiFree(pShareEle->pvInfo);
  2914. PkiFree(pShareEle);
  2915. }
  2916. LeaveCriticalSection(&ShareElementCriticalSection);
  2917. }
  2918. //+-------------------------------------------------------------------------
  2919. // Read and allocate the store element. Possibly adjust the cbEncoded to
  2920. // excluded trailing bytes.
  2921. //--------------------------------------------------------------------------
  2922. STATIC ReadStoreElement(
  2923. IN HANDLE h,
  2924. IN PFNREAD pfnRead,
  2925. IN DWORD dwEncodingType,
  2926. OUT BYTE **ppbEncoded,
  2927. IN OUT DWORD *pcbEncoded
  2928. )
  2929. {
  2930. BOOL fResult;
  2931. BYTE *pbEncoded = NULL;
  2932. DWORD cbEncoded = *pcbEncoded;
  2933. if (NULL == (pbEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  2934. goto OutOfMemory;
  2935. if (!pfnRead(
  2936. h,
  2937. pbEncoded,
  2938. cbEncoded))
  2939. goto ReadError;
  2940. cbEncoded = AdjustEncodedLength(dwEncodingType, pbEncoded, cbEncoded);
  2941. fResult = TRUE;
  2942. CommonReturn:
  2943. *ppbEncoded = pbEncoded;
  2944. *pcbEncoded = cbEncoded;
  2945. return fResult;
  2946. ErrorReturn:
  2947. PkiFree(pbEncoded);
  2948. pbEncoded = NULL;
  2949. fResult = FALSE;
  2950. goto CommonReturn;
  2951. TRACE_ERROR(OutOfMemory)
  2952. TRACE_ERROR(ReadError)
  2953. }
  2954. //+-------------------------------------------------------------------------
  2955. // Create the store element.
  2956. //
  2957. // If CERT_STORE_SHARE_CONTEXT_FLAG is set, a share element is either found
  2958. // or created.
  2959. //
  2960. // Normally, the sha1 hash will have been read as a serialized property
  2961. // and passed in and won't need to be calculated here. Also, for a
  2962. // found share element, the encoded element bytes can be skipped instead
  2963. // of being allocated and read.
  2964. //
  2965. // In all cases, the context specific CreateElement function is called.
  2966. //--------------------------------------------------------------------------
  2967. STATIC PCONTEXT_ELEMENT CreateStoreElement(
  2968. IN HANDLE h,
  2969. IN PFNREAD pfnRead,
  2970. IN PFNSKIP pfnSkip,
  2971. IN PCERT_STORE pStore,
  2972. IN DWORD dwEncodingType,
  2973. IN DWORD dwContextType,
  2974. IN DWORD cbEncoded,
  2975. IN OPTIONAL BYTE *pbSha1Hash
  2976. )
  2977. {
  2978. PCONTEXT_ELEMENT pEle = NULL;
  2979. PSHARE_ELEMENT pShareEle = NULL;
  2980. BYTE *pbEncoded = NULL;
  2981. assert(pStore);
  2982. if (pStore->dwFlags & CERT_STORE_SHARE_CONTEXT_FLAG) {
  2983. BYTE rgbSha1Hash[SHA1_HASH_LEN];
  2984. if (NULL == pbSha1Hash) {
  2985. DWORD cbData;
  2986. if (!ReadStoreElement(h, pfnRead, dwEncodingType,
  2987. &pbEncoded, &cbEncoded))
  2988. goto ReadError;
  2989. cbData = SHA1_HASH_LEN;
  2990. if (!CryptHashCertificate(
  2991. 0, // hCryptProv
  2992. CALG_SHA1,
  2993. 0, // dwFlags
  2994. pbEncoded,
  2995. cbEncoded,
  2996. rgbSha1Hash,
  2997. &cbData) || SHA1_HASH_LEN != cbData)
  2998. goto HashError;
  2999. pbSha1Hash = rgbSha1Hash;
  3000. }
  3001. pShareEle = FindShareElement(pbSha1Hash, dwContextType);
  3002. if (pShareEle) {
  3003. if (NULL == pbEncoded) {
  3004. if (!pfnSkip(
  3005. h,
  3006. cbEncoded))
  3007. goto SkipError;
  3008. } else
  3009. PkiFree(pbEncoded);
  3010. pbEncoded = pShareEle->pbEncoded;
  3011. cbEncoded = pShareEle->cbEncoded;
  3012. } else {
  3013. if (NULL == pbEncoded) {
  3014. if (!ReadStoreElement(h, pfnRead, dwEncodingType,
  3015. &pbEncoded, &cbEncoded))
  3016. goto ReadError;
  3017. }
  3018. if (NULL == (pShareEle = CreateShareElement(
  3019. pbSha1Hash,
  3020. dwContextType,
  3021. dwEncodingType,
  3022. pbEncoded,
  3023. cbEncoded
  3024. )))
  3025. goto CreateShareElementError;
  3026. assert(pbEncoded == pShareEle->pbEncoded);
  3027. assert(cbEncoded == pShareEle->cbEncoded);
  3028. }
  3029. } else {
  3030. if (!ReadStoreElement(h, pfnRead, dwEncodingType,
  3031. &pbEncoded, &cbEncoded))
  3032. goto ReadError;
  3033. }
  3034. if (NULL == (pEle = rgpfnCreateElement[dwContextType](
  3035. pStore,
  3036. dwEncodingType,
  3037. pbEncoded,
  3038. cbEncoded,
  3039. pShareEle
  3040. )))
  3041. goto CreateElementError;
  3042. CommonReturn:
  3043. return pEle;
  3044. ErrorReturn:
  3045. if (pShareEle) {
  3046. if (pbEncoded != pShareEle->pbEncoded)
  3047. PkiFree(pbEncoded);
  3048. ReleaseShareElement(pShareEle);
  3049. } else {
  3050. PkiFree(pbEncoded);
  3051. }
  3052. assert(NULL == pEle);
  3053. goto CommonReturn;
  3054. TRACE_ERROR(ReadError)
  3055. TRACE_ERROR(HashError)
  3056. TRACE_ERROR(SkipError)
  3057. TRACE_ERROR(CreateShareElementError)
  3058. TRACE_ERROR(CreateElementError)
  3059. }
  3060. //+-------------------------------------------------------------------------
  3061. // Loads a serialized certificate, CRL or CTL with properties into a store.
  3062. //
  3063. // Also supports decoding of KeyIdentifier properties.
  3064. //--------------------------------------------------------------------------
  3065. STATIC DWORD LoadStoreElement(
  3066. IN HANDLE h,
  3067. IN PFNREAD pfnRead,
  3068. IN PFNSKIP pfnSkip,
  3069. IN DWORD cbReadSize,
  3070. IN OPTIONAL PCERT_STORE pStore, // NULL for fKeyIdAllowed
  3071. IN DWORD dwAddDisposition,
  3072. IN DWORD dwContextTypeFlags,
  3073. OUT OPTIONAL DWORD *pdwContextType,
  3074. OUT OPTIONAL const void **ppvContext,
  3075. IN BOOL fKeyIdAllowed = FALSE
  3076. )
  3077. {
  3078. BYTE *pbEncoded = NULL;
  3079. PCONTEXT_ELEMENT pContextEle = NULL;
  3080. PCONTEXT_ELEMENT pStoreEle = NULL;
  3081. PPROP_ELEMENT pPropHead = NULL;
  3082. BYTE *pbSha1Hash = NULL; // not allocated
  3083. FILE_ELEMENT_HDR EleHdr;
  3084. BOOL fIsProp;
  3085. DWORD csStatus;
  3086. DWORD dwContextType;
  3087. do {
  3088. fIsProp = FALSE;
  3089. if (!pfnRead(
  3090. h,
  3091. &EleHdr,
  3092. sizeof(EleHdr))) goto ReadError;
  3093. if (EleHdr.dwEleType == FILE_ELEMENT_END_TYPE) {
  3094. if (pPropHead != NULL)
  3095. goto PrematureEndError;
  3096. csStatus = CSEnd;
  3097. goto ZeroOutParameterReturn;
  3098. }
  3099. if (EleHdr.dwLen > cbReadSize)
  3100. goto ExceedReadSizeError;
  3101. switch (EleHdr.dwEleType) {
  3102. case FILE_ELEMENT_CERT_TYPE:
  3103. dwContextType = CERT_STORE_CERTIFICATE_CONTEXT;
  3104. break;
  3105. case FILE_ELEMENT_CRL_TYPE:
  3106. dwContextType = CERT_STORE_CRL_CONTEXT;
  3107. break;
  3108. case FILE_ELEMENT_CTL_TYPE:
  3109. dwContextType = CERT_STORE_CTL_CONTEXT;
  3110. break;
  3111. default:
  3112. dwContextType = 0;
  3113. }
  3114. if (0 != dwContextType) {
  3115. if (0 == (dwContextTypeFlags & (1 << dwContextType)))
  3116. goto ContextNotAllowedError;
  3117. if (NULL == (pContextEle = CreateStoreElement(
  3118. h,
  3119. pfnRead,
  3120. pfnSkip,
  3121. pStore,
  3122. EleHdr.dwEncodingType,
  3123. dwContextType - 1,
  3124. EleHdr.dwLen,
  3125. pbSha1Hash
  3126. )))
  3127. goto CreateStoreElementError;
  3128. pbEncoded = NULL;
  3129. pContextEle->Cache.pPropHead = pPropHead;
  3130. pPropHead = NULL;
  3131. if (!AddElementToStore(pStore, pContextEle, dwAddDisposition,
  3132. ppvContext ? &pStoreEle : NULL))
  3133. goto AddStoreElementError;
  3134. else
  3135. pContextEle = NULL;
  3136. if (pdwContextType)
  3137. *pdwContextType = dwContextType;
  3138. if (ppvContext)
  3139. *((PCCERT_CONTEXT *) ppvContext) = ToCertContext(pStoreEle);
  3140. } else {
  3141. // EleHdr.dwLen may be 0 for a property
  3142. if (EleHdr.dwLen > 0) {
  3143. if (NULL == (pbEncoded = (BYTE *) PkiNonzeroAlloc(
  3144. EleHdr.dwLen)))
  3145. goto OutOfMemory;
  3146. if (!pfnRead(
  3147. h,
  3148. pbEncoded,
  3149. EleHdr.dwLen)) goto ReadError;
  3150. }
  3151. if (EleHdr.dwEleType == FILE_ELEMENT_KEYID_TYPE) {
  3152. PKEYID_ELEMENT pKeyIdEle;
  3153. if (!fKeyIdAllowed)
  3154. goto KeyIdNotAllowedError;
  3155. if (NULL == (pKeyIdEle = CreateKeyIdElement(
  3156. pbEncoded,
  3157. EleHdr.dwLen
  3158. )))
  3159. goto CreateKeyIdElementError;
  3160. pbEncoded = NULL;
  3161. pKeyIdEle->pPropHead = pPropHead;
  3162. pPropHead = NULL;
  3163. assert(ppvContext);
  3164. if (ppvContext)
  3165. *((PKEYID_ELEMENT *) ppvContext) = pKeyIdEle;
  3166. } else if (EleHdr.dwEleType > CERT_LAST_USER_PROP_ID) {
  3167. // Silently discard any IDs exceeding 0xFFFF. The
  3168. // FIRST_USER_PROP_ID used to start at 0x10000.
  3169. fIsProp = TRUE;
  3170. PkiFree(pbEncoded);
  3171. pbEncoded = NULL;
  3172. } else if (EleHdr.dwEleType == CERT_KEY_CONTEXT_PROP_ID) {
  3173. goto InvalidPropId;
  3174. } else {
  3175. PPROP_ELEMENT pPropEle;
  3176. fIsProp = TRUE;
  3177. if (NULL == (pPropEle = CreatePropElement(
  3178. EleHdr.dwEleType,
  3179. 0, // dwFlags
  3180. pbEncoded,
  3181. EleHdr.dwLen
  3182. ))) goto CreatePropElementError;
  3183. if (CERT_SHA1_HASH_PROP_ID == EleHdr.dwEleType &&
  3184. SHA1_HASH_LEN == EleHdr.dwLen)
  3185. pbSha1Hash = pbEncoded;
  3186. pbEncoded = NULL;
  3187. AddPropElement(&pPropHead, pPropEle);
  3188. }
  3189. }
  3190. } while (fIsProp);
  3191. assert(pPropHead == NULL);
  3192. assert(pbEncoded == NULL);
  3193. assert(pContextEle == NULL);
  3194. csStatus = CSContinue;
  3195. CommonReturn:
  3196. return csStatus;
  3197. ErrorReturn:
  3198. PkiFree(pbEncoded);
  3199. if (pContextEle)
  3200. FreeContextElement(pContextEle);
  3201. while (pPropHead) {
  3202. PPROP_ELEMENT pEle = pPropHead;
  3203. pPropHead = pPropHead->pNext;
  3204. FreePropElement(pEle);
  3205. }
  3206. csStatus = CSError;
  3207. ZeroOutParameterReturn:
  3208. if (pdwContextType)
  3209. *pdwContextType = 0;
  3210. if (ppvContext)
  3211. *ppvContext = NULL;
  3212. goto CommonReturn;
  3213. TRACE_ERROR(ReadError)
  3214. SET_ERROR(PrematureEndError, CRYPT_E_FILE_ERROR)
  3215. SET_ERROR(ExceedReadSizeError, CRYPT_E_FILE_ERROR)
  3216. TRACE_ERROR(OutOfMemory)
  3217. SET_ERROR(ContextNotAllowedError, E_INVALIDARG)
  3218. TRACE_ERROR(CreateStoreElementError)
  3219. TRACE_ERROR(AddStoreElementError)
  3220. TRACE_ERROR(CreatePropElementError)
  3221. SET_ERROR(KeyIdNotAllowedError, E_INVALIDARG)
  3222. TRACE_ERROR(CreateKeyIdElementError)
  3223. SET_ERROR(InvalidPropId, CRYPT_E_FILE_ERROR)
  3224. }
  3225. //+-------------------------------------------------------------------------
  3226. // Add the serialized certificate, CRL or CTL element to the store.
  3227. //--------------------------------------------------------------------------
  3228. BOOL
  3229. WINAPI
  3230. CertAddSerializedElementToStore(
  3231. IN HCERTSTORE hCertStore,
  3232. IN const BYTE *pbElement,
  3233. IN DWORD cbElement,
  3234. IN DWORD dwAddDisposition,
  3235. IN DWORD dwFlags,
  3236. IN DWORD dwContextTypeFlags,
  3237. OUT OPTIONAL DWORD *pdwContextType,
  3238. OUT OPTIONAL const void **ppvContext
  3239. )
  3240. {
  3241. MEMINFO MemInfo;
  3242. DWORD csStatus;
  3243. PCERT_STORE pStore =
  3244. hCertStore ? (PCERT_STORE) hCertStore : &NullCertStore;
  3245. MemInfo.pByte = (BYTE*) pbElement;
  3246. MemInfo.cb = cbElement;
  3247. MemInfo.cbSeek = 0;
  3248. csStatus = LoadStoreElement(
  3249. (HANDLE) &MemInfo,
  3250. ReadFromMemory,
  3251. SkipInMemory,
  3252. cbElement,
  3253. pStore,
  3254. dwAddDisposition,
  3255. dwContextTypeFlags,
  3256. pdwContextType,
  3257. ppvContext);
  3258. if (CSContinue == csStatus)
  3259. return TRUE;
  3260. else {
  3261. if (CSEnd == csStatus)
  3262. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  3263. return FALSE;
  3264. }
  3265. }
  3266. //+=========================================================================
  3267. // Store Control APIs
  3268. //==========================================================================
  3269. STATIC BOOL EnableAutoResync(
  3270. IN PCERT_STORE pStore
  3271. )
  3272. {
  3273. BOOL fResult;
  3274. HANDLE hEvent;
  3275. fResult = TRUE;
  3276. hEvent = NULL;
  3277. LockStore(pStore);
  3278. if (NULL == pStore->hAutoResyncEvent) {
  3279. // Create event to be notified
  3280. if (hEvent = CreateEvent(
  3281. NULL, // lpsa
  3282. FALSE, // fManualReset
  3283. FALSE, // fInitialState
  3284. NULL)) // lpszEventName
  3285. pStore->hAutoResyncEvent = hEvent;
  3286. else
  3287. fResult = FALSE;
  3288. }
  3289. UnlockStore(pStore);
  3290. if (!fResult)
  3291. goto CreateEventError;
  3292. if (hEvent) {
  3293. if (!CertControlStore(
  3294. (HCERTSTORE) pStore,
  3295. CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG,
  3296. CERT_STORE_CTRL_NOTIFY_CHANGE,
  3297. &hEvent
  3298. )) {
  3299. DWORD dwErr = GetLastError();
  3300. // Bug 484023 Certificate store event handle closed before
  3301. // being removed from list.
  3302. CertControlStore(
  3303. (HCERTSTORE) pStore,
  3304. 0, // dwFlags
  3305. CERT_STORE_CTRL_CANCEL_NOTIFY,
  3306. &hEvent
  3307. );
  3308. LockStore(pStore);
  3309. pStore->hAutoResyncEvent = NULL;
  3310. UnlockStore(pStore);
  3311. CloseHandle(hEvent);
  3312. SetLastError(dwErr);
  3313. goto CtrlNotifyChangeError;
  3314. }
  3315. }
  3316. CommonReturn:
  3317. return fResult;
  3318. ErrorReturn:
  3319. fResult = FALSE;
  3320. goto CommonReturn;
  3321. TRACE_ERROR(CreateEventError)
  3322. TRACE_ERROR(CtrlNotifyChangeError)
  3323. }
  3324. // For a collection, iterates through all the sibling stores. For an error,
  3325. // continues on to the remaining stores. LastError is updated with the
  3326. // LastError of the first failing store.
  3327. STATIC BOOL ControlCollectionStore(
  3328. IN PCERT_STORE pCollection,
  3329. IN DWORD dwFlags,
  3330. IN DWORD dwCtrlType,
  3331. IN void const *pvCtrlPara
  3332. )
  3333. {
  3334. BOOL fResult = TRUE;
  3335. BOOL fOneSiblingSuccess = FALSE;
  3336. DWORD dwError = ERROR_CALL_NOT_IMPLEMENTED;
  3337. PCERT_STORE_LINK pStoreLink;
  3338. PCERT_STORE_LINK pPrevStoreLink = NULL;
  3339. // Iterate through all the siblings and call the control function
  3340. LockStore(pCollection);
  3341. pStoreLink = pCollection->pStoreListHead;
  3342. for (; pStoreLink; pStoreLink = pStoreLink->pNext) {
  3343. // Advance past deleted store link
  3344. if (pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG)
  3345. continue;
  3346. AddRefStoreLink(pStoreLink);
  3347. UnlockStore(pCollection);
  3348. if (pPrevStoreLink)
  3349. ReleaseStoreLink(pPrevStoreLink);
  3350. pPrevStoreLink = pStoreLink;
  3351. if (CertControlStore(
  3352. (HCERTSTORE) pStoreLink->pSibling,
  3353. dwFlags,
  3354. dwCtrlType,
  3355. pvCtrlPara
  3356. )) {
  3357. fOneSiblingSuccess = TRUE;
  3358. if (ERROR_CALL_NOT_IMPLEMENTED == dwError)
  3359. fResult = TRUE;
  3360. } else if (ERROR_CALL_NOT_IMPLEMENTED == dwError) {
  3361. dwError = GetLastError();
  3362. if (!fOneSiblingSuccess || ERROR_CALL_NOT_IMPLEMENTED != dwError)
  3363. fResult = FALSE;
  3364. }
  3365. LockStore(pCollection);
  3366. }
  3367. UnlockStore(pCollection);
  3368. if (pPrevStoreLink)
  3369. ReleaseStoreLink(pPrevStoreLink);
  3370. if (!fResult)
  3371. SetLastError(dwError);
  3372. return fResult;
  3373. }
  3374. BOOL
  3375. WINAPI
  3376. CertControlStore(
  3377. IN HCERTSTORE hCertStore,
  3378. IN DWORD dwFlags,
  3379. IN DWORD dwCtrlType,
  3380. IN void const *pvCtrlPara
  3381. )
  3382. {
  3383. BOOL fResult;
  3384. PCERT_STORE pStore = (PCERT_STORE) hCertStore;
  3385. PFN_CERT_STORE_PROV_CONTROL pfnStoreProvControl;
  3386. if (CERT_STORE_CTRL_AUTO_RESYNC == dwCtrlType)
  3387. return EnableAutoResync(pStore);
  3388. if (STORE_TYPE_COLLECTION == pStore->dwStoreType)
  3389. return ControlCollectionStore(
  3390. pStore,
  3391. dwFlags,
  3392. dwCtrlType,
  3393. pvCtrlPara
  3394. );
  3395. // Check if the store supports the control callback
  3396. if (pStore->StoreProvInfo.cStoreProvFunc <=
  3397. CERT_STORE_PROV_CONTROL_FUNC ||
  3398. NULL == (pfnStoreProvControl = (PFN_CERT_STORE_PROV_CONTROL)
  3399. pStore->StoreProvInfo.rgpvStoreProvFunc[
  3400. CERT_STORE_PROV_CONTROL_FUNC]))
  3401. goto ProvControlNotSupported;
  3402. // The caller is holding a reference count on the store.
  3403. if (!pfnStoreProvControl(
  3404. pStore->StoreProvInfo.hStoreProv,
  3405. dwFlags,
  3406. dwCtrlType,
  3407. pvCtrlPara
  3408. ))
  3409. goto StoreProvControlError;
  3410. fResult = TRUE;
  3411. CommonReturn:
  3412. return fResult;
  3413. ErrorReturn:
  3414. fResult = FALSE;
  3415. goto CommonReturn;
  3416. SET_ERROR(ProvControlNotSupported, ERROR_CALL_NOT_IMPLEMENTED)
  3417. TRACE_ERROR(StoreProvControlError)
  3418. }
  3419. //+=========================================================================
  3420. // Store Collection APIs
  3421. //==========================================================================
  3422. BOOL
  3423. WINAPI
  3424. CertAddStoreToCollection(
  3425. IN HCERTSTORE hCollectionStore,
  3426. IN OPTIONAL HCERTSTORE hSiblingStore,
  3427. IN DWORD dwUpdateFlags,
  3428. IN DWORD dwPriority
  3429. )
  3430. {
  3431. BOOL fResult;
  3432. PCERT_STORE pCollection = (PCERT_STORE) hCollectionStore;
  3433. PCERT_STORE pSibling = (PCERT_STORE) hSiblingStore;
  3434. PCERT_STORE_LINK pAddLink = NULL;
  3435. LockStore(pCollection);
  3436. if (STORE_TYPE_COLLECTION == pCollection->dwStoreType)
  3437. fResult = TRUE;
  3438. else if (STORE_TYPE_CACHE == pCollection->dwStoreType &&
  3439. STORE_STATE_OPENING == pCollection->dwState &&
  3440. IsEmptyStore(pCollection)) {
  3441. pCollection->dwStoreType = STORE_TYPE_COLLECTION;
  3442. fResult = TRUE;
  3443. } else
  3444. fResult = FALSE;
  3445. UnlockStore(pCollection);
  3446. if (!fResult)
  3447. goto InvalidCollectionStore;
  3448. if (NULL == hSiblingStore)
  3449. goto CommonReturn;
  3450. // Create a link to the store to be added. It duplicates pSibling.
  3451. if (NULL == (pAddLink = CreateStoreLink(
  3452. pCollection,
  3453. pSibling,
  3454. dwUpdateFlags,
  3455. dwPriority)))
  3456. goto CreateStoreLinkError;
  3457. LockStore(pCollection);
  3458. if (NULL == pCollection->pStoreListHead)
  3459. pCollection->pStoreListHead = pAddLink;
  3460. else {
  3461. PCERT_STORE_LINK pLink;
  3462. pLink = pCollection->pStoreListHead;
  3463. if (dwPriority > pLink->dwPriority) {
  3464. // Insert at beginning before first link
  3465. pAddLink->pNext = pLink;
  3466. pLink->pPrev = pAddLink;
  3467. pCollection->pStoreListHead = pAddLink;
  3468. } else {
  3469. // Insert after the link whose next link has
  3470. // lower priority or insert after the last link
  3471. while (pLink->pNext && dwPriority <= pLink->pNext->dwPriority)
  3472. pLink = pLink->pNext;
  3473. pAddLink->pPrev = pLink;
  3474. pAddLink->pNext = pLink->pNext;
  3475. if (pLink->pNext)
  3476. pLink->pNext->pPrev = pAddLink;
  3477. pLink->pNext = pAddLink;
  3478. }
  3479. }
  3480. UnlockStore(pCollection);
  3481. fResult = TRUE;
  3482. CommonReturn:
  3483. return fResult;
  3484. ErrorReturn:
  3485. fResult = FALSE;
  3486. goto CommonReturn;
  3487. SET_ERROR(InvalidCollectionStore, E_INVALIDARG)
  3488. TRACE_ERROR(CreateStoreLinkError)
  3489. }
  3490. void
  3491. WINAPI
  3492. CertRemoveStoreFromCollection(
  3493. IN HCERTSTORE hCollectionStore,
  3494. IN HCERTSTORE hSiblingStore
  3495. )
  3496. {
  3497. PCERT_STORE pCollection = (PCERT_STORE) hCollectionStore;
  3498. PCERT_STORE pSibling = (PCERT_STORE) hSiblingStore;
  3499. PCERT_STORE_LINK pLink;
  3500. LockStore(pCollection);
  3501. assert(STORE_TYPE_COLLECTION == pCollection->dwStoreType);
  3502. pLink = pCollection->pStoreListHead;
  3503. for (; pLink; pLink = pLink->pNext) {
  3504. if (pSibling == pLink->pSibling &&
  3505. 0 == (pLink->dwFlags & STORE_LINK_DELETED_FLAG)) {
  3506. // Remove the collection's reference
  3507. pLink->dwFlags |= STORE_LINK_DELETED_FLAG;
  3508. UnlockStore(pCollection);
  3509. ReleaseStoreLink(pLink);
  3510. return;
  3511. }
  3512. }
  3513. UnlockStore(pCollection);
  3514. }
  3515. //+=========================================================================
  3516. // Cert Store Property Functions
  3517. //==========================================================================
  3518. //+-------------------------------------------------------------------------
  3519. // Set a store property.
  3520. //--------------------------------------------------------------------------
  3521. BOOL
  3522. WINAPI
  3523. CertSetStoreProperty(
  3524. IN HCERTSTORE hCertStore,
  3525. IN DWORD dwPropId,
  3526. IN DWORD dwFlags,
  3527. IN const void *pvData
  3528. )
  3529. {
  3530. BOOL fResult;
  3531. PCERT_STORE pStore = (PCERT_STORE) hCertStore;
  3532. LockStore(pStore);
  3533. fResult = SetCallerProperty(
  3534. &pStore->pPropHead,
  3535. dwPropId,
  3536. dwFlags,
  3537. pvData
  3538. );
  3539. UnlockStore(pStore);
  3540. return fResult;
  3541. }
  3542. //+-------------------------------------------------------------------------
  3543. // Get a store property.
  3544. //--------------------------------------------------------------------------
  3545. BOOL
  3546. WINAPI
  3547. CertGetStoreProperty(
  3548. IN HCERTSTORE hCertStore,
  3549. IN DWORD dwPropId,
  3550. OUT void *pvData,
  3551. IN OUT DWORD *pcbData
  3552. )
  3553. {
  3554. BOOL fResult;
  3555. PCERT_STORE pStore = (PCERT_STORE) hCertStore;
  3556. if (dwPropId == CERT_ACCESS_STATE_PROP_ID) {
  3557. DWORD dwAccessStateFlags;
  3558. DWORD cbIn;
  3559. dwAccessStateFlags = 0;
  3560. if (0 == (pStore->dwFlags & CERT_STORE_READONLY_FLAG) &&
  3561. 0 == (pStore->StoreProvInfo.dwStoreProvFlags &
  3562. CERT_STORE_PROV_NO_PERSIST_FLAG))
  3563. {
  3564. if (STORE_TYPE_COLLECTION == pStore->dwStoreType) {
  3565. // If all its children are READONLY, then NO WRITE_PERSIST
  3566. PCERT_STORE_LINK pStoreLink;
  3567. PCERT_STORE_LINK pPrevStoreLink = NULL;
  3568. LockStore(pStore);
  3569. for (pStoreLink = pStore->pStoreListHead;
  3570. pStoreLink; pStoreLink = pStoreLink->pNext) {
  3571. DWORD dwSiblingAccessStateFlags;
  3572. DWORD cbSiblingData;
  3573. // Advance past deleted store link
  3574. if (pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG)
  3575. continue;
  3576. AddRefStoreLink(pStoreLink);
  3577. UnlockStore(pStore);
  3578. if (pPrevStoreLink)
  3579. ReleaseStoreLink(pPrevStoreLink);
  3580. pPrevStoreLink = pStoreLink;
  3581. dwSiblingAccessStateFlags = 0;
  3582. cbSiblingData = sizeof(dwSiblingAccessStateFlags);
  3583. CertGetStoreProperty(
  3584. (HCERTSTORE) pStoreLink->pSibling,
  3585. CERT_ACCESS_STATE_PROP_ID,
  3586. &dwSiblingAccessStateFlags,
  3587. &cbSiblingData
  3588. );
  3589. LockStore(pStore);
  3590. if (dwSiblingAccessStateFlags &
  3591. CERT_ACCESS_STATE_WRITE_PERSIST_FLAG) {
  3592. dwAccessStateFlags =
  3593. CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
  3594. break;
  3595. }
  3596. }
  3597. UnlockStore(pStore);
  3598. if (pPrevStoreLink)
  3599. ReleaseStoreLink(pPrevStoreLink);
  3600. } else
  3601. dwAccessStateFlags = CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
  3602. }
  3603. if (pStore->StoreProvInfo.dwStoreProvFlags &
  3604. CERT_STORE_PROV_SYSTEM_STORE_FLAG)
  3605. dwAccessStateFlags |= CERT_ACCESS_STATE_SYSTEM_STORE_FLAG;
  3606. if (pStore->StoreProvInfo.dwStoreProvFlags &
  3607. CERT_STORE_PROV_LM_SYSTEM_STORE_FLAG)
  3608. dwAccessStateFlags |= CERT_ACCESS_STATE_LM_SYSTEM_STORE_FLAG;
  3609. fResult = TRUE;
  3610. if (pvData == NULL)
  3611. cbIn = 0;
  3612. else
  3613. cbIn = *pcbData;
  3614. if (cbIn < sizeof(DWORD)) {
  3615. if (pvData) {
  3616. SetLastError((DWORD) ERROR_MORE_DATA);
  3617. fResult = FALSE;
  3618. }
  3619. } else
  3620. *((DWORD * ) pvData) = dwAccessStateFlags;
  3621. *pcbData = sizeof(DWORD);
  3622. return fResult;
  3623. }
  3624. LockStore(pStore);
  3625. fResult = GetCallerProperty(
  3626. pStore->pPropHead,
  3627. dwPropId,
  3628. FALSE, // fAlloc
  3629. pvData,
  3630. pcbData
  3631. );
  3632. UnlockStore(pStore);
  3633. return fResult;
  3634. }
  3635. //+=========================================================================
  3636. // Certificate APIs
  3637. //==========================================================================
  3638. BOOL
  3639. WINAPI
  3640. CertAddEncodedCertificateToStore(
  3641. IN HCERTSTORE hCertStore,
  3642. IN DWORD dwCertEncodingType,
  3643. IN const BYTE *pbCertEncoded,
  3644. IN DWORD cbCertEncoded,
  3645. IN DWORD dwAddDisposition,
  3646. OUT OPTIONAL PCCERT_CONTEXT *ppCertContext
  3647. )
  3648. {
  3649. BOOL fResult;
  3650. PCONTEXT_ELEMENT pStoreEle = NULL;
  3651. fResult = AddEncodedContextToStore(
  3652. (PCERT_STORE) hCertStore,
  3653. CERT_STORE_CERTIFICATE_CONTEXT - 1,
  3654. dwCertEncodingType,
  3655. pbCertEncoded,
  3656. cbCertEncoded,
  3657. dwAddDisposition,
  3658. ppCertContext ? &pStoreEle : NULL
  3659. );
  3660. if (ppCertContext)
  3661. *ppCertContext = ToCertContext(pStoreEle);
  3662. return fResult;
  3663. }
  3664. BOOL
  3665. WINAPI
  3666. CertAddCertificateContextToStore(
  3667. IN HCERTSTORE hCertStore,
  3668. IN PCCERT_CONTEXT pCertContext,
  3669. IN DWORD dwAddDisposition,
  3670. OUT OPTIONAL PCCERT_CONTEXT *ppStoreContext
  3671. )
  3672. {
  3673. BOOL fResult;
  3674. PCONTEXT_ELEMENT pStoreEle = NULL;
  3675. fResult = AddContextToStore(
  3676. (PCERT_STORE) hCertStore,
  3677. ToContextElement(pCertContext),
  3678. pCertContext->dwCertEncodingType,
  3679. pCertContext->pbCertEncoded,
  3680. pCertContext->cbCertEncoded,
  3681. dwAddDisposition,
  3682. ppStoreContext ? &pStoreEle : NULL
  3683. );
  3684. if (ppStoreContext)
  3685. *ppStoreContext = ToCertContext(pStoreEle);
  3686. return fResult;
  3687. }
  3688. BOOL
  3689. WINAPI
  3690. CertAddCertificateLinkToStore(
  3691. IN HCERTSTORE hCertStore,
  3692. IN PCCERT_CONTEXT pCertContext,
  3693. IN DWORD dwAddDisposition,
  3694. OUT OPTIONAL PCCERT_CONTEXT *ppStoreContext
  3695. )
  3696. {
  3697. BOOL fResult;
  3698. PCONTEXT_ELEMENT pStoreEle = NULL;
  3699. fResult = AddLinkContextToCacheStore(
  3700. (PCERT_STORE) hCertStore,
  3701. ToContextElement(pCertContext),
  3702. dwAddDisposition,
  3703. ppStoreContext ? &pStoreEle : NULL
  3704. );
  3705. if (ppStoreContext)
  3706. *ppStoreContext = ToCertContext(pStoreEle);
  3707. return fResult;
  3708. }
  3709. //+-------------------------------------------------------------------------
  3710. // Serialize the certificate context's encoded certificate and its
  3711. // properties.
  3712. //--------------------------------------------------------------------------
  3713. BOOL
  3714. WINAPI
  3715. CertSerializeCertificateStoreElement(
  3716. IN PCCERT_CONTEXT pCertContext,
  3717. IN DWORD dwFlags,
  3718. OUT BYTE *pbElement,
  3719. IN OUT DWORD *pcbElement
  3720. )
  3721. {
  3722. return SerializeContextElement(
  3723. ToContextElement(pCertContext),
  3724. dwFlags,
  3725. pbElement,
  3726. pcbElement
  3727. );
  3728. }
  3729. //+-------------------------------------------------------------------------
  3730. // Delete the specified certificate from the store.
  3731. //
  3732. // All subsequent gets or finds for the certificate will fail. However,
  3733. // memory allocated for the certificate isn't freed until all of its contexts
  3734. // have also been freed.
  3735. //
  3736. // The pCertContext is obtained from a get, find or duplicate.
  3737. //
  3738. // Some store provider implementations might also delete the issuer's CRLs
  3739. // if this is the last certificate for the issuer in the store.
  3740. //
  3741. // NOTE: the pCertContext is always CertFreeCertificateContext'ed by
  3742. // this function, even for an error.
  3743. //--------------------------------------------------------------------------
  3744. BOOL
  3745. WINAPI
  3746. CertDeleteCertificateFromStore(
  3747. IN PCCERT_CONTEXT pCertContext
  3748. )
  3749. {
  3750. assert(NULL == pCertContext || (CERT_STORE_CERTIFICATE_CONTEXT - 1) ==
  3751. ToContextElement(pCertContext)->dwContextType);
  3752. return DeleteContextElement(ToContextElement(pCertContext));
  3753. }
  3754. //+-------------------------------------------------------------------------
  3755. // Get the subject certificate context uniquely identified by its Issuer and
  3756. // SerialNumber from the store.
  3757. //
  3758. // If the certificate isn't found, NULL is returned. Otherwise, a pointer to
  3759. // a read only CERT_CONTEXT is returned. CERT_CONTEXT must be freed by calling
  3760. // CertFreeCertificateContext. CertDuplicateCertificateContext can be called to make a
  3761. // duplicate.
  3762. //
  3763. // The returned certificate might not be valid. Normally, it would be
  3764. // verified when getting its issuer certificate (CertGetIssuerCertificateFromStore).
  3765. //--------------------------------------------------------------------------
  3766. PCCERT_CONTEXT
  3767. WINAPI
  3768. CertGetSubjectCertificateFromStore(
  3769. IN HCERTSTORE hCertStore,
  3770. IN DWORD dwCertEncodingType,
  3771. IN PCERT_INFO pCertId // Only the Issuer and SerialNumber
  3772. // fields are used
  3773. )
  3774. {
  3775. CERT_STORE_PROV_FIND_INFO FindInfo;
  3776. if (pCertId == NULL) {
  3777. SetLastError((DWORD) E_INVALIDARG);
  3778. return NULL;
  3779. }
  3780. FindInfo.cbSize = sizeof(FindInfo);
  3781. FindInfo.dwMsgAndCertEncodingType = dwCertEncodingType,
  3782. FindInfo.dwFindFlags = 0;
  3783. FindInfo.dwFindType = CERT_FIND_SUBJECT_CERT;
  3784. FindInfo.pvFindPara = pCertId;
  3785. return ToCertContext(CheckAutoResyncAndFindElementInStore(
  3786. (PCERT_STORE) hCertStore,
  3787. CERT_STORE_CERTIFICATE_CONTEXT - 1,
  3788. &FindInfo,
  3789. NULL // pPrevEle
  3790. ));
  3791. }
  3792. //+-------------------------------------------------------------------------
  3793. // Enumerate the certificate contexts in the store.
  3794. //
  3795. // If a certificate isn't found, NULL is returned.
  3796. // Otherwise, a pointer to a read only CERT_CONTEXT is returned. CERT_CONTEXT
  3797. // must be freed by calling CertFreeCertificateContext or is freed when passed as the
  3798. // pPrevCertContext on a subsequent call. CertDuplicateCertificateContext
  3799. // can be called to make a duplicate.
  3800. //
  3801. // pPrevCertContext MUST BE NULL to enumerate the first
  3802. // certificate in the store. Successive certificates are enumerated by setting
  3803. // pPrevCertContext to the CERT_CONTEXT returned by a previous call.
  3804. //
  3805. // NOTE: a NON-NULL pPrevCertContext is always CertFreeCertificateContext'ed by
  3806. // this function, even for an error.
  3807. //--------------------------------------------------------------------------
  3808. PCCERT_CONTEXT
  3809. WINAPI
  3810. CertEnumCertificatesInStore(
  3811. IN HCERTSTORE hCertStore,
  3812. IN PCCERT_CONTEXT pPrevCertContext
  3813. )
  3814. {
  3815. return ToCertContext(CheckAutoResyncAndFindElementInStore(
  3816. (PCERT_STORE) hCertStore,
  3817. CERT_STORE_CERTIFICATE_CONTEXT - 1,
  3818. &FindAnyInfo,
  3819. ToContextElement(pPrevCertContext)
  3820. ));
  3821. }
  3822. //+-------------------------------------------------------------------------
  3823. // Find the first or next certificate context in the store.
  3824. //
  3825. // The certificate is found according to the dwFindType and its pvFindPara.
  3826. // See below for a list of the find types and its parameters.
  3827. //
  3828. // Currently dwFindFlags is only used for CERT_FIND_SUBJECT_ATTR or
  3829. // CERT_FIND_ISSUER_ATTR. Otherwise, must be set to 0.
  3830. //
  3831. // Usage of dwCertEncodingType depends on the dwFindType.
  3832. //
  3833. // If the first or next certificate isn't found, NULL is returned.
  3834. // Otherwise, a pointer to a read only CERT_CONTEXT is returned. CERT_CONTEXT
  3835. // must be freed by calling CertFreeCertificateContext or is freed when passed as the
  3836. // pPrevCertContext on a subsequent call. CertDuplicateCertificateContext
  3837. // can be called to make a duplicate.
  3838. //
  3839. // pPrevCertContext MUST BE NULL on the first
  3840. // call to find the certificate. To find the next certificate, the
  3841. // pPrevCertContext is set to the CERT_CONTEXT returned by a previous call.
  3842. //
  3843. // NOTE: a NON-NULL pPrevCertContext is always CertFreeCertificateContext'ed by
  3844. // this function, even for an error.
  3845. //--------------------------------------------------------------------------
  3846. PCCERT_CONTEXT
  3847. WINAPI
  3848. CertFindCertificateInStore(
  3849. IN HCERTSTORE hCertStore,
  3850. IN DWORD dwCertEncodingType,
  3851. IN DWORD dwFindFlags,
  3852. IN DWORD dwFindType,
  3853. IN const void *pvFindPara,
  3854. IN PCCERT_CONTEXT pPrevCertContext
  3855. )
  3856. {
  3857. CERT_STORE_PROV_FIND_INFO FindInfo;
  3858. FindInfo.cbSize = sizeof(FindInfo);
  3859. FindInfo.dwMsgAndCertEncodingType = dwCertEncodingType;
  3860. FindInfo.dwFindFlags = dwFindFlags;
  3861. FindInfo.dwFindType = dwFindType;
  3862. FindInfo.pvFindPara = pvFindPara;
  3863. return ToCertContext(CheckAutoResyncAndFindElementInStore(
  3864. (PCERT_STORE) hCertStore,
  3865. CERT_STORE_CERTIFICATE_CONTEXT - 1,
  3866. &FindInfo,
  3867. ToContextElement(pPrevCertContext)
  3868. ));
  3869. }
  3870. //+-------------------------------------------------------------------------
  3871. // Perform the revocation check on the subject certificate
  3872. // using the issuer certificate and store
  3873. //--------------------------------------------------------------------------
  3874. STATIC void VerifySubjectCertRevocation(
  3875. IN PCCERT_CONTEXT pSubject,
  3876. IN PCCERT_CONTEXT pIssuer,
  3877. IN HCERTSTORE hIssuerStore,
  3878. IN OUT DWORD *pdwFlags
  3879. )
  3880. {
  3881. PCCRL_CONTEXT rgpCrlContext[MAX_CRL_LIST];
  3882. PCRL_INFO rgpCrlInfo[MAX_CRL_LIST];
  3883. PCCRL_CONTEXT pCrlContext = NULL;
  3884. DWORD cCrl = 0;
  3885. assert(pIssuer && hIssuerStore);
  3886. assert(*pdwFlags & CERT_STORE_REVOCATION_FLAG);
  3887. while (TRUE) {
  3888. DWORD dwFlags = CERT_STORE_SIGNATURE_FLAG;
  3889. pCrlContext = CertGetCRLFromStore(
  3890. hIssuerStore,
  3891. pIssuer,
  3892. pCrlContext,
  3893. &dwFlags
  3894. );
  3895. if (pCrlContext == NULL) break;
  3896. if (cCrl == MAX_CRL_LIST) {
  3897. assert(cCrl > MAX_CRL_LIST);
  3898. CertFreeCRLContext(pCrlContext);
  3899. break;
  3900. }
  3901. if (dwFlags == 0) {
  3902. rgpCrlContext[cCrl] = CertDuplicateCRLContext(pCrlContext);
  3903. rgpCrlInfo[cCrl] = pCrlContext->pCrlInfo;
  3904. cCrl++;
  3905. } else {
  3906. // Need to log or remove a bad CRL from the store
  3907. ;
  3908. }
  3909. }
  3910. if (cCrl == 0)
  3911. *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
  3912. else {
  3913. if (CertVerifyCRLRevocation(
  3914. pSubject->dwCertEncodingType,
  3915. pSubject->pCertInfo,
  3916. cCrl,
  3917. rgpCrlInfo
  3918. ))
  3919. *pdwFlags &= ~CERT_STORE_REVOCATION_FLAG;
  3920. while (cCrl--)
  3921. CertFreeCRLContext(rgpCrlContext[cCrl]);
  3922. }
  3923. }
  3924. #ifdef CMS_PKCS7
  3925. //+-------------------------------------------------------------------------
  3926. // If the verify certificate signature fails with CRYPT_E_MISSING_PUBKEY_PARA,
  3927. // build a certificate chain. Retry. Hopefully, the issuer's
  3928. // CERT_PUBKEY_ALG_PARA_PROP_ID property gets set while building the chain.
  3929. //--------------------------------------------------------------------------
  3930. STATIC BOOL VerifyCertificateSignatureWithChainPubKeyParaInheritance(
  3931. IN HCRYPTPROV hCryptProv,
  3932. IN DWORD dwCertEncodingType,
  3933. IN DWORD dwSubjectType,
  3934. IN void *pvSubject,
  3935. IN PCCERT_CONTEXT pIssuer
  3936. );
  3937. #endif // CMS_PKCS7
  3938. //+-------------------------------------------------------------------------
  3939. // Perform the enabled verification checks on the subject certificate
  3940. // using the issuer
  3941. //--------------------------------------------------------------------------
  3942. STATIC void VerifySubjectCert(
  3943. IN PCCERT_CONTEXT pSubject,
  3944. IN OPTIONAL PCCERT_CONTEXT pIssuer,
  3945. IN OUT DWORD *pdwFlags
  3946. )
  3947. {
  3948. if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG) {
  3949. if (CertVerifyTimeValidity(NULL,
  3950. pSubject->pCertInfo) == 0)
  3951. *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
  3952. }
  3953. if (pIssuer == NULL) {
  3954. if (*pdwFlags & (CERT_STORE_SIGNATURE_FLAG |
  3955. CERT_STORE_REVOCATION_FLAG))
  3956. *pdwFlags |= CERT_STORE_NO_ISSUER_FLAG;
  3957. return;
  3958. }
  3959. if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG) {
  3960. PCERT_STORE pStore = (PCERT_STORE) pIssuer->hCertStore;
  3961. HCRYPTPROV hProv;
  3962. DWORD dwProvFlags;
  3963. // Attempt to get the store's crypt provider. Serialize crypto
  3964. // operations by entering critical section.
  3965. hProv = GetCryptProv(pStore, &dwProvFlags);
  3966. #if 0
  3967. // Slow down the provider while holding the provider reference
  3968. // count
  3969. Sleep(1700);
  3970. #endif
  3971. #ifdef CMS_PKCS7
  3972. if (VerifyCertificateSignatureWithChainPubKeyParaInheritance(
  3973. hProv,
  3974. pSubject->dwCertEncodingType,
  3975. CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
  3976. (void *) pSubject,
  3977. pIssuer
  3978. ))
  3979. #else
  3980. if (CryptVerifyCertificateSignature(
  3981. hProv,
  3982. pSubject->dwCertEncodingType,
  3983. pSubject->pbCertEncoded,
  3984. pSubject->cbCertEncoded,
  3985. &pIssuer->pCertInfo->SubjectPublicKeyInfo
  3986. ))
  3987. #endif // CMS_PKCS7
  3988. *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
  3989. // For the store's crypt provider, release reference count. Leave
  3990. // crypto operations critical section.
  3991. ReleaseCryptProv(pStore, dwProvFlags);
  3992. }
  3993. if (*pdwFlags & CERT_STORE_REVOCATION_FLAG) {
  3994. *pdwFlags &= ~CERT_STORE_NO_CRL_FLAG;
  3995. VerifySubjectCertRevocation(
  3996. pSubject,
  3997. pIssuer,
  3998. pIssuer->hCertStore,
  3999. pdwFlags
  4000. );
  4001. if (*pdwFlags & CERT_STORE_NO_CRL_FLAG) {
  4002. PCONTEXT_ELEMENT pIssuerEle = ToContextElement(pIssuer);
  4003. if (ELEMENT_TYPE_LINK_CONTEXT == pIssuerEle->dwElementType) {
  4004. // Skip past the link elements. A store containing a link
  4005. // may not have any CRLs. Try the store containing the
  4006. // real issuer element.
  4007. DWORD dwInnerDepth = 0;
  4008. for ( ; ELEMENT_TYPE_LINK_CONTEXT ==
  4009. pIssuerEle->dwElementType;
  4010. pIssuerEle = pIssuerEle->pEle) {
  4011. dwInnerDepth++;
  4012. assert(dwInnerDepth <= MAX_LINK_DEPTH);
  4013. assert(pIssuerEle != pIssuerEle->pEle);
  4014. if (dwInnerDepth > MAX_LINK_DEPTH)
  4015. break;
  4016. }
  4017. if ((HCERTSTORE) pIssuerEle->pStore != pIssuer->hCertStore) {
  4018. *pdwFlags &= ~CERT_STORE_NO_CRL_FLAG;
  4019. VerifySubjectCertRevocation(
  4020. pSubject,
  4021. pIssuer,
  4022. (HCERTSTORE) pIssuerEle->pStore,
  4023. pdwFlags
  4024. );
  4025. }
  4026. }
  4027. }
  4028. }
  4029. }
  4030. //+-------------------------------------------------------------------------
  4031. // Get the certificate context from the store for the first or next issuer
  4032. // of the specified subject certificate. Perform the enabled
  4033. // verification checks on the subject. (Note, the checks are on the subject
  4034. // using the returned issuer certificate.)
  4035. //
  4036. // If the first or next issuer certificate isn't found, NULL is returned.
  4037. // Otherwise, a pointer to a read only CERT_CONTEXT is returned. CERT_CONTEXT
  4038. // must be freed by calling CertFreeCertificateContext or is freed when passed as the
  4039. // pPrevIssuerContext on a subsequent call. CertDuplicateCertificateContext
  4040. // can be called to make a duplicate.
  4041. //
  4042. // The pSubjectContext may have been obtained from this store, another store
  4043. // or created by the caller application. When created by the caller, the
  4044. // CertCreateCertificateContext function must have been called.
  4045. //
  4046. // An issuer may have multiple certificates. This may occur when the validity
  4047. // period is about to change. pPrevIssuerContext MUST BE NULL on the first
  4048. // call to get the issuer. To get the next certificate for the issuer, the
  4049. // pPrevIssuerContext is set to the CERT_CONTEXT returned by a previous call.
  4050. //
  4051. // NOTE: a NON-NULL pPrevIssuerContext is always CertFreeCertificateContext'ed by
  4052. // this function, even for an error.
  4053. //
  4054. // The following flags can be set in *pdwFlags to enable verification checks
  4055. // on the subject certificate context:
  4056. // CERT_STORE_SIGNATURE_FLAG - use the public key in the returned
  4057. // issuer certificate to verify the
  4058. // signature on the subject certificate.
  4059. // Note, if pSubjectContext->hCertStore ==
  4060. // hCertStore, the store provider might
  4061. // be able to eliminate a redo of
  4062. // the signature verify.
  4063. // CERT_STORE_TIME_VALIDITY_FLAG - get the current time and verify that
  4064. // its within the subject certificate's
  4065. // validity period
  4066. // CERT_STORE_REVOCATION_FLAG - check if the subject certificate is on
  4067. // the issuer's revocation list
  4068. //
  4069. // If an enabled verification check fails, then, its flag is set upon return.
  4070. // If CERT_STORE_REVOCATION_FLAG was enabled and the issuer doesn't have a
  4071. // CRL in the store, then, CERT_STORE_NO_CRL_FLAG is set in addition to
  4072. // the CERT_STORE_REVOCATION_FLAG.
  4073. //
  4074. // If CERT_STORE_SIGNATURE_FLAG or CERT_STORE_REVOCATION_FLAG is set, then,
  4075. // CERT_STORE_NO_ISSUER_FLAG is set if it doesn't have an issuer certificate
  4076. // in the store.
  4077. //
  4078. // For a verification check failure, a pointer to the issuer's CERT_CONTEXT
  4079. // is still returned and SetLastError isn't updated.
  4080. //--------------------------------------------------------------------------
  4081. PCCERT_CONTEXT
  4082. WINAPI
  4083. CertGetIssuerCertificateFromStore(
  4084. IN HCERTSTORE hCertStore,
  4085. IN PCCERT_CONTEXT pSubjectContext,
  4086. IN OPTIONAL PCCERT_CONTEXT pPrevIssuerContext,
  4087. IN OUT DWORD *pdwFlags
  4088. )
  4089. {
  4090. PCCERT_CONTEXT pIssuerContext;
  4091. if (*pdwFlags & ~(CERT_STORE_SIGNATURE_FLAG |
  4092. CERT_STORE_TIME_VALIDITY_FLAG |
  4093. CERT_STORE_REVOCATION_FLAG))
  4094. goto InvalidArg;
  4095. // Check if self signed certificate, issuer == subject
  4096. if (CertCompareCertificateName(
  4097. pSubjectContext->dwCertEncodingType,
  4098. &pSubjectContext->pCertInfo->Subject,
  4099. &pSubjectContext->pCertInfo->Issuer
  4100. )) {
  4101. VerifySubjectCert(
  4102. pSubjectContext,
  4103. pSubjectContext,
  4104. pdwFlags
  4105. );
  4106. SetLastError((DWORD) CRYPT_E_SELF_SIGNED);
  4107. goto ErrorReturn;
  4108. } else {
  4109. CERT_STORE_PROV_FIND_INFO FindInfo;
  4110. FindInfo.cbSize = sizeof(FindInfo);
  4111. FindInfo.dwMsgAndCertEncodingType = pSubjectContext->dwCertEncodingType;
  4112. FindInfo.dwFindFlags = 0;
  4113. FindInfo.dwFindType = CERT_FIND_ISSUER_OF;
  4114. FindInfo.pvFindPara = pSubjectContext;
  4115. if (pIssuerContext = ToCertContext(CheckAutoResyncAndFindElementInStore(
  4116. (PCERT_STORE) hCertStore,
  4117. CERT_STORE_CERTIFICATE_CONTEXT - 1,
  4118. &FindInfo,
  4119. ToContextElement(pPrevIssuerContext)
  4120. )))
  4121. VerifySubjectCert(
  4122. pSubjectContext,
  4123. pIssuerContext,
  4124. pdwFlags
  4125. );
  4126. }
  4127. CommonReturn:
  4128. return pIssuerContext;
  4129. ErrorReturn:
  4130. if (pPrevIssuerContext)
  4131. CertFreeCertificateContext(pPrevIssuerContext);
  4132. pIssuerContext = NULL;
  4133. goto CommonReturn;
  4134. SET_ERROR(InvalidArg, E_INVALIDARG)
  4135. }
  4136. //+-------------------------------------------------------------------------
  4137. // Perform the enabled verification checks on the subject certificate
  4138. // using the issuer. Same checks and flags definitions as for the above
  4139. // CertGetIssuerCertificateFromStore.
  4140. //
  4141. // For a verification check failure, SUCCESS is still returned.
  4142. //
  4143. // pIssuer must come from a store that is still open.
  4144. //--------------------------------------------------------------------------
  4145. BOOL
  4146. WINAPI
  4147. CertVerifySubjectCertificateContext(
  4148. IN PCCERT_CONTEXT pSubject,
  4149. IN OPTIONAL PCCERT_CONTEXT pIssuer,
  4150. IN OUT DWORD *pdwFlags
  4151. )
  4152. {
  4153. if (*pdwFlags & ~(CERT_STORE_SIGNATURE_FLAG |
  4154. CERT_STORE_TIME_VALIDITY_FLAG |
  4155. CERT_STORE_REVOCATION_FLAG)) {
  4156. SetLastError((DWORD) E_INVALIDARG);
  4157. return FALSE;
  4158. }
  4159. if (*pdwFlags & (CERT_STORE_SIGNATURE_FLAG | CERT_STORE_REVOCATION_FLAG)) {
  4160. if (pIssuer == NULL) {
  4161. SetLastError((DWORD) E_INVALIDARG);
  4162. return FALSE;
  4163. }
  4164. }
  4165. VerifySubjectCert(
  4166. pSubject,
  4167. pIssuer,
  4168. pdwFlags
  4169. );
  4170. return TRUE;
  4171. }
  4172. //+-------------------------------------------------------------------------
  4173. // Duplicate a certificate context
  4174. //--------------------------------------------------------------------------
  4175. PCCERT_CONTEXT
  4176. WINAPI
  4177. CertDuplicateCertificateContext(
  4178. IN PCCERT_CONTEXT pCertContext
  4179. )
  4180. {
  4181. if (pCertContext)
  4182. AddRefContextElement(ToContextElement(pCertContext));
  4183. return pCertContext;
  4184. }
  4185. //+-------------------------------------------------------------------------
  4186. // Create a certificate context from the encoded certificate. The created
  4187. // context isn't put in a store.
  4188. //
  4189. // Makes a copy of the encoded certificate in the created context.
  4190. //
  4191. // If unable to decode and create the certificate context, NULL is returned.
  4192. // Otherwise, a pointer to a read only CERT_CONTEXT is returned.
  4193. // CERT_CONTEXT must be freed by calling CertFreeCertificateContext.
  4194. // CertDuplicateCertificateContext can be called to make a duplicate.
  4195. //
  4196. // CertSetCertificateContextProperty and CertGetCertificateContextProperty can be called
  4197. // to store properties for the certificate.
  4198. //--------------------------------------------------------------------------
  4199. PCCERT_CONTEXT
  4200. WINAPI
  4201. CertCreateCertificateContext(
  4202. IN DWORD dwCertEncodingType,
  4203. IN const BYTE *pbCertEncoded,
  4204. IN DWORD cbCertEncoded
  4205. )
  4206. {
  4207. PCCERT_CONTEXT pCertContext;
  4208. CertAddEncodedCertificateToStore(
  4209. NULL, // hCertStore
  4210. dwCertEncodingType,
  4211. pbCertEncoded,
  4212. cbCertEncoded,
  4213. CERT_STORE_ADD_ALWAYS,
  4214. &pCertContext
  4215. );
  4216. return pCertContext;
  4217. }
  4218. //+-------------------------------------------------------------------------
  4219. // Free a certificate context
  4220. //
  4221. // There needs to be a corresponding free for each context obtained by a
  4222. // get, find, duplicate or create.
  4223. //--------------------------------------------------------------------------
  4224. BOOL
  4225. WINAPI
  4226. CertFreeCertificateContext(
  4227. IN PCCERT_CONTEXT pCertContext
  4228. )
  4229. {
  4230. ReleaseContextElement(ToContextElement(pCertContext));
  4231. return TRUE;
  4232. }
  4233. //+-------------------------------------------------------------------------
  4234. // Set the property for the specified certificate context.
  4235. //
  4236. // If the certificate context was obtained from a store, then, the property
  4237. // is added to the store.
  4238. //
  4239. // The type definition for pvData depends on the dwPropId value. There are
  4240. // three predefined types:
  4241. // CERT_KEY_PROV_HANDLE_PROP_ID - a HCRYPTPROV for the certificate's
  4242. // private key is passed in pvData. If the
  4243. // CERT_STORE_NO_CRYPT_RELEASE_FLAG isn't set, HCRYPTPROV is implicitly
  4244. // released when either the property is set to NULL or on the final
  4245. // free of the CertContext.
  4246. //
  4247. // CERT_KEY_PROV_INFO_PROP_ID - a PCRYPT_KEY_PROV_INFO for the certificate's
  4248. // private key is passed in pvData.
  4249. //
  4250. // CERT_SHA1_HASH_PROP_ID -
  4251. // CERT_MD5_HASH_PROP_ID -
  4252. // CERT_SIGNATURE_HASH_PROP_ID - normally, a hash property is implicitly
  4253. // set by doing a CertGetCertificateContextProperty. pvData points to a
  4254. // CRYPT_HASH_BLOB.
  4255. //
  4256. // For all the other PROP_IDs: an encoded PCRYPT_DATA_BLOB is passed in pvData.
  4257. //
  4258. // If the property already exists, then, the old value is deleted and silently
  4259. // replaced. Setting, pvData to NULL, deletes the property.
  4260. //--------------------------------------------------------------------------
  4261. BOOL
  4262. WINAPI
  4263. CertSetCertificateContextProperty(
  4264. IN PCCERT_CONTEXT pCertContext,
  4265. IN DWORD dwPropId,
  4266. IN DWORD dwFlags,
  4267. IN const void *pvData
  4268. )
  4269. {
  4270. return SetProperty(
  4271. ToContextElement(pCertContext),
  4272. dwPropId,
  4273. dwFlags,
  4274. pvData
  4275. );
  4276. }
  4277. //+-------------------------------------------------------------------------
  4278. // Get the property for the specified certificate context.
  4279. //
  4280. // For CERT_KEY_PROV_HANDLE_PROP_ID, pvData points to a HCRYPTPROV.
  4281. //
  4282. // For CERT_KEY_PROV_INFO_PROP_ID, pvData points to a CRYPT_KEY_PROV_INFO structure.
  4283. // Elements pointed to by fields in the pvData structure follow the
  4284. // structure. Therefore, *pcbData may exceed the size of the structure.
  4285. //
  4286. // For CERT_SHA1_HASH_PROP_ID or CERT_MD5_HASH_PROP_ID, if the hash
  4287. // doesn't already exist, then, its computed via CryptHashCertificate()
  4288. // and then set. pvData points to the computed hash. Normally, the length
  4289. // is 20 bytes for SHA and 16 for MD5.
  4290. // MD5.
  4291. //
  4292. // For CERT_SIGNATURE_HASH_PROP_ID, if the hash
  4293. // doesn't already exist, then, its computed via CryptHashToBeSigned()
  4294. // and then set. pvData points to the computed hash. Normally, the length
  4295. // is 20 bytes for SHA and 16 for MD5.
  4296. //
  4297. // For all other PROP_IDs, pvData points to an encoded array of bytes.
  4298. //--------------------------------------------------------------------------
  4299. BOOL
  4300. WINAPI
  4301. CertGetCertificateContextProperty(
  4302. IN PCCERT_CONTEXT pCertContext,
  4303. IN DWORD dwPropId,
  4304. OUT void *pvData,
  4305. IN OUT DWORD *pcbData
  4306. )
  4307. {
  4308. return GetProperty(
  4309. ToContextElement(pCertContext),
  4310. dwPropId,
  4311. pvData,
  4312. pcbData
  4313. );
  4314. }
  4315. //+-------------------------------------------------------------------------
  4316. // Enumerate the properties for the specified certificate context.
  4317. //--------------------------------------------------------------------------
  4318. DWORD
  4319. WINAPI
  4320. CertEnumCertificateContextProperties(
  4321. IN PCCERT_CONTEXT pCertContext,
  4322. IN DWORD dwPropId
  4323. )
  4324. {
  4325. return EnumProperties(
  4326. ToContextElement(pCertContext),
  4327. dwPropId
  4328. );
  4329. }
  4330. //+=========================================================================
  4331. // CRL APIs
  4332. //==========================================================================
  4333. BOOL
  4334. WINAPI
  4335. CertAddEncodedCRLToStore(
  4336. IN HCERTSTORE hCertStore,
  4337. IN DWORD dwCertEncodingType,
  4338. IN const BYTE *pbCrlEncoded,
  4339. IN DWORD cbCrlEncoded,
  4340. IN DWORD dwAddDisposition,
  4341. OUT OPTIONAL PCCRL_CONTEXT *ppCrlContext
  4342. )
  4343. {
  4344. BOOL fResult;
  4345. PCONTEXT_ELEMENT pStoreEle = NULL;
  4346. fResult = AddEncodedContextToStore(
  4347. (PCERT_STORE) hCertStore,
  4348. CERT_STORE_CRL_CONTEXT - 1,
  4349. dwCertEncodingType,
  4350. pbCrlEncoded,
  4351. cbCrlEncoded,
  4352. dwAddDisposition,
  4353. ppCrlContext ? &pStoreEle : NULL
  4354. );
  4355. if (ppCrlContext)
  4356. *ppCrlContext = ToCrlContext(pStoreEle);
  4357. return fResult;
  4358. }
  4359. BOOL
  4360. WINAPI
  4361. CertAddCRLContextToStore(
  4362. IN HCERTSTORE hCertStore,
  4363. IN PCCRL_CONTEXT pCrlContext,
  4364. IN DWORD dwAddDisposition,
  4365. OUT OPTIONAL PCCRL_CONTEXT *ppStoreContext
  4366. )
  4367. {
  4368. BOOL fResult;
  4369. PCONTEXT_ELEMENT pStoreEle = NULL;
  4370. fResult = AddContextToStore(
  4371. (PCERT_STORE) hCertStore,
  4372. ToContextElement(pCrlContext),
  4373. pCrlContext->dwCertEncodingType,
  4374. pCrlContext->pbCrlEncoded,
  4375. pCrlContext->cbCrlEncoded,
  4376. dwAddDisposition,
  4377. ppStoreContext ? &pStoreEle : NULL
  4378. );
  4379. if (ppStoreContext)
  4380. *ppStoreContext = ToCrlContext(pStoreEle);
  4381. return fResult;
  4382. }
  4383. BOOL
  4384. WINAPI
  4385. CertAddCRLLinkToStore(
  4386. IN HCERTSTORE hCertStore,
  4387. IN PCCRL_CONTEXT pCrlContext,
  4388. IN DWORD dwAddDisposition,
  4389. OUT OPTIONAL PCCRL_CONTEXT *ppStoreContext
  4390. )
  4391. {
  4392. BOOL fResult;
  4393. PCONTEXT_ELEMENT pStoreEle = NULL;
  4394. fResult = AddLinkContextToCacheStore(
  4395. (PCERT_STORE) hCertStore,
  4396. ToContextElement(pCrlContext),
  4397. dwAddDisposition,
  4398. ppStoreContext ? &pStoreEle : NULL
  4399. );
  4400. if (ppStoreContext)
  4401. *ppStoreContext = ToCrlContext(pStoreEle);
  4402. return fResult;
  4403. }
  4404. //+-------------------------------------------------------------------------
  4405. // Serialize the CRL context's encoded CRL and its properties.
  4406. //--------------------------------------------------------------------------
  4407. BOOL
  4408. WINAPI
  4409. CertSerializeCRLStoreElement(
  4410. IN PCCRL_CONTEXT pCrlContext,
  4411. IN DWORD dwFlags,
  4412. OUT BYTE *pbElement,
  4413. IN OUT DWORD *pcbElement
  4414. )
  4415. {
  4416. return SerializeContextElement(
  4417. ToContextElement(pCrlContext),
  4418. dwFlags,
  4419. pbElement,
  4420. pcbElement
  4421. );
  4422. }
  4423. //+-------------------------------------------------------------------------
  4424. // Delete the specified CRL from the store.
  4425. //
  4426. // All subsequent gets for the CRL will fail. However,
  4427. // memory allocated for the CRL isn't freed until all of its contexts
  4428. // have also been freed.
  4429. //
  4430. // The pCrlContext is obtained from a get or duplicate.
  4431. //
  4432. // NOTE: the pCrlContext is always CertFreeCRLContext'ed by
  4433. // this function, even for an error.
  4434. //--------------------------------------------------------------------------
  4435. BOOL
  4436. WINAPI
  4437. CertDeleteCRLFromStore(
  4438. IN PCCRL_CONTEXT pCrlContext
  4439. )
  4440. {
  4441. assert(NULL == pCrlContext || (CERT_STORE_CRL_CONTEXT - 1) ==
  4442. ToContextElement(pCrlContext)->dwContextType);
  4443. return DeleteContextElement(ToContextElement(pCrlContext));
  4444. }
  4445. //+-------------------------------------------------------------------------
  4446. // Perform the enabled verification checks on the CRL using the issuer
  4447. //--------------------------------------------------------------------------
  4448. STATIC void VerifyCrl(
  4449. IN PCCRL_CONTEXT pCrl,
  4450. IN OPTIONAL PCCERT_CONTEXT pIssuer,
  4451. IN OUT DWORD *pdwFlags
  4452. )
  4453. {
  4454. if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG) {
  4455. if (CertVerifyCRLTimeValidity(NULL,
  4456. pCrl->pCrlInfo) == 0)
  4457. *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
  4458. }
  4459. if (*pdwFlags & (CERT_STORE_BASE_CRL_FLAG | CERT_STORE_DELTA_CRL_FLAG)) {
  4460. PCERT_EXTENSION pDeltaExt;
  4461. pDeltaExt = CertFindExtension(
  4462. szOID_DELTA_CRL_INDICATOR,
  4463. pCrl->pCrlInfo->cExtension,
  4464. pCrl->pCrlInfo->rgExtension
  4465. );
  4466. if (*pdwFlags & CERT_STORE_DELTA_CRL_FLAG) {
  4467. if (NULL != pDeltaExt)
  4468. *pdwFlags &= ~CERT_STORE_DELTA_CRL_FLAG;
  4469. }
  4470. if (*pdwFlags & CERT_STORE_BASE_CRL_FLAG) {
  4471. if (NULL == pDeltaExt)
  4472. *pdwFlags &= ~CERT_STORE_BASE_CRL_FLAG;
  4473. }
  4474. }
  4475. if (pIssuer == NULL) {
  4476. if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
  4477. *pdwFlags |= CERT_STORE_NO_ISSUER_FLAG;
  4478. return;
  4479. }
  4480. if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG) {
  4481. PCERT_STORE pStore = (PCERT_STORE) pIssuer->hCertStore;
  4482. HCRYPTPROV hProv;
  4483. DWORD dwProvFlags;
  4484. // Attempt to get the store's crypt provider. Serialize crypto
  4485. // operations by entering critical section.
  4486. hProv = GetCryptProv(pStore, &dwProvFlags);
  4487. #ifdef CMS_PKCS7
  4488. if (VerifyCertificateSignatureWithChainPubKeyParaInheritance(
  4489. hProv,
  4490. pCrl->dwCertEncodingType,
  4491. CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL,
  4492. (void *) pCrl,
  4493. pIssuer
  4494. ))
  4495. #else
  4496. if (CryptVerifyCertificateSignature(
  4497. hProv,
  4498. pCrl->dwCertEncodingType,
  4499. pCrl->pbCrlEncoded,
  4500. pCrl->cbCrlEncoded,
  4501. &pIssuer->pCertInfo->SubjectPublicKeyInfo
  4502. ))
  4503. #endif // CMS_PKCS7
  4504. *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
  4505. // For the store's crypt provider, release reference count. Leave
  4506. // crypto operations critical section.
  4507. ReleaseCryptProv(pStore, dwProvFlags);
  4508. }
  4509. }
  4510. //+-------------------------------------------------------------------------
  4511. // Get the first or next CRL context from the store for the specified
  4512. // issuer certificate. Perform the enabled verification checks on the CRL.
  4513. //
  4514. // If the first or next CRL isn't found, NULL is returned.
  4515. // Otherwise, a pointer to a read only CRL_CONTEXT is returned. CRL_CONTEXT
  4516. // must be freed by calling CertFreeCRLContext or is freed when passed as the
  4517. // pPrevCrlContext on a subsequent call. CertDuplicateCRLContext
  4518. // can be called to make a duplicate.
  4519. //
  4520. // The pIssuerContext may have been obtained from this store, another store
  4521. // or created by the caller application. When created by the caller, the
  4522. // CertCreateCertificateContext function must have been called.
  4523. //
  4524. // If pIssuerContext == NULL, finds all the CRLs in the store.
  4525. //
  4526. // An issuer may have multiple CRLs. For example, it generates delta CRLs
  4527. // using a X.509 v3 extension. pPrevCrlContext MUST BE NULL on the first
  4528. // call to get the CRL. To get the next CRL for the issuer, the
  4529. // pPrevCrlContext is set to the CRL_CONTEXT returned by a previous call.
  4530. //
  4531. // NOTE: a NON-NULL pPrevCrlContext is always CertFreeCRLContext'ed by
  4532. // this function, even for an error.
  4533. //
  4534. // The following flags can be set in *pdwFlags to enable verification checks
  4535. // on the returned CRL:
  4536. // CERT_STORE_SIGNATURE_FLAG - use the public key in the
  4537. // issuer's certificate to verify the
  4538. // signature on the returned CRL.
  4539. // Note, if pIssuerContext->hCertStore ==
  4540. // hCertStore, the store provider might
  4541. // be able to eliminate a redo of
  4542. // the signature verify.
  4543. // CERT_STORE_TIME_VALIDITY_FLAG - get the current time and verify that
  4544. // its within the CRL's ThisUpdate and
  4545. // NextUpdate validity period.
  4546. // CERT_STORE_BASE_CRL_FLAG - get base CRL.
  4547. // CERT_STORE_DELTA_CRL_FLAG - get delta CRL.
  4548. //
  4549. // If only one of CERT_STORE_BASE_CRL_FLAG or CERT_STORE_DELTA_CRL_FLAG is
  4550. // set, then, only returns either a base or delta CRL. In any case, the
  4551. // appropriate base or delta flag will be cleared upon returned. If both
  4552. // flags are set, then, only one of flags will be cleared.
  4553. //
  4554. // If an enabled verification check fails, then, its flag is set upon return.
  4555. //
  4556. // If pIssuerContext == NULL, then, an enabled CERT_STORE_SIGNATURE_FLAG
  4557. // always fails and the CERT_STORE_NO_ISSUER_FLAG is also set.
  4558. //
  4559. // For a verification check failure, a pointer to the first or next
  4560. // CRL_CONTEXT is still returned and SetLastError isn't updated.
  4561. //--------------------------------------------------------------------------
  4562. PCCRL_CONTEXT
  4563. WINAPI
  4564. CertGetCRLFromStore(
  4565. IN HCERTSTORE hCertStore,
  4566. IN OPTIONAL PCCERT_CONTEXT pIssuerContext,
  4567. IN PCCRL_CONTEXT pPrevCrlContext,
  4568. IN OUT DWORD *pdwFlags
  4569. )
  4570. {
  4571. CERT_STORE_PROV_FIND_INFO FindInfo;
  4572. DWORD dwMsgAndCertEncodingType;
  4573. PCCRL_CONTEXT pCrlContext;
  4574. if (*pdwFlags & ~(CERT_STORE_SIGNATURE_FLAG |
  4575. CERT_STORE_TIME_VALIDITY_FLAG |
  4576. CERT_STORE_BASE_CRL_FLAG |
  4577. CERT_STORE_DELTA_CRL_FLAG))
  4578. goto InvalidArg;
  4579. if (NULL == pIssuerContext)
  4580. dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
  4581. else
  4582. dwMsgAndCertEncodingType = pIssuerContext->dwCertEncodingType;
  4583. FindInfo.cbSize = sizeof(FindInfo);
  4584. FindInfo.dwMsgAndCertEncodingType = dwMsgAndCertEncodingType;
  4585. FindInfo.dwFindFlags = 0;
  4586. if (*pdwFlags & CERT_STORE_BASE_CRL_FLAG)
  4587. FindInfo.dwFindFlags |= CRL_FIND_ISSUED_BY_BASE_FLAG;
  4588. if (*pdwFlags & CERT_STORE_DELTA_CRL_FLAG)
  4589. FindInfo.dwFindFlags |= CRL_FIND_ISSUED_BY_DELTA_FLAG;
  4590. FindInfo.dwFindType = CRL_FIND_ISSUED_BY;
  4591. FindInfo.pvFindPara = pIssuerContext;
  4592. if (pCrlContext = ToCrlContext(CheckAutoResyncAndFindElementInStore(
  4593. (PCERT_STORE) hCertStore,
  4594. CERT_STORE_CRL_CONTEXT - 1,
  4595. &FindInfo,
  4596. ToContextElement(pPrevCrlContext)
  4597. )))
  4598. VerifyCrl(
  4599. pCrlContext,
  4600. pIssuerContext,
  4601. pdwFlags
  4602. );
  4603. CommonReturn:
  4604. return pCrlContext;
  4605. ErrorReturn:
  4606. if (pPrevCrlContext)
  4607. CertFreeCRLContext(pPrevCrlContext);
  4608. pCrlContext = NULL;
  4609. goto CommonReturn;
  4610. SET_ERROR(InvalidArg, E_INVALIDARG)
  4611. }
  4612. //+-------------------------------------------------------------------------
  4613. // Enumerate the CRL contexts in the store.
  4614. //
  4615. // If a CRL isn't found, NULL is returned.
  4616. // Otherwise, a pointer to a read only CRL_CONTEXT is returned. CRL_CONTEXT
  4617. // must be freed by calling CertFreeCRLContext or is freed when passed as the
  4618. // pPrevCrlContext on a subsequent call. CertDuplicateCRLContext
  4619. // can be called to make a duplicate.
  4620. //
  4621. // pPrevCrlContext MUST BE NULL to enumerate the first
  4622. // CRL in the store. Successive CRLs are enumerated by setting
  4623. // pPrevCrlContext to the CRL_CONTEXT returned by a previous call.
  4624. //
  4625. // NOTE: a NON-NULL pPrevCrlContext is always CertFreeCRLContext'ed by
  4626. // this function, even for an error.
  4627. //--------------------------------------------------------------------------
  4628. PCCRL_CONTEXT
  4629. WINAPI
  4630. CertEnumCRLsInStore(
  4631. IN HCERTSTORE hCertStore,
  4632. IN PCCRL_CONTEXT pPrevCrlContext
  4633. )
  4634. {
  4635. return ToCrlContext(CheckAutoResyncAndFindElementInStore(
  4636. (PCERT_STORE) hCertStore,
  4637. CERT_STORE_CRL_CONTEXT - 1,
  4638. &FindAnyInfo,
  4639. ToContextElement(pPrevCrlContext)
  4640. ));
  4641. }
  4642. //+-------------------------------------------------------------------------
  4643. // Find the first or next CRL context in the store.
  4644. //
  4645. // The CRL is found according to the dwFindType and its pvFindPara.
  4646. // See below for a list of the find types and its parameters.
  4647. //
  4648. // Currently dwFindFlags isn't used and must be set to 0.
  4649. //
  4650. // Usage of dwCertEncodingType depends on the dwFindType.
  4651. //
  4652. // If the first or next CRL isn't found, NULL is returned.
  4653. // Otherwise, a pointer to a read only CRL_CONTEXT is returned. CRL_CONTEXT
  4654. // must be freed by calling CertFreeCRLContext or is freed when passed as the
  4655. // pPrevCrlContext on a subsequent call. CertDuplicateCRLContext
  4656. // can be called to make a duplicate.
  4657. //
  4658. // pPrevCrlContext MUST BE NULL on the first
  4659. // call to find the CRL. To find the next CRL, the
  4660. // pPrevCrlContext is set to the CRL_CONTEXT returned by a previous call.
  4661. //
  4662. // NOTE: a NON-NULL pPrevCrlContext is always CertFreeCRLContext'ed by
  4663. // this function, even for an error.
  4664. //--------------------------------------------------------------------------
  4665. PCCRL_CONTEXT
  4666. WINAPI
  4667. CertFindCRLInStore(
  4668. IN HCERTSTORE hCertStore,
  4669. IN DWORD dwCertEncodingType,
  4670. IN DWORD dwFindFlags,
  4671. IN DWORD dwFindType,
  4672. IN const void *pvFindPara,
  4673. IN PCCRL_CONTEXT pPrevCrlContext
  4674. )
  4675. {
  4676. CERT_STORE_PROV_FIND_INFO FindInfo;
  4677. FindInfo.cbSize = sizeof(FindInfo);
  4678. FindInfo.dwMsgAndCertEncodingType = dwCertEncodingType;
  4679. FindInfo.dwFindFlags = dwFindFlags;
  4680. FindInfo.dwFindType = dwFindType;
  4681. FindInfo.pvFindPara = pvFindPara;
  4682. return ToCrlContext(CheckAutoResyncAndFindElementInStore(
  4683. (PCERT_STORE) hCertStore,
  4684. CERT_STORE_CRL_CONTEXT - 1,
  4685. &FindInfo,
  4686. ToContextElement(pPrevCrlContext)
  4687. ));
  4688. }
  4689. //+-------------------------------------------------------------------------
  4690. // Duplicate a CRL context
  4691. //--------------------------------------------------------------------------
  4692. PCCRL_CONTEXT
  4693. WINAPI
  4694. CertDuplicateCRLContext(
  4695. IN PCCRL_CONTEXT pCrlContext
  4696. )
  4697. {
  4698. if (pCrlContext)
  4699. AddRefContextElement(ToContextElement(pCrlContext));
  4700. return pCrlContext;
  4701. }
  4702. //+-------------------------------------------------------------------------
  4703. // Create a CRL context from the encoded CRL. The created
  4704. // context isn't put in a store.
  4705. //
  4706. // Makes a copy of the encoded CRL in the created context.
  4707. //
  4708. // If unable to decode and create the CRL context, NULL is returned.
  4709. // Otherwise, a pointer to a read only CRL_CONTEXT is returned.
  4710. // CRL_CONTEXT must be freed by calling CertFreeCRLContext.
  4711. // CertDuplicateCRLContext can be called to make a duplicate.
  4712. //
  4713. // CertSetCRLContextProperty and CertGetCRLContextProperty can be called
  4714. // to store properties for the CRL.
  4715. //--------------------------------------------------------------------------
  4716. PCCRL_CONTEXT
  4717. WINAPI
  4718. CertCreateCRLContext(
  4719. IN DWORD dwCertEncodingType,
  4720. IN const BYTE *pbCrlEncoded,
  4721. IN DWORD cbCrlEncoded
  4722. )
  4723. {
  4724. PCCRL_CONTEXT pCrlContext;
  4725. CertAddEncodedCRLToStore(
  4726. NULL, // hCertStore
  4727. dwCertEncodingType,
  4728. pbCrlEncoded,
  4729. cbCrlEncoded,
  4730. CERT_STORE_ADD_ALWAYS,
  4731. &pCrlContext
  4732. );
  4733. return pCrlContext;
  4734. }
  4735. //+-------------------------------------------------------------------------
  4736. // Free a CRL context
  4737. //
  4738. // There needs to be a corresponding free for each context obtained by a
  4739. // get, duplicate or create.
  4740. //--------------------------------------------------------------------------
  4741. BOOL
  4742. WINAPI
  4743. CertFreeCRLContext(
  4744. IN PCCRL_CONTEXT pCrlContext
  4745. )
  4746. {
  4747. ReleaseContextElement(ToContextElement(pCrlContext));
  4748. return TRUE;
  4749. }
  4750. //+-------------------------------------------------------------------------
  4751. // Set the property for the specified CRL context.
  4752. //
  4753. // Same Property Ids and semantics as CertSetCertificateContextProperty.
  4754. //--------------------------------------------------------------------------
  4755. BOOL
  4756. WINAPI
  4757. CertSetCRLContextProperty(
  4758. IN PCCRL_CONTEXT pCrlContext,
  4759. IN DWORD dwPropId,
  4760. IN DWORD dwFlags,
  4761. IN const void *pvData
  4762. )
  4763. {
  4764. return SetProperty(
  4765. ToContextElement(pCrlContext),
  4766. dwPropId,
  4767. dwFlags,
  4768. pvData
  4769. );
  4770. }
  4771. //+-------------------------------------------------------------------------
  4772. // Get the property for the specified CRL context.
  4773. //
  4774. // Same Property Ids and semantics as CertGetCertificateContextProperty.
  4775. //
  4776. // CERT_SHA1_HASH_PROP_ID, CERT_MD5_HASH_PROP_ID or
  4777. // CERT_SIGNATURE_HASH_PROP_ID is the predefined property of most interest.
  4778. //--------------------------------------------------------------------------
  4779. BOOL
  4780. WINAPI
  4781. CertGetCRLContextProperty(
  4782. IN PCCRL_CONTEXT pCrlContext,
  4783. IN DWORD dwPropId,
  4784. OUT void *pvData,
  4785. IN OUT DWORD *pcbData
  4786. )
  4787. {
  4788. return GetProperty(
  4789. ToContextElement(pCrlContext),
  4790. dwPropId,
  4791. pvData,
  4792. pcbData
  4793. );
  4794. }
  4795. //+-------------------------------------------------------------------------
  4796. // Enumerate the properties for the specified CRL context.
  4797. //--------------------------------------------------------------------------
  4798. DWORD
  4799. WINAPI
  4800. CertEnumCRLContextProperties(
  4801. IN PCCRL_CONTEXT pCrlContext,
  4802. IN DWORD dwPropId
  4803. )
  4804. {
  4805. return EnumProperties(
  4806. ToContextElement(pCrlContext),
  4807. dwPropId
  4808. );
  4809. }
  4810. //+-------------------------------------------------------------------------
  4811. // Called by qsort.
  4812. //
  4813. // Compare's the CRL entry's serial numbers. Note, since we won't be adding
  4814. // any entries, don't need to worry about leading 0's or ff's. Also, ASN.1
  4815. // decoding should have removed them.
  4816. //
  4817. // The elements being sorted are pointers to the CRL entries. Not the
  4818. // CRL entries.
  4819. //--------------------------------------------------------------------------
  4820. STATIC int __cdecl CompareCrlEntry(
  4821. IN const void *pelem1,
  4822. IN const void *pelem2
  4823. )
  4824. {
  4825. PCRL_ENTRY p1 = *((PCRL_ENTRY *) pelem1);
  4826. PCRL_ENTRY p2 = *((PCRL_ENTRY *) pelem2);
  4827. DWORD cb1 = p1->SerialNumber.cbData;
  4828. DWORD cb2 = p2->SerialNumber.cbData;
  4829. if (cb1 == cb2) {
  4830. if (0 == cb1)
  4831. return 0;
  4832. else
  4833. return memcmp(p1->SerialNumber.pbData, p2->SerialNumber.pbData,
  4834. cb1);
  4835. } else if (cb1 < cb2)
  4836. return -1;
  4837. else
  4838. return 1;
  4839. }
  4840. //+-------------------------------------------------------------------------
  4841. // Called by bsearch.
  4842. //
  4843. // Compare's the key's serial number with the CRL entry's serial number
  4844. //
  4845. // The elements being searched are pointers to the CRL entries. Not the
  4846. // CRL entries.
  4847. //--------------------------------------------------------------------------
  4848. STATIC int __cdecl CompareCrlEntrySerialNumber(
  4849. IN const void *pkey,
  4850. IN const void *pvalue
  4851. )
  4852. {
  4853. PCRYPT_INTEGER_BLOB pSerialNumber = (PCRYPT_INTEGER_BLOB) pkey;
  4854. PCRL_ENTRY pCrlEntry = *((PCRL_ENTRY *) pvalue);
  4855. DWORD cb1 = pSerialNumber->cbData;
  4856. DWORD cb2 = pCrlEntry->SerialNumber.cbData;
  4857. if (cb1 == cb2) {
  4858. if (0 == cb1)
  4859. return 0;
  4860. else
  4861. return memcmp(pSerialNumber->pbData,
  4862. pCrlEntry->SerialNumber.pbData, cb1);
  4863. } else if (cb1 < cb2)
  4864. return -1;
  4865. else
  4866. return 1;
  4867. }
  4868. //+-------------------------------------------------------------------------
  4869. // Search the CRL's list of entries for the specified certificate.
  4870. //
  4871. // TRUE is returned if we were able to search the list. Otherwise, FALSE is
  4872. // returned,
  4873. //
  4874. // For success, if the certificate was found in the list, *ppCrlEntry is
  4875. // updated with a pointer to the entry. Otherwise, *ppCrlEntry is set to NULL.
  4876. // The returned entry isn't allocated and must not be freed.
  4877. //
  4878. // dwFlags and pvReserved currently aren't used and must be set to 0 or NULL.
  4879. //--------------------------------------------------------------------------
  4880. BOOL
  4881. WINAPI
  4882. CertFindCertificateInCRL(
  4883. IN PCCERT_CONTEXT pCert,
  4884. IN PCCRL_CONTEXT pCrlContext,
  4885. IN DWORD dwFlags,
  4886. IN OPTIONAL void *pvReserved,
  4887. OUT PCRL_ENTRY *ppCrlEntry
  4888. )
  4889. {
  4890. BOOL fResult;
  4891. PCRL_INFO pInfo = pCrlContext->pCrlInfo;
  4892. PCONTEXT_ELEMENT pCacheEle;
  4893. PCERT_STORE pCacheStore;
  4894. PCRL_ENTRY *ppSortedEntry;
  4895. DWORD cEntry;
  4896. PCRL_ENTRY *ppFoundEntry;
  4897. *ppCrlEntry = NULL;
  4898. // Get qsorted pointers to the CRL Entries
  4899. if (0 == (cEntry = pInfo->cCRLEntry))
  4900. goto SuccessReturn;
  4901. if (NULL == (pCacheEle = GetCacheElement(ToContextElement(pCrlContext))))
  4902. goto NoCacheElementError;
  4903. pCacheStore = pCacheEle->pStore;
  4904. LockStore(pCacheStore);
  4905. if (NULL == (ppSortedEntry =
  4906. ToCrlContextSuffix(pCacheEle)->ppSortedEntry)) {
  4907. if (ppSortedEntry = (PCRL_ENTRY *) PkiNonzeroAlloc(
  4908. cEntry * sizeof(PCRL_ENTRY))) {
  4909. // Initialize the array of entry pointers
  4910. DWORD c = cEntry;
  4911. PCRL_ENTRY p = pInfo->rgCRLEntry;
  4912. PCRL_ENTRY *pp = ppSortedEntry;
  4913. for ( ; c > 0; c--, p++, pp++)
  4914. *pp = p;
  4915. // Now sort the CRL entry pointers
  4916. qsort(ppSortedEntry, cEntry, sizeof(PCRL_ENTRY), CompareCrlEntry);
  4917. ToCrlContextSuffix(pCacheEle)->ppSortedEntry = ppSortedEntry;
  4918. }
  4919. }
  4920. UnlockStore(pCacheStore);
  4921. if (NULL == ppSortedEntry)
  4922. goto OutOfMemory;
  4923. // Search the sorted subject entry pointers
  4924. if (ppFoundEntry = (PCRL_ENTRY *) bsearch(&pCert->pCertInfo->SerialNumber,
  4925. ppSortedEntry, cEntry, sizeof(PCRL_ENTRY),
  4926. CompareCrlEntrySerialNumber))
  4927. *ppCrlEntry = *ppFoundEntry;
  4928. SuccessReturn:
  4929. fResult = TRUE;
  4930. CommonReturn:
  4931. return fResult;
  4932. ErrorReturn:
  4933. *ppCrlEntry = (PCRL_ENTRY) 1;
  4934. fResult = FALSE;
  4935. goto CommonReturn;
  4936. TRACE_ERROR(NoCacheElementError)
  4937. TRACE_ERROR(OutOfMemory)
  4938. }
  4939. //+=========================================================================
  4940. // CTL APIs
  4941. //==========================================================================
  4942. BOOL
  4943. WINAPI
  4944. CertAddEncodedCTLToStore(
  4945. IN HCERTSTORE hCertStore,
  4946. IN DWORD dwMsgAndCertEncodingType,
  4947. IN const BYTE *pbCtlEncoded,
  4948. IN DWORD cbCtlEncoded,
  4949. IN DWORD dwAddDisposition,
  4950. OUT OPTIONAL PCCTL_CONTEXT *ppCtlContext
  4951. )
  4952. {
  4953. BOOL fResult;
  4954. PCONTEXT_ELEMENT pStoreEle = NULL;
  4955. fResult = AddEncodedContextToStore(
  4956. (PCERT_STORE) hCertStore,
  4957. CERT_STORE_CTL_CONTEXT - 1,
  4958. dwMsgAndCertEncodingType,
  4959. pbCtlEncoded,
  4960. cbCtlEncoded,
  4961. dwAddDisposition,
  4962. ppCtlContext ? &pStoreEle : NULL
  4963. );
  4964. if (ppCtlContext)
  4965. *ppCtlContext = ToCtlContext(pStoreEle);
  4966. return fResult;
  4967. }
  4968. BOOL
  4969. WINAPI
  4970. CertAddCTLContextToStore(
  4971. IN HCERTSTORE hCertStore,
  4972. IN PCCTL_CONTEXT pCtlContext,
  4973. IN DWORD dwAddDisposition,
  4974. OUT OPTIONAL PCCTL_CONTEXT *ppStoreContext
  4975. )
  4976. {
  4977. BOOL fResult;
  4978. PCONTEXT_ELEMENT pStoreEle = NULL;
  4979. fResult = AddContextToStore(
  4980. (PCERT_STORE) hCertStore,
  4981. ToContextElement(pCtlContext),
  4982. pCtlContext->dwMsgAndCertEncodingType,
  4983. pCtlContext->pbCtlEncoded,
  4984. pCtlContext->cbCtlEncoded,
  4985. dwAddDisposition,
  4986. ppStoreContext ? &pStoreEle : NULL
  4987. );
  4988. if (ppStoreContext)
  4989. *ppStoreContext = ToCtlContext(pStoreEle);
  4990. return fResult;
  4991. }
  4992. BOOL
  4993. WINAPI
  4994. CertAddCTLLinkToStore(
  4995. IN HCERTSTORE hCertStore,
  4996. IN PCCTL_CONTEXT pCtlContext,
  4997. IN DWORD dwAddDisposition,
  4998. OUT OPTIONAL PCCTL_CONTEXT *ppStoreContext
  4999. )
  5000. {
  5001. BOOL fResult;
  5002. PCONTEXT_ELEMENT pStoreEle = NULL;
  5003. fResult = AddLinkContextToCacheStore(
  5004. (PCERT_STORE) hCertStore,
  5005. ToContextElement(pCtlContext),
  5006. dwAddDisposition,
  5007. ppStoreContext ? &pStoreEle : NULL
  5008. );
  5009. if (ppStoreContext)
  5010. *ppStoreContext = ToCtlContext(pStoreEle);
  5011. return fResult;
  5012. }
  5013. //+-------------------------------------------------------------------------
  5014. // Serialize the CTL context's encoded CTL and its properties.
  5015. //--------------------------------------------------------------------------
  5016. BOOL
  5017. WINAPI
  5018. CertSerializeCTLStoreElement(
  5019. IN PCCTL_CONTEXT pCtlContext,
  5020. IN DWORD dwFlags,
  5021. OUT BYTE *pbElement,
  5022. IN OUT DWORD *pcbElement
  5023. )
  5024. {
  5025. return SerializeContextElement(
  5026. ToContextElement(pCtlContext),
  5027. dwFlags,
  5028. pbElement,
  5029. pcbElement
  5030. );
  5031. }
  5032. //+-------------------------------------------------------------------------
  5033. // Delete the specified CTL from the store.
  5034. //
  5035. // All subsequent gets for the CTL will fail. However,
  5036. // memory allocated for the CTL isn't freed until all of its contexts
  5037. // have also been freed.
  5038. //
  5039. // The pCtlContext is obtained from a get or duplicate.
  5040. //
  5041. // NOTE: the pCtlContext is always CertFreeCTLContext'ed by
  5042. // this function, even for an error.
  5043. //--------------------------------------------------------------------------
  5044. BOOL
  5045. WINAPI
  5046. CertDeleteCTLFromStore(
  5047. IN PCCTL_CONTEXT pCtlContext
  5048. )
  5049. {
  5050. assert(NULL == pCtlContext || (CERT_STORE_CTL_CONTEXT - 1) ==
  5051. ToContextElement(pCtlContext)->dwContextType);
  5052. return DeleteContextElement(ToContextElement(pCtlContext));
  5053. }
  5054. //+-------------------------------------------------------------------------
  5055. // Duplicate a CTL context
  5056. //--------------------------------------------------------------------------
  5057. PCCTL_CONTEXT
  5058. WINAPI
  5059. CertDuplicateCTLContext(
  5060. IN PCCTL_CONTEXT pCtlContext
  5061. )
  5062. {
  5063. if (pCtlContext)
  5064. AddRefContextElement(ToContextElement(pCtlContext));
  5065. return pCtlContext;
  5066. }
  5067. //+-------------------------------------------------------------------------
  5068. // Create a CTL context from the encoded CTL. The created
  5069. // context isn't put in a store.
  5070. //
  5071. // Makes a copy of the encoded CTL in the created context.
  5072. //
  5073. // If unable to decode and create the CTL context, NULL is returned.
  5074. // Otherwise, a pointer to a read only CTL_CONTEXT is returned.
  5075. // CTL_CONTEXT must be freed by calling CertFreeCTLContext.
  5076. // CertDuplicateCTLContext can be called to make a duplicate.
  5077. //
  5078. // CertSetCTLContextProperty and CertGetCTLContextProperty can be called
  5079. // to store properties for the CTL.
  5080. //--------------------------------------------------------------------------
  5081. PCCTL_CONTEXT
  5082. WINAPI
  5083. CertCreateCTLContext(
  5084. IN DWORD dwMsgAndCertEncodingType,
  5085. IN const BYTE *pbCtlEncoded,
  5086. IN DWORD cbCtlEncoded
  5087. )
  5088. {
  5089. PCCTL_CONTEXT pCtlContext;
  5090. CertAddEncodedCTLToStore(
  5091. NULL, // hCertStore
  5092. dwMsgAndCertEncodingType,
  5093. pbCtlEncoded,
  5094. cbCtlEncoded,
  5095. CERT_STORE_ADD_ALWAYS,
  5096. &pCtlContext
  5097. );
  5098. return pCtlContext;
  5099. }
  5100. //+-------------------------------------------------------------------------
  5101. // Free a CTL context
  5102. //
  5103. // There needs to be a corresponding free for each context obtained by a
  5104. // get, duplicate or create.
  5105. //--------------------------------------------------------------------------
  5106. BOOL
  5107. WINAPI
  5108. CertFreeCTLContext(
  5109. IN PCCTL_CONTEXT pCtlContext
  5110. )
  5111. {
  5112. ReleaseContextElement(ToContextElement(pCtlContext));
  5113. return TRUE;
  5114. }
  5115. //+-------------------------------------------------------------------------
  5116. // Set the property for the specified CTL context.
  5117. //
  5118. // Same Property Ids and semantics as CertSetCertificateContextProperty.
  5119. //--------------------------------------------------------------------------
  5120. BOOL
  5121. WINAPI
  5122. CertSetCTLContextProperty(
  5123. IN PCCTL_CONTEXT pCtlContext,
  5124. IN DWORD dwPropId,
  5125. IN DWORD dwFlags,
  5126. IN const void *pvData
  5127. )
  5128. {
  5129. return SetProperty(
  5130. ToContextElement(pCtlContext),
  5131. dwPropId,
  5132. dwFlags,
  5133. pvData
  5134. );
  5135. }
  5136. //+-------------------------------------------------------------------------
  5137. // Get the property for the specified CTL context.
  5138. //
  5139. // Same Property Ids and semantics as CertGetCertificateContextProperty.
  5140. //
  5141. // CERT_SHA1_HASH_PROP_ID or CERT_MD5_HASH_PROP_ID is the predefined
  5142. // property of most interest.
  5143. //--------------------------------------------------------------------------
  5144. BOOL
  5145. WINAPI
  5146. CertGetCTLContextProperty(
  5147. IN PCCTL_CONTEXT pCtlContext,
  5148. IN DWORD dwPropId,
  5149. OUT void *pvData,
  5150. IN OUT DWORD *pcbData
  5151. )
  5152. {
  5153. return GetProperty(
  5154. ToContextElement(pCtlContext),
  5155. dwPropId,
  5156. pvData,
  5157. pcbData
  5158. );
  5159. }
  5160. //+-------------------------------------------------------------------------
  5161. // Enumerate the properties for the specified CTL context.
  5162. //--------------------------------------------------------------------------
  5163. DWORD
  5164. WINAPI
  5165. CertEnumCTLContextProperties(
  5166. IN PCCTL_CONTEXT pCtlContext,
  5167. IN DWORD dwPropId
  5168. )
  5169. {
  5170. return EnumProperties(
  5171. ToContextElement(pCtlContext),
  5172. dwPropId
  5173. );
  5174. }
  5175. //+-------------------------------------------------------------------------
  5176. // Enumerate the CTL contexts in the store.
  5177. //
  5178. // If a CTL isn't found, NULL is returned.
  5179. // Otherwise, a pointer to a read only CTL_CONTEXT is returned. CTL_CONTEXT
  5180. // must be freed by calling CertFreeCTLContext or is freed when passed as the
  5181. // pPrevCtlContext on a subsequent call. CertDuplicateCTLContext
  5182. // can be called to make a duplicate.
  5183. //
  5184. // pPrevCtlContext MUST BE NULL to enumerate the first
  5185. // CTL in the store. Successive CTLs are enumerated by setting
  5186. // pPrevCtlContext to the CTL_CONTEXT returned by a previous call.
  5187. //
  5188. // NOTE: a NON-NULL pPrevCtlContext is always CertFreeCTLContext'ed by
  5189. // this function, even for an error.
  5190. //--------------------------------------------------------------------------
  5191. PCCTL_CONTEXT
  5192. WINAPI
  5193. CertEnumCTLsInStore(
  5194. IN HCERTSTORE hCertStore,
  5195. IN PCCTL_CONTEXT pPrevCtlContext
  5196. )
  5197. {
  5198. return ToCtlContext(CheckAutoResyncAndFindElementInStore(
  5199. (PCERT_STORE) hCertStore,
  5200. CERT_STORE_CTL_CONTEXT - 1,
  5201. &FindAnyInfo,
  5202. ToContextElement(pPrevCtlContext)
  5203. ));
  5204. }
  5205. STATIC BOOL CompareAlgorithmIdentifier(
  5206. IN DWORD dwEncodingType,
  5207. IN PCRYPT_ALGORITHM_IDENTIFIER pAlg1,
  5208. IN PCRYPT_ALGORITHM_IDENTIFIER pAlg2
  5209. )
  5210. {
  5211. BOOL fResult = FALSE;
  5212. if (NULL == pAlg1->pszObjId) {
  5213. if (NULL == pAlg2->pszObjId)
  5214. // Both are NULL
  5215. fResult = TRUE;
  5216. // else
  5217. // One of the OIDs is NULL
  5218. } else if (pAlg2->pszObjId) {
  5219. if (0 == strcmp(pAlg1->pszObjId, pAlg2->pszObjId)) {
  5220. DWORD cb1 = pAlg1->Parameters.cbData;
  5221. BYTE *pb1 = pAlg1->Parameters.pbData;
  5222. DWORD cb2 = pAlg2->Parameters.cbData;
  5223. BYTE *pb2 = pAlg2->Parameters.pbData;
  5224. if (X509_ASN_ENCODING == GET_CERT_ENCODING_TYPE(dwEncodingType)) {
  5225. // Check for NULL parameters: {0x05, 0x00}
  5226. if (2 == cb1 && 0x05 == pb1[0] && 0x00 == pb1[1])
  5227. cb1 = 0;
  5228. if (2 == cb2 && 0x05 == pb2[0] && 0x00 == pb2[1])
  5229. cb2 = 0;
  5230. }
  5231. if (cb1 == cb2) {
  5232. if (0 == cb1 || 0 == memcmp(pb1, pb2, cb1))
  5233. fResult = TRUE;
  5234. }
  5235. }
  5236. }
  5237. // else
  5238. // One of the OIDs is NULL
  5239. return fResult;
  5240. }
  5241. //+-------------------------------------------------------------------------
  5242. // Called by qsort. Compare's the CTL entry's SubjectIdentifier.
  5243. //
  5244. // The elements being sorted are pointers to the CTL entries. Not the
  5245. // CTL entries.
  5246. //--------------------------------------------------------------------------
  5247. STATIC int __cdecl CompareCtlEntry(
  5248. IN const void *pelem1,
  5249. IN const void *pelem2
  5250. )
  5251. {
  5252. PCTL_ENTRY p1 = *((PCTL_ENTRY *) pelem1);
  5253. PCTL_ENTRY p2 = *((PCTL_ENTRY *) pelem2);
  5254. DWORD cb1 = p1->SubjectIdentifier.cbData;
  5255. DWORD cb2 = p2->SubjectIdentifier.cbData;
  5256. if (cb1 == cb2) {
  5257. if (0 == cb1)
  5258. return 0;
  5259. else
  5260. return memcmp(p1->SubjectIdentifier.pbData,
  5261. p2->SubjectIdentifier.pbData, cb1);
  5262. } else if (cb1 < cb2)
  5263. return -1;
  5264. else
  5265. return 1;
  5266. }
  5267. //+-------------------------------------------------------------------------
  5268. // Called by bsearch. Compare's the key's SubjectIdentifier with the CTL
  5269. // entry's SubjectIdentifier.
  5270. //
  5271. // The elements being searched are pointers to the CTL entries. Not the
  5272. // CTL entries.
  5273. //--------------------------------------------------------------------------
  5274. STATIC int __cdecl CompareCtlEntrySubjectIdentifier(
  5275. IN const void *pkey,
  5276. IN const void *pvalue
  5277. )
  5278. {
  5279. PCRYPT_DATA_BLOB pSubjectIdentifier = (PCRYPT_DATA_BLOB) pkey;
  5280. PCTL_ENTRY pCtlEntry = *((PCTL_ENTRY *) pvalue);
  5281. DWORD cb1 = pSubjectIdentifier->cbData;
  5282. DWORD cb2 = pCtlEntry->SubjectIdentifier.cbData;
  5283. if (cb1 == cb2) {
  5284. if (0 == cb1)
  5285. return 0;
  5286. else
  5287. return memcmp(pSubjectIdentifier->pbData,
  5288. pCtlEntry->SubjectIdentifier.pbData, cb1);
  5289. } else if (cb1 < cb2)
  5290. return -1;
  5291. else
  5292. return 1;
  5293. }
  5294. //+-------------------------------------------------------------------------
  5295. // Attempt to find the specified subject in the CTL.
  5296. //
  5297. // For CTL_CERT_SUBJECT_TYPE, pvSubject points to a CERT_CONTEXT. The CTL's
  5298. // SubjectAlgorithm is examined to determine the representation of the
  5299. // subject's identity. Initially, only SHA1 or MD5 hash will be supported.
  5300. // The appropriate hash property is obtained from the CERT_CONTEXT.
  5301. //
  5302. // For CTL_ANY_SUBJECT_TYPE, pvSubject points to the CTL_ANY_SUBJECT_INFO
  5303. // structure which contains the SubjectAlgorithm to be matched in the CTL
  5304. // and the SubjectIdentifer to be matched in one of the CTL entries.
  5305. //
  5306. // The cetificate's hash or the CTL_ANY_SUBJECT_INFO's SubjectIdentifier
  5307. // is used as the key in searching the subject entries. A binary
  5308. // memory comparison is done between the key and the entry's SubjectIdentifer.
  5309. //
  5310. // dwEncodingType isn't used for either of the above SubjectTypes.
  5311. //--------------------------------------------------------------------------
  5312. PCTL_ENTRY
  5313. WINAPI
  5314. CertFindSubjectInCTL(
  5315. IN DWORD dwEncodingType,
  5316. IN DWORD dwSubjectType,
  5317. IN void *pvSubject,
  5318. IN PCCTL_CONTEXT pCtlContext,
  5319. IN DWORD dwFlags
  5320. )
  5321. {
  5322. PCTL_ENTRY *ppSubjectEntry;
  5323. PCTL_ENTRY pSubjectEntry;
  5324. PCTL_INFO pInfo = pCtlContext->pCtlInfo;
  5325. PCONTEXT_ELEMENT pCacheEle;
  5326. PCERT_STORE pCacheStore;
  5327. BYTE rgbHash[MAX_HASH_LEN];
  5328. CRYPT_DATA_BLOB Key;
  5329. PCTL_ENTRY *ppSortedEntry;
  5330. DWORD cEntry;
  5331. // Get Key to be used in bsearch
  5332. switch (dwSubjectType) {
  5333. case CTL_CERT_SUBJECT_TYPE:
  5334. {
  5335. DWORD Algid;
  5336. DWORD dwPropId;
  5337. if (NULL == pInfo->SubjectAlgorithm.pszObjId)
  5338. goto NoSubjectAlgorithm;
  5339. Algid = CertOIDToAlgId(pInfo->SubjectAlgorithm.pszObjId);
  5340. switch (Algid) {
  5341. case CALG_SHA1:
  5342. dwPropId = CERT_SHA1_HASH_PROP_ID;
  5343. break;
  5344. case CALG_MD5:
  5345. dwPropId = CERT_MD5_HASH_PROP_ID;
  5346. break;
  5347. default:
  5348. goto UnknownAlgid;
  5349. }
  5350. Key.cbData = MAX_HASH_LEN;
  5351. if (!CertGetCertificateContextProperty(
  5352. (PCCERT_CONTEXT) pvSubject,
  5353. dwPropId,
  5354. rgbHash,
  5355. &Key.cbData) || 0 == Key.cbData)
  5356. goto GetHashError;
  5357. Key.pbData = rgbHash;
  5358. }
  5359. break;
  5360. case CTL_ANY_SUBJECT_TYPE:
  5361. {
  5362. PCTL_ANY_SUBJECT_INFO pAnyInfo =
  5363. (PCTL_ANY_SUBJECT_INFO) pvSubject;
  5364. if (pAnyInfo->SubjectAlgorithm.pszObjId &&
  5365. !CompareAlgorithmIdentifier(
  5366. (pCtlContext->dwMsgAndCertEncodingType >> 16) &
  5367. CERT_ENCODING_TYPE_MASK,
  5368. &pAnyInfo->SubjectAlgorithm,
  5369. &pInfo->SubjectAlgorithm))
  5370. goto NotFoundError;
  5371. Key = pAnyInfo->SubjectIdentifier;
  5372. }
  5373. break;
  5374. default:
  5375. goto InvalidSubjectType;
  5376. }
  5377. // Get qsorted pointers to the Subject Entries
  5378. if (0 == (cEntry = pInfo->cCTLEntry))
  5379. goto NoEntryError;
  5380. if (NULL == (pCacheEle = GetCacheElement(ToContextElement(pCtlContext))))
  5381. goto NoCacheElementError;
  5382. pCacheStore = pCacheEle->pStore;
  5383. LockStore(pCacheStore);
  5384. if (NULL == (ppSortedEntry =
  5385. ToCtlContextSuffix(pCacheEle)->ppSortedEntry)) {
  5386. if (ppSortedEntry = (PCTL_ENTRY *) PkiNonzeroAlloc(
  5387. cEntry * sizeof(PCTL_ENTRY))) {
  5388. // Initialize the array of entry pointers
  5389. DWORD c = cEntry;
  5390. PCTL_ENTRY p = pInfo->rgCTLEntry;
  5391. PCTL_ENTRY *pp = ppSortedEntry;
  5392. for ( ; c > 0; c--, p++, pp++)
  5393. *pp = p;
  5394. // Now sort the subject entry pointers
  5395. qsort(ppSortedEntry, cEntry, sizeof(PCTL_ENTRY), CompareCtlEntry);
  5396. ToCtlContextSuffix(pCacheEle)->ppSortedEntry = ppSortedEntry;
  5397. }
  5398. }
  5399. UnlockStore(pCacheStore);
  5400. if (NULL == ppSortedEntry)
  5401. goto OutOfMemory;
  5402. // Search the sorted subject entry pointers
  5403. if (NULL == (ppSubjectEntry = (PCTL_ENTRY *) bsearch(&Key,
  5404. ppSortedEntry, cEntry, sizeof(PCTL_ENTRY),
  5405. CompareCtlEntrySubjectIdentifier)))
  5406. goto NotFoundError;
  5407. pSubjectEntry = *ppSubjectEntry;
  5408. CommonReturn:
  5409. return pSubjectEntry;
  5410. NotFoundError:
  5411. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  5412. ErrorReturn:
  5413. pSubjectEntry = NULL;
  5414. goto CommonReturn;
  5415. SET_ERROR(NoSubjectAlgorithm, CRYPT_E_NOT_FOUND)
  5416. SET_ERROR(UnknownAlgid, NTE_BAD_ALGID)
  5417. SET_ERROR(NoEntryError, CRYPT_E_NOT_FOUND)
  5418. TRACE_ERROR(NoCacheElementError)
  5419. TRACE_ERROR(GetHashError)
  5420. SET_ERROR(InvalidSubjectType, E_INVALIDARG)
  5421. TRACE_ERROR(OutOfMemory)
  5422. }
  5423. //+-------------------------------------------------------------------------
  5424. // Find the first or next CTL context in the store.
  5425. //
  5426. // The CTL is found according to the dwFindType and its pvFindPara.
  5427. // See below for a list of the find types and its parameters.
  5428. //
  5429. // Currently dwFindFlags isn't used and must be set to 0.
  5430. //
  5431. // Usage of dwMsgAndCertEncodingType depends on the dwFindType.
  5432. //
  5433. // If the first or next CTL isn't found, NULL is returned.
  5434. // Otherwise, a pointer to a read only CTL_CONTEXT is returned. CTL_CONTEXT
  5435. // must be freed by calling CertFreeCTLContext or is freed when passed as the
  5436. // pPrevCtlContext on a subsequent call. CertDuplicateCTLContext
  5437. // can be called to make a duplicate.
  5438. //
  5439. // pPrevCtlContext MUST BE NULL on the first
  5440. // call to find the CTL. To find the next CTL, the
  5441. // pPrevCtlContext is set to the CTL_CONTEXT returned by a previous call.
  5442. //
  5443. // NOTE: a NON-NULL pPrevCtlContext is always CertFreeCTLContext'ed by
  5444. // this function, even for an error.
  5445. //--------------------------------------------------------------------------
  5446. PCCTL_CONTEXT
  5447. WINAPI
  5448. CertFindCTLInStore(
  5449. IN HCERTSTORE hCertStore,
  5450. IN DWORD dwMsgAndCertEncodingType,
  5451. IN DWORD dwFindFlags,
  5452. IN DWORD dwFindType,
  5453. IN const void *pvFindPara,
  5454. IN PCCTL_CONTEXT pPrevCtlContext
  5455. )
  5456. {
  5457. CERT_STORE_PROV_FIND_INFO FindInfo;
  5458. FindInfo.cbSize = sizeof(FindInfo);
  5459. FindInfo.dwMsgAndCertEncodingType = dwMsgAndCertEncodingType;
  5460. FindInfo.dwFindFlags = dwFindFlags;
  5461. FindInfo.dwFindType = dwFindType;
  5462. FindInfo.pvFindPara = pvFindPara;
  5463. return ToCtlContext(CheckAutoResyncAndFindElementInStore(
  5464. (PCERT_STORE) hCertStore,
  5465. CERT_STORE_CTL_CONTEXT - 1,
  5466. &FindInfo,
  5467. ToContextElement(pPrevCtlContext)
  5468. ));
  5469. }
  5470. //+=========================================================================
  5471. // CERT_CONTEXT Functions
  5472. //==========================================================================
  5473. // pbCertEncoded has already been allocated
  5474. STATIC PCONTEXT_ELEMENT CreateCertElement(
  5475. IN PCERT_STORE pStore,
  5476. IN DWORD dwCertEncodingType,
  5477. IN BYTE *pbCertEncoded,
  5478. IN DWORD cbCertEncoded,
  5479. IN OPTIONAL PSHARE_ELEMENT pShareEle
  5480. )
  5481. {
  5482. PCONTEXT_ELEMENT pEle = NULL;
  5483. PCERT_CONTEXT pCert;
  5484. PCERT_INFO pInfo = NULL;
  5485. if (0 == GET_CERT_ENCODING_TYPE(dwCertEncodingType)) {
  5486. SetLastError((DWORD) E_INVALIDARG);
  5487. goto ErrorReturn;
  5488. }
  5489. if (NULL == pShareEle) {
  5490. cbCertEncoded = AdjustEncodedLength(
  5491. dwCertEncodingType, pbCertEncoded, cbCertEncoded);
  5492. if (NULL == (pInfo = (PCERT_INFO) AllocAndDecodeObject(
  5493. dwCertEncodingType,
  5494. X509_CERT_TO_BE_SIGNED,
  5495. pbCertEncoded,
  5496. cbCertEncoded))) goto ErrorReturn;
  5497. }
  5498. // Allocate and initialize the cert element structure
  5499. pEle = (PCONTEXT_ELEMENT) PkiZeroAlloc(sizeof(CONTEXT_ELEMENT) +
  5500. sizeof(CERT_CONTEXT));
  5501. if (pEle == NULL) goto ErrorReturn;
  5502. pEle->dwElementType = ELEMENT_TYPE_CACHE;
  5503. pEle->dwContextType = CERT_STORE_CERTIFICATE_CONTEXT - 1;
  5504. pEle->lRefCnt = 1;
  5505. pEle->pEle = pEle;
  5506. pEle->pStore = pStore;
  5507. pEle->pProvStore = pStore;
  5508. pCert = (PCERT_CONTEXT) ToCertContext(pEle);
  5509. pCert->dwCertEncodingType =
  5510. dwCertEncodingType & CERT_ENCODING_TYPE_MASK;
  5511. pCert->pbCertEncoded = pbCertEncoded;
  5512. pCert->cbCertEncoded = cbCertEncoded;
  5513. if (pShareEle) {
  5514. pEle->pShareEle = pShareEle;
  5515. assert(pShareEle->pvInfo);
  5516. pCert->pCertInfo = (PCERT_INFO) pShareEle->pvInfo;
  5517. assert(pbCertEncoded == pShareEle->pbEncoded);
  5518. assert(cbCertEncoded == pShareEle->cbEncoded);
  5519. } else {
  5520. pCert->pCertInfo = pInfo;
  5521. CertPerfIncrementCertElementCurrentCount();
  5522. CertPerfIncrementCertElementTotalCount();
  5523. }
  5524. pCert->hCertStore = (HCERTSTORE) pStore;
  5525. CommonReturn:
  5526. return pEle;
  5527. ErrorReturn:
  5528. if (pEle) {
  5529. PkiFree(pEle);
  5530. pEle = NULL;
  5531. }
  5532. PkiFree(pInfo);
  5533. goto CommonReturn;
  5534. }
  5535. STATIC void FreeCertElement(IN PCONTEXT_ELEMENT pEle)
  5536. {
  5537. PCCERT_CONTEXT pCert = ToCertContext(pEle);
  5538. if (pEle->pShareEle)
  5539. ReleaseShareElement(pEle->pShareEle);
  5540. else {
  5541. PkiFree(pCert->pbCertEncoded);
  5542. PkiFree(pCert->pCertInfo);
  5543. CertPerfDecrementCertElementCurrentCount();
  5544. }
  5545. PkiFree(pEle);
  5546. }
  5547. STATIC BOOL CompareCertHash(
  5548. IN PCCERT_CONTEXT pCert,
  5549. IN DWORD dwPropId,
  5550. IN PCRYPT_HASH_BLOB pHash
  5551. )
  5552. {
  5553. BYTE rgbHash[MAX_HASH_LEN];
  5554. DWORD cbHash = MAX_HASH_LEN;
  5555. CertGetCertificateContextProperty(
  5556. pCert,
  5557. dwPropId,
  5558. rgbHash,
  5559. &cbHash
  5560. );
  5561. if (cbHash == pHash->cbData &&
  5562. memcmp(rgbHash, pHash->pbData, cbHash) == 0)
  5563. return TRUE;
  5564. else
  5565. return FALSE;
  5566. }
  5567. STATIC BOOL CompareNameStrW(
  5568. IN DWORD dwCertEncodingType,
  5569. IN PCERT_NAME_BLOB pName,
  5570. IN LPCWSTR pwszFind
  5571. )
  5572. {
  5573. BOOL fResult = FALSE;
  5574. DWORD cwszFind;
  5575. LPWSTR pwszName = NULL;
  5576. DWORD cwszName;
  5577. if (pwszFind == NULL || *pwszFind == L'\0')
  5578. return TRUE;
  5579. cwszName = CertNameToStrW(
  5580. dwCertEncodingType,
  5581. pName,
  5582. CERT_SIMPLE_NAME_STR,
  5583. NULL, // pwsz
  5584. 0 // cwsz
  5585. );
  5586. if (pwszName = (LPWSTR) PkiNonzeroAlloc(cwszName * sizeof(WCHAR))) {
  5587. cwszName = CertNameToStrW(
  5588. dwCertEncodingType,
  5589. pName,
  5590. CERT_SIMPLE_NAME_STR,
  5591. pwszName,
  5592. cwszName) - 1;
  5593. cwszFind = wcslen(pwszFind);
  5594. // Start at end of the certificate's name and slide one character
  5595. // to the left until a match or reach the beginning of the
  5596. // certificate name.
  5597. for ( ; cwszName >= cwszFind; cwszName--) {
  5598. pwszName[cwszName] = L'\0';
  5599. if (CSTR_EQUAL == CompareStringU(
  5600. LOCALE_USER_DEFAULT,
  5601. NORM_IGNORECASE,
  5602. pwszFind,
  5603. -1,
  5604. &pwszName[cwszName - cwszFind],
  5605. -1
  5606. )) {
  5607. fResult = TRUE;
  5608. break;
  5609. }
  5610. }
  5611. PkiFree(pwszName);
  5612. }
  5613. return fResult;
  5614. }
  5615. STATIC BOOL CompareNameStrA(
  5616. IN DWORD dwCertEncodingType,
  5617. IN PCERT_NAME_BLOB pName,
  5618. IN LPCSTR pszFind
  5619. )
  5620. {
  5621. BOOL fResult = FALSE;
  5622. DWORD cszFind;
  5623. LPSTR pszName = NULL;
  5624. DWORD cszName;
  5625. if (pszFind == NULL || *pszFind == '\0')
  5626. return TRUE;
  5627. cszName = CertNameToStrA(
  5628. dwCertEncodingType,
  5629. pName,
  5630. CERT_SIMPLE_NAME_STR,
  5631. NULL, // psz
  5632. 0 // csz
  5633. );
  5634. if (pszName = (LPSTR) PkiNonzeroAlloc(cszName)) {
  5635. cszName = CertNameToStrA(
  5636. dwCertEncodingType,
  5637. pName,
  5638. CERT_SIMPLE_NAME_STR,
  5639. pszName,
  5640. cszName) - 1;
  5641. cszFind = strlen(pszFind);
  5642. // Start at end of the certificate's name and slide one character
  5643. // to the left until a match or reach the beginning of the
  5644. // certificate name.
  5645. for ( ; cszName >= cszFind; cszName--) {
  5646. pszName[cszName] = '\0';
  5647. if (CSTR_EQUAL == CompareStringA(
  5648. LOCALE_USER_DEFAULT,
  5649. NORM_IGNORECASE,
  5650. pszFind,
  5651. -1,
  5652. &pszName[cszName - cszFind],
  5653. -1
  5654. )) {
  5655. fResult = TRUE;
  5656. break;
  5657. }
  5658. }
  5659. PkiFree(pszName);
  5660. }
  5661. return fResult;
  5662. }
  5663. STATIC BOOL CompareCtlUsageIdentifiers(
  5664. IN PCTL_USAGE pPara,
  5665. IN DWORD cUsage,
  5666. IN PCTL_USAGE pUsage,
  5667. IN BOOL fOrUsage
  5668. )
  5669. {
  5670. if (pPara && pPara->cUsageIdentifier) {
  5671. DWORD cId1 = pPara->cUsageIdentifier;
  5672. LPSTR *ppszId1 = pPara->rgpszUsageIdentifier;
  5673. for ( ; cId1 > 0; cId1--, ppszId1++) {
  5674. DWORD i;
  5675. for (i = 0; i < cUsage; i++) {
  5676. DWORD cId2 = pUsage[i].cUsageIdentifier;
  5677. LPSTR *ppszId2 = pUsage[i].rgpszUsageIdentifier;
  5678. for ( ; cId2 > 0; cId2--, ppszId2++) {
  5679. if (0 == strcmp(*ppszId1, *ppszId2)) {
  5680. if (fOrUsage)
  5681. return TRUE;
  5682. break;
  5683. }
  5684. }
  5685. if (cId2 > 0)
  5686. break;
  5687. }
  5688. if (i == cUsage && !fOrUsage)
  5689. return FALSE;
  5690. }
  5691. if (fOrUsage)
  5692. // For the "OR" option we're here without any match
  5693. return FALSE;
  5694. // else
  5695. // For the "AND" option we have matched all the specified
  5696. // identifiers
  5697. }
  5698. return TRUE;
  5699. }
  5700. STATIC BOOL CompareCertUsage(
  5701. IN PCCERT_CONTEXT pCert,
  5702. IN DWORD dwFindFlags,
  5703. IN PCTL_USAGE pPara
  5704. )
  5705. {
  5706. BOOL fResult;
  5707. PCERT_INFO pInfo = pCert->pCertInfo;
  5708. PCERT_EXTENSION pExt; // not allocated
  5709. DWORD cbData;
  5710. PCTL_USAGE pExtUsage = NULL;
  5711. PCTL_USAGE pPropUsage = NULL;
  5712. BYTE *pbPropData = NULL;
  5713. CTL_USAGE rgUsage[2]; // Ext and/or Prop
  5714. DWORD cUsage = 0;
  5715. if (CERT_FIND_VALID_CTL_USAGE_FLAG & dwFindFlags)
  5716. return IFC_IsEndCertValidForUsages(
  5717. pCert,
  5718. pPara,
  5719. 0 != (dwFindFlags & CERT_FIND_OR_CTL_USAGE_FLAG));
  5720. if (0 == (CERT_FIND_PROP_ONLY_CTL_USAGE_FLAG & dwFindFlags)) {
  5721. // Is there an Enhanced Key Usage Extension ??
  5722. if (pExt = CertFindExtension(
  5723. szOID_ENHANCED_KEY_USAGE,
  5724. pInfo->cExtension,
  5725. pInfo->rgExtension
  5726. )) {
  5727. if (pExtUsage = (PCTL_USAGE) AllocAndDecodeObject(
  5728. pCert->dwCertEncodingType,
  5729. X509_ENHANCED_KEY_USAGE,
  5730. pExt->Value.pbData,
  5731. pExt->Value.cbData))
  5732. rgUsage[cUsage++] = *pExtUsage;
  5733. }
  5734. }
  5735. if (0 == (CERT_FIND_EXT_ONLY_CTL_USAGE_FLAG & dwFindFlags)) {
  5736. // Is there an Enhanced Key Usage (CTL Usage) property ??
  5737. if (CertGetCertificateContextProperty(
  5738. pCert,
  5739. CERT_CTL_USAGE_PROP_ID,
  5740. NULL, // pvData
  5741. &cbData) && cbData) {
  5742. if (pbPropData = (BYTE *) PkiNonzeroAlloc(cbData)) {
  5743. if (CertGetCertificateContextProperty(
  5744. pCert,
  5745. CERT_CTL_USAGE_PROP_ID,
  5746. pbPropData,
  5747. &cbData)) {
  5748. if (pPropUsage = (PCTL_USAGE) AllocAndDecodeObject(
  5749. pCert->dwCertEncodingType,
  5750. X509_ENHANCED_KEY_USAGE,
  5751. pbPropData,
  5752. cbData))
  5753. rgUsage[cUsage++] = *pPropUsage;
  5754. }
  5755. }
  5756. }
  5757. }
  5758. if (cUsage > 0) {
  5759. if (dwFindFlags & CERT_FIND_NO_CTL_USAGE_FLAG)
  5760. fResult = FALSE;
  5761. else
  5762. fResult = CompareCtlUsageIdentifiers(pPara, cUsage, rgUsage,
  5763. 0 != (dwFindFlags & CERT_FIND_OR_CTL_USAGE_FLAG));
  5764. } else if (dwFindFlags & (CERT_FIND_OPTIONAL_CTL_USAGE_FLAG |
  5765. CERT_FIND_NO_CTL_USAGE_FLAG))
  5766. fResult = TRUE;
  5767. else
  5768. fResult = FALSE;
  5769. PkiFree(pExtUsage);
  5770. PkiFree(pPropUsage);
  5771. PkiFree(pbPropData);
  5772. return fResult;
  5773. }
  5774. STATIC BOOL IsSameCert(
  5775. IN PCCERT_CONTEXT pCert,
  5776. IN PCCERT_CONTEXT pNew
  5777. )
  5778. {
  5779. BYTE rgbCertHash[SHA1_HASH_LEN];
  5780. DWORD cbCertHash = SHA1_HASH_LEN;
  5781. BYTE rgbNewHash[SHA1_HASH_LEN];
  5782. DWORD cbNewHash = SHA1_HASH_LEN;
  5783. CertGetCertificateContextProperty(
  5784. pCert,
  5785. CERT_SHA1_HASH_PROP_ID,
  5786. rgbCertHash,
  5787. &cbCertHash
  5788. );
  5789. CertGetCertificateContextProperty(
  5790. pNew,
  5791. CERT_SHA1_HASH_PROP_ID,
  5792. rgbNewHash,
  5793. &cbNewHash
  5794. );
  5795. if (SHA1_HASH_LEN == cbCertHash && SHA1_HASH_LEN == cbNewHash &&
  5796. 0 == memcmp(rgbCertHash, rgbNewHash, SHA1_HASH_LEN))
  5797. return TRUE;
  5798. else
  5799. return FALSE;
  5800. }
  5801. STATIC BOOL CompareCertElement(
  5802. IN PCONTEXT_ELEMENT pEle,
  5803. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  5804. IN BOOL fArchived
  5805. )
  5806. {
  5807. PCCERT_CONTEXT pCert = ToCertContext(pEle);
  5808. DWORD dwCmp = (pFindInfo->dwFindType >> CERT_COMPARE_SHIFT) &
  5809. CERT_COMPARE_MASK;
  5810. const void *pvFindPara = pFindInfo->pvFindPara;
  5811. if (fArchived) {
  5812. switch (dwCmp) {
  5813. case CERT_COMPARE_SHA1_HASH:
  5814. case CERT_COMPARE_MD5_HASH:
  5815. case CERT_COMPARE_SIGNATURE_HASH:
  5816. case CERT_COMPARE_SUBJECT_CERT:
  5817. #ifdef CMS_PKCS7
  5818. case CERT_COMPARE_CERT_ID:
  5819. #endif // CMS_PKCS7
  5820. case CERT_COMPARE_PUBKEY_MD5_HASH:
  5821. break;
  5822. default:
  5823. return FALSE;
  5824. }
  5825. }
  5826. switch (dwCmp) {
  5827. case CERT_COMPARE_ANY:
  5828. return TRUE;
  5829. break;
  5830. case CERT_COMPARE_SHA1_HASH:
  5831. case CERT_COMPARE_MD5_HASH:
  5832. case CERT_COMPARE_SIGNATURE_HASH:
  5833. case CERT_COMPARE_KEY_IDENTIFIER:
  5834. case CERT_COMPARE_PUBKEY_MD5_HASH:
  5835. {
  5836. DWORD dwPropId;
  5837. switch (dwCmp) {
  5838. case CERT_COMPARE_SHA1_HASH:
  5839. dwPropId = CERT_SHA1_HASH_PROP_ID;
  5840. break;
  5841. case CERT_COMPARE_SIGNATURE_HASH:
  5842. dwPropId = CERT_SIGNATURE_HASH_PROP_ID;
  5843. break;
  5844. case CERT_COMPARE_KEY_IDENTIFIER:
  5845. dwPropId = CERT_KEY_IDENTIFIER_PROP_ID;
  5846. break;
  5847. case CERT_COMPARE_PUBKEY_MD5_HASH:
  5848. dwPropId = CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID;
  5849. break;
  5850. case CERT_COMPARE_MD5_HASH:
  5851. default:
  5852. dwPropId = CERT_MD5_HASH_PROP_ID;
  5853. }
  5854. return CompareCertHash(pCert, dwPropId,
  5855. (PCRYPT_HASH_BLOB) pvFindPara);
  5856. }
  5857. break;
  5858. case CERT_COMPARE_NAME:
  5859. {
  5860. PCERT_NAME_BLOB pName;
  5861. DWORD dwInfo = pFindInfo->dwFindType & 0xFF;
  5862. DWORD dwCertEncodingType =
  5863. pFindInfo->dwMsgAndCertEncodingType &
  5864. CERT_ENCODING_TYPE_MASK;
  5865. if (dwInfo == CERT_INFO_SUBJECT_FLAG)
  5866. pName = &pCert->pCertInfo->Subject;
  5867. else if (dwInfo == CERT_INFO_ISSUER_FLAG)
  5868. pName = &pCert->pCertInfo->Issuer;
  5869. else goto BadParameter;
  5870. return dwCertEncodingType == pCert->dwCertEncodingType &&
  5871. CertCompareCertificateName(dwCertEncodingType,
  5872. pName, (PCERT_NAME_BLOB) pvFindPara);
  5873. }
  5874. break;
  5875. case CERT_COMPARE_ATTR:
  5876. {
  5877. PCERT_NAME_BLOB pName;
  5878. DWORD dwInfo = pFindInfo->dwFindType & 0xFF;
  5879. DWORD dwCertEncodingType =
  5880. pFindInfo->dwMsgAndCertEncodingType &
  5881. CERT_ENCODING_TYPE_MASK;
  5882. if (dwInfo == CERT_INFO_SUBJECT_FLAG)
  5883. pName = &pCert->pCertInfo->Subject;
  5884. else if (dwInfo == CERT_INFO_ISSUER_FLAG)
  5885. pName = &pCert->pCertInfo->Issuer;
  5886. else goto BadParameter;
  5887. return dwCertEncodingType == pCert->dwCertEncodingType &&
  5888. CertIsRDNAttrsInCertificateName(dwCertEncodingType,
  5889. pFindInfo->dwFindFlags, pName,
  5890. (PCERT_RDN) pvFindPara);
  5891. }
  5892. break;
  5893. case CERT_COMPARE_PROPERTY:
  5894. {
  5895. DWORD dwPropId = *((DWORD *) pvFindPara);
  5896. DWORD cbData = 0;
  5897. return CertGetCertificateContextProperty(
  5898. pCert,
  5899. dwPropId,
  5900. NULL, //pvData
  5901. &cbData);
  5902. }
  5903. break;
  5904. case CERT_COMPARE_PUBLIC_KEY:
  5905. {
  5906. return CertComparePublicKeyInfo(
  5907. pCert->dwCertEncodingType,
  5908. &pCert->pCertInfo->SubjectPublicKeyInfo,
  5909. (PCERT_PUBLIC_KEY_INFO) pvFindPara);
  5910. }
  5911. break;
  5912. case CERT_COMPARE_NAME_STR_A:
  5913. case CERT_COMPARE_NAME_STR_W:
  5914. {
  5915. PCERT_NAME_BLOB pName;
  5916. DWORD dwInfo = pFindInfo->dwFindType & 0xFF;
  5917. DWORD dwCertEncodingType =
  5918. pFindInfo->dwMsgAndCertEncodingType &
  5919. CERT_ENCODING_TYPE_MASK;
  5920. if (dwInfo == CERT_INFO_SUBJECT_FLAG)
  5921. pName = &pCert->pCertInfo->Subject;
  5922. else if (dwInfo == CERT_INFO_ISSUER_FLAG)
  5923. pName = &pCert->pCertInfo->Issuer;
  5924. else goto BadParameter;
  5925. if (dwCertEncodingType == pCert->dwCertEncodingType) {
  5926. if (dwCmp == CERT_COMPARE_NAME_STR_W)
  5927. return CompareNameStrW(dwCertEncodingType,
  5928. pName, (LPCWSTR) pvFindPara);
  5929. else
  5930. return CompareNameStrA(dwCertEncodingType,
  5931. pName, (LPCSTR) pvFindPara);
  5932. } else
  5933. return FALSE;
  5934. }
  5935. break;
  5936. case CERT_COMPARE_KEY_SPEC:
  5937. {
  5938. DWORD dwKeySpec;
  5939. DWORD cbData = sizeof(dwKeySpec);
  5940. return CertGetCertificateContextProperty(
  5941. pCert,
  5942. CERT_KEY_SPEC_PROP_ID,
  5943. &dwKeySpec,
  5944. &cbData) &&
  5945. dwKeySpec == *((DWORD *) pvFindPara);
  5946. }
  5947. break;
  5948. case CERT_COMPARE_CTL_USAGE:
  5949. return CompareCertUsage(pCert, pFindInfo->dwFindFlags,
  5950. (PCTL_USAGE) pvFindPara);
  5951. break;
  5952. case CERT_COMPARE_SUBJECT_CERT:
  5953. {
  5954. DWORD dwCertEncodingType =
  5955. pFindInfo->dwMsgAndCertEncodingType &
  5956. CERT_ENCODING_TYPE_MASK;
  5957. PCERT_INFO pCertId = (PCERT_INFO) pvFindPara;
  5958. CRYPT_HASH_BLOB KeyId;
  5959. if (dwCertEncodingType != pCert->dwCertEncodingType)
  5960. return FALSE;
  5961. if (Asn1UtilExtractKeyIdFromCertInfo(
  5962. pCertId,
  5963. &KeyId
  5964. ))
  5965. return CompareCertHash(pCert,
  5966. CERT_KEY_IDENTIFIER_PROP_ID,
  5967. &KeyId
  5968. );
  5969. else
  5970. return CertCompareCertificate(
  5971. dwCertEncodingType,
  5972. pCertId,
  5973. pCert->pCertInfo);
  5974. }
  5975. break;
  5976. case CERT_COMPARE_ISSUER_OF:
  5977. {
  5978. PCCERT_CONTEXT pSubject =
  5979. (PCCERT_CONTEXT) pvFindPara;
  5980. return pSubject->dwCertEncodingType ==
  5981. pCert->dwCertEncodingType &&
  5982. CertCompareCertificateName(
  5983. pSubject->dwCertEncodingType,
  5984. &pSubject->pCertInfo->Issuer,
  5985. &pCert->pCertInfo->Subject);
  5986. }
  5987. break;
  5988. case CERT_COMPARE_EXISTING:
  5989. return IsSameCert((PCCERT_CONTEXT) pvFindPara, pCert);
  5990. break;
  5991. #ifdef CMS_PKCS7
  5992. case CERT_COMPARE_CERT_ID:
  5993. {
  5994. PCERT_ID pCertId = (PCERT_ID) pvFindPara;
  5995. switch (pCertId->dwIdChoice) {
  5996. case CERT_ID_ISSUER_SERIAL_NUMBER:
  5997. {
  5998. PCRYPT_INTEGER_BLOB pCertSerialNumber =
  5999. &pCert->pCertInfo->SerialNumber;
  6000. PCERT_NAME_BLOB pCertIssuer =
  6001. &pCert->pCertInfo->Issuer;
  6002. PCRYPT_INTEGER_BLOB pParaSerialNumber =
  6003. &pCertId->IssuerSerialNumber.SerialNumber;
  6004. PCERT_NAME_BLOB pParaIssuer =
  6005. &pCertId->IssuerSerialNumber.Issuer;
  6006. if (CertCompareIntegerBlob(pCertSerialNumber,
  6007. pParaSerialNumber)
  6008. &&
  6009. pCertIssuer->cbData == pParaIssuer->cbData
  6010. &&
  6011. memcmp(pCertIssuer->pbData,
  6012. pParaIssuer->pbData,
  6013. pCertIssuer->cbData) == 0)
  6014. return TRUE;
  6015. else
  6016. return FALSE;
  6017. }
  6018. break;
  6019. case CERT_ID_KEY_IDENTIFIER:
  6020. return CompareCertHash(pCert,
  6021. CERT_KEY_IDENTIFIER_PROP_ID,
  6022. &pCertId->KeyId
  6023. );
  6024. break;
  6025. case CERT_ID_SHA1_HASH:
  6026. return CompareCertHash(pCert,
  6027. CERT_SHA1_HASH_PROP_ID,
  6028. &pCertId->HashId
  6029. );
  6030. break;
  6031. default:
  6032. goto BadParameter;
  6033. }
  6034. }
  6035. break;
  6036. #endif // CMS_PKCS7
  6037. case CERT_COMPARE_CROSS_CERT_DIST_POINTS:
  6038. {
  6039. DWORD cbData = 0;
  6040. if (CertFindExtension(
  6041. szOID_CROSS_CERT_DIST_POINTS,
  6042. pCert->pCertInfo->cExtension,
  6043. pCert->pCertInfo->rgExtension) ||
  6044. CertGetCertificateContextProperty(
  6045. pCert,
  6046. CERT_CROSS_CERT_DIST_POINTS_PROP_ID,
  6047. NULL, // pvData
  6048. &cbData))
  6049. return TRUE;
  6050. else
  6051. return FALSE;
  6052. }
  6053. break;
  6054. default:
  6055. goto BadParameter;
  6056. }
  6057. BadParameter:
  6058. SetLastError((DWORD) E_INVALIDARG);
  6059. return FALSE;
  6060. }
  6061. STATIC BOOL IsNewerCertElement(
  6062. IN PCONTEXT_ELEMENT pNewEle,
  6063. IN PCONTEXT_ELEMENT pExistingEle
  6064. )
  6065. {
  6066. PCCERT_CONTEXT pNewCert = ToCertContext(pNewEle);
  6067. PCCERT_CONTEXT pExistingCert = ToCertContext(pExistingEle);
  6068. // CompareFileTime returns +1 if first time > second time
  6069. return (0 < CompareFileTime(
  6070. &pNewCert->pCertInfo->NotBefore,
  6071. &pExistingCert->pCertInfo->NotBefore
  6072. ));
  6073. }
  6074. //+=========================================================================
  6075. // CRL_CONTEXT Functions
  6076. //==========================================================================
  6077. // pbCrlEncoded has already been allocated
  6078. STATIC PCONTEXT_ELEMENT CreateCrlElement(
  6079. IN PCERT_STORE pStore,
  6080. IN DWORD dwCertEncodingType,
  6081. IN BYTE *pbCrlEncoded,
  6082. IN DWORD cbCrlEncoded,
  6083. IN OPTIONAL PSHARE_ELEMENT pShareEle
  6084. )
  6085. {
  6086. PCONTEXT_ELEMENT pEle = NULL;
  6087. PCRL_CONTEXT pCrl;
  6088. PCRL_CONTEXT_SUFFIX pCrlSuffix;
  6089. PCRL_INFO pInfo = NULL;
  6090. if (0 == GET_CERT_ENCODING_TYPE(dwCertEncodingType)) {
  6091. SetLastError((DWORD) E_INVALIDARG);
  6092. goto ErrorReturn;
  6093. }
  6094. if (NULL == pShareEle) {
  6095. cbCrlEncoded = AdjustEncodedLength(
  6096. dwCertEncodingType, pbCrlEncoded, cbCrlEncoded);
  6097. if (NULL == (pInfo = (PCRL_INFO) AllocAndDecodeObject(
  6098. dwCertEncodingType,
  6099. X509_CERT_CRL_TO_BE_SIGNED,
  6100. pbCrlEncoded,
  6101. cbCrlEncoded))) goto ErrorReturn;
  6102. }
  6103. // Allocate and initialize the CRL element structure
  6104. pEle = (PCONTEXT_ELEMENT) PkiZeroAlloc(sizeof(CONTEXT_ELEMENT) +
  6105. sizeof(CRL_CONTEXT) + sizeof(CRL_CONTEXT_SUFFIX));
  6106. if (pEle == NULL) goto ErrorReturn;
  6107. pEle->dwElementType = ELEMENT_TYPE_CACHE;
  6108. pEle->dwContextType = CERT_STORE_CRL_CONTEXT - 1;
  6109. pEle->lRefCnt = 1;
  6110. pEle->pEle = pEle;
  6111. pEle->pStore = pStore;
  6112. pEle->pProvStore = pStore;
  6113. pCrl = (PCRL_CONTEXT) ToCrlContext(pEle);
  6114. pCrl->dwCertEncodingType =
  6115. dwCertEncodingType & CERT_ENCODING_TYPE_MASK;
  6116. pCrl->pbCrlEncoded = pbCrlEncoded;
  6117. pCrl->cbCrlEncoded = cbCrlEncoded;
  6118. if (pShareEle) {
  6119. pEle->pShareEle = pShareEle;
  6120. assert(pShareEle->pvInfo);
  6121. pCrl->pCrlInfo = (PCRL_INFO) pShareEle->pvInfo;
  6122. assert(pbCrlEncoded == pShareEle->pbEncoded);
  6123. assert(cbCrlEncoded == pShareEle->cbEncoded);
  6124. } else {
  6125. pCrl->pCrlInfo = pInfo;
  6126. CertPerfIncrementCrlElementCurrentCount();
  6127. CertPerfIncrementCrlElementTotalCount();
  6128. }
  6129. pCrl->hCertStore = (HCERTSTORE) pStore;
  6130. pCrlSuffix = ToCrlContextSuffix(pEle);
  6131. pCrlSuffix->ppSortedEntry = NULL;
  6132. CommonReturn:
  6133. return pEle;
  6134. ErrorReturn:
  6135. if (pEle) {
  6136. PkiFree(pEle);
  6137. pEle = NULL;
  6138. }
  6139. PkiFree(pInfo);
  6140. goto CommonReturn;
  6141. }
  6142. STATIC void FreeCrlElement(IN PCONTEXT_ELEMENT pEle)
  6143. {
  6144. PCCRL_CONTEXT pCrl = ToCrlContext(pEle);
  6145. PCRL_CONTEXT_SUFFIX pCrlSuffix = ToCrlContextSuffix(pEle);
  6146. if (pEle->pShareEle)
  6147. ReleaseShareElement(pEle->pShareEle);
  6148. else {
  6149. PkiFree(pCrl->pbCrlEncoded);
  6150. PkiFree(pCrl->pCrlInfo);
  6151. CertPerfDecrementCrlElementCurrentCount();
  6152. }
  6153. PkiFree(pCrlSuffix->ppSortedEntry);
  6154. PkiFree(pEle);
  6155. }
  6156. STATIC BOOL IsSameEncodedCrlExtension(
  6157. IN LPCSTR pszObjId,
  6158. IN PCCRL_CONTEXT pCrl,
  6159. IN PCCRL_CONTEXT pNew
  6160. )
  6161. {
  6162. PCERT_EXTENSION pCrlExt;
  6163. PCERT_EXTENSION pNewExt;
  6164. // If they exist, compare the encoded extensions.
  6165. pNewExt = CertFindExtension(
  6166. pszObjId,
  6167. pNew->pCrlInfo->cExtension,
  6168. pNew->pCrlInfo->rgExtension
  6169. );
  6170. pCrlExt = CertFindExtension(
  6171. pszObjId,
  6172. pCrl->pCrlInfo->cExtension,
  6173. pCrl->pCrlInfo->rgExtension
  6174. );
  6175. if (pNewExt) {
  6176. if (pCrlExt) {
  6177. DWORD dwCertEncodingType = pCrl->dwCertEncodingType;
  6178. DWORD cbNewExt = pNewExt->Value.cbData;
  6179. BYTE *pbNewExt = pNewExt->Value.pbData;
  6180. DWORD cbCrlExt = pCrlExt->Value.cbData;
  6181. BYTE *pbCrlExt = pCrlExt->Value.pbData;
  6182. // Before comparing, adjust lengths to only include the
  6183. // encoded bytes
  6184. cbNewExt = AdjustEncodedLength(dwCertEncodingType,
  6185. pbNewExt, cbNewExt);
  6186. cbCrlExt = AdjustEncodedLength(dwCertEncodingType,
  6187. pbCrlExt, cbCrlExt);
  6188. if (cbNewExt != cbCrlExt ||
  6189. 0 != memcmp(pbNewExt, pbCrlExt, cbNewExt))
  6190. return FALSE;
  6191. } else
  6192. // Only one has the extension
  6193. return FALSE;
  6194. } else if (pCrlExt)
  6195. // Only one has the extension
  6196. return FALSE;
  6197. // else
  6198. // Neither has the extension
  6199. return TRUE;
  6200. }
  6201. STATIC BOOL IsSameCrl(
  6202. IN PCCRL_CONTEXT pCrl,
  6203. IN PCCRL_CONTEXT pNew
  6204. )
  6205. {
  6206. DWORD dwCertEncodingType;
  6207. PCERT_EXTENSION pCrlDeltaExt;
  6208. PCERT_EXTENSION pNewDeltaExt;
  6209. // Check: encoding type and issuer name
  6210. dwCertEncodingType = pNew->dwCertEncodingType;
  6211. if (dwCertEncodingType != pCrl->dwCertEncodingType ||
  6212. !CertCompareCertificateName(
  6213. dwCertEncodingType,
  6214. &pCrl->pCrlInfo->Issuer,
  6215. &pNew->pCrlInfo->Issuer))
  6216. return FALSE;
  6217. // Check that both are either base or delta CRLs
  6218. pNewDeltaExt = CertFindExtension(
  6219. szOID_DELTA_CRL_INDICATOR,
  6220. pNew->pCrlInfo->cExtension,
  6221. pNew->pCrlInfo->rgExtension
  6222. );
  6223. pCrlDeltaExt = CertFindExtension(
  6224. szOID_DELTA_CRL_INDICATOR,
  6225. pCrl->pCrlInfo->cExtension,
  6226. pCrl->pCrlInfo->rgExtension
  6227. );
  6228. if (pNewDeltaExt) {
  6229. if (NULL == pCrlDeltaExt)
  6230. // Only one has a Delta extension
  6231. return FALSE;
  6232. // else
  6233. // Both have a Delta extension
  6234. } else if (pCrlDeltaExt)
  6235. // Only one has a Delta extension
  6236. return FALSE;
  6237. // else
  6238. // Neither has a Delta extension
  6239. // If they exist, compare encoded AuthorityKeyIdentifier and
  6240. // IssuingDistributionPoint extensions.
  6241. if (!IsSameEncodedCrlExtension(
  6242. szOID_AUTHORITY_KEY_IDENTIFIER2,
  6243. pCrl,
  6244. pNew
  6245. ))
  6246. return FALSE;
  6247. if (!IsSameEncodedCrlExtension(
  6248. szOID_ISSUING_DIST_POINT,
  6249. pCrl,
  6250. pNew
  6251. ))
  6252. return FALSE;
  6253. return TRUE;
  6254. }
  6255. STATIC BOOL IsIssuedByCrl(
  6256. IN PCCRL_CONTEXT pCrl,
  6257. IN PCCERT_CONTEXT pIssuer,
  6258. IN PCERT_NAME_BLOB pIssuerName,
  6259. IN DWORD dwFindFlags
  6260. )
  6261. {
  6262. DWORD dwCertEncodingType;
  6263. if (dwFindFlags &
  6264. (CRL_FIND_ISSUED_BY_DELTA_FLAG | CRL_FIND_ISSUED_BY_BASE_FLAG)) {
  6265. PCERT_EXTENSION pDeltaExt;
  6266. pDeltaExt = CertFindExtension(
  6267. szOID_DELTA_CRL_INDICATOR,
  6268. pCrl->pCrlInfo->cExtension,
  6269. pCrl->pCrlInfo->rgExtension
  6270. );
  6271. if (pDeltaExt) {
  6272. if (0 == (dwFindFlags & CRL_FIND_ISSUED_BY_DELTA_FLAG))
  6273. return FALSE;
  6274. } else {
  6275. if (0 == (dwFindFlags & CRL_FIND_ISSUED_BY_BASE_FLAG))
  6276. return FALSE;
  6277. }
  6278. }
  6279. if (NULL == pIssuer)
  6280. return TRUE;
  6281. dwCertEncodingType = pIssuer->dwCertEncodingType;
  6282. if (dwCertEncodingType != pCrl->dwCertEncodingType ||
  6283. !CertCompareCertificateName(
  6284. dwCertEncodingType,
  6285. &pCrl->pCrlInfo->Issuer,
  6286. pIssuerName))
  6287. return FALSE;
  6288. if (dwFindFlags & CRL_FIND_ISSUED_BY_AKI_FLAG) {
  6289. PCERT_EXTENSION pCrlAKIExt;
  6290. pCrlAKIExt = CertFindExtension(
  6291. szOID_AUTHORITY_KEY_IDENTIFIER2,
  6292. pCrl->pCrlInfo->cExtension,
  6293. pCrl->pCrlInfo->rgExtension
  6294. );
  6295. if (pCrlAKIExt) {
  6296. PCERT_AUTHORITY_KEY_ID2_INFO pInfo;
  6297. BOOL fResult;
  6298. if (NULL == (pInfo =
  6299. (PCERT_AUTHORITY_KEY_ID2_INFO) AllocAndDecodeObject(
  6300. dwCertEncodingType,
  6301. X509_AUTHORITY_KEY_ID2,
  6302. pCrlAKIExt->Value.pbData,
  6303. pCrlAKIExt->Value.cbData
  6304. )))
  6305. return FALSE;
  6306. if (pInfo->KeyId.cbData)
  6307. fResult = CompareCertHash(
  6308. pIssuer,
  6309. CERT_KEY_IDENTIFIER_PROP_ID,
  6310. &pInfo->KeyId
  6311. );
  6312. else
  6313. fResult = TRUE;
  6314. PkiFree(pInfo);
  6315. if (!fResult)
  6316. return FALSE;
  6317. }
  6318. }
  6319. if (dwFindFlags & CRL_FIND_ISSUED_BY_SIGNATURE_FLAG) {
  6320. DWORD dwFlags;
  6321. dwFlags = CERT_STORE_SIGNATURE_FLAG;
  6322. VerifyCrl(pCrl, pIssuer, &dwFlags);
  6323. if (0 != dwFlags)
  6324. return FALSE;
  6325. }
  6326. return TRUE;
  6327. }
  6328. STATIC BOOL CompareCrlElement(
  6329. IN PCONTEXT_ELEMENT pEle,
  6330. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  6331. IN BOOL fArchived
  6332. )
  6333. {
  6334. PCCRL_CONTEXT pCrl = ToCrlContext(pEle);
  6335. DWORD dwFindType = pFindInfo->dwFindType;
  6336. const void *pvFindPara = pFindInfo->pvFindPara;
  6337. if (fArchived)
  6338. return FALSE;
  6339. switch (dwFindType) {
  6340. case CRL_FIND_ANY:
  6341. return TRUE;
  6342. break;
  6343. case CRL_FIND_ISSUED_BY:
  6344. {
  6345. PCCERT_CONTEXT pIssuer = (PCCERT_CONTEXT) pvFindPara;
  6346. return IsIssuedByCrl(
  6347. pCrl,
  6348. pIssuer,
  6349. (NULL != pIssuer) ? &pIssuer->pCertInfo->Subject : NULL,
  6350. pFindInfo->dwFindFlags
  6351. );
  6352. }
  6353. break;
  6354. case CRL_FIND_ISSUED_FOR:
  6355. {
  6356. PCRL_FIND_ISSUED_FOR_PARA pPara =
  6357. (PCRL_FIND_ISSUED_FOR_PARA) pvFindPara;
  6358. return IsIssuedByCrl(
  6359. pCrl,
  6360. pPara->pIssuerCert,
  6361. &pPara->pSubjectCert->pCertInfo->Issuer,
  6362. pFindInfo->dwFindFlags
  6363. );
  6364. }
  6365. break;
  6366. case CRL_FIND_EXISTING:
  6367. return IsSameCrl(pCrl, (PCCRL_CONTEXT) pvFindPara);
  6368. break;
  6369. default:
  6370. goto BadParameter;
  6371. }
  6372. BadParameter:
  6373. SetLastError((DWORD) E_INVALIDARG);
  6374. return FALSE;
  6375. }
  6376. STATIC BOOL IsNewerCrlElement(
  6377. IN PCONTEXT_ELEMENT pNewEle,
  6378. IN PCONTEXT_ELEMENT pExistingEle
  6379. )
  6380. {
  6381. PCCRL_CONTEXT pNewCrl = ToCrlContext(pNewEle);
  6382. PCCRL_CONTEXT pExistingCrl = ToCrlContext(pExistingEle);
  6383. // CompareFileTime returns +1 if first time > second time
  6384. return (0 < CompareFileTime(
  6385. &pNewCrl->pCrlInfo->ThisUpdate,
  6386. &pExistingCrl->pCrlInfo->ThisUpdate
  6387. ));
  6388. }
  6389. STATIC BOOL IsSameAltNameEntry(
  6390. IN PCERT_ALT_NAME_ENTRY pE1,
  6391. IN PCERT_ALT_NAME_ENTRY pE2
  6392. )
  6393. {
  6394. DWORD dwAltNameChoice;
  6395. dwAltNameChoice = pE1->dwAltNameChoice;
  6396. if (dwAltNameChoice != pE2->dwAltNameChoice)
  6397. return FALSE;
  6398. switch (dwAltNameChoice) {
  6399. case CERT_ALT_NAME_OTHER_NAME:
  6400. if (0 == strcmp(pE1->pOtherName->pszObjId,
  6401. pE2->pOtherName->pszObjId)
  6402. &&
  6403. pE1->pOtherName->Value.cbData ==
  6404. pE2->pOtherName->Value.cbData
  6405. &&
  6406. 0 == memcmp(pE1->pOtherName->Value.pbData,
  6407. pE2->pOtherName->Value.pbData,
  6408. pE1->pOtherName->Value.cbData))
  6409. return TRUE;
  6410. break;
  6411. case CERT_ALT_NAME_RFC822_NAME:
  6412. case CERT_ALT_NAME_DNS_NAME:
  6413. case CERT_ALT_NAME_URL:
  6414. if (0 == _wcsicmp(pE1->pwszRfc822Name, pE2->pwszRfc822Name))
  6415. return TRUE;
  6416. break;
  6417. case CERT_ALT_NAME_X400_ADDRESS:
  6418. case CERT_ALT_NAME_EDI_PARTY_NAME:
  6419. // Not implemented
  6420. break;
  6421. case CERT_ALT_NAME_DIRECTORY_NAME:
  6422. case CERT_ALT_NAME_IP_ADDRESS:
  6423. if (pE1->DirectoryName.cbData == pE2->DirectoryName.cbData &&
  6424. 0 == memcmp(pE1->DirectoryName.pbData,
  6425. pE2->DirectoryName.pbData,
  6426. pE1->DirectoryName.cbData))
  6427. return TRUE;
  6428. break;
  6429. case CERT_ALT_NAME_REGISTERED_ID:
  6430. if (0 == strcmp(pE1->pszRegisteredID, pE2->pszRegisteredID))
  6431. return TRUE;
  6432. break;
  6433. default:
  6434. break;
  6435. }
  6436. return FALSE;
  6437. }
  6438. //+-------------------------------------------------------------------------
  6439. // Is the specified CRL valid for the certificate.
  6440. //
  6441. // Returns TRUE if the CRL's list of entries would contain the certificate
  6442. // if it was revoked. Note, doesn't check that the certificate is in the
  6443. // list of entries.
  6444. //
  6445. // If the CRL has an Issuing Distribution Point (IDP) extension, checks
  6446. // that it's valid for the subject certificate.
  6447. //
  6448. // dwFlags and pvReserved currently aren't used and must be set to 0 and NULL.
  6449. //--------------------------------------------------------------------------
  6450. WINCRYPT32API
  6451. BOOL
  6452. WINAPI
  6453. CertIsValidCRLForCertificate(
  6454. IN PCCERT_CONTEXT pCert,
  6455. IN PCCRL_CONTEXT pCrl,
  6456. IN DWORD dwFlags,
  6457. IN void *pvReserved
  6458. )
  6459. {
  6460. BOOL fResult;
  6461. PCERT_EXTENSION pIDPExt; // not allocated
  6462. PCERT_EXTENSION pCDPExt; // not allocated
  6463. PCERT_EXTENSION pBasicConstraintsExt; // not allocated
  6464. PCRL_ISSUING_DIST_POINT pIDPInfo = NULL;
  6465. PCRL_DIST_POINTS_INFO pCDPInfo = NULL;
  6466. PCERT_BASIC_CONSTRAINTS2_INFO pBasicConstraintsInfo = NULL;
  6467. DWORD cIDPAltEntry;
  6468. PCERT_ALT_NAME_ENTRY pIDPAltEntry; // not allocated
  6469. pIDPExt = CertFindExtension(
  6470. szOID_ISSUING_DIST_POINT,
  6471. pCrl->pCrlInfo->cExtension,
  6472. pCrl->pCrlInfo->rgExtension
  6473. );
  6474. if (NULL == pIDPExt)
  6475. return TRUE;
  6476. if (NULL == (pIDPInfo = (PCRL_ISSUING_DIST_POINT) AllocAndDecodeObject(
  6477. pCrl->dwCertEncodingType,
  6478. X509_ISSUING_DIST_POINT,
  6479. pIDPExt->Value.pbData,
  6480. pIDPExt->Value.cbData
  6481. )))
  6482. goto IDPDecodeError;
  6483. // Ignore IDPs having OnlySomeReasonFlags or an indirect CRL
  6484. if (0 != pIDPInfo->OnlySomeReasonFlags.cbData ||
  6485. pIDPInfo->fIndirectCRL)
  6486. goto UnsupportedIDPError;
  6487. if (!(CRL_DIST_POINT_NO_NAME ==
  6488. pIDPInfo->DistPointName.dwDistPointNameChoice ||
  6489. CRL_DIST_POINT_FULL_NAME ==
  6490. pIDPInfo->DistPointName.dwDistPointNameChoice))
  6491. goto UnsupportedIDPError;
  6492. if (pIDPInfo->fOnlyContainsUserCerts ||
  6493. pIDPInfo->fOnlyContainsCACerts) {
  6494. // Determine if the cert is an end entity or a CA.
  6495. // Default to an end entity
  6496. BOOL fCA = FALSE;
  6497. pBasicConstraintsExt = CertFindExtension(
  6498. szOID_BASIC_CONSTRAINTS2,
  6499. pCert->pCertInfo->cExtension,
  6500. pCert->pCertInfo->rgExtension
  6501. );
  6502. if (pBasicConstraintsExt) {
  6503. if (NULL == (pBasicConstraintsInfo =
  6504. (PCERT_BASIC_CONSTRAINTS2_INFO) AllocAndDecodeObject(
  6505. pCert->dwCertEncodingType,
  6506. X509_BASIC_CONSTRAINTS2,
  6507. pBasicConstraintsExt->Value.pbData,
  6508. pBasicConstraintsExt->Value.cbData
  6509. )))
  6510. goto BasicConstraintsDecodeError;
  6511. fCA = pBasicConstraintsInfo->fCA;
  6512. }
  6513. if (pIDPInfo->fOnlyContainsUserCerts && fCA)
  6514. goto OnlyContainsUserCertsError;
  6515. if (pIDPInfo->fOnlyContainsCACerts && !fCA)
  6516. goto OnlyContainsCACertsError;
  6517. }
  6518. if (CRL_DIST_POINT_FULL_NAME !=
  6519. pIDPInfo->DistPointName.dwDistPointNameChoice)
  6520. // The IDP doesn't have any name choice to check
  6521. goto SuccessReturn;
  6522. cIDPAltEntry = pIDPInfo->DistPointName.FullName.cAltEntry;
  6523. if (0 == cIDPAltEntry)
  6524. // The IDP doesn't have any DistPoint entries to check
  6525. goto SuccessReturn;
  6526. pIDPAltEntry = pIDPInfo->DistPointName.FullName.rgAltEntry;
  6527. pCDPExt = CertFindExtension(
  6528. szOID_CRL_DIST_POINTS,
  6529. pCert->pCertInfo->cExtension,
  6530. pCert->pCertInfo->rgExtension
  6531. );
  6532. if (NULL == pCDPExt)
  6533. goto NoCDPError;
  6534. if (NULL == (pCDPInfo = (PCRL_DIST_POINTS_INFO) AllocAndDecodeObject(
  6535. pCert->dwCertEncodingType,
  6536. X509_CRL_DIST_POINTS,
  6537. pCDPExt->Value.pbData,
  6538. pCDPExt->Value.cbData
  6539. )))
  6540. goto CDPDecodeError;
  6541. for ( ; 0 < cIDPAltEntry; pIDPAltEntry++, cIDPAltEntry--) {
  6542. DWORD cCDPDistPoint;
  6543. PCRL_DIST_POINT pCDPDistPoint;
  6544. cCDPDistPoint = pCDPInfo->cDistPoint;
  6545. pCDPDistPoint = pCDPInfo->rgDistPoint;
  6546. for ( ; 0 < cCDPDistPoint; pCDPDistPoint++, cCDPDistPoint--) {
  6547. DWORD cCDPAltEntry;
  6548. PCERT_ALT_NAME_ENTRY pCDPAltEntry;
  6549. if (0 != pCDPDistPoint->ReasonFlags.cbData)
  6550. continue;
  6551. if (0 != pCDPDistPoint->CRLIssuer.cAltEntry)
  6552. continue;
  6553. if (CRL_DIST_POINT_FULL_NAME !=
  6554. pCDPDistPoint->DistPointName.dwDistPointNameChoice)
  6555. continue;
  6556. cCDPAltEntry = pCDPDistPoint->DistPointName.FullName.cAltEntry;
  6557. pCDPAltEntry = pCDPDistPoint->DistPointName.FullName.rgAltEntry;
  6558. for ( ; 0 < cCDPAltEntry; pCDPAltEntry++, cCDPAltEntry--) {
  6559. if (IsSameAltNameEntry(pIDPAltEntry, pCDPAltEntry))
  6560. goto SuccessReturn;
  6561. }
  6562. }
  6563. }
  6564. goto NoAltNameMatchError;
  6565. SuccessReturn:
  6566. fResult = TRUE;
  6567. CommonReturn:
  6568. PkiFree(pIDPInfo);
  6569. PkiFree(pCDPInfo);
  6570. PkiFree(pBasicConstraintsInfo);
  6571. return fResult;
  6572. ErrorReturn:
  6573. fResult = FALSE;
  6574. goto CommonReturn;
  6575. SET_ERROR(NoCDPError, CRYPT_E_NO_MATCH)
  6576. TRACE_ERROR(IDPDecodeError)
  6577. SET_ERROR(UnsupportedIDPError, E_NOTIMPL)
  6578. TRACE_ERROR(BasicConstraintsDecodeError)
  6579. SET_ERROR(OnlyContainsUserCertsError, CRYPT_E_NO_MATCH)
  6580. SET_ERROR(OnlyContainsCACertsError, CRYPT_E_NO_MATCH)
  6581. TRACE_ERROR(CDPDecodeError)
  6582. SET_ERROR(NoAltNameMatchError, CRYPT_E_NO_MATCH)
  6583. }
  6584. //+=========================================================================
  6585. // CTL_CONTEXT Functions
  6586. //==========================================================================
  6587. //+-------------------------------------------------------------------------
  6588. // If both msg and cert encoding types are present, or neither are present,
  6589. // return without any changes. Otherwise, set the missing encoding type
  6590. // with the encoding type that is present.
  6591. //--------------------------------------------------------------------------
  6592. STATIC DWORD GetCtlEncodingType(IN DWORD dwMsgAndCertEncodingType)
  6593. {
  6594. if (0 == dwMsgAndCertEncodingType)
  6595. return 0;
  6596. else if (0 == (dwMsgAndCertEncodingType & CMSG_ENCODING_TYPE_MASK))
  6597. return dwMsgAndCertEncodingType |
  6598. ((dwMsgAndCertEncodingType << 16) & CMSG_ENCODING_TYPE_MASK);
  6599. else if (0 == (dwMsgAndCertEncodingType & CERT_ENCODING_TYPE_MASK))
  6600. return dwMsgAndCertEncodingType |
  6601. ((dwMsgAndCertEncodingType >> 16) & CERT_ENCODING_TYPE_MASK);
  6602. else
  6603. // Both specified
  6604. return dwMsgAndCertEncodingType;
  6605. }
  6606. #if 0
  6607. // pbCtlEncoded has already been allocated
  6608. STATIC PCONTEXT_ELEMENT SlowCreateCtlElement(
  6609. IN PCERT_STORE pStore,
  6610. IN DWORD dwMsgAndCertEncodingType,
  6611. IN BYTE *pbCtlEncoded,
  6612. IN DWORD cbCtlEncoded
  6613. )
  6614. {
  6615. DWORD dwEncodingType;
  6616. HCRYPTPROV hProv = 0;
  6617. DWORD dwProvFlags = 0;
  6618. HCRYPTMSG hMsg = NULL;
  6619. BYTE *pbContent = NULL;
  6620. DWORD cbContent;
  6621. PCTL_INFO pInfo = NULL;
  6622. PCONTEXT_ELEMENT pEle = NULL;
  6623. PCTL_CONTEXT pCtl;
  6624. PCTL_CONTEXT_SUFFIX pCtlSuffix;
  6625. // Attempt to get the store's crypt provider. Serialize crypto
  6626. // operations.
  6627. hProv = GetCryptProv(pStore, &dwProvFlags);
  6628. if (0 == (dwMsgAndCertEncodingType = GetCtlEncodingType(
  6629. dwMsgAndCertEncodingType)))
  6630. goto InvalidArg;
  6631. // The message encoding type takes precedence
  6632. dwEncodingType = (dwMsgAndCertEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
  6633. // Assumption:: only definite length encoded PKCS #7
  6634. cbCtlEncoded = AdjustEncodedLength(
  6635. dwEncodingType, pbCtlEncoded, cbCtlEncoded);
  6636. // First decode as a PKCS#7 SignedData message
  6637. if (NULL == (hMsg = CryptMsgOpenToDecode(
  6638. dwMsgAndCertEncodingType,
  6639. 0, // dwFlags
  6640. 0, // dwMsgType
  6641. hProv,
  6642. NULL, // pRecipientInfo
  6643. NULL // pStreamInfo
  6644. ))) goto MsgOpenToDecodeError;
  6645. if (!CryptMsgUpdate(
  6646. hMsg,
  6647. pbCtlEncoded,
  6648. cbCtlEncoded,
  6649. TRUE // fFinal
  6650. )) goto MsgUpdateError;
  6651. else {
  6652. // Verify that the outer ContentType is SignedData and the inner
  6653. // ContentType is a CertificateTrustList
  6654. DWORD dwMsgType = 0;
  6655. DWORD cbData;
  6656. char szInnerContentType[64];
  6657. assert(sizeof(szInnerContentType) > strlen(szOID_CTL));
  6658. cbData = sizeof(dwMsgType);
  6659. if (!CryptMsgGetParam(
  6660. hMsg,
  6661. CMSG_TYPE_PARAM,
  6662. 0, // dwIndex
  6663. &dwMsgType,
  6664. &cbData
  6665. )) goto GetTypeError;
  6666. if (CMSG_SIGNED != dwMsgType)
  6667. goto UnexpectedMsgTypeError;
  6668. cbData = sizeof(szInnerContentType);
  6669. if (!CryptMsgGetParam(
  6670. hMsg,
  6671. CMSG_INNER_CONTENT_TYPE_PARAM,
  6672. 0, // dwIndex
  6673. szInnerContentType,
  6674. &cbData
  6675. )) goto GetInnerContentTypeError;
  6676. if (0 != strcmp(szInnerContentType, szOID_CTL))
  6677. goto UnexpectedInnerContentTypeError;
  6678. }
  6679. // Get the inner content.
  6680. if (NULL == (pbContent = (BYTE *) AllocAndGetMsgParam(
  6681. hMsg,
  6682. CMSG_CONTENT_PARAM,
  6683. 0, // dwIndex
  6684. &cbContent))) goto GetContentError;
  6685. // Decode inner content
  6686. if (NULL == (pInfo = (PCTL_INFO) AllocAndDecodeObject(
  6687. dwEncodingType,
  6688. PKCS_CTL,
  6689. pbContent,
  6690. cbContent))) goto DecodeError;
  6691. // Allocate and initialize the CTL element structure
  6692. if (NULL == (pEle = (PCONTEXT_ELEMENT) PkiZeroAlloc(
  6693. sizeof(CONTEXT_ELEMENT) + sizeof(CTL_CONTEXT) +
  6694. sizeof(CTL_CONTEXT_SUFFIX))))
  6695. goto OutOfMemory;
  6696. pEle->dwElementType = ELEMENT_TYPE_CACHE;
  6697. pEle->dwContextType = CERT_STORE_CTL_CONTEXT - 1;
  6698. pEle->lRefCnt = 1;
  6699. pEle->pEle = pEle;
  6700. pEle->pStore = pStore;
  6701. pEle->pProvStore = pStore;
  6702. pCtl = (PCTL_CONTEXT) ToCtlContext(pEle);
  6703. pCtl->dwMsgAndCertEncodingType =
  6704. dwMsgAndCertEncodingType;
  6705. pCtl->pbCtlEncoded = pbCtlEncoded;
  6706. pCtl->cbCtlEncoded = cbCtlEncoded;
  6707. pCtl->pCtlInfo = pInfo;
  6708. pCtl->hCertStore = (HCERTSTORE) pStore;
  6709. pCtl->hCryptMsg = hMsg;
  6710. pCtl->pbCtlContent = pbContent;
  6711. pCtl->cbCtlContent = cbContent;
  6712. pCtlSuffix = ToCtlContextSuffix(pEle);
  6713. pCtlSuffix->ppSortedEntry = NULL;
  6714. pCtlSuffix->pSortedCtlFindInfo = NULL;
  6715. CommonReturn:
  6716. // For the store's crypt provider, release reference count. Leave
  6717. // crypto operations critical section.
  6718. //
  6719. // Also, any subsequent CryptMsg cryptographic operations will
  6720. // be done outside of critical section. This critical section is needed
  6721. // because CAPI 1.0 isn't thread safe. This should be fixed!!!! ?????
  6722. ReleaseCryptProv(pStore, dwProvFlags);
  6723. return pEle;
  6724. ErrorReturn:
  6725. if (hMsg)
  6726. CryptMsgClose(hMsg);
  6727. PkiFree(pInfo);
  6728. PkiFree(pbContent);
  6729. if (pEle) {
  6730. PkiFree(pEle);
  6731. pEle = NULL;
  6732. }
  6733. goto CommonReturn;
  6734. SET_ERROR(InvalidArg, E_INVALIDARG)
  6735. TRACE_ERROR(MsgOpenToDecodeError)
  6736. TRACE_ERROR(MsgUpdateError)
  6737. TRACE_ERROR(GetTypeError)
  6738. SET_ERROR(UnexpectedMsgTypeError, CRYPT_E_UNEXPECTED_MSG_TYPE)
  6739. TRACE_ERROR(GetInnerContentTypeError)
  6740. SET_ERROR(UnexpectedInnerContentTypeError, CRYPT_E_UNEXPECTED_MSG_TYPE)
  6741. TRACE_ERROR(GetContentError)
  6742. TRACE_ERROR(OutOfMemory)
  6743. TRACE_ERROR(DecodeError)
  6744. }
  6745. void
  6746. StoreMessageBox(
  6747. IN LPSTR pszText
  6748. )
  6749. {
  6750. MessageBoxA(
  6751. NULL, // hwndOwner
  6752. pszText,
  6753. "Check FastCreateCtlElement",
  6754. MB_TOPMOST | MB_OK | MB_ICONQUESTION |
  6755. MB_SERVICE_NOTIFICATION
  6756. );
  6757. }
  6758. #endif
  6759. // pbCtlEncoded has already been allocated
  6760. STATIC PCONTEXT_ELEMENT FastCreateCtlElement(
  6761. IN PCERT_STORE pStore,
  6762. IN DWORD dwMsgAndCertEncodingType,
  6763. IN const BYTE *pbCtlEncoded,
  6764. IN DWORD cbCtlEncoded,
  6765. IN OPTIONAL PSHARE_ELEMENT pShareEle,
  6766. IN DWORD dwFlags
  6767. );
  6768. // pbCtlEncoded has already been allocated
  6769. STATIC PCONTEXT_ELEMENT CreateCtlElement(
  6770. IN PCERT_STORE pStore,
  6771. IN DWORD dwMsgAndCertEncodingType,
  6772. IN BYTE *pbCtlEncoded,
  6773. IN DWORD cbCtlEncoded,
  6774. IN OPTIONAL PSHARE_ELEMENT pShareEle
  6775. )
  6776. {
  6777. #if 1
  6778. return FastCreateCtlElement(
  6779. pStore,
  6780. dwMsgAndCertEncodingType,
  6781. pbCtlEncoded,
  6782. cbCtlEncoded,
  6783. pShareEle,
  6784. 0 // dwFlags
  6785. );
  6786. #else
  6787. PCONTEXT_ELEMENT pSlowEle;
  6788. PCONTEXT_ELEMENT pFastEle;
  6789. pFastEle = FastCreateCtlElement(
  6790. pStore,
  6791. dwMsgAndCertEncodingType,
  6792. pbCtlEncoded,
  6793. cbCtlEncoded,
  6794. pShareEle,
  6795. 0 // dwFlags
  6796. );
  6797. pSlowEle = NULL;
  6798. if (cbCtlEncoded) {
  6799. BYTE *pbSlowCtlEncoded = NULL;
  6800. pbSlowCtlEncoded = (BYTE *) PkiNonzeroAlloc(cbCtlEncoded);
  6801. if (pbSlowCtlEncoded) {
  6802. memcpy(pbSlowCtlEncoded, pbCtlEncoded, cbCtlEncoded);
  6803. pSlowEle = SlowCreateCtlElement(
  6804. &NullCertStore,
  6805. dwMsgAndCertEncodingType,
  6806. pbSlowCtlEncoded,
  6807. cbCtlEncoded
  6808. );
  6809. if (NULL == pSlowEle)
  6810. PkiFree(pbSlowCtlEncoded);
  6811. }
  6812. }
  6813. if (NULL == pFastEle) {
  6814. if (pSlowEle)
  6815. StoreMessageBox("fast failed, slow succeeded");
  6816. } else if (NULL == pSlowEle) {
  6817. StoreMessageBox("fast succeeded, slow failed");
  6818. } else {
  6819. PCTL_INFO pFastInfo = ToCtlContext(pFastEle)->pCtlInfo;
  6820. PCTL_INFO pSlowInfo = ToCtlContext(pSlowEle)->pCtlInfo;
  6821. // Check that headers match
  6822. if (pFastInfo->dwVersion != pSlowInfo->dwVersion ||
  6823. pFastInfo->SubjectUsage.cUsageIdentifier !=
  6824. pSlowInfo->SubjectUsage.cUsageIdentifier ||
  6825. 0 != CompareFileTime(&pFastInfo->ThisUpdate,
  6826. &pSlowInfo->ThisUpdate) ||
  6827. 0 != CompareFileTime(&pFastInfo->NextUpdate,
  6828. &pSlowInfo->NextUpdate) ||
  6829. 0 != strcmp(pFastInfo->SubjectAlgorithm.pszObjId,
  6830. pSlowInfo->SubjectAlgorithm.pszObjId) ||
  6831. pFastInfo->SubjectAlgorithm.Parameters.cbData !=
  6832. pSlowInfo->SubjectAlgorithm.Parameters.cbData)
  6833. StoreMessageBox("fast and slow info doesn't match\n");
  6834. else {
  6835. // Check that the extensions match
  6836. DWORD cFastExt = pFastInfo->cExtension;
  6837. PCERT_EXTENSION pFastExt = pFastInfo->rgExtension;
  6838. DWORD cSlowExt = pSlowInfo->cExtension;
  6839. PCERT_EXTENSION pSlowExt = pSlowInfo->rgExtension;
  6840. if (cFastExt != cSlowExt)
  6841. StoreMessageBox("fast and slow extension count doesn't match");
  6842. else {
  6843. for ( ; cFastExt; cFastExt--, pFastExt++, pSlowExt++) {
  6844. if (0 != strcmp(pFastExt->pszObjId, pSlowExt->pszObjId) ||
  6845. pFastExt->fCritical != pSlowExt->fCritical ||
  6846. pFastExt->Value.cbData != pSlowExt->Value.cbData) {
  6847. StoreMessageBox(
  6848. "fast and slow extension doesn't match");
  6849. goto Done;
  6850. }
  6851. if (pFastExt->Value.cbData && 0 != memcmp(
  6852. pFastExt->Value.pbData, pSlowExt->Value.pbData,
  6853. pFastExt->Value.cbData)) {
  6854. StoreMessageBox(
  6855. "fast and slow extension doesn't match");
  6856. goto Done;
  6857. }
  6858. }
  6859. }
  6860. }
  6861. if (pFastInfo->cCTLEntry != pSlowInfo->cCTLEntry)
  6862. StoreMessageBox("fast and slow entry count doesn't match");
  6863. else {
  6864. DWORD cEntry = pFastInfo->cCTLEntry;
  6865. PCTL_ENTRY pFastEntry = pFastInfo->rgCTLEntry;
  6866. PCTL_ENTRY pSlowEntry = pSlowInfo->rgCTLEntry;
  6867. for ( ; cEntry; cEntry--, pFastEntry++, pSlowEntry++) {
  6868. if (pFastEntry->SubjectIdentifier.cbData !=
  6869. pSlowEntry->SubjectIdentifier.cbData ||
  6870. 0 != memcmp(pFastEntry->SubjectIdentifier.pbData,
  6871. pSlowEntry->SubjectIdentifier.pbData,
  6872. pFastEntry->SubjectIdentifier.cbData)) {
  6873. StoreMessageBox(
  6874. "fast and slow SubjectIdentifier doesn't match");
  6875. goto Done;
  6876. }
  6877. if (pFastEntry->cAttribute != pSlowEntry->cAttribute) {
  6878. StoreMessageBox(
  6879. "fast and slow Attribute Count doesn't match");
  6880. goto Done;
  6881. } else if (0 < pFastEntry->cAttribute) {
  6882. DWORD cAttr = pFastEntry->cAttribute;
  6883. PCRYPT_ATTRIBUTE pFastAttr = pFastEntry->rgAttribute;
  6884. PCRYPT_ATTRIBUTE pSlowAttr = pSlowEntry->rgAttribute;
  6885. for ( ; cAttr; cAttr--, pFastAttr++, pSlowAttr++) {
  6886. if (0 != strcmp(pFastAttr->pszObjId,
  6887. pSlowAttr->pszObjId)) {
  6888. StoreMessageBox(
  6889. "fast and slow Attribute OID doesn't match");
  6890. goto Done;
  6891. }
  6892. if (pFastAttr->cValue != pSlowAttr->cValue) {
  6893. StoreMessageBox(
  6894. "fast and slow Value Count doesn't match");
  6895. goto Done;
  6896. }
  6897. if (0 < pFastAttr->cValue) {
  6898. DWORD cValue = pFastAttr->cValue;
  6899. PCRYPT_ATTR_BLOB pFastValue = pFastAttr->rgValue;
  6900. PCRYPT_ATTR_BLOB pSlowValue = pSlowAttr->rgValue;
  6901. for ( ; cValue;
  6902. cValue--, pFastValue++, pSlowValue++) {
  6903. if (pFastValue->cbData !=
  6904. pSlowValue->cbData ||
  6905. 0 != memcmp(pFastValue->pbData,
  6906. pSlowValue->pbData,
  6907. pFastValue->cbData)) {
  6908. StoreMessageBox(
  6909. "fast and slow Value doesn't match");
  6910. goto Done;
  6911. }
  6912. }
  6913. }
  6914. }
  6915. }
  6916. }
  6917. }
  6918. }
  6919. Done:
  6920. if (pSlowEle)
  6921. FreeContextElement(pSlowEle);
  6922. return pFastEle;
  6923. #endif
  6924. }
  6925. STATIC void FreeCtlElement(IN PCONTEXT_ELEMENT pEle)
  6926. {
  6927. PCCTL_CONTEXT pCtl = ToCtlContext(pEle);
  6928. PCTL_CONTEXT_SUFFIX pCtlSuffix = ToCtlContextSuffix(pEle);
  6929. if (pEle->pShareEle)
  6930. ReleaseShareElement(pEle->pShareEle);
  6931. else {
  6932. PkiFree(pCtl->pbCtlEncoded);
  6933. CertPerfDecrementCtlElementCurrentCount();
  6934. }
  6935. PkiFree(pCtl->pCtlInfo);
  6936. PkiFree(pCtlSuffix->ppSortedEntry);
  6937. CryptMsgClose(pCtl->hCryptMsg);
  6938. if (pCtlSuffix->fFastCreate) {
  6939. PSORTED_CTL_FIND_INFO pSortedCtlFindInfo =
  6940. pCtlSuffix->pSortedCtlFindInfo;
  6941. PkiFree(pCtlSuffix->pCTLEntry);
  6942. PkiFree(pCtlSuffix->pExtInfo);
  6943. if (pSortedCtlFindInfo) {
  6944. PkiFree(pSortedCtlFindInfo->pdwHashBucketHead);
  6945. PkiFree(pSortedCtlFindInfo->pHashBucketEntry);
  6946. }
  6947. } else
  6948. PkiFree(pCtl->pbCtlContent);
  6949. PkiFree(pEle);
  6950. }
  6951. STATIC BOOL CompareCtlHash(
  6952. IN PCCTL_CONTEXT pCtl,
  6953. IN DWORD dwPropId,
  6954. IN PCRYPT_HASH_BLOB pHash
  6955. )
  6956. {
  6957. BYTE rgbHash[MAX_HASH_LEN];
  6958. DWORD cbHash = MAX_HASH_LEN;
  6959. CertGetCTLContextProperty(
  6960. pCtl,
  6961. dwPropId,
  6962. rgbHash,
  6963. &cbHash
  6964. );
  6965. if (cbHash == pHash->cbData &&
  6966. memcmp(rgbHash, pHash->pbData, cbHash) == 0)
  6967. return TRUE;
  6968. else
  6969. return FALSE;
  6970. }
  6971. STATIC BOOL CompareCtlUsage(
  6972. IN PCCTL_CONTEXT pCtl,
  6973. IN DWORD dwMsgAndCertEncodingType,
  6974. IN DWORD dwFindFlags,
  6975. IN PCTL_FIND_USAGE_PARA pPara
  6976. )
  6977. {
  6978. PCTL_INFO pInfo = pCtl->pCtlInfo;
  6979. if (NULL == pPara ||
  6980. pPara->cbSize < (offsetof(CTL_FIND_USAGE_PARA, SubjectUsage) +
  6981. sizeof(pPara->SubjectUsage)))
  6982. return TRUE;
  6983. if ((CTL_FIND_SAME_USAGE_FLAG & dwFindFlags) &&
  6984. pPara->SubjectUsage.cUsageIdentifier !=
  6985. pInfo->SubjectUsage.cUsageIdentifier)
  6986. return FALSE;
  6987. if (!CompareCtlUsageIdentifiers(&pPara->SubjectUsage,
  6988. 1, &pInfo->SubjectUsage, FALSE))
  6989. return FALSE;
  6990. assert(offsetof(CTL_FIND_USAGE_PARA, ListIdentifier) >
  6991. offsetof(CTL_FIND_USAGE_PARA, SubjectUsage));
  6992. if (pPara->cbSize < offsetof(CTL_FIND_USAGE_PARA, ListIdentifier) +
  6993. sizeof(pPara->ListIdentifier))
  6994. return TRUE;
  6995. if (pPara->ListIdentifier.cbData) {
  6996. DWORD cb = pPara->ListIdentifier.cbData;
  6997. if (CTL_FIND_NO_LIST_ID_CBDATA == cb)
  6998. cb = 0;
  6999. if (cb != pInfo->ListIdentifier.cbData)
  7000. return FALSE;
  7001. if (0 != cb && 0 != memcmp(pPara->ListIdentifier.pbData,
  7002. pInfo->ListIdentifier.pbData, cb))
  7003. return FALSE;
  7004. }
  7005. assert(offsetof(CTL_FIND_USAGE_PARA, pSigner) >
  7006. offsetof(CTL_FIND_USAGE_PARA, ListIdentifier));
  7007. if (pPara->cbSize < offsetof(CTL_FIND_USAGE_PARA, pSigner) +
  7008. sizeof(pPara->pSigner))
  7009. return TRUE;
  7010. if (CTL_FIND_NO_SIGNER_PTR == pPara->pSigner) {
  7011. DWORD cbData;
  7012. DWORD dwSignerCount;
  7013. cbData = sizeof(dwSignerCount);
  7014. if (!CryptMsgGetParam(
  7015. pCtl->hCryptMsg,
  7016. CMSG_SIGNER_COUNT_PARAM,
  7017. 0, // dwIndex
  7018. &dwSignerCount,
  7019. &cbData) || 0 != dwSignerCount)
  7020. return FALSE;
  7021. } else if (pPara->pSigner) {
  7022. DWORD dwCertEncodingType;
  7023. PCERT_INFO pCertId1 = pPara->pSigner;
  7024. HCRYPTMSG hMsg = pCtl->hCryptMsg;
  7025. DWORD cbData;
  7026. DWORD dwSignerCount;
  7027. DWORD i;
  7028. dwCertEncodingType = GetCertEncodingType(dwMsgAndCertEncodingType);
  7029. if (dwCertEncodingType != GET_CERT_ENCODING_TYPE(
  7030. pCtl->dwMsgAndCertEncodingType))
  7031. return FALSE;
  7032. cbData = sizeof(dwSignerCount);
  7033. if (!CryptMsgGetParam(
  7034. hMsg,
  7035. CMSG_SIGNER_COUNT_PARAM,
  7036. 0, // dwIndex
  7037. &dwSignerCount,
  7038. &cbData) || 0 == dwSignerCount)
  7039. return FALSE;
  7040. for (i = 0; i < dwSignerCount; i++) {
  7041. BOOL fResult;
  7042. PCERT_INFO pCertId2;
  7043. if (NULL == (pCertId2 = (PCERT_INFO) AllocAndGetMsgParam(
  7044. hMsg,
  7045. CMSG_SIGNER_CERT_INFO_PARAM,
  7046. i,
  7047. &cbData)))
  7048. continue;
  7049. fResult = CertCompareCertificate(
  7050. dwCertEncodingType,
  7051. pCertId1,
  7052. pCertId2);
  7053. PkiFree(pCertId2);
  7054. if (fResult)
  7055. break;
  7056. }
  7057. if (i == dwSignerCount)
  7058. return FALSE;
  7059. }
  7060. return TRUE;
  7061. }
  7062. STATIC BOOL CompareCtlSubject(
  7063. IN PCCTL_CONTEXT pCtl,
  7064. IN DWORD dwMsgAndCertEncodingType,
  7065. IN DWORD dwFindFlags,
  7066. IN PCTL_FIND_SUBJECT_PARA pPara
  7067. )
  7068. {
  7069. if (NULL == pPara ||
  7070. pPara->cbSize < (offsetof(CTL_FIND_SUBJECT_PARA, pUsagePara) +
  7071. sizeof(pPara->pUsagePara)))
  7072. return TRUE;
  7073. if (pPara->pUsagePara && !CompareCtlUsage(pCtl,
  7074. dwMsgAndCertEncodingType, dwFindFlags, pPara->pUsagePara))
  7075. return FALSE;
  7076. assert(offsetof(CTL_FIND_SUBJECT_PARA, pvSubject) >
  7077. offsetof(CTL_FIND_SUBJECT_PARA, pUsagePara));
  7078. if (pPara->cbSize < offsetof(CTL_FIND_SUBJECT_PARA, pvSubject) +
  7079. sizeof(pPara->pvSubject))
  7080. return TRUE;
  7081. if (pPara->pvSubject && NULL == CertFindSubjectInCTL(
  7082. dwMsgAndCertEncodingType,
  7083. pPara->dwSubjectType,
  7084. pPara->pvSubject,
  7085. pCtl,
  7086. 0)) // dwFlags
  7087. return FALSE;
  7088. return TRUE;
  7089. }
  7090. STATIC BOOL IsSameCtl(
  7091. IN PCCTL_CONTEXT pCtl,
  7092. IN PCCTL_CONTEXT pNew
  7093. )
  7094. {
  7095. PCTL_INFO pInfo = pNew->pCtlInfo;
  7096. HCRYPTMSG hMsg = pNew->hCryptMsg;
  7097. CTL_FIND_USAGE_PARA FindPara;
  7098. DWORD dwFindFlags;
  7099. DWORD cbData;
  7100. DWORD dwSignerCount;
  7101. DWORD i;
  7102. cbData = sizeof(dwSignerCount);
  7103. if (!CryptMsgGetParam(
  7104. hMsg,
  7105. CMSG_SIGNER_COUNT_PARAM,
  7106. 0, // dwIndex
  7107. &dwSignerCount,
  7108. &cbData))
  7109. return FALSE;
  7110. memset(&FindPara, 0, sizeof(FindPara));
  7111. FindPara.cbSize = sizeof(FindPara);
  7112. FindPara.SubjectUsage = pInfo->SubjectUsage;
  7113. FindPara.ListIdentifier = pInfo->ListIdentifier;
  7114. if (0 == FindPara.ListIdentifier.cbData)
  7115. FindPara.ListIdentifier.cbData = CTL_FIND_NO_LIST_ID_CBDATA;
  7116. dwFindFlags = CTL_FIND_SAME_USAGE_FLAG;
  7117. if (0 == dwSignerCount) {
  7118. FindPara.pSigner = CTL_FIND_NO_SIGNER_PTR;
  7119. return CompareCtlUsage(
  7120. pCtl,
  7121. pNew->dwMsgAndCertEncodingType,
  7122. dwFindFlags,
  7123. &FindPara
  7124. );
  7125. } else {
  7126. for (i = 0; i < dwSignerCount; i++) {
  7127. BOOL fResult;
  7128. PCERT_INFO pSigner;
  7129. if (NULL == (pSigner = (PCERT_INFO) AllocAndGetMsgParam(
  7130. hMsg,
  7131. CMSG_SIGNER_CERT_INFO_PARAM,
  7132. i,
  7133. &cbData)))
  7134. continue;
  7135. FindPara.pSigner = pSigner;
  7136. fResult = CompareCtlUsage(
  7137. pCtl,
  7138. pNew->dwMsgAndCertEncodingType,
  7139. dwFindFlags,
  7140. &FindPara
  7141. );
  7142. PkiFree(pSigner);
  7143. if (fResult)
  7144. return TRUE;
  7145. }
  7146. }
  7147. return FALSE;
  7148. }
  7149. STATIC BOOL CompareCtlElement(
  7150. IN PCONTEXT_ELEMENT pEle,
  7151. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  7152. IN BOOL fArchived
  7153. )
  7154. {
  7155. PCCTL_CONTEXT pCtl = ToCtlContext(pEle);
  7156. DWORD dwFindType = pFindInfo->dwFindType;
  7157. const void *pvFindPara = pFindInfo->pvFindPara;
  7158. if (fArchived) {
  7159. switch (dwFindType) {
  7160. case CTL_FIND_SHA1_HASH:
  7161. case CTL_FIND_MD5_HASH:
  7162. break;
  7163. default:
  7164. return FALSE;
  7165. }
  7166. }
  7167. switch (dwFindType) {
  7168. case CTL_FIND_ANY:
  7169. return TRUE;
  7170. break;
  7171. case CTL_FIND_SHA1_HASH:
  7172. case CTL_FIND_MD5_HASH:
  7173. {
  7174. DWORD dwPropId;
  7175. if (dwFindType == CTL_FIND_SHA1_HASH)
  7176. dwPropId = CERT_SHA1_HASH_PROP_ID;
  7177. else
  7178. dwPropId = CERT_MD5_HASH_PROP_ID;
  7179. return CompareCtlHash(pCtl, dwPropId,
  7180. (PCRYPT_HASH_BLOB) pvFindPara);
  7181. }
  7182. break;
  7183. case CTL_FIND_USAGE:
  7184. return CompareCtlUsage(pCtl, pFindInfo->dwMsgAndCertEncodingType,
  7185. pFindInfo->dwFindFlags, (PCTL_FIND_USAGE_PARA) pvFindPara);
  7186. break;
  7187. case CTL_FIND_SUBJECT:
  7188. return CompareCtlSubject(pCtl, pFindInfo->dwMsgAndCertEncodingType,
  7189. pFindInfo->dwFindFlags, (PCTL_FIND_SUBJECT_PARA) pvFindPara);
  7190. break;
  7191. case CTL_FIND_EXISTING:
  7192. {
  7193. PCCTL_CONTEXT pNew = (PCCTL_CONTEXT) pFindInfo->pvFindPara;
  7194. return IsSameCtl(pCtl, pNew);
  7195. }
  7196. break;
  7197. default:
  7198. goto BadParameter;
  7199. }
  7200. BadParameter:
  7201. SetLastError((DWORD) E_INVALIDARG);
  7202. return FALSE;
  7203. }
  7204. STATIC BOOL IsNewerCtlElement(
  7205. IN PCONTEXT_ELEMENT pNewEle,
  7206. IN PCONTEXT_ELEMENT pExistingEle
  7207. )
  7208. {
  7209. PCCTL_CONTEXT pNewCtl = ToCtlContext(pNewEle);
  7210. PCCTL_CONTEXT pExistingCtl = ToCtlContext(pExistingEle);
  7211. // CompareFileTime returns +1 if first time > second time
  7212. return (0 < CompareFileTime(
  7213. &pNewCtl->pCtlInfo->ThisUpdate,
  7214. &pExistingCtl->pCtlInfo->ThisUpdate
  7215. ));
  7216. }
  7217. //+=========================================================================
  7218. // Store Link Functions
  7219. //==========================================================================
  7220. STATIC PCERT_STORE_LINK CreateStoreLink(
  7221. IN PCERT_STORE pCollection,
  7222. IN PCERT_STORE pSibling,
  7223. IN DWORD dwUpdateFlags,
  7224. IN DWORD dwPriority
  7225. )
  7226. {
  7227. PCERT_STORE_LINK pLink;
  7228. if (NULL == (pLink = (PCERT_STORE_LINK) PkiZeroAlloc(
  7229. sizeof(CERT_STORE_LINK))))
  7230. return NULL;
  7231. pLink->lRefCnt = 1;
  7232. pLink->dwUpdateFlags = dwUpdateFlags;
  7233. pLink->dwPriority = dwPriority;
  7234. pLink->pCollection = pCollection;
  7235. pLink->pSibling = (PCERT_STORE) CertDuplicateStore((HCERTSTORE) pSibling);
  7236. if (pSibling->dwFlags & CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG)
  7237. InterlockedIncrement(&pSibling->lDeferCloseRefCnt);
  7238. return pLink;
  7239. }
  7240. // Not locked upon entry
  7241. STATIC void FreeStoreLink(
  7242. IN PCERT_STORE_LINK pStoreLink
  7243. )
  7244. {
  7245. PCERT_STORE pSibling = pStoreLink->pSibling;
  7246. if (pSibling->dwFlags & CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG)
  7247. InterlockedDecrement(&pSibling->lDeferCloseRefCnt);
  7248. CertCloseStore((HCERTSTORE) pSibling, 0);
  7249. PkiFree(pStoreLink);
  7250. }
  7251. STATIC void RemoveStoreLink(
  7252. IN PCERT_STORE_LINK pStoreLink
  7253. )
  7254. {
  7255. PCERT_STORE pCollection = pStoreLink->pCollection;
  7256. LockStore(pCollection);
  7257. // Remove store link from the store's collection
  7258. if (pStoreLink->pNext)
  7259. pStoreLink->pNext->pPrev = pStoreLink->pPrev;
  7260. if (pStoreLink->pPrev)
  7261. pStoreLink->pPrev->pNext = pStoreLink->pNext;
  7262. else if (pStoreLink == pCollection->pStoreListHead)
  7263. pCollection->pStoreListHead = pStoreLink->pNext;
  7264. // else
  7265. // Not on any list
  7266. // Unlocks the store or deletes the store if this was the
  7267. // last link in a closed store
  7268. FreeStore(pCollection);
  7269. }
  7270. STATIC void RemoveAndFreeStoreLink(
  7271. IN PCERT_STORE_LINK pStoreLink
  7272. )
  7273. {
  7274. RemoveStoreLink(pStoreLink);
  7275. FreeStoreLink(pStoreLink);
  7276. }
  7277. STATIC void ReleaseStoreLink(
  7278. IN PCERT_STORE_LINK pStoreLink
  7279. )
  7280. {
  7281. if (0 == InterlockedDecrement(&pStoreLink->lRefCnt)) {
  7282. assert(pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG);
  7283. assert(pStoreLink->pSibling);
  7284. RemoveAndFreeStoreLink(pStoreLink);
  7285. }
  7286. }
  7287. //+=========================================================================
  7288. // Context Element Functions
  7289. //==========================================================================
  7290. STATIC DWORD GetContextEncodingType(
  7291. IN PCONTEXT_ELEMENT pEle
  7292. )
  7293. {
  7294. DWORD dwContextType = pEle->dwContextType;
  7295. DWORD *pdwEncodingType;
  7296. pdwEncodingType = (DWORD *) ((BYTE *) pEle + sizeof(CONTEXT_ELEMENT) +
  7297. rgOffsetofEncodingType[dwContextType]);
  7298. return *pdwEncodingType;
  7299. }
  7300. STATIC void GetContextEncodedInfo(
  7301. IN PCONTEXT_ELEMENT pEle,
  7302. OUT BYTE **ppbEncoded,
  7303. OUT DWORD *pcbEncoded
  7304. )
  7305. {
  7306. DWORD dwContextType = pEle->dwContextType;
  7307. BYTE **ppbSrcEncoded;
  7308. DWORD *pcbSrcEncoded;
  7309. ppbSrcEncoded = (BYTE **) ((BYTE *) pEle + sizeof(CONTEXT_ELEMENT) +
  7310. rgOffsetofEncodedPointer[dwContextType]);
  7311. *ppbEncoded = *ppbSrcEncoded;
  7312. pcbSrcEncoded = (DWORD *) ((BYTE *) pEle + sizeof(CONTEXT_ELEMENT) +
  7313. rgOffsetofEncodedCount[dwContextType]);
  7314. *pcbEncoded = *pcbSrcEncoded;
  7315. }
  7316. STATIC PCONTEXT_ELEMENT GetCacheElement(
  7317. IN PCONTEXT_ELEMENT pCacheEle
  7318. )
  7319. {
  7320. DWORD dwInnerDepth;
  7321. // Skip past any links to get to the cache element
  7322. dwInnerDepth = 0;
  7323. for ( ; pCacheEle != pCacheEle->pEle; pCacheEle = pCacheEle->pEle) {
  7324. dwInnerDepth++;
  7325. assert(dwInnerDepth <= MAX_LINK_DEPTH);
  7326. assert(ELEMENT_TYPE_CACHE != pCacheEle->dwElementType);
  7327. if (dwInnerDepth > MAX_LINK_DEPTH)
  7328. goto ExceededMaxLinkDepth;
  7329. }
  7330. assert(pCacheEle);
  7331. assert(ELEMENT_TYPE_CACHE == pCacheEle->dwElementType);
  7332. CommonReturn:
  7333. return pCacheEle;
  7334. ErrorReturn:
  7335. pCacheEle = NULL;
  7336. goto CommonReturn;
  7337. SET_ERROR(ExceededMaxLinkDepth, E_UNEXPECTED)
  7338. }
  7339. STATIC void AddContextElement(
  7340. IN PCONTEXT_ELEMENT pEle
  7341. )
  7342. {
  7343. PCERT_STORE pStore = pEle->pStore;
  7344. DWORD dwContextType = pEle->dwContextType;
  7345. LockStore(pStore);
  7346. pEle->pNext = pStore->rgpContextListHead[dwContextType];
  7347. pEle->pPrev = NULL;
  7348. if (pStore->rgpContextListHead[dwContextType])
  7349. pStore->rgpContextListHead[dwContextType]->pPrev = pEle;
  7350. pStore->rgpContextListHead[dwContextType] = pEle;
  7351. UnlockStore(pStore);
  7352. }
  7353. STATIC void RemoveContextElement(
  7354. IN PCONTEXT_ELEMENT pEle
  7355. )
  7356. {
  7357. PCERT_STORE pStore = pEle->pStore;
  7358. DWORD dwContextType = pEle->dwContextType;
  7359. LockStore(pStore);
  7360. // Remove context from the store's list
  7361. if (pEle->pNext)
  7362. pEle->pNext->pPrev = pEle->pPrev;
  7363. if (pEle->pPrev)
  7364. pEle->pPrev->pNext = pEle->pNext;
  7365. else if (pEle == pStore->rgpContextListHead[dwContextType])
  7366. pStore->rgpContextListHead[dwContextType] = pEle->pNext;
  7367. // else
  7368. // Not on any list
  7369. // Unlocks the store or deletes the store if this was the
  7370. // last context in a closed store
  7371. FreeStore(pStore);
  7372. }
  7373. STATIC void FreeContextElement(
  7374. IN PCONTEXT_ELEMENT pEle
  7375. )
  7376. {
  7377. PPROP_ELEMENT pPropEle;
  7378. PCONTEXT_NOCOPY_INFO pNoCopyInfo;
  7379. // Free its property elements
  7380. while ((pPropEle = pEle->Cache.pPropHead) != NULL) {
  7381. RemovePropElement(pEle, pPropEle);
  7382. FreePropElement(pPropEle);
  7383. }
  7384. // For NOCOPY of the pbEncoded, call the NOCOPY pfnFree callback
  7385. if (pNoCopyInfo = pEle->pNoCopyInfo) {
  7386. PFN_CRYPT_FREE pfnFree;
  7387. BYTE **ppbEncoded;
  7388. if (pfnFree = pNoCopyInfo->pfnFree) {
  7389. assert(pNoCopyInfo->pvFree);
  7390. pfnFree(pNoCopyInfo->pvFree);
  7391. }
  7392. // Inhibit following rgpfnFreeElement[] from freeing pbEncoded
  7393. ppbEncoded = (BYTE **) ((BYTE *) pEle + sizeof(CONTEXT_ELEMENT) +
  7394. rgOffsetofEncodedPointer[pEle->dwContextType]);
  7395. *ppbEncoded = NULL;
  7396. PkiFree(pNoCopyInfo);
  7397. }
  7398. rgpfnFreeElement[pEle->dwContextType](pEle);
  7399. }
  7400. STATIC void RemoveAndFreeContextElement(
  7401. IN PCONTEXT_ELEMENT pEle
  7402. )
  7403. {
  7404. RemoveContextElement(pEle);
  7405. FreeContextElement(pEle);
  7406. }
  7407. STATIC void AddRefContextElement(
  7408. IN PCONTEXT_ELEMENT pEle
  7409. )
  7410. {
  7411. InterlockedIncrement(&pEle->lRefCnt);
  7412. if (pEle->pStore->dwFlags & CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG)
  7413. InterlockedIncrement(&pEle->pStore->lDeferCloseRefCnt);
  7414. }
  7415. STATIC void AddRefDeferClose(
  7416. IN PCONTEXT_ELEMENT pEle
  7417. )
  7418. {
  7419. if (pEle->pStore->dwFlags & CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG)
  7420. InterlockedIncrement(&pEle->pStore->lDeferCloseRefCnt);
  7421. }
  7422. STATIC void ReleaseContextElement(
  7423. IN PCONTEXT_ELEMENT pEle
  7424. )
  7425. {
  7426. DWORD dwErr;
  7427. PCERT_STORE pStore;
  7428. DWORD dwStoreFlags;
  7429. if (pEle == NULL)
  7430. return;
  7431. pStore = pEle->pStore;
  7432. dwStoreFlags = pStore->dwFlags;
  7433. if (0 == InterlockedDecrement(&pEle->lRefCnt)) {
  7434. // Check that the store still doesn't hold a reference
  7435. assert(pEle->dwFlags & ELEMENT_DELETED_FLAG);
  7436. if (dwStoreFlags & CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG)
  7437. InterlockedDecrement(&pStore->lDeferCloseRefCnt);
  7438. dwErr = GetLastError();
  7439. if (ELEMENT_TYPE_CACHE == pEle->dwElementType)
  7440. RemoveAndFreeContextElement(pEle);
  7441. else
  7442. RemoveAndFreeLinkElement(pEle);
  7443. SetLastError(dwErr);
  7444. } else if (dwStoreFlags & CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG) {
  7445. LockStore(pStore);
  7446. if (0 == InterlockedDecrement(&pStore->lDeferCloseRefCnt)) {
  7447. if (STORE_STATE_DEFER_CLOSING == pStore->dwState) {
  7448. dwErr = GetLastError();
  7449. CloseStore(pStore, 0);
  7450. SetLastError(dwErr);
  7451. return;
  7452. }
  7453. }
  7454. UnlockStore(pStore);
  7455. }
  7456. }
  7457. STATIC BOOL DeleteContextElement(
  7458. IN PCONTEXT_ELEMENT pEle
  7459. )
  7460. {
  7461. BOOL fResult;
  7462. if (NULL == pEle) {
  7463. SetLastError((DWORD) E_INVALIDARG);
  7464. return FALSE;
  7465. }
  7466. switch (pEle->dwElementType) {
  7467. case ELEMENT_TYPE_LINK_CONTEXT:
  7468. // Only delete the link itself
  7469. break;
  7470. case ELEMENT_TYPE_COLLECTION:
  7471. // Delete element pointed to
  7472. assert(pEle != pEle->pEle);
  7473. if (pEle != pEle->pEle) {
  7474. // Since delete releases refCnt, need to do an extra
  7475. // addRef here.
  7476. AddRefContextElement(pEle->pEle);
  7477. if (!DeleteContextElement(pEle->pEle))
  7478. goto DeleteCacheCollectionError;
  7479. } else
  7480. goto InvalidElement;
  7481. break;
  7482. case ELEMENT_TYPE_CACHE:
  7483. case ELEMENT_TYPE_EXTERNAL:
  7484. {
  7485. PCERT_STORE pProvStore = pEle->pProvStore;
  7486. const DWORD dwStoreProvDeleteIndex =
  7487. rgdwStoreProvDeleteIndex[pEle->dwContextType];
  7488. PFN_CERT_STORE_PROV_DELETE_CERT pfnStoreProvDeleteCert;
  7489. assert(STORE_TYPE_CACHE == pProvStore->dwStoreType ||
  7490. STORE_TYPE_EXTERNAL == pProvStore->dwStoreType);
  7491. fResult = TRUE;
  7492. LockStore(pProvStore);
  7493. // Check if we need to call the store provider's writethru
  7494. // function.
  7495. if (dwStoreProvDeleteIndex <
  7496. pProvStore->StoreProvInfo.cStoreProvFunc &&
  7497. NULL != (pfnStoreProvDeleteCert =
  7498. (PFN_CERT_STORE_PROV_DELETE_CERT)
  7499. pProvStore->StoreProvInfo.rgpvStoreProvFunc[
  7500. dwStoreProvDeleteIndex])) {
  7501. // Since we can't hold a lock while calling the provider
  7502. // function, bump the store's provider reference count
  7503. // to inhibit the closing of the store and freeing of
  7504. // the provider functions.
  7505. //
  7506. // When the store is closed,
  7507. // pProvStore->StoreProvInfo.cStoreProvFunc is set to 0.
  7508. AddRefStoreProv(pProvStore);
  7509. UnlockStore(pProvStore);
  7510. // Check if its OK to delete from the store.
  7511. fResult = pfnStoreProvDeleteCert(
  7512. pProvStore->StoreProvInfo.hStoreProv,
  7513. ToCertContext(pEle->pEle),
  7514. 0 // dwFlags
  7515. );
  7516. LockStore(pProvStore);
  7517. ReleaseStoreProv(pProvStore);
  7518. }
  7519. UnlockStore(pProvStore);
  7520. if (!fResult)
  7521. goto StoreProvDeleteError;
  7522. }
  7523. break;
  7524. default:
  7525. goto InvalidElementType;
  7526. }
  7527. LockStore(pEle->pStore);
  7528. if (0 == (pEle->dwFlags & ELEMENT_DELETED_FLAG)) {
  7529. // On the store's list. There should be at least two reference
  7530. // counts on the context, the store's and the caller's.
  7531. assert(pEle->pStore->dwState == STORE_STATE_OPEN ||
  7532. pEle->pStore->dwState == STORE_STATE_OPENING ||
  7533. pEle->pStore->dwState == STORE_STATE_DEFER_CLOSING ||
  7534. pEle->pStore->dwState == STORE_STATE_CLOSING);
  7535. // Remove the store's reference
  7536. if (0 == InterlockedDecrement(&pEle->lRefCnt)) {
  7537. assert(pEle->lRefCnt > 0);
  7538. // Put back the reference to allow the ReleaseContextElement
  7539. // to do the context remove and free
  7540. pEle->lRefCnt = 1;
  7541. }
  7542. pEle->dwFlags |= ELEMENT_DELETED_FLAG;
  7543. }
  7544. UnlockStore(pEle->pStore);
  7545. fResult = TRUE;
  7546. CommonReturn:
  7547. // Release the caller's reference on the context
  7548. ReleaseContextElement(pEle);
  7549. return fResult;
  7550. ErrorReturn:
  7551. fResult = FALSE;
  7552. goto CommonReturn;
  7553. TRACE_ERROR(DeleteCacheCollectionError)
  7554. SET_ERROR(InvalidElement, E_INVALIDARG)
  7555. TRACE_ERROR(StoreProvDeleteError)
  7556. SET_ERROR(InvalidElementType, E_INVALIDARG)
  7557. }
  7558. // Returns TRUE if both elements have identical SHA1 hash.
  7559. STATIC BOOL IsIdenticalContextElement(
  7560. IN PCONTEXT_ELEMENT pEle1,
  7561. IN PCONTEXT_ELEMENT pEle2
  7562. )
  7563. {
  7564. BYTE rgbHash1[SHA1_HASH_LEN];
  7565. BYTE rgbHash2[SHA1_HASH_LEN];
  7566. DWORD cbHash;
  7567. cbHash = SHA1_HASH_LEN;
  7568. if (!GetProperty(
  7569. pEle1,
  7570. CERT_SHA1_HASH_PROP_ID,
  7571. rgbHash1,
  7572. &cbHash
  7573. ) || SHA1_HASH_LEN != cbHash)
  7574. return FALSE;
  7575. if (!GetProperty(
  7576. pEle2,
  7577. CERT_SHA1_HASH_PROP_ID,
  7578. rgbHash2,
  7579. &cbHash
  7580. ) || SHA1_HASH_LEN != cbHash)
  7581. return FALSE;
  7582. if (0 == memcmp(rgbHash1, rgbHash2, SHA1_HASH_LEN))
  7583. return TRUE;
  7584. else
  7585. return FALSE;
  7586. }
  7587. //+-------------------------------------------------------------------------
  7588. // Serialize a store element and its properties
  7589. //--------------------------------------------------------------------------
  7590. STATIC BOOL SerializeStoreElement(
  7591. IN HANDLE h,
  7592. IN PFNWRITE pfn,
  7593. IN PCONTEXT_ELEMENT pEle
  7594. )
  7595. {
  7596. BOOL fResult;
  7597. BYTE *pbEncoded;
  7598. DWORD cbEncoded;
  7599. if (!SerializeProperty(
  7600. h,
  7601. pfn,
  7602. pEle
  7603. ))
  7604. goto SerializePropertyError;
  7605. GetContextEncodedInfo(pEle, &pbEncoded, &cbEncoded);
  7606. if (!WriteStoreElement(
  7607. h,
  7608. pfn,
  7609. GetContextEncodingType(pEle),
  7610. rgdwFileElementType[pEle->dwContextType],
  7611. pbEncoded,
  7612. cbEncoded
  7613. ))
  7614. goto WriteElementError;
  7615. fResult = TRUE;
  7616. CommonReturn:
  7617. return fResult;
  7618. ErrorReturn:
  7619. fResult = FALSE;
  7620. goto CommonReturn;
  7621. TRACE_ERROR(SerializePropertyError);
  7622. TRACE_ERROR(WriteElementError);
  7623. }
  7624. //+-------------------------------------------------------------------------
  7625. // Serialize the context's encoded data and its properties.
  7626. //--------------------------------------------------------------------------
  7627. STATIC BOOL SerializeContextElement(
  7628. IN PCONTEXT_ELEMENT pEle,
  7629. IN DWORD dwFlags,
  7630. OUT BYTE *pbElement,
  7631. IN OUT DWORD *pcbElement
  7632. )
  7633. {
  7634. BOOL fResult;
  7635. MEMINFO MemInfo;
  7636. MemInfo.pByte = pbElement;
  7637. if (pbElement == NULL)
  7638. MemInfo.cb = 0;
  7639. else
  7640. MemInfo.cb = *pcbElement;
  7641. MemInfo.cbSeek = 0;
  7642. if (fResult = SerializeStoreElement(
  7643. (HANDLE) &MemInfo,
  7644. WriteToMemory,
  7645. pEle)) {
  7646. if (MemInfo.cbSeek > MemInfo.cb && pbElement) {
  7647. SetLastError((DWORD) ERROR_MORE_DATA);
  7648. fResult = FALSE;
  7649. }
  7650. *pcbElement = MemInfo.cbSeek;
  7651. } else
  7652. *pcbElement = 0;
  7653. return fResult;
  7654. }
  7655. //+=========================================================================
  7656. // Collection Stack Functions
  7657. //==========================================================================
  7658. // No locks upon entry
  7659. STATIC BOOL PushCollectionStack(
  7660. IN OUT PCOLLECTION_STACK_ENTRY *ppStack,
  7661. IN PCERT_STORE pCollection
  7662. )
  7663. {
  7664. PCOLLECTION_STACK_ENTRY pNew;
  7665. PCERT_STORE_LINK pStoreLink;
  7666. if (NULL == (pNew = (PCOLLECTION_STACK_ENTRY) PkiZeroAlloc(
  7667. sizeof(COLLECTION_STACK_ENTRY))))
  7668. return FALSE;
  7669. LockStore(pCollection);
  7670. pStoreLink = pCollection->pStoreListHead;
  7671. // Advance past deleted store links
  7672. while (pStoreLink && (pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG))
  7673. pStoreLink = pStoreLink->pNext;
  7674. if (pStoreLink)
  7675. AddRefStoreLink(pStoreLink);
  7676. UnlockStore(pCollection);
  7677. pNew->pCollection = pCollection;
  7678. pNew->pStoreLink = pStoreLink;
  7679. pNew->pPrev = *ppStack;
  7680. *ppStack = pNew;
  7681. return TRUE;
  7682. };
  7683. // No locks upon entry
  7684. STATIC void AdvanceToNextStackStoreLink(
  7685. IN PCOLLECTION_STACK_ENTRY pStack
  7686. )
  7687. {
  7688. PCERT_STORE pStackCollectionStore;
  7689. PCERT_STORE_LINK pStoreLink;
  7690. if (NULL == pStack)
  7691. return;
  7692. pStoreLink = pStack->pStoreLink;
  7693. if (NULL == pStoreLink)
  7694. return;
  7695. pStackCollectionStore = pStack->pCollection;
  7696. assert(pStackCollectionStore);
  7697. LockStore(pStackCollectionStore);
  7698. pStoreLink = pStoreLink->pNext;
  7699. // Advance past deleted store links
  7700. while (pStoreLink && (pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG))
  7701. pStoreLink = pStoreLink->pNext;
  7702. if (pStoreLink)
  7703. AddRefStoreLink(pStoreLink);
  7704. UnlockStore(pStackCollectionStore);
  7705. ReleaseStoreLink(pStack->pStoreLink);
  7706. pStack->pStoreLink = pStoreLink;
  7707. }
  7708. // No locks upon entry
  7709. STATIC void PopCollectionStack(
  7710. IN OUT PCOLLECTION_STACK_ENTRY *ppStack
  7711. )
  7712. {
  7713. PCOLLECTION_STACK_ENTRY pStack = *ppStack;
  7714. if (pStack) {
  7715. PCOLLECTION_STACK_ENTRY pPrevStack;
  7716. if (pStack->pStoreLink)
  7717. ReleaseStoreLink(pStack->pStoreLink);
  7718. pPrevStack = pStack->pPrev;
  7719. *ppStack = pPrevStack;
  7720. PkiFree(pStack);
  7721. if (pPrevStack)
  7722. AdvanceToNextStackStoreLink(pPrevStack);
  7723. }
  7724. }
  7725. // No locks upon entry
  7726. STATIC void ClearCollectionStack(
  7727. IN PCOLLECTION_STACK_ENTRY pStack
  7728. )
  7729. {
  7730. while (pStack) {
  7731. PCOLLECTION_STACK_ENTRY pFreeStack;
  7732. if (pStack->pStoreLink)
  7733. ReleaseStoreLink(pStack->pStoreLink);
  7734. pFreeStack = pStack;
  7735. pStack = pStack->pPrev;
  7736. PkiFree(pFreeStack);
  7737. }
  7738. }
  7739. //+=========================================================================
  7740. // Link Element Functions
  7741. //==========================================================================
  7742. STATIC PCONTEXT_ELEMENT CreateLinkElement(
  7743. IN DWORD dwContextType
  7744. )
  7745. {
  7746. PCONTEXT_ELEMENT pLinkEle;
  7747. const DWORD cbContext = rgcbContext[dwContextType];
  7748. if (NULL == (pLinkEle = (PCONTEXT_ELEMENT) PkiZeroAlloc(
  7749. sizeof(CONTEXT_ELEMENT) + cbContext)))
  7750. return NULL;
  7751. pLinkEle->dwContextType = dwContextType;
  7752. return pLinkEle;
  7753. }
  7754. static inline void SetStoreHandle(
  7755. IN PCONTEXT_ELEMENT pEle
  7756. )
  7757. {
  7758. HCERTSTORE *phStore;
  7759. phStore = (HCERTSTORE *) ((BYTE *) pEle + sizeof(CONTEXT_ELEMENT) +
  7760. rgOffsetofStoreHandle[pEle->dwContextType]);
  7761. *phStore = (HCERTSTORE) pEle->pStore;
  7762. }
  7763. // The store doesn't hold a reference on the external element.
  7764. // Therefore, its lRefCnt is 1 and the ELEMENT_DELETED_FLAG is set.
  7765. STATIC void InitAndAddExternalElement(
  7766. IN PCONTEXT_ELEMENT pLinkEle,
  7767. IN PCERT_STORE pStore, // EXTERNAL
  7768. IN PCONTEXT_ELEMENT pProvEle, // already AddRef'ed
  7769. IN DWORD dwFlags,
  7770. IN OPTIONAL void *pvProvInfo
  7771. )
  7772. {
  7773. const DWORD cbContext = rgcbContext[pLinkEle->dwContextType];
  7774. assert(STORE_TYPE_EXTERNAL == pStore->dwStoreType);
  7775. pLinkEle->dwElementType = ELEMENT_TYPE_EXTERNAL;
  7776. pLinkEle->dwFlags = dwFlags | ELEMENT_DELETED_FLAG;
  7777. pLinkEle->lRefCnt = 1;
  7778. pLinkEle->pEle = pProvEle;
  7779. pLinkEle->pStore = pStore;
  7780. pLinkEle->pProvStore = pStore;
  7781. pLinkEle->External.pvProvInfo = pvProvInfo;
  7782. memcpy(((BYTE *) pLinkEle) + sizeof(CONTEXT_ELEMENT),
  7783. ((BYTE *) pProvEle) + sizeof(CONTEXT_ELEMENT),
  7784. cbContext);
  7785. SetStoreHandle(pLinkEle);
  7786. AddContextElement(pLinkEle);
  7787. AddRefDeferClose(pLinkEle);
  7788. }
  7789. // The store doesn't hold a reference on the collection element.
  7790. // Therefore, its RefCount is 1 and the ELEMENT_DELETED_FLAG is set.
  7791. STATIC void InitAndAddCollectionElement(
  7792. IN PCONTEXT_ELEMENT pLinkEle,
  7793. IN PCERT_STORE pStore, // COLLECTION
  7794. IN PCONTEXT_ELEMENT pSiblingEle, // already AddRef'ed
  7795. IN OPTIONAL PCOLLECTION_STACK_ENTRY pCollectionStack
  7796. )
  7797. {
  7798. const DWORD cbContext = rgcbContext[pLinkEle->dwContextType];
  7799. assert(STORE_TYPE_COLLECTION == pStore->dwStoreType);
  7800. pLinkEle->dwElementType = ELEMENT_TYPE_COLLECTION;
  7801. pLinkEle->dwFlags = ELEMENT_DELETED_FLAG;
  7802. pLinkEle->lRefCnt = 1;
  7803. pLinkEle->pEle = pSiblingEle;
  7804. pLinkEle->pStore = pStore;
  7805. pLinkEle->pProvStore = pSiblingEle->pProvStore;
  7806. pLinkEle->Collection.pCollectionStack = pCollectionStack;
  7807. memcpy(((BYTE *) pLinkEle) + sizeof(CONTEXT_ELEMENT),
  7808. ((BYTE *) pSiblingEle) + sizeof(CONTEXT_ELEMENT),
  7809. cbContext);
  7810. SetStoreHandle(pLinkEle);
  7811. AddContextElement(pLinkEle);
  7812. AddRefDeferClose(pLinkEle);
  7813. }
  7814. // The store holds a reference on the link context element.
  7815. // Therefore, the ELEMENT_DELETED_FLAG is clear.
  7816. STATIC void InitAndAddLinkContextElement(
  7817. IN PCONTEXT_ELEMENT pLinkEle,
  7818. IN PCERT_STORE pStore, // CACHE
  7819. IN PCONTEXT_ELEMENT pContextEle // already AddRef'ed
  7820. )
  7821. {
  7822. const DWORD cbContext = rgcbContext[pLinkEle->dwContextType];
  7823. assert(STORE_TYPE_CACHE == pStore->dwStoreType);
  7824. pLinkEle->dwElementType = ELEMENT_TYPE_LINK_CONTEXT;
  7825. pLinkEle->lRefCnt = 1;
  7826. pLinkEle->pEle = pContextEle;
  7827. pLinkEle->pStore = pStore;
  7828. pLinkEle->pProvStore = pContextEle->pProvStore;
  7829. memcpy(((BYTE *) pLinkEle) + sizeof(CONTEXT_ELEMENT),
  7830. ((BYTE *) pContextEle) + sizeof(CONTEXT_ELEMENT),
  7831. cbContext);
  7832. SetStoreHandle(pLinkEle);
  7833. AddContextElement(pLinkEle);
  7834. }
  7835. // Upon entry no locks
  7836. STATIC void RemoveAndFreeLinkElement(
  7837. IN PCONTEXT_ELEMENT pEle
  7838. )
  7839. {
  7840. if (ELEMENT_TYPE_EXTERNAL == pEle->dwElementType) {
  7841. PCERT_STORE pProvStore = pEle->pProvStore;
  7842. const DWORD dwStoreProvFreeFindIndex =
  7843. rgdwStoreProvFreeFindIndex[pEle->dwContextType];
  7844. PFN_CERT_STORE_PROV_FREE_FIND_CERT pfnStoreProvFreeFindCert;
  7845. assert(pEle->pStore == pEle->pProvStore);
  7846. assert(STORE_TYPE_EXTERNAL == pProvStore->dwStoreType);
  7847. LockStore(pProvStore);
  7848. // Check if we need to call the store provider's free find cert
  7849. // function.
  7850. if (pEle->dwFlags & ELEMENT_FIND_NEXT_FLAG) {
  7851. pEle->dwFlags &= ~ELEMENT_FIND_NEXT_FLAG;
  7852. if (dwStoreProvFreeFindIndex <
  7853. pProvStore->StoreProvInfo.cStoreProvFunc &&
  7854. NULL != (pfnStoreProvFreeFindCert =
  7855. (PFN_CERT_STORE_PROV_FREE_FIND_CERT)
  7856. pProvStore->StoreProvInfo.rgpvStoreProvFunc[
  7857. dwStoreProvFreeFindIndex])) {
  7858. // Since we can't hold a lock while calling the provider
  7859. // function, bump the store's provider reference count
  7860. // to inhibit the closing of the store and freeing of
  7861. // the provider functions.
  7862. //
  7863. // When the store is closed,
  7864. // pProvStore->StoreProvInfo.cStoreProvFunc is set to 0.
  7865. AddRefStoreProv(pProvStore);
  7866. UnlockStore(pProvStore);
  7867. pfnStoreProvFreeFindCert(
  7868. pProvStore->StoreProvInfo.hStoreProv,
  7869. ToCertContext(pEle->pEle),
  7870. pEle->External.pvProvInfo,
  7871. 0 // dwFlags
  7872. );
  7873. LockStore(pProvStore);
  7874. ReleaseStoreProv(pProvStore);
  7875. }
  7876. }
  7877. UnlockStore(pProvStore);
  7878. } else if (ELEMENT_TYPE_COLLECTION == pEle->dwElementType) {
  7879. if (pEle->Collection.pCollectionStack)
  7880. ClearCollectionStack(pEle->Collection.pCollectionStack);
  7881. }
  7882. ReleaseContextElement(pEle->pEle);
  7883. // Remove from store
  7884. RemoveContextElement(pEle);
  7885. FreeLinkElement(pEle);
  7886. }
  7887. STATIC void FreeLinkContextElement(
  7888. IN PCONTEXT_ELEMENT pLinkEle
  7889. )
  7890. {
  7891. ReleaseContextElement(pLinkEle->pEle);
  7892. FreeLinkElement(pLinkEle);
  7893. }
  7894. //+=========================================================================
  7895. // Find Element Functions
  7896. //==========================================================================
  7897. // For Add, called with store already locked and store remains locked. The
  7898. // find type for the Add is FIND_EXISTING.
  7899. // CacheStore may contain either cache or context link elements
  7900. STATIC PCONTEXT_ELEMENT FindElementInCacheStore(
  7901. IN PCERT_STORE pStore,
  7902. IN DWORD dwContextType,
  7903. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  7904. IN OPTIONAL PCONTEXT_ELEMENT pPrevEle,
  7905. IN BOOL fForceEnumArchived = FALSE
  7906. )
  7907. {
  7908. PCONTEXT_ELEMENT pEle;
  7909. assert(STORE_TYPE_CACHE == pStore->dwStoreType);
  7910. LockStore(pStore);
  7911. if (pPrevEle) {
  7912. if (pPrevEle->pStore != pStore ||
  7913. pPrevEle->dwContextType != dwContextType) {
  7914. UnlockStore(pStore);
  7915. goto InvalidPreviousContext;
  7916. }
  7917. pEle = pPrevEle->pNext;
  7918. } else if (STORE_STATE_NULL == pStore->dwState)
  7919. // For NULL store, all elements are already deleted
  7920. pEle = NULL;
  7921. else
  7922. pEle = pStore->rgpContextListHead[dwContextType];
  7923. for ( ; pEle; pEle = pEle->pNext) {
  7924. PCONTEXT_ELEMENT pCacheEle;
  7925. BOOL fArchived;
  7926. assert(ELEMENT_TYPE_CACHE == pEle->dwElementType ||
  7927. ELEMENT_TYPE_LINK_CONTEXT == pEle->dwElementType);
  7928. // Skip past deleted elements
  7929. if (pEle->dwFlags & ELEMENT_DELETED_FLAG)
  7930. continue;
  7931. if (ELEMENT_TYPE_CACHE == pEle->dwElementType)
  7932. pCacheEle = pEle;
  7933. else {
  7934. pCacheEle = GetCacheElement(pEle);
  7935. if (NULL == pCacheEle)
  7936. pCacheEle = pEle;
  7937. }
  7938. fArchived = ((pCacheEle->dwFlags & ELEMENT_ARCHIVED_FLAG) &&
  7939. 0 == (pStore->dwFlags & CERT_STORE_ENUM_ARCHIVED_FLAG) &&
  7940. !fForceEnumArchived);
  7941. AddRefContextElement(pEle);
  7942. UnlockStore(pStore);
  7943. // Handle MappedFile Exceptions
  7944. __try {
  7945. if (rgpfnCompareElement[dwContextType](pEle, pFindInfo, fArchived))
  7946. goto CommonReturn;
  7947. } __except(EXCEPTION_EXECUTE_HANDLER) {
  7948. SetLastError(GetExceptionCode());
  7949. goto ErrorReturn;
  7950. }
  7951. if (pPrevEle)
  7952. ReleaseContextElement(pPrevEle);
  7953. pPrevEle = pEle;
  7954. LockStore(pStore);
  7955. }
  7956. UnlockStore(pStore);
  7957. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  7958. CommonReturn:
  7959. if (pPrevEle)
  7960. ReleaseContextElement(pPrevEle);
  7961. return pEle;
  7962. ErrorReturn:
  7963. pEle = NULL;
  7964. goto CommonReturn;
  7965. SET_ERROR(InvalidPreviousContext, E_INVALIDARG)
  7966. }
  7967. STATIC PCONTEXT_ELEMENT FindElementInExternalStore(
  7968. IN PCERT_STORE pStore, // EXTERNAL
  7969. IN DWORD dwContextType,
  7970. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  7971. IN OPTIONAL PCONTEXT_ELEMENT pPrevEle
  7972. )
  7973. {
  7974. PCONTEXT_ELEMENT pEle = NULL;
  7975. const DWORD dwStoreProvFindIndex = rgdwStoreProvFindIndex[dwContextType];
  7976. // All the context types have the same find callback signature.
  7977. PFN_CERT_STORE_PROV_FIND_CERT pfnStoreProvFind;
  7978. void *pvProvInfo;
  7979. PCONTEXT_ELEMENT pPrevProvEle = NULL;
  7980. PCCERT_CONTEXT pProvCertContext;
  7981. assert(STORE_TYPE_EXTERNAL == pStore->dwStoreType);
  7982. if (NULL == (pEle = CreateLinkElement(dwContextType)))
  7983. goto CreateLinkElementError;
  7984. if (pPrevEle) {
  7985. BOOL fResult;
  7986. if (pPrevEle->pStore != pStore ||
  7987. pPrevEle->dwContextType != dwContextType)
  7988. goto InvalidPreviousContext;
  7989. assert(ELEMENT_TYPE_EXTERNAL == pPrevEle->dwElementType);
  7990. LockStore(pStore);
  7991. fResult = pPrevEle->dwFlags & ELEMENT_FIND_NEXT_FLAG;
  7992. if (fResult) {
  7993. assert(dwStoreProvFindIndex <
  7994. pStore->StoreProvInfo.cStoreProvFunc &&
  7995. pStore->StoreProvInfo.rgpvStoreProvFunc[dwStoreProvFindIndex]);
  7996. pvProvInfo = pPrevEle->External.pvProvInfo;
  7997. pPrevEle->External.pvProvInfo = NULL;
  7998. pPrevEle->dwFlags &= ~ELEMENT_FIND_NEXT_FLAG;
  7999. pPrevProvEle = pPrevEle->pEle;
  8000. assert(pPrevProvEle);
  8001. }
  8002. UnlockStore(pStore);
  8003. if (!fResult)
  8004. goto InvalidExternalFindNext;
  8005. } else {
  8006. pvProvInfo = NULL;
  8007. pPrevProvEle = NULL;
  8008. }
  8009. // Check if external store supports the context type
  8010. if (dwStoreProvFindIndex >= pStore->StoreProvInfo.cStoreProvFunc ||
  8011. NULL == (pfnStoreProvFind = (PFN_CERT_STORE_PROV_FIND_CERT)
  8012. pStore->StoreProvInfo.rgpvStoreProvFunc[dwStoreProvFindIndex]))
  8013. goto ProvFindNotSupported;
  8014. pProvCertContext = NULL;
  8015. if (!pfnStoreProvFind(
  8016. pStore->StoreProvInfo.hStoreProv,
  8017. pFindInfo,
  8018. ToCertContext(pPrevProvEle),
  8019. 0, // dwFlags
  8020. &pvProvInfo,
  8021. &pProvCertContext) || NULL == pProvCertContext)
  8022. goto ErrorReturn;
  8023. InitAndAddExternalElement(
  8024. pEle,
  8025. pStore,
  8026. ToContextElement(pProvCertContext),
  8027. ELEMENT_FIND_NEXT_FLAG,
  8028. pvProvInfo
  8029. );
  8030. CommonReturn:
  8031. if (pPrevEle)
  8032. ReleaseContextElement(pPrevEle);
  8033. return pEle;
  8034. ErrorReturn:
  8035. if (pEle) {
  8036. FreeLinkElement(pEle);
  8037. pEle = NULL;
  8038. }
  8039. goto CommonReturn;
  8040. SET_ERROR(InvalidPreviousContext, E_INVALIDARG)
  8041. SET_ERROR(InvalidExternalFindNext, E_INVALIDARG)
  8042. SET_ERROR(ProvFindNotSupported, ERROR_CALL_NOT_IMPLEMENTED)
  8043. TRACE_ERROR(CreateLinkElementError)
  8044. }
  8045. STATIC PCONTEXT_ELEMENT FindElementInCollectionStore(
  8046. IN PCERT_STORE pCollection,
  8047. IN DWORD dwContextType,
  8048. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  8049. IN OPTIONAL PCONTEXT_ELEMENT pPrevEle,
  8050. IN BOOL fFindForAdd = FALSE
  8051. )
  8052. {
  8053. PCONTEXT_ELEMENT pEle = NULL;
  8054. PCOLLECTION_STACK_ENTRY pStack = NULL;
  8055. if (pPrevEle) {
  8056. // Get previous element's collection stack
  8057. if (pPrevEle->pStore != pCollection ||
  8058. pPrevEle->dwContextType != dwContextType)
  8059. goto InvalidPreviousContext;
  8060. LockStore(pCollection);
  8061. pStack = pPrevEle->Collection.pCollectionStack;
  8062. pPrevEle->Collection.pCollectionStack = NULL;
  8063. UnlockStore(pCollection);
  8064. if (NULL == pStack)
  8065. goto InvalidCollectionFindNext;
  8066. // Note, pStack->pCollection is only equal to pCollection
  8067. // for a single level collection.
  8068. assert(pStack->pStoreLink);
  8069. assert(ELEMENT_TYPE_EXTERNAL == pPrevEle->dwElementType ||
  8070. ELEMENT_TYPE_COLLECTION == pPrevEle->dwElementType);
  8071. } else {
  8072. // Initialize collection stack with the collection store's
  8073. // first link
  8074. if (!PushCollectionStack(&pStack, pCollection))
  8075. goto PushStackError;
  8076. }
  8077. while (pStack) {
  8078. PCERT_STORE pStackCollectionStore;
  8079. PCERT_STORE_LINK pStoreLink;
  8080. PCERT_STORE pFindStore;
  8081. pStackCollectionStore = pStack->pCollection;
  8082. pStoreLink = pStack->pStoreLink; // may be NULL
  8083. if (NULL == pPrevEle) {
  8084. LockStore(pStackCollectionStore);
  8085. // Advance past any deleted store links
  8086. //
  8087. // Also if doing a find before doing an add to a collection,
  8088. // check that the store link allows an ADD
  8089. while (pStoreLink &&
  8090. ((pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG) ||
  8091. (fFindForAdd && 0 == (pStoreLink->dwUpdateFlags &
  8092. CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG))))
  8093. pStoreLink = pStoreLink->pNext;
  8094. if (pStoreLink && pStoreLink != pStack->pStoreLink)
  8095. AddRefStoreLink(pStoreLink);
  8096. UnlockStore(pStackCollectionStore);
  8097. if (NULL == pStoreLink) {
  8098. // Reached end of collection's store links
  8099. PopCollectionStack(&pStack);
  8100. continue;
  8101. } else if (pStoreLink != pStack->pStoreLink) {
  8102. ReleaseStoreLink(pStack->pStoreLink);
  8103. pStack->pStoreLink = pStoreLink;
  8104. }
  8105. }
  8106. assert(pStoreLink);
  8107. pFindStore = pStoreLink->pSibling;
  8108. if (STORE_TYPE_COLLECTION == pFindStore->dwStoreType) {
  8109. assert(NULL == pPrevEle);
  8110. // Add inner collection store to stack
  8111. if (!PushCollectionStack(&pStack, pFindStore))
  8112. goto PushStackError;
  8113. } else if (STORE_TYPE_CACHE == pFindStore->dwStoreType ||
  8114. STORE_TYPE_EXTERNAL == pFindStore->dwStoreType) {
  8115. PCONTEXT_ELEMENT pPrevSiblingEle;
  8116. PCONTEXT_ELEMENT pSiblingEle;
  8117. if (pPrevEle) {
  8118. assert(ELEMENT_TYPE_COLLECTION ==
  8119. pPrevEle->dwElementType);
  8120. pPrevSiblingEle = pPrevEle->pEle;
  8121. // FindElementInCacheStore or FindElementInExternalStore
  8122. // does an implicit Free
  8123. AddRefContextElement(pPrevSiblingEle);
  8124. } else
  8125. pPrevSiblingEle = NULL;
  8126. if (pSiblingEle = FindElementInStore(
  8127. pFindStore,
  8128. dwContextType,
  8129. pFindInfo,
  8130. pPrevSiblingEle
  8131. )) {
  8132. if (NULL == (pEle =
  8133. CreateLinkElement(dwContextType))) {
  8134. ReleaseContextElement(pSiblingEle);
  8135. goto CreateLinkElementError;
  8136. }
  8137. InitAndAddCollectionElement(
  8138. pEle,
  8139. pCollection,
  8140. pSiblingEle,
  8141. pStack
  8142. );
  8143. goto CommonReturn;
  8144. }
  8145. if (pPrevEle) {
  8146. ReleaseContextElement(pPrevEle);
  8147. pPrevEle = NULL;
  8148. }
  8149. // Advance to the next store link in the collection
  8150. AdvanceToNextStackStoreLink(pStack);
  8151. } else
  8152. goto InvalidStoreType;
  8153. }
  8154. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  8155. CommonReturn:
  8156. if (pPrevEle)
  8157. ReleaseContextElement(pPrevEle);
  8158. return pEle;
  8159. ErrorReturn:
  8160. ClearCollectionStack(pStack);
  8161. pEle = NULL;
  8162. goto CommonReturn;
  8163. SET_ERROR(InvalidPreviousContext, E_INVALIDARG)
  8164. SET_ERROR(InvalidCollectionFindNext, E_INVALIDARG)
  8165. TRACE_ERROR(PushStackError)
  8166. TRACE_ERROR(CreateLinkElementError)
  8167. SET_ERROR(InvalidStoreType, E_INVALIDARG)
  8168. }
  8169. STATIC PCONTEXT_ELEMENT FindElementInStore(
  8170. IN PCERT_STORE pStore,
  8171. IN DWORD dwContextType,
  8172. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  8173. IN OPTIONAL PCONTEXT_ELEMENT pPrevEle
  8174. )
  8175. {
  8176. assert(pStore->dwState == STORE_STATE_OPEN ||
  8177. pStore->dwState == STORE_STATE_OPENING ||
  8178. pStore->dwState == STORE_STATE_DEFER_CLOSING ||
  8179. pStore->dwState == STORE_STATE_CLOSING ||
  8180. pStore->dwState == STORE_STATE_NULL);
  8181. switch (pStore->dwStoreType) {
  8182. case STORE_TYPE_CACHE:
  8183. return FindElementInCacheStore(
  8184. pStore,
  8185. dwContextType,
  8186. pFindInfo,
  8187. pPrevEle
  8188. );
  8189. break;
  8190. case STORE_TYPE_EXTERNAL:
  8191. return FindElementInExternalStore(
  8192. pStore,
  8193. dwContextType,
  8194. pFindInfo,
  8195. pPrevEle
  8196. );
  8197. break;
  8198. case STORE_TYPE_COLLECTION:
  8199. return FindElementInCollectionStore(
  8200. pStore,
  8201. dwContextType,
  8202. pFindInfo,
  8203. pPrevEle
  8204. );
  8205. break;
  8206. default:
  8207. goto InvalidStoreType;
  8208. }
  8209. ErrorReturn:
  8210. return NULL;
  8211. SET_ERROR(InvalidStoreType, E_INVALIDARG)
  8212. }
  8213. STATIC void AutoResyncStore(
  8214. IN PCERT_STORE pStore
  8215. )
  8216. {
  8217. if (pStore->hAutoResyncEvent) {
  8218. if (WAIT_OBJECT_0 == WaitForSingleObjectEx(
  8219. pStore->hAutoResyncEvent,
  8220. 0, // dwMilliseconds
  8221. FALSE // bAlertable
  8222. ))
  8223. CertControlStore(
  8224. (HCERTSTORE) pStore,
  8225. CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG,
  8226. CERT_STORE_CTRL_RESYNC,
  8227. &pStore->hAutoResyncEvent
  8228. );
  8229. } else if (STORE_TYPE_COLLECTION == pStore->dwStoreType) {
  8230. // Iterate through all the siblings and attempt to AutoResync
  8231. PCERT_STORE_LINK pStoreLink;
  8232. PCERT_STORE_LINK pPrevStoreLink = NULL;
  8233. LockStore(pStore);
  8234. pStoreLink = pStore->pStoreListHead;
  8235. for (; pStoreLink; pStoreLink = pStoreLink->pNext) {
  8236. // Advance past deleted store link
  8237. if (pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG)
  8238. continue;
  8239. AddRefStoreLink(pStoreLink);
  8240. UnlockStore(pStore);
  8241. if (pPrevStoreLink)
  8242. ReleaseStoreLink(pPrevStoreLink);
  8243. pPrevStoreLink = pStoreLink;
  8244. AutoResyncStore(pStoreLink->pSibling);
  8245. LockStore(pStore);
  8246. }
  8247. UnlockStore(pStore);
  8248. if (pPrevStoreLink)
  8249. ReleaseStoreLink(pPrevStoreLink);
  8250. }
  8251. }
  8252. STATIC PCONTEXT_ELEMENT CheckAutoResyncAndFindElementInStore(
  8253. IN PCERT_STORE pStore,
  8254. IN DWORD dwContextType,
  8255. IN PCCERT_STORE_PROV_FIND_INFO pFindInfo,
  8256. IN OPTIONAL PCONTEXT_ELEMENT pPrevEle
  8257. )
  8258. {
  8259. if (NULL == pPrevEle)
  8260. AutoResyncStore(pStore);
  8261. return FindElementInStore(
  8262. pStore,
  8263. dwContextType,
  8264. pFindInfo,
  8265. pPrevEle
  8266. );
  8267. }
  8268. //+=========================================================================
  8269. // Add Element Functions
  8270. //==========================================================================
  8271. STATIC void SetFindInfoToFindExisting(
  8272. IN PCONTEXT_ELEMENT pEle,
  8273. IN OUT PCERT_STORE_PROV_FIND_INFO pFindInfo
  8274. )
  8275. {
  8276. memset(pFindInfo, 0, sizeof(*pFindInfo));
  8277. pFindInfo->cbSize = sizeof(*pFindInfo);
  8278. pFindInfo->dwFindType = rgdwFindTypeToFindExisting[pEle->dwContextType];
  8279. pFindInfo->pvFindPara = ToCertContext(pEle);
  8280. }
  8281. STATIC BOOL AddLinkContextToCacheStore(
  8282. IN PCERT_STORE pStore,
  8283. IN PCONTEXT_ELEMENT pEle,
  8284. IN DWORD dwAddDisposition,
  8285. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  8286. )
  8287. {
  8288. BOOL fResult;
  8289. PCONTEXT_ELEMENT pLinkEle = NULL;
  8290. PCONTEXT_ELEMENT pGetEle = NULL;
  8291. if (STORE_TYPE_CACHE != pStore->dwStoreType)
  8292. goto InvalidStoreType;
  8293. // Note, CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES or
  8294. // CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
  8295. // isn't allowed for adding links
  8296. if (!(CERT_STORE_ADD_NEW == dwAddDisposition ||
  8297. CERT_STORE_ADD_USE_EXISTING == dwAddDisposition ||
  8298. CERT_STORE_ADD_REPLACE_EXISTING == dwAddDisposition ||
  8299. CERT_STORE_ADD_ALWAYS == dwAddDisposition ||
  8300. CERT_STORE_ADD_NEWER == dwAddDisposition))
  8301. goto InvalidAddDisposition;
  8302. LockStore(pStore);
  8303. if (CERT_STORE_ADD_ALWAYS != dwAddDisposition) {
  8304. // Check if the context is already in the store.
  8305. CERT_STORE_PROV_FIND_INFO FindInfo;
  8306. // Check if the context element is already in the store
  8307. SetFindInfoToFindExisting(pEle, &FindInfo);
  8308. if (pGetEle = FindElementInCacheStore(
  8309. pStore,
  8310. pEle->dwContextType,
  8311. &FindInfo,
  8312. NULL // pPrevEle
  8313. )) {
  8314. UnlockStore(pStore);
  8315. switch (dwAddDisposition) {
  8316. case CERT_STORE_ADD_NEW:
  8317. goto NotNewError;
  8318. break;
  8319. case CERT_STORE_ADD_NEWER:
  8320. if (!rgpfnIsNewerElement[pEle->dwContextType](pEle, pGetEle))
  8321. goto NotNewError;
  8322. // fall through
  8323. case CERT_STORE_ADD_REPLACE_EXISTING:
  8324. if (DeleteContextElement(pGetEle))
  8325. // Try again. It shouldn't be in the store.
  8326. return AddLinkContextToCacheStore(
  8327. pStore,
  8328. pEle,
  8329. dwAddDisposition,
  8330. ppStoreEle);
  8331. else {
  8332. // Provider didn't allow the delete
  8333. pGetEle = NULL;
  8334. goto DeleteError;
  8335. }
  8336. break;
  8337. case CERT_STORE_ADD_USE_EXISTING:
  8338. if (ppStoreEle)
  8339. *ppStoreEle = pGetEle;
  8340. else
  8341. ReleaseContextElement(pGetEle);
  8342. return TRUE;
  8343. break;
  8344. default:
  8345. goto InvalidArg;
  8346. break;
  8347. }
  8348. }
  8349. }
  8350. if (NULL == (pLinkEle = CreateLinkElement(pEle->dwContextType))) {
  8351. UnlockStore(pStore);
  8352. goto CreateLinkElementError;
  8353. }
  8354. AddRefContextElement(pEle);
  8355. InitAndAddLinkContextElement(
  8356. pLinkEle,
  8357. pStore,
  8358. pEle
  8359. );
  8360. if (ppStoreEle) {
  8361. AddRefContextElement(pLinkEle);
  8362. *ppStoreEle = pLinkEle;
  8363. }
  8364. UnlockStore(pStore);
  8365. fResult = TRUE;
  8366. CommonReturn:
  8367. return fResult;
  8368. ErrorReturn:
  8369. if (pGetEle)
  8370. ReleaseContextElement(pGetEle);
  8371. if (ppStoreEle)
  8372. *ppStoreEle = NULL;
  8373. fResult = FALSE;
  8374. goto CommonReturn;
  8375. SET_ERROR(InvalidStoreType, E_INVALIDARG)
  8376. SET_ERROR(InvalidAddDisposition, E_INVALIDARG)
  8377. SET_ERROR(NotNewError, CRYPT_E_EXISTS)
  8378. SET_ERROR(InvalidArg, E_INVALIDARG)
  8379. TRACE_ERROR(DeleteError)
  8380. TRACE_ERROR(CreateLinkElementError)
  8381. }
  8382. // pEle is used or freed for success only, Otherwise, its left alone and
  8383. // will be freed by the caller.
  8384. //
  8385. // This routine may be called recursively
  8386. //
  8387. // For pStore != pEle->pStore, pEle->pStore is the outer collection store.
  8388. // pStore is the cache store.
  8389. STATIC BOOL AddElementToCacheStore(
  8390. IN PCERT_STORE pStore,
  8391. IN PCONTEXT_ELEMENT pEle,
  8392. IN DWORD dwAddDisposition,
  8393. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  8394. )
  8395. {
  8396. BOOL fResult;
  8397. PCONTEXT_ELEMENT pGetEle = NULL;
  8398. PCONTEXT_ELEMENT pCollectionEle;
  8399. PCERT_STORE pCollectionStore = NULL;
  8400. const DWORD dwStoreProvWriteIndex =
  8401. rgdwStoreProvWriteIndex[pEle->dwContextType];
  8402. PFN_CERT_STORE_PROV_WRITE_CERT pfnStoreProvWriteCert;
  8403. BOOL fUpdateKeyId;
  8404. LockStore(pStore);
  8405. assert(STORE_STATE_DELETED != pStore->dwState &&
  8406. STORE_STATE_CLOSED != pStore->dwState);
  8407. if (STORE_STATE_NULL == pStore->dwState) {
  8408. // CertCreate*Context, CertAddSerializedElementToStore
  8409. // or CertAddEncoded*ToStore with hCertStore == NULL.
  8410. pEle->dwFlags |= ELEMENT_DELETED_FLAG;
  8411. dwAddDisposition = CERT_STORE_ADD_ALWAYS;
  8412. }
  8413. assert(CERT_STORE_ADD_NEW == dwAddDisposition ||
  8414. CERT_STORE_ADD_USE_EXISTING == dwAddDisposition ||
  8415. CERT_STORE_ADD_REPLACE_EXISTING == dwAddDisposition ||
  8416. CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES ==
  8417. dwAddDisposition ||
  8418. CERT_STORE_ADD_ALWAYS == dwAddDisposition ||
  8419. CERT_STORE_ADD_NEWER == dwAddDisposition ||
  8420. CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES == dwAddDisposition);
  8421. if (CERT_STORE_ADD_ALWAYS != dwAddDisposition) {
  8422. // Check if the context is already in the store.
  8423. CERT_STORE_PROV_FIND_INFO FindInfo;
  8424. // Check if the context element is already in the store
  8425. SetFindInfoToFindExisting(pEle, &FindInfo);
  8426. if (pGetEle = FindElementInCacheStore(
  8427. pStore,
  8428. pEle->dwContextType,
  8429. &FindInfo,
  8430. NULL // pPrevEle
  8431. )) {
  8432. UnlockStore(pStore);
  8433. if (CERT_STORE_ADD_NEWER == dwAddDisposition ||
  8434. CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES ==
  8435. dwAddDisposition) {
  8436. if (!rgpfnIsNewerElement[pEle->dwContextType](pEle, pGetEle))
  8437. goto NotNewError;
  8438. }
  8439. if (CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES ==
  8440. dwAddDisposition ||
  8441. CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES ==
  8442. dwAddDisposition) {
  8443. // If element in the store isn't identical to the one being
  8444. // added, then, inherit properties from and delete the
  8445. // element in the store.
  8446. if (!IsIdenticalContextElement(pEle, pGetEle)) {
  8447. if (!CopyProperties(
  8448. pGetEle,
  8449. pEle,
  8450. COPY_PROPERTY_USE_EXISTING_FLAG |
  8451. COPY_PROPERTY_INHIBIT_PROV_SET_FLAG
  8452. ))
  8453. goto CopyPropertiesError;
  8454. dwAddDisposition = CERT_STORE_ADD_REPLACE_EXISTING;
  8455. }
  8456. }
  8457. switch (dwAddDisposition) {
  8458. case CERT_STORE_ADD_NEW:
  8459. goto NotNewError;
  8460. break;
  8461. case CERT_STORE_ADD_REPLACE_EXISTING:
  8462. case CERT_STORE_ADD_NEWER:
  8463. if (DeleteContextElement(pGetEle))
  8464. // Try again. It shouldn't be in the store.
  8465. return AddElementToCacheStore(
  8466. pStore,
  8467. pEle,
  8468. dwAddDisposition,
  8469. ppStoreEle);
  8470. else {
  8471. // Provider didn't allow the delete
  8472. pGetEle = NULL;
  8473. goto DeleteError;
  8474. }
  8475. break;
  8476. case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
  8477. case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
  8478. case CERT_STORE_ADD_USE_EXISTING:
  8479. // For USE_EXISTING, copy any new non-existing properties.
  8480. // Otherwise, copy all properties, replacing existing
  8481. // properties.
  8482. if (!CopyProperties(
  8483. pEle,
  8484. pGetEle,
  8485. CERT_STORE_ADD_USE_EXISTING == dwAddDisposition ?
  8486. COPY_PROPERTY_USE_EXISTING_FLAG : 0
  8487. ))
  8488. goto CopyPropertiesError;
  8489. if (ppStoreEle) {
  8490. if (pStore != pEle->pStore) {
  8491. assert(STORE_TYPE_COLLECTION ==
  8492. pEle->pStore->dwStoreType);
  8493. if (NULL == (*ppStoreEle = CreateLinkElement(
  8494. pEle->dwContextType)))
  8495. goto CreateLinkElementError;
  8496. InitAndAddCollectionElement(
  8497. *ppStoreEle,
  8498. pEle->pStore,
  8499. pGetEle,
  8500. NULL // pCollectionStack
  8501. );
  8502. } else
  8503. *ppStoreEle = pGetEle;
  8504. } else
  8505. ReleaseContextElement(pGetEle);
  8506. FreeContextElement(pEle);
  8507. return TRUE;
  8508. break;
  8509. default:
  8510. goto InvalidArg;
  8511. break;
  8512. }
  8513. }
  8514. }
  8515. // The element doesn't exist in the store.
  8516. // Check if we need to write through to the provider.
  8517. if (pStore->StoreProvInfo.cStoreProvFunc >
  8518. dwStoreProvWriteIndex &&
  8519. NULL != (pfnStoreProvWriteCert = (PFN_CERT_STORE_PROV_WRITE_CERT)
  8520. pStore->StoreProvInfo.rgpvStoreProvFunc[
  8521. dwStoreProvWriteIndex])) {
  8522. // Don't ever call the provider holding a lock!!
  8523. // Also, the caller is holding a reference count on the store.
  8524. UnlockStore(pStore);
  8525. if (!pfnStoreProvWriteCert(
  8526. pStore->StoreProvInfo.hStoreProv,
  8527. ToCertContext(pEle),
  8528. (dwAddDisposition << 16) | CERT_STORE_PROV_WRITE_ADD_FLAG))
  8529. goto StoreProvWriteError;
  8530. LockStore(pStore);
  8531. if (CERT_STORE_ADD_ALWAYS != dwAddDisposition) {
  8532. // Check if the certificate was added while the store was unlocked
  8533. CERT_STORE_PROV_FIND_INFO FindInfo;
  8534. // Check if the context element is already in the store
  8535. SetFindInfoToFindExisting(pEle, &FindInfo);
  8536. if (pGetEle = FindElementInCacheStore(
  8537. pStore,
  8538. pEle->dwContextType,
  8539. &FindInfo,
  8540. NULL // pPrevEle
  8541. )) {
  8542. // Try again
  8543. UnlockStore(pStore);
  8544. ReleaseContextElement(pGetEle);
  8545. return AddElementToCacheStore(pStore, pEle, dwAddDisposition,
  8546. ppStoreEle);
  8547. }
  8548. }
  8549. }
  8550. pCollectionEle = NULL;
  8551. fUpdateKeyId = (pStore->dwFlags & CERT_STORE_UPDATE_KEYID_FLAG) &&
  8552. STORE_STATE_OPENING != pStore->dwState;
  8553. if (pStore != pEle->pStore) {
  8554. assert(STORE_TYPE_COLLECTION == pEle->pStore->dwStoreType);
  8555. if (ppStoreEle) {
  8556. if (NULL == (pCollectionEle =
  8557. CreateLinkElement(pEle->dwContextType))) {
  8558. UnlockStore(pStore);
  8559. goto CreateLinkElementError;
  8560. }
  8561. pCollectionStore = pEle->pStore;
  8562. }
  8563. // Update the element's store. This is needed when adding to a store in
  8564. // a collection
  8565. pEle->pProvStore = pStore;
  8566. pEle->pStore = pStore;
  8567. SetStoreHandle(pEle);
  8568. }
  8569. if (FindPropElement(pEle, CERT_ARCHIVED_PROP_ID))
  8570. pEle->dwFlags |= ELEMENT_ARCHIVED_FLAG;
  8571. // Finally, add the element to the store.
  8572. AddContextElement(pEle);
  8573. AddRefContextElement(pEle); // needed for fUpdateKeyId
  8574. if (pCollectionEle) {
  8575. assert(pCollectionStore && ppStoreEle);
  8576. AddRefContextElement(pEle);
  8577. UnlockStore(pStore);
  8578. InitAndAddCollectionElement(
  8579. pCollectionEle,
  8580. pCollectionStore,
  8581. pEle,
  8582. NULL // pCollectionStack
  8583. );
  8584. *ppStoreEle = pCollectionEle;
  8585. } else {
  8586. if (STORE_STATE_NULL == pStore->dwState) {
  8587. if (ppStoreEle)
  8588. // Since the NULL store doesn't hold a reference, use it.
  8589. *ppStoreEle = pEle;
  8590. else
  8591. ReleaseContextElement(pEle);
  8592. } else if (ppStoreEle) {
  8593. AddRefContextElement(pEle);
  8594. *ppStoreEle = pEle;
  8595. }
  8596. UnlockStore(pStore);
  8597. }
  8598. fResult = TRUE;
  8599. if (fUpdateKeyId)
  8600. SetCryptKeyIdentifierKeyProvInfoProperty(pEle);
  8601. ReleaseContextElement(pEle);
  8602. CommonReturn:
  8603. return fResult;
  8604. ErrorReturn:
  8605. if (pGetEle)
  8606. ReleaseContextElement(pGetEle);
  8607. if (ppStoreEle)
  8608. *ppStoreEle = NULL;
  8609. fResult = FALSE;
  8610. goto CommonReturn;
  8611. SET_ERROR(NotNewError, CRYPT_E_EXISTS)
  8612. SET_ERROR(InvalidArg, E_INVALIDARG)
  8613. TRACE_ERROR(DeleteError)
  8614. TRACE_ERROR(CopyPropertiesError)
  8615. TRACE_ERROR(CreateLinkElementError)
  8616. TRACE_ERROR(StoreProvWriteError)
  8617. }
  8618. // pEle is used or freed for success only, Otherwise, its left alone and
  8619. // will be freed by the caller.
  8620. //
  8621. // This routine may be called recursively
  8622. //
  8623. // The caller is holding a reference count on the store
  8624. //
  8625. // For pStore != pEle->pStore, pEle->pStore is the outer collection store.
  8626. // pStore is the external store.
  8627. STATIC BOOL AddElementToExternalStore(
  8628. IN PCERT_STORE pStore,
  8629. IN PCONTEXT_ELEMENT pEle,
  8630. IN DWORD dwAddDisposition,
  8631. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  8632. )
  8633. {
  8634. BOOL fResult;
  8635. const DWORD dwStoreProvWriteIndex =
  8636. rgdwStoreProvWriteIndex[pEle->dwContextType];
  8637. PFN_CERT_STORE_PROV_WRITE_CERT pfnStoreProvWriteCert;
  8638. PCONTEXT_ELEMENT pExternalEle = NULL;
  8639. PCONTEXT_ELEMENT pCollectionEle = NULL;
  8640. PCERT_STORE pEleStore;
  8641. BOOL fUpdateKeyId;
  8642. // Check if the store supports the write callback
  8643. if (pStore->StoreProvInfo.cStoreProvFunc <=
  8644. dwStoreProvWriteIndex ||
  8645. NULL == (pfnStoreProvWriteCert = (PFN_CERT_STORE_PROV_WRITE_CERT)
  8646. pStore->StoreProvInfo.rgpvStoreProvFunc[
  8647. dwStoreProvWriteIndex]))
  8648. goto ProvWriteNotSupported;
  8649. // Remember the Element's store.
  8650. pEleStore = pEle->pStore;
  8651. fUpdateKeyId = pStore->dwFlags & CERT_STORE_UPDATE_KEYID_FLAG;
  8652. if (ppStoreEle) {
  8653. if (NULL == (pExternalEle = CreateLinkElement(pEle->dwContextType)))
  8654. goto CreateLinkElementError;
  8655. if (pStore != pEleStore) {
  8656. assert(STORE_TYPE_COLLECTION == pEleStore->dwStoreType);
  8657. if (NULL == (pCollectionEle =
  8658. CreateLinkElement(pEle->dwContextType)))
  8659. goto CreateLinkElementError;
  8660. }
  8661. }
  8662. // Update the Element to use the NULL store.
  8663. pEle->pProvStore = &NullCertStore;
  8664. pEle->pStore = &NullCertStore;
  8665. SetStoreHandle(pEle);
  8666. // Also, the caller is holding a reference count on the store.
  8667. if (!pfnStoreProvWriteCert(
  8668. pStore->StoreProvInfo.hStoreProv,
  8669. ToCertContext(pEle),
  8670. (dwAddDisposition << 16) | CERT_STORE_PROV_WRITE_ADD_FLAG)) {
  8671. // Restore the Element's store
  8672. pEle->pProvStore = pEleStore;
  8673. pEle->pStore = pEleStore;
  8674. SetStoreHandle(pEle);
  8675. goto StoreProvWriteError;
  8676. }
  8677. // Add to the NULL store
  8678. pEle->dwFlags |= ELEMENT_DELETED_FLAG;
  8679. AddContextElement(pEle);
  8680. AddRefContextElement(pEle); // needed for fUpdateKeyId
  8681. if (ppStoreEle) {
  8682. InitAndAddExternalElement(
  8683. pExternalEle,
  8684. pStore, // pProvStore
  8685. pEle,
  8686. 0, // dwFlags
  8687. NULL // pvProvInfo
  8688. );
  8689. if (pStore != pEleStore) {
  8690. InitAndAddCollectionElement(
  8691. pCollectionEle,
  8692. pEleStore,
  8693. pExternalEle,
  8694. NULL // pCollectionStack
  8695. );
  8696. *ppStoreEle = pCollectionEle;
  8697. } else
  8698. *ppStoreEle = pExternalEle;
  8699. } else
  8700. ReleaseContextElement(pEle);
  8701. if (fUpdateKeyId)
  8702. SetCryptKeyIdentifierKeyProvInfoProperty(pEle);
  8703. ReleaseContextElement(pEle);
  8704. fResult = TRUE;
  8705. CommonReturn:
  8706. return fResult;
  8707. ErrorReturn:
  8708. fResult = FALSE;
  8709. if (pExternalEle)
  8710. FreeLinkElement(pExternalEle);
  8711. if (pCollectionEle)
  8712. FreeLinkElement(pCollectionEle);
  8713. if (ppStoreEle)
  8714. *ppStoreEle = NULL;
  8715. goto CommonReturn;
  8716. TRACE_ERROR(CreateLinkElementError)
  8717. TRACE_ERROR(StoreProvWriteError)
  8718. SET_ERROR(ProvWriteNotSupported, E_NOTIMPL)
  8719. }
  8720. // pEle is used or freed for success only, Otherwise, its left alone and
  8721. // will be freed by the caller.
  8722. //
  8723. // This routine may be called recursively
  8724. STATIC BOOL AddElementToCollectionStore(
  8725. IN PCERT_STORE pCollection,
  8726. IN PCONTEXT_ELEMENT pEle,
  8727. IN DWORD dwAddDisposition,
  8728. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  8729. )
  8730. {
  8731. BOOL fResult;
  8732. PCERT_STORE pOuterCollection;
  8733. PCONTEXT_ELEMENT pGetEle = NULL;
  8734. PCERT_STORE_LINK pStoreLink;
  8735. PCERT_STORE_LINK pPrevStoreLink = NULL;
  8736. DWORD dwAddErr;
  8737. pOuterCollection = pEle->pStore;
  8738. // Only need to do the find once for the outer most collection
  8739. if (pOuterCollection == pCollection &&
  8740. CERT_STORE_ADD_ALWAYS != dwAddDisposition) {
  8741. CERT_STORE_PROV_FIND_INFO FindInfo;
  8742. // Check if the context element is already in any of the collection's
  8743. // stores
  8744. SetFindInfoToFindExisting(pEle, &FindInfo);
  8745. if (pGetEle = FindElementInCollectionStore(
  8746. pCollection,
  8747. pEle->dwContextType,
  8748. &FindInfo,
  8749. NULL, // pPrevEle
  8750. FALSE // fFindForAdd
  8751. )) {
  8752. if (CERT_STORE_ADD_NEWER == dwAddDisposition ||
  8753. CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES ==
  8754. dwAddDisposition) {
  8755. if (!rgpfnIsNewerElement[pEle->dwContextType](pEle, pGetEle))
  8756. goto NotNewError;
  8757. }
  8758. switch (dwAddDisposition) {
  8759. case CERT_STORE_ADD_NEW:
  8760. goto NotNewError;
  8761. break;
  8762. case CERT_STORE_ADD_REPLACE_EXISTING:
  8763. case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
  8764. case CERT_STORE_ADD_USE_EXISTING:
  8765. case CERT_STORE_ADD_NEWER:
  8766. case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
  8767. // For success pEle will be used or freed by the called function
  8768. // Add to either the cache or external store
  8769. assert(STORE_TYPE_CACHE == pGetEle->pProvStore->dwStoreType ||
  8770. STORE_TYPE_EXTERNAL == pGetEle->pProvStore->dwStoreType);
  8771. fResult = AddElementToStore(
  8772. pGetEle->pProvStore,
  8773. pEle,
  8774. dwAddDisposition,
  8775. ppStoreEle
  8776. );
  8777. goto CommonReturn;
  8778. default:
  8779. goto InvalidArg;
  8780. break;
  8781. }
  8782. }
  8783. }
  8784. // The element doesn't exist in any of the collection's stores.
  8785. // Iterate and try to add to first where adding is allowed
  8786. LockStore(pCollection);
  8787. dwAddErr = (DWORD) E_ACCESSDENIED;
  8788. pStoreLink = pCollection->pStoreListHead;
  8789. for (; pStoreLink; pStoreLink = pStoreLink->pNext) {
  8790. // Advance past deleted store links and links not enabling adds
  8791. if ((pStoreLink->dwFlags & STORE_LINK_DELETED_FLAG) ||
  8792. 0 == (pStoreLink->dwUpdateFlags &
  8793. CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG))
  8794. continue;
  8795. AddRefStoreLink(pStoreLink);
  8796. UnlockStore(pCollection);
  8797. if (pPrevStoreLink)
  8798. ReleaseStoreLink(pPrevStoreLink);
  8799. pPrevStoreLink = pStoreLink;
  8800. if (AddElementToStore(
  8801. pStoreLink->pSibling,
  8802. pEle,
  8803. dwAddDisposition,
  8804. ppStoreEle
  8805. )) {
  8806. fResult = TRUE;
  8807. goto CommonReturn;
  8808. } else if (E_ACCESSDENIED == dwAddErr) {
  8809. DWORD dwErr = GetLastError();
  8810. if (0 != dwErr)
  8811. dwAddErr = dwErr;
  8812. }
  8813. LockStore(pCollection);
  8814. }
  8815. UnlockStore(pCollection);
  8816. goto NoAddEnabledStore;
  8817. CommonReturn:
  8818. if (pGetEle)
  8819. ReleaseContextElement(pGetEle);
  8820. if (pPrevStoreLink)
  8821. ReleaseStoreLink(pPrevStoreLink);
  8822. return fResult;
  8823. ErrorReturn:
  8824. fResult = FALSE;
  8825. if (ppStoreEle)
  8826. *ppStoreEle = NULL;
  8827. goto CommonReturn;
  8828. SET_ERROR(NotNewError, CRYPT_E_EXISTS)
  8829. SET_ERROR(InvalidArg, E_INVALIDARG)
  8830. SET_ERROR_VAR(NoAddEnabledStore, dwAddErr)
  8831. }
  8832. // pEle is used or freed for success only, Otherwise, its left alone and
  8833. // will be freed by the caller.
  8834. //
  8835. // This routine may be called recursively
  8836. //
  8837. // For pStore != pEle->pStore, pEle->pStore is the outer collection store.
  8838. // pStore is the inner store
  8839. STATIC BOOL AddElementToStore(
  8840. IN PCERT_STORE pStore,
  8841. IN PCONTEXT_ELEMENT pEle,
  8842. IN DWORD dwAddDisposition,
  8843. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  8844. )
  8845. {
  8846. // Check for valid disposition values
  8847. if (!(CERT_STORE_ADD_NEW == dwAddDisposition ||
  8848. CERT_STORE_ADD_USE_EXISTING == dwAddDisposition ||
  8849. CERT_STORE_ADD_REPLACE_EXISTING == dwAddDisposition ||
  8850. CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES ==
  8851. dwAddDisposition ||
  8852. CERT_STORE_ADD_ALWAYS == dwAddDisposition ||
  8853. CERT_STORE_ADD_NEWER == dwAddDisposition ||
  8854. CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES == dwAddDisposition)) {
  8855. *ppStoreEle = NULL;
  8856. SetLastError((DWORD) E_INVALIDARG);
  8857. return FALSE;
  8858. }
  8859. switch (pStore->dwStoreType) {
  8860. case STORE_TYPE_CACHE:
  8861. return AddElementToCacheStore(
  8862. pStore,
  8863. pEle,
  8864. dwAddDisposition,
  8865. ppStoreEle
  8866. );
  8867. break;
  8868. case STORE_TYPE_EXTERNAL:
  8869. return AddElementToExternalStore(
  8870. pStore,
  8871. pEle,
  8872. dwAddDisposition,
  8873. ppStoreEle
  8874. );
  8875. break;
  8876. case STORE_TYPE_COLLECTION:
  8877. return AddElementToCollectionStore(
  8878. pStore,
  8879. pEle,
  8880. dwAddDisposition,
  8881. ppStoreEle
  8882. );
  8883. break;
  8884. default:
  8885. goto InvalidStoreType;
  8886. }
  8887. ErrorReturn:
  8888. return NULL;
  8889. SET_ERROR(InvalidStoreType, E_INVALIDARG)
  8890. }
  8891. STATIC BOOL AddEncodedContextToStore(
  8892. IN PCERT_STORE pStore,
  8893. IN DWORD dwContextType,
  8894. IN DWORD dwCertEncodingType,
  8895. IN const BYTE *pbEncoded,
  8896. IN DWORD cbEncoded,
  8897. IN DWORD dwAddDisposition,
  8898. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  8899. )
  8900. {
  8901. BOOL fResult;
  8902. BYTE *pbAllocEncoded = NULL;
  8903. PCONTEXT_ELEMENT pEle = NULL;
  8904. DWORD dwExceptionCode;
  8905. // Handle MappedFile Exceptions
  8906. __try {
  8907. if (NULL == pStore)
  8908. pStore = &NullCertStore;
  8909. if (NULL == (pbAllocEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  8910. goto OutOfMemory;
  8911. // If pbEncoded is a MappedFile, the following copy may raise
  8912. // an exception
  8913. memcpy(pbAllocEncoded, pbEncoded, cbEncoded);
  8914. if (NULL == (pEle = rgpfnCreateElement[dwContextType](
  8915. pStore,
  8916. dwCertEncodingType,
  8917. pbAllocEncoded,
  8918. cbEncoded,
  8919. NULL // pShareEle
  8920. )))
  8921. goto CreateElementError;
  8922. if (!AddElementToStore(
  8923. pStore,
  8924. pEle,
  8925. dwAddDisposition,
  8926. ppStoreEle
  8927. ))
  8928. goto AddElementError;
  8929. fResult = TRUE;
  8930. } __except(EXCEPTION_EXECUTE_HANDLER) {
  8931. dwExceptionCode = GetExceptionCode();
  8932. goto ExceptionError;
  8933. }
  8934. CommonReturn:
  8935. return fResult;
  8936. ErrorReturn:
  8937. if (pEle)
  8938. FreeContextElement(pEle);
  8939. else
  8940. PkiFree(pbAllocEncoded);
  8941. if (ppStoreEle)
  8942. *ppStoreEle = NULL;
  8943. fResult = FALSE;
  8944. goto CommonReturn;
  8945. TRACE_ERROR(OutOfMemory)
  8946. TRACE_ERROR(CreateElementError)
  8947. TRACE_ERROR(AddElementError)
  8948. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  8949. }
  8950. STATIC BOOL AddContextToStore(
  8951. IN PCERT_STORE pStore,
  8952. IN PCONTEXT_ELEMENT pSrcEle,
  8953. IN DWORD dwCertEncodingType,
  8954. IN const BYTE *pbEncoded,
  8955. IN DWORD cbEncoded,
  8956. IN DWORD dwAddDisposition,
  8957. OUT OPTIONAL PCONTEXT_ELEMENT *ppStoreEle
  8958. )
  8959. {
  8960. BOOL fResult;
  8961. BYTE *pbAllocEncoded = NULL;
  8962. PCONTEXT_ELEMENT pEle = NULL;
  8963. DWORD dwExceptionCode;
  8964. // Handle MappedFile Exceptions
  8965. __try {
  8966. if (NULL == pStore)
  8967. pStore = &NullCertStore;
  8968. if (NULL == (pbAllocEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  8969. goto OutOfMemory;
  8970. // If pbEncoded is a MappedFile, the following copy may raise
  8971. // an exception
  8972. memcpy(pbAllocEncoded, pbEncoded, cbEncoded);
  8973. if (NULL == (pEle = rgpfnCreateElement[pSrcEle->dwContextType](
  8974. pStore,
  8975. dwCertEncodingType,
  8976. pbAllocEncoded,
  8977. cbEncoded,
  8978. NULL // pShareEle
  8979. )))
  8980. goto CreateElementError;
  8981. if (!CopyProperties(
  8982. pSrcEle,
  8983. pEle,
  8984. COPY_PROPERTY_INHIBIT_PROV_SET_FLAG
  8985. ))
  8986. goto CopyPropertiesError;
  8987. if (!AddElementToStore(
  8988. pStore,
  8989. pEle,
  8990. dwAddDisposition,
  8991. ppStoreEle
  8992. ))
  8993. goto AddElementError;
  8994. fResult = TRUE;
  8995. } __except(EXCEPTION_EXECUTE_HANDLER) {
  8996. dwExceptionCode = GetExceptionCode();
  8997. goto ExceptionError;
  8998. }
  8999. CommonReturn:
  9000. return fResult;
  9001. ErrorReturn:
  9002. if (pEle)
  9003. FreeContextElement(pEle);
  9004. else
  9005. PkiFree(pbAllocEncoded);
  9006. if (ppStoreEle)
  9007. *ppStoreEle = NULL;
  9008. fResult = FALSE;
  9009. goto CommonReturn;
  9010. TRACE_ERROR(OutOfMemory)
  9011. TRACE_ERROR(CreateElementError)
  9012. TRACE_ERROR(CopyPropertiesError)
  9013. TRACE_ERROR(AddElementError)
  9014. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  9015. }
  9016. //+=========================================================================
  9017. // PROP_ELEMENT Functions
  9018. //==========================================================================
  9019. // pbData has already been allocated
  9020. STATIC PPROP_ELEMENT CreatePropElement(
  9021. IN DWORD dwPropId,
  9022. IN DWORD dwFlags,
  9023. IN BYTE *pbData,
  9024. IN DWORD cbData
  9025. )
  9026. {
  9027. PPROP_ELEMENT pEle = NULL;
  9028. // Allocate and initialize the prop element structure
  9029. pEle = (PPROP_ELEMENT) PkiZeroAlloc(sizeof(PROP_ELEMENT));
  9030. if (pEle == NULL) return NULL;
  9031. pEle->dwPropId = dwPropId;
  9032. pEle->dwFlags = dwFlags;
  9033. pEle->pbData = pbData;
  9034. pEle->cbData = cbData;
  9035. pEle->pNext = NULL;
  9036. pEle->pPrev = NULL;
  9037. return pEle;
  9038. }
  9039. STATIC void FreePropElement(IN PPROP_ELEMENT pEle)
  9040. {
  9041. if (pEle->dwPropId == CERT_KEY_CONTEXT_PROP_ID) {
  9042. HCRYPTPROV hProv = ((PCERT_KEY_CONTEXT) pEle->pbData)->hCryptProv;
  9043. if (hProv && (pEle->dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG) == 0) {
  9044. DWORD dwErr = GetLastError();
  9045. CryptReleaseContext(hProv, 0);
  9046. SetLastError(dwErr);
  9047. }
  9048. }
  9049. PkiFree(pEle->pbData);
  9050. PkiFree(pEle);
  9051. }
  9052. // Upon entry/exit: Store/Element is locked
  9053. STATIC PPROP_ELEMENT FindPropElement(
  9054. IN PPROP_ELEMENT pPropEle,
  9055. IN DWORD dwPropId
  9056. )
  9057. {
  9058. while (pPropEle) {
  9059. if (pPropEle->dwPropId == dwPropId)
  9060. return pPropEle;
  9061. pPropEle = pPropEle->pNext;
  9062. }
  9063. return NULL;
  9064. }
  9065. STATIC PPROP_ELEMENT FindPropElement(
  9066. IN PCONTEXT_ELEMENT pCacheEle,
  9067. IN DWORD dwPropId
  9068. )
  9069. {
  9070. assert(ELEMENT_TYPE_CACHE == pCacheEle->dwElementType);
  9071. return FindPropElement(pCacheEle->Cache.pPropHead, dwPropId);
  9072. }
  9073. // Upon entry/exit: Store/Element is locked
  9074. STATIC void AddPropElement(
  9075. IN OUT PPROP_ELEMENT *ppPropHead,
  9076. IN PPROP_ELEMENT pPropEle
  9077. )
  9078. {
  9079. // Insert property in the certificate/CRL/CTL's list of properties
  9080. pPropEle->pNext = *ppPropHead;
  9081. pPropEle->pPrev = NULL;
  9082. if (*ppPropHead)
  9083. (*ppPropHead)->pPrev = pPropEle;
  9084. *ppPropHead = pPropEle;
  9085. }
  9086. STATIC void AddPropElement(
  9087. IN OUT PCONTEXT_ELEMENT pCacheEle,
  9088. IN PPROP_ELEMENT pPropEle
  9089. )
  9090. {
  9091. assert(ELEMENT_TYPE_CACHE == pCacheEle->dwElementType);
  9092. AddPropElement(&pCacheEle->Cache.pPropHead, pPropEle);
  9093. }
  9094. // Upon entry/exit: Store/Element is locked
  9095. STATIC void RemovePropElement(
  9096. IN OUT PPROP_ELEMENT *ppPropHead,
  9097. IN PPROP_ELEMENT pPropEle
  9098. )
  9099. {
  9100. if (pPropEle->pNext)
  9101. pPropEle->pNext->pPrev = pPropEle->pPrev;
  9102. if (pPropEle->pPrev)
  9103. pPropEle->pPrev->pNext = pPropEle->pNext;
  9104. else if (pPropEle == *ppPropHead)
  9105. *ppPropHead = pPropEle->pNext;
  9106. // else
  9107. // Not on any list
  9108. }
  9109. STATIC void RemovePropElement(
  9110. IN OUT PCONTEXT_ELEMENT pCacheEle,
  9111. IN PPROP_ELEMENT pPropEle
  9112. )
  9113. {
  9114. assert(ELEMENT_TYPE_CACHE == pCacheEle->dwElementType);
  9115. RemovePropElement(&pCacheEle->Cache.pPropHead, pPropEle);
  9116. }
  9117. //+=========================================================================
  9118. // Property Functions
  9119. //==========================================================================
  9120. // Upon entry/exit the store is locked
  9121. STATIC void DeleteProperty(
  9122. IN OUT PPROP_ELEMENT *ppPropHead,
  9123. IN DWORD dwPropId
  9124. )
  9125. {
  9126. PPROP_ELEMENT pPropEle;
  9127. // Delete the property
  9128. pPropEle = FindPropElement(*ppPropHead, dwPropId);
  9129. if (pPropEle) {
  9130. RemovePropElement(ppPropHead, pPropEle);
  9131. FreePropElement(pPropEle);
  9132. }
  9133. }
  9134. STATIC void DeleteProperty(
  9135. IN OUT PCONTEXT_ELEMENT pCacheEle,
  9136. IN DWORD dwPropId
  9137. )
  9138. {
  9139. DeleteProperty(&pCacheEle->Cache.pPropHead, dwPropId);
  9140. }
  9141. //+-------------------------------------------------------------------------
  9142. // Set the property for the specified element
  9143. //--------------------------------------------------------------------------
  9144. STATIC BOOL SetProperty(
  9145. IN PCONTEXT_ELEMENT pEle,
  9146. IN DWORD dwPropId,
  9147. IN DWORD dwFlags,
  9148. IN const void *pvData,
  9149. IN BOOL fInhibitProvSet
  9150. )
  9151. {
  9152. BOOL fResult;
  9153. PCONTEXT_ELEMENT pCacheEle;
  9154. PCERT_STORE pCacheStore;
  9155. PPROP_ELEMENT pPropEle;
  9156. BYTE *pbEncoded = NULL;
  9157. DWORD cbEncoded;
  9158. CERT_KEY_CONTEXT KeyContext;
  9159. if (dwPropId == 0 || dwPropId > CERT_LAST_USER_PROP_ID) {
  9160. SetLastError((DWORD) E_INVALIDARG);
  9161. return FALSE;
  9162. }
  9163. if (dwFlags & CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG)
  9164. fInhibitProvSet = TRUE;
  9165. if (NULL == (pCacheEle = GetCacheElement(pEle)))
  9166. return FALSE;
  9167. pCacheStore = pCacheEle->pStore;
  9168. LockStore(pCacheStore);
  9169. if (dwPropId == CERT_KEY_PROV_HANDLE_PROP_ID ||
  9170. dwPropId == CERT_KEY_SPEC_PROP_ID) {
  9171. // Map to the CERT_KEY_CONTEXT_PROP_ID and update its
  9172. // hCryptProv and/or dwKeySpec field(s).
  9173. DWORD cbData = sizeof(KeyContext);
  9174. if ((fResult = GetProperty(
  9175. pCacheEle,
  9176. CERT_KEY_CONTEXT_PROP_ID,
  9177. &KeyContext,
  9178. &cbData))) {
  9179. if (dwPropId == CERT_KEY_SPEC_PROP_ID) {
  9180. // Inhibit hCryptProv from being closed by the subsequent
  9181. // DeleteProperty. Also, use the existing dwFlags.
  9182. pPropEle = FindPropElement(pCacheEle,
  9183. CERT_KEY_CONTEXT_PROP_ID);
  9184. assert(pPropEle);
  9185. if (pPropEle) {
  9186. dwFlags = pPropEle->dwFlags;
  9187. pPropEle->dwFlags = CERT_STORE_NO_CRYPT_RELEASE_FLAG;
  9188. }
  9189. }
  9190. } else {
  9191. memset(&KeyContext, 0, sizeof(KeyContext));
  9192. KeyContext.cbSize = sizeof(KeyContext);
  9193. if (pvData && dwPropId != CERT_KEY_SPEC_PROP_ID) {
  9194. // Try to get the KeySpec from a CERT_KEY_PROV_INFO_PROP_ID.
  9195. // Need to do without any locks.
  9196. UnlockStore(pCacheStore);
  9197. cbData = sizeof(DWORD);
  9198. GetProperty(
  9199. pEle,
  9200. CERT_KEY_SPEC_PROP_ID,
  9201. &KeyContext.dwKeySpec,
  9202. &cbData);
  9203. LockStore(pCacheStore);
  9204. // Check if CERT_KEY_CONTEXT_PROP_ID was added while store
  9205. // was unlocked.
  9206. if (FindPropElement(pCacheEle, CERT_KEY_CONTEXT_PROP_ID)) {
  9207. // We now have a CERT_KEY_CONTEXT_PROP_ID property.
  9208. // Try again
  9209. UnlockStore(pCacheStore);
  9210. return SetProperty(
  9211. pEle,
  9212. dwPropId,
  9213. dwFlags,
  9214. pvData,
  9215. fInhibitProvSet
  9216. );
  9217. }
  9218. }
  9219. }
  9220. if (dwPropId == CERT_KEY_PROV_HANDLE_PROP_ID) {
  9221. KeyContext.hCryptProv = (HCRYPTPROV) pvData;
  9222. } else {
  9223. if (pvData)
  9224. KeyContext.dwKeySpec = *((DWORD *) pvData);
  9225. else
  9226. KeyContext.dwKeySpec = 0;
  9227. }
  9228. if (fResult || pvData)
  9229. // CERT_KEY_CONTEXT_PROP_ID exists or we are creating a
  9230. // new CERT_KEY_CONTEXT_PROP_ID
  9231. pvData = &KeyContext;
  9232. dwPropId = CERT_KEY_CONTEXT_PROP_ID;
  9233. } else if (dwPropId == CERT_KEY_CONTEXT_PROP_ID) {
  9234. if (pvData) {
  9235. PCERT_KEY_CONTEXT pKeyContext = (PCERT_KEY_CONTEXT) pvData;
  9236. if (pKeyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
  9237. goto InvalidArg;
  9238. }
  9239. } else if (!fInhibitProvSet) {
  9240. // Check if we need to call the store provider's writethru function.
  9241. // Note, since the above properties aren't persisted they don't
  9242. // need to be checked.
  9243. const DWORD dwStoreProvSetPropertyIndex =
  9244. rgdwStoreProvSetPropertyIndex[pEle->dwContextType];
  9245. PCERT_STORE pProvStore = pEle->pProvStore;
  9246. PFN_CERT_STORE_PROV_SET_CERT_PROPERTY pfnStoreProvSetProperty;
  9247. // Use provider store. May be in a collection.
  9248. UnlockStore(pCacheStore);
  9249. LockStore(pProvStore);
  9250. if (dwStoreProvSetPropertyIndex <
  9251. pProvStore->StoreProvInfo.cStoreProvFunc &&
  9252. NULL != (pfnStoreProvSetProperty =
  9253. (PFN_CERT_STORE_PROV_SET_CERT_PROPERTY)
  9254. pProvStore->StoreProvInfo.rgpvStoreProvFunc[
  9255. dwStoreProvSetPropertyIndex])) {
  9256. // Since we can't hold a lock while calling the provider function,
  9257. // bump the store's provider reference count to inhibit the closing
  9258. // of the store and freeing of the provider functions.
  9259. //
  9260. // When the store is closed, pStore->StoreProvInfo.cStoreProvFunc
  9261. // is set to 0.
  9262. AddRefStoreProv(pProvStore);
  9263. UnlockStore(pProvStore);
  9264. #if 0
  9265. // Slow down the provider while holding the provider reference
  9266. // count.
  9267. Sleep(1500);
  9268. #endif
  9269. // Note: PFN_CERT_STORE_PROV_SET_CRL_PROPERTY has the same signature
  9270. // except, PCCRL_CONTEXT replaces the PCCERT_CONTEXT parameter.
  9271. fResult = pfnStoreProvSetProperty(
  9272. pProvStore->StoreProvInfo.hStoreProv,
  9273. ToCertContext(pEle->pEle),
  9274. dwPropId,
  9275. dwFlags,
  9276. pvData);
  9277. LockStore(pProvStore);
  9278. ReleaseStoreProv(pProvStore);
  9279. UnlockStore(pProvStore);
  9280. LockStore(pCacheStore);
  9281. if (!fResult && !IS_CERT_HASH_PROP_ID(dwPropId) &&
  9282. !IS_CHAIN_HASH_PROP_ID(dwPropId) &&
  9283. 0 == (dwFlags & CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG))
  9284. goto StoreProvSetCertPropertyError;
  9285. // else
  9286. // Silently ignore any complaints about setting the
  9287. // property.
  9288. } else {
  9289. UnlockStore(pProvStore);
  9290. LockStore(pCacheStore);
  9291. }
  9292. }
  9293. if (pvData != NULL) {
  9294. // First, delete the property
  9295. DeleteProperty(pCacheEle, dwPropId);
  9296. if (dwPropId == CERT_KEY_CONTEXT_PROP_ID) {
  9297. cbEncoded = sizeof(CERT_KEY_CONTEXT);
  9298. if (NULL == (pbEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  9299. goto OutOfMemory;
  9300. memcpy(pbEncoded, (BYTE *) pvData, cbEncoded);
  9301. } else if (dwPropId == CERT_KEY_PROV_INFO_PROP_ID) {
  9302. if (!AllocAndEncodeKeyProvInfo(
  9303. (PCRYPT_KEY_PROV_INFO) pvData,
  9304. &pbEncoded,
  9305. &cbEncoded
  9306. )) goto AllocAndEncodeKeyProvInfoError;
  9307. } else {
  9308. PCRYPT_DATA_BLOB pDataBlob = (PCRYPT_DATA_BLOB) pvData;
  9309. cbEncoded = pDataBlob->cbData;
  9310. if (cbEncoded) {
  9311. if (NULL == (pbEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  9312. goto OutOfMemory;
  9313. memcpy(pbEncoded, pDataBlob->pbData, cbEncoded);
  9314. }
  9315. }
  9316. if (NULL == (pPropEle = CreatePropElement(
  9317. dwPropId,
  9318. dwFlags,
  9319. pbEncoded,
  9320. cbEncoded))) goto CreatePropElementError;
  9321. AddPropElement(pCacheEle, pPropEle);
  9322. if (CERT_ARCHIVED_PROP_ID == dwPropId)
  9323. pCacheEle->dwFlags |= ELEMENT_ARCHIVED_FLAG;
  9324. } else {
  9325. // Delete the property
  9326. DeleteProperty(pCacheEle, dwPropId);
  9327. if (CERT_ARCHIVED_PROP_ID == dwPropId)
  9328. pCacheEle->dwFlags &= ~ELEMENT_ARCHIVED_FLAG;
  9329. }
  9330. fResult = TRUE;
  9331. CommonReturn:
  9332. UnlockStore(pCacheStore);
  9333. if (fResult && pvData && !fInhibitProvSet &&
  9334. ((pCacheStore->dwFlags & CERT_STORE_UPDATE_KEYID_FLAG) ||
  9335. (pEle->pStore->dwFlags & CERT_STORE_UPDATE_KEYID_FLAG)))
  9336. SetCryptKeyIdentifierKeyProvInfoProperty(
  9337. pEle,
  9338. dwPropId,
  9339. pvData
  9340. );
  9341. return fResult;
  9342. ErrorReturn:
  9343. PkiFree(pbEncoded);
  9344. fResult = FALSE;
  9345. goto CommonReturn;
  9346. SET_ERROR(InvalidArg, E_INVALIDARG)
  9347. TRACE_ERROR(StoreProvSetCertPropertyError)
  9348. TRACE_ERROR(OutOfMemory)
  9349. TRACE_ERROR(AllocAndEncodeKeyProvInfoError)
  9350. TRACE_ERROR(CreatePropElementError)
  9351. }
  9352. STATIC BOOL AllocAndGetProperty(
  9353. IN PCONTEXT_ELEMENT pEle,
  9354. IN DWORD dwPropId,
  9355. OUT void **ppvData,
  9356. OUT DWORD *pcbData
  9357. )
  9358. {
  9359. BOOL fResult;
  9360. void *pvData = NULL;
  9361. DWORD cbData;
  9362. if (!GetProperty(
  9363. pEle,
  9364. dwPropId,
  9365. NULL, // pvData
  9366. &cbData)) goto GetPropertyError;
  9367. if (cbData) {
  9368. if (NULL == (pvData = PkiNonzeroAlloc(cbData))) goto OutOfMemory;
  9369. if (!GetProperty(
  9370. pEle,
  9371. dwPropId,
  9372. pvData,
  9373. &cbData)) goto GetPropertyError;
  9374. }
  9375. fResult = TRUE;
  9376. CommonReturn:
  9377. *ppvData = pvData;
  9378. *pcbData = cbData;
  9379. return fResult;
  9380. ErrorReturn:
  9381. PkiFree(pvData);
  9382. pvData = NULL;
  9383. cbData = 0;
  9384. fResult = FALSE;
  9385. goto CommonReturn;
  9386. TRACE_ERROR(GetPropertyError)
  9387. TRACE_ERROR(OutOfMemory)
  9388. }
  9389. //+-------------------------------------------------------------------------
  9390. // Get the property for the specified element
  9391. //
  9392. // Note the pEle's cache store may be locked on entry by the above
  9393. // SetProperty for a CERT_KEY_CONTEXT_PROP_ID.
  9394. //--------------------------------------------------------------------------
  9395. STATIC BOOL GetProperty(
  9396. IN PCONTEXT_ELEMENT pEle,
  9397. IN DWORD dwPropId,
  9398. OUT void *pvData,
  9399. IN OUT DWORD *pcbData
  9400. )
  9401. {
  9402. PCONTEXT_ELEMENT pCacheEle;
  9403. PCERT_STORE pCacheStore;
  9404. PCERT_STORE pProvStore;
  9405. DWORD cbIn;
  9406. if (pvData == NULL)
  9407. cbIn = 0;
  9408. else
  9409. cbIn = *pcbData;
  9410. *pcbData = 0;
  9411. if (dwPropId == CERT_KEY_PROV_HANDLE_PROP_ID ||
  9412. dwPropId == CERT_KEY_SPEC_PROP_ID) {
  9413. // These two properties are fields within CERT_KEY_CONTEXT_PROP_ID.
  9414. BOOL fResult;
  9415. CERT_KEY_CONTEXT KeyContext;
  9416. DWORD cbData;
  9417. BYTE *pbData;
  9418. cbData = sizeof(KeyContext);
  9419. fResult = GetProperty(
  9420. pEle,
  9421. CERT_KEY_CONTEXT_PROP_ID,
  9422. &KeyContext,
  9423. &cbData
  9424. );
  9425. if (fResult && sizeof(KeyContext) != cbData) {
  9426. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  9427. fResult = FALSE;
  9428. }
  9429. if (dwPropId == CERT_KEY_PROV_HANDLE_PROP_ID) {
  9430. cbData = sizeof(HCRYPTPROV);
  9431. pbData = (BYTE *) &KeyContext.hCryptProv;
  9432. } else {
  9433. if (!fResult) {
  9434. // Try to get the dwKeySpec from the CERT_KEY_PROV_INFO_PROP_ID
  9435. PCRYPT_KEY_PROV_INFO pInfo;
  9436. if (fResult = AllocAndGetProperty(
  9437. pEle,
  9438. CERT_KEY_PROV_INFO_PROP_ID,
  9439. (void **) &pInfo,
  9440. &cbData)) {
  9441. KeyContext.dwKeySpec = pInfo->dwKeySpec;
  9442. PkiFree(pInfo);
  9443. }
  9444. }
  9445. cbData = sizeof(DWORD);
  9446. pbData = (BYTE *) &KeyContext.dwKeySpec;
  9447. }
  9448. if (fResult) {
  9449. *pcbData = cbData;
  9450. if (cbIn < cbData) {
  9451. if (pvData) {
  9452. SetLastError((DWORD) ERROR_MORE_DATA);
  9453. fResult = FALSE;
  9454. }
  9455. } else if (cbData)
  9456. memcpy((BYTE *) pvData, pbData, cbData);
  9457. }
  9458. return fResult;
  9459. } else if (dwPropId == CERT_ACCESS_STATE_PROP_ID) {
  9460. DWORD dwAccessStateFlags;
  9461. pProvStore = pEle->pProvStore;
  9462. if ((pProvStore->dwFlags & CERT_STORE_READONLY_FLAG) ||
  9463. (pProvStore->StoreProvInfo.dwStoreProvFlags &
  9464. CERT_STORE_PROV_NO_PERSIST_FLAG))
  9465. dwAccessStateFlags = 0;
  9466. else
  9467. dwAccessStateFlags = CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
  9468. if ((pEle->pStore->StoreProvInfo.dwStoreProvFlags &
  9469. CERT_STORE_PROV_SYSTEM_STORE_FLAG) ||
  9470. (pProvStore->StoreProvInfo.dwStoreProvFlags &
  9471. CERT_STORE_PROV_SYSTEM_STORE_FLAG))
  9472. dwAccessStateFlags |= CERT_ACCESS_STATE_SYSTEM_STORE_FLAG;
  9473. if ((pEle->pStore->StoreProvInfo.dwStoreProvFlags &
  9474. CERT_STORE_PROV_LM_SYSTEM_STORE_FLAG) ||
  9475. (pProvStore->StoreProvInfo.dwStoreProvFlags &
  9476. CERT_STORE_PROV_LM_SYSTEM_STORE_FLAG))
  9477. dwAccessStateFlags |= CERT_ACCESS_STATE_LM_SYSTEM_STORE_FLAG;
  9478. *pcbData = sizeof(DWORD);
  9479. if (cbIn < sizeof(DWORD)) {
  9480. if (pvData) {
  9481. SetLastError((DWORD) ERROR_MORE_DATA);
  9482. return FALSE;
  9483. }
  9484. } else
  9485. *((DWORD * ) pvData) = dwAccessStateFlags;
  9486. return TRUE;
  9487. }
  9488. if (NULL == (pCacheEle = GetCacheElement(pEle)))
  9489. return FALSE;
  9490. pCacheStore = pCacheEle->pStore;
  9491. LockStore(pCacheStore);
  9492. PPROP_ELEMENT pPropEle = FindPropElement(pCacheEle, dwPropId);
  9493. if (pPropEle) {
  9494. BOOL fResult;
  9495. DWORD cbData = pPropEle->cbData;
  9496. if (dwPropId == CERT_KEY_PROV_INFO_PROP_ID) {
  9497. *pcbData = cbIn;
  9498. fResult = DecodeKeyProvInfo(
  9499. (PSERIALIZED_KEY_PROV_INFO) pPropEle->pbData,
  9500. cbData,
  9501. (PCRYPT_KEY_PROV_INFO) pvData,
  9502. pcbData
  9503. );
  9504. } else {
  9505. fResult = TRUE;
  9506. if (cbIn < cbData) {
  9507. if (pvData) {
  9508. SetLastError((DWORD) ERROR_MORE_DATA);
  9509. fResult = FALSE;
  9510. }
  9511. } else if (cbData)
  9512. memcpy((BYTE *) pvData, pPropEle->pbData, cbData);
  9513. *pcbData = cbData;
  9514. }
  9515. UnlockStore(pCacheStore);
  9516. return fResult;
  9517. } else
  9518. UnlockStore(pCacheStore);
  9519. // We're here with property not found and store unlocked.
  9520. // For CERT_*_HASH_PROP_ID: compute its hash and do a SetProperty
  9521. // Also, compute the MD5 hash of the public key bits.
  9522. if (IS_CERT_HASH_PROP_ID(dwPropId)
  9523. ||
  9524. ((CERT_STORE_CERTIFICATE_CONTEXT - 1) == pEle->dwContextType
  9525. &&
  9526. (CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID == dwPropId ||
  9527. CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID == dwPropId ||
  9528. CERT_SUBJECT_NAME_MD5_HASH_PROP_ID == dwPropId))) {
  9529. BOOL fResult;
  9530. PCERT_STORE pEleStore;
  9531. BYTE *pbEncoded;
  9532. DWORD cbEncoded;
  9533. BYTE Hash[MAX_HASH_LEN];
  9534. CRYPT_DATA_BLOB HashBlob;
  9535. BYTE *pbAlloc = NULL;
  9536. switch (dwPropId) {
  9537. case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
  9538. {
  9539. PCRYPT_BIT_BLOB pPublicKey;
  9540. assert((CERT_STORE_CERTIFICATE_CONTEXT - 1) ==
  9541. pEle->dwContextType);
  9542. pPublicKey =
  9543. &(ToCertContext(pEle)->pCertInfo->SubjectPublicKeyInfo.PublicKey);
  9544. pbEncoded = pPublicKey->pbData;
  9545. cbEncoded = pPublicKey->cbData;
  9546. }
  9547. break;
  9548. case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
  9549. {
  9550. PCERT_NAME_BLOB pIssuer;
  9551. PCRYPT_INTEGER_BLOB pSerialNumber;
  9552. assert((CERT_STORE_CERTIFICATE_CONTEXT - 1) ==
  9553. pEle->dwContextType);
  9554. pIssuer = &(ToCertContext(pEle)->pCertInfo->Issuer);
  9555. pSerialNumber = &(ToCertContext(pEle)->pCertInfo->SerialNumber);
  9556. cbEncoded = pIssuer->cbData + pSerialNumber->cbData;
  9557. if (0 == cbEncoded)
  9558. pbAlloc = NULL;
  9559. else {
  9560. if (NULL == (pbAlloc = (BYTE *) PkiNonzeroAlloc(
  9561. cbEncoded)))
  9562. return FALSE;
  9563. if (pIssuer->cbData)
  9564. memcpy(pbAlloc, pIssuer->pbData, pIssuer->cbData);
  9565. if (pSerialNumber->cbData)
  9566. memcpy(pbAlloc + pIssuer->cbData,
  9567. pSerialNumber->pbData, pSerialNumber->cbData);
  9568. }
  9569. pbEncoded = pbAlloc;
  9570. }
  9571. break;
  9572. case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
  9573. {
  9574. PCERT_NAME_BLOB pSubject;
  9575. assert((CERT_STORE_CERTIFICATE_CONTEXT - 1) ==
  9576. pEle->dwContextType);
  9577. pSubject = &(ToCertContext(pEle)->pCertInfo->Subject);
  9578. pbEncoded = pSubject->pbData;
  9579. cbEncoded = pSubject->cbData;
  9580. }
  9581. break;
  9582. default:
  9583. GetContextEncodedInfo(
  9584. pEle,
  9585. &pbEncoded,
  9586. &cbEncoded
  9587. );
  9588. }
  9589. pEleStore = pEle->pStore;
  9590. HashBlob.pbData = Hash;
  9591. HashBlob.cbData = sizeof(Hash);
  9592. if (CERT_SIGNATURE_HASH_PROP_ID == dwPropId)
  9593. fResult = CryptHashToBeSigned(
  9594. 0, // hCryptProv
  9595. GetContextEncodingType(pEle),
  9596. pbEncoded,
  9597. cbEncoded,
  9598. Hash,
  9599. &HashBlob.cbData);
  9600. else
  9601. fResult = CryptHashCertificate(
  9602. 0, // hCryptProv
  9603. dwPropId == CERT_SHA1_HASH_PROP_ID ? CALG_SHA1 : CALG_MD5,
  9604. 0, //dwFlags
  9605. pbEncoded,
  9606. cbEncoded,
  9607. Hash,
  9608. &HashBlob.cbData);
  9609. if (pbAlloc)
  9610. PkiFree(pbAlloc);
  9611. if (!fResult) {
  9612. assert(HashBlob.cbData <= MAX_HASH_LEN);
  9613. return FALSE;
  9614. }
  9615. assert(HashBlob.cbData);
  9616. if (HashBlob.cbData == 0)
  9617. return FALSE;
  9618. if (!SetProperty(
  9619. pEle,
  9620. dwPropId,
  9621. 0, // dwFlags
  9622. &HashBlob
  9623. )) return FALSE;
  9624. *pcbData = cbIn;
  9625. return GetProperty(
  9626. pEle,
  9627. dwPropId,
  9628. pvData,
  9629. pcbData);
  9630. } else if (CERT_KEY_IDENTIFIER_PROP_ID == dwPropId) {
  9631. *pcbData = cbIn;
  9632. return GetKeyIdProperty(
  9633. pEle,
  9634. dwPropId,
  9635. pvData,
  9636. pcbData);
  9637. }
  9638. // We're here with property not found and not a hash or KeyId property
  9639. // Since the cache store may be locked when called from SetProperty for
  9640. // a CERT_KEY_CONTEXT_PROP_ID and since this property isn't persisted,
  9641. // don't look in the external store for this property.
  9642. pProvStore = pEle->pProvStore;
  9643. if (STORE_TYPE_EXTERNAL == pProvStore->dwStoreType &&
  9644. CERT_KEY_CONTEXT_PROP_ID != dwPropId) {
  9645. // Check if provider supports getting a non-cached property
  9646. const DWORD dwStoreProvGetPropertyIndex =
  9647. rgdwStoreProvGetPropertyIndex[pEle->dwContextType];
  9648. PFN_CERT_STORE_PROV_GET_CERT_PROPERTY pfnStoreProvGetProperty;
  9649. LockStore(pProvStore);
  9650. if (dwStoreProvGetPropertyIndex <
  9651. pProvStore->StoreProvInfo.cStoreProvFunc &&
  9652. NULL != (pfnStoreProvGetProperty =
  9653. (PFN_CERT_STORE_PROV_GET_CERT_PROPERTY)
  9654. pProvStore->StoreProvInfo.rgpvStoreProvFunc[
  9655. dwStoreProvGetPropertyIndex])) {
  9656. BOOL fResult;
  9657. // Since we can't hold a lock while calling the provider
  9658. // function, bump the store's provider reference count
  9659. // to inhibit the closing of the store and freeing of
  9660. // the provider functions.
  9661. //
  9662. // When the store is closed,
  9663. // pProvStore->StoreProvInfo.cStoreProvFunc is set to 0.
  9664. AddRefStoreProv(pProvStore);
  9665. UnlockStore(pProvStore);
  9666. *pcbData = cbIn;
  9667. fResult = pfnStoreProvGetProperty(
  9668. pProvStore->StoreProvInfo.hStoreProv,
  9669. ToCertContext(pEle->pEle),
  9670. dwPropId,
  9671. 0, // dwFlags
  9672. pvData,
  9673. pcbData
  9674. );
  9675. LockStore(pProvStore);
  9676. ReleaseStoreProv(pProvStore);
  9677. UnlockStore(pProvStore);
  9678. return fResult;
  9679. } else
  9680. UnlockStore(pProvStore);
  9681. }
  9682. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  9683. return FALSE;
  9684. }
  9685. //+-------------------------------------------------------------------------
  9686. // Serialize a Property
  9687. //--------------------------------------------------------------------------
  9688. STATIC BOOL SerializeProperty(
  9689. IN HANDLE h,
  9690. IN PFNWRITE pfn,
  9691. IN PCONTEXT_ELEMENT pEle
  9692. )
  9693. {
  9694. BOOL fResult;
  9695. PCONTEXT_ELEMENT pCacheEle;
  9696. PCERT_STORE pCacheStore;
  9697. PPROP_ELEMENT pPropEle;
  9698. if (NULL == (pCacheEle = GetCacheElement(pEle)))
  9699. return FALSE;
  9700. pCacheStore = pCacheEle->pStore;
  9701. LockStore(pCacheStore);
  9702. fResult = TRUE;
  9703. for (pPropEle = pCacheEle->Cache.pPropHead; pPropEle;
  9704. pPropEle = pPropEle->pNext) {
  9705. if (pPropEle->dwPropId != CERT_KEY_CONTEXT_PROP_ID) {
  9706. if(!WriteStoreElement(
  9707. h,
  9708. pfn,
  9709. GetContextEncodingType(pCacheEle),
  9710. pPropEle->dwPropId,
  9711. pPropEle->pbData,
  9712. pPropEle->cbData
  9713. )) {
  9714. fResult = FALSE;
  9715. break;
  9716. }
  9717. }
  9718. }
  9719. UnlockStore(pCacheStore);
  9720. return(fResult);
  9721. }
  9722. //+-------------------------------------------------------------------------
  9723. // Get the first or next PropId for the specified element.
  9724. //
  9725. // Only enumerates cached properties. Doesn't try to enumerate any external
  9726. // properties.
  9727. //
  9728. // Set dwPropId = 0, to get the first. Returns 0, if no more properties.
  9729. //--------------------------------------------------------------------------
  9730. STATIC DWORD EnumProperties(
  9731. IN PCONTEXT_ELEMENT pEle,
  9732. IN DWORD dwPropId
  9733. )
  9734. {
  9735. PPROP_ELEMENT pPropEle;
  9736. PCONTEXT_ELEMENT pCacheEle;
  9737. PCERT_STORE pCacheStore;
  9738. if (NULL == (pCacheEle = GetCacheElement(pEle)))
  9739. return 0;
  9740. pCacheStore = pCacheEle->pStore;
  9741. LockStore(pCacheStore);
  9742. if (0 == dwPropId)
  9743. pPropEle = pCacheEle->Cache.pPropHead;
  9744. else {
  9745. pPropEle = FindPropElement(pCacheEle, dwPropId);
  9746. if (pPropEle)
  9747. pPropEle = pPropEle->pNext;
  9748. }
  9749. if (pPropEle)
  9750. dwPropId = pPropEle->dwPropId;
  9751. else
  9752. dwPropId = 0;
  9753. UnlockStore(pCacheStore);
  9754. return dwPropId;
  9755. }
  9756. STATIC BOOL CopyProperties(
  9757. IN PCONTEXT_ELEMENT pSrcEle,
  9758. IN PCONTEXT_ELEMENT pDstEle,
  9759. IN DWORD dwFlags
  9760. )
  9761. {
  9762. BOOL fResult;
  9763. DWORD dwPropId;
  9764. if (dwFlags & COPY_PROPERTY_SYNC_FLAG) {
  9765. // Delete any properties from the Dst element that don't exist
  9766. // in the Src element.
  9767. DWORD dwNextPropId;
  9768. dwNextPropId = EnumProperties(pDstEle, 0);
  9769. while (dwNextPropId) {
  9770. PPROP_ELEMENT pPropEle;
  9771. PCONTEXT_ELEMENT pSrcCacheEle;
  9772. PCERT_STORE pSrcCacheStore;
  9773. PCONTEXT_ELEMENT pDstCacheEle;
  9774. PCERT_STORE pDstCacheStore;
  9775. dwPropId = dwNextPropId;
  9776. dwNextPropId = EnumProperties(pDstEle, dwNextPropId);
  9777. // Don't delete hCryptProv or KeySpec or hash properties
  9778. if (CERT_KEY_CONTEXT_PROP_ID == dwPropId ||
  9779. IS_CERT_HASH_PROP_ID(dwPropId) ||
  9780. IS_CHAIN_HASH_PROP_ID(dwPropId))
  9781. continue;
  9782. #ifdef CMS_PKCS7
  9783. if (CERT_PUBKEY_ALG_PARA_PROP_ID == dwPropId)
  9784. continue;
  9785. #endif // CMS_PKCS7
  9786. if (NULL == (pSrcCacheEle = GetCacheElement(pSrcEle)))
  9787. continue;
  9788. pSrcCacheStore = pSrcCacheEle->pStore;
  9789. // Don't delete if the src also has the property
  9790. LockStore(pSrcCacheStore);
  9791. pPropEle = FindPropElement(pSrcCacheEle, dwPropId);
  9792. UnlockStore(pSrcCacheStore);
  9793. if (pPropEle)
  9794. continue;
  9795. // Don't delete any non persisted properties
  9796. if (NULL == (pDstCacheEle = GetCacheElement(pDstEle)))
  9797. continue;
  9798. pDstCacheStore = pDstCacheEle->pStore;
  9799. LockStore(pDstCacheStore);
  9800. pPropEle = FindPropElement(pDstCacheEle, dwPropId);
  9801. UnlockStore(pDstCacheStore);
  9802. if (NULL == pPropEle || 0 != (pPropEle->dwFlags &
  9803. CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG))
  9804. continue;
  9805. SetProperty(
  9806. pDstEle,
  9807. dwPropId,
  9808. 0, // dwFlags
  9809. NULL, // NULL deletes
  9810. dwFlags & COPY_PROPERTY_INHIBIT_PROV_SET_FLAG // fInhibitProvSet
  9811. );
  9812. }
  9813. }
  9814. fResult = TRUE;
  9815. dwPropId = 0;
  9816. while (dwPropId = EnumProperties(pSrcEle, dwPropId)) {
  9817. void *pvData;
  9818. DWORD cbData;
  9819. // Don't copy hCryptProv or KeySpec
  9820. if (CERT_KEY_CONTEXT_PROP_ID == dwPropId)
  9821. continue;
  9822. if (dwFlags & COPY_PROPERTY_USE_EXISTING_FLAG) {
  9823. PPROP_ELEMENT pPropEle;
  9824. PCONTEXT_ELEMENT pDstCacheEle;
  9825. PCERT_STORE pDstCacheStore;
  9826. // For existing, don't copy any hash properties
  9827. if (IS_CERT_HASH_PROP_ID(dwPropId) ||
  9828. IS_CHAIN_HASH_PROP_ID(dwPropId))
  9829. continue;
  9830. if (NULL == (pDstCacheEle = GetCacheElement(pDstEle)))
  9831. continue;
  9832. pDstCacheStore = pDstCacheEle->pStore;
  9833. // Don't copy if the destination already has the property
  9834. LockStore(pDstCacheStore);
  9835. pPropEle = FindPropElement(pDstCacheEle, dwPropId);
  9836. UnlockStore(pDstCacheStore);
  9837. if (pPropEle)
  9838. continue;
  9839. }
  9840. if (!AllocAndGetProperty(
  9841. pSrcEle,
  9842. dwPropId,
  9843. &pvData,
  9844. &cbData)) {
  9845. if (CRYPT_E_NOT_FOUND == GetLastError()) {
  9846. // Its been deleted after we did the Enum. Start over
  9847. // from the beginning.
  9848. dwPropId = 0;
  9849. continue;
  9850. } else {
  9851. fResult = FALSE;
  9852. break;
  9853. }
  9854. } else {
  9855. CRYPT_DATA_BLOB DataBlob;
  9856. void *pvSetData;
  9857. if (CERT_KEY_PROV_INFO_PROP_ID == dwPropId)
  9858. pvSetData = pvData;
  9859. else {
  9860. DataBlob.pbData = (BYTE *) pvData;
  9861. DataBlob.cbData = cbData;
  9862. pvSetData = &DataBlob;
  9863. }
  9864. fResult = SetProperty(
  9865. pDstEle,
  9866. dwPropId,
  9867. 0, // dwFlags
  9868. pvSetData,
  9869. dwFlags & COPY_PROPERTY_INHIBIT_PROV_SET_FLAG // fInhibitProvSet
  9870. );
  9871. if (pvData)
  9872. PkiFree(pvData);
  9873. if (!fResult)
  9874. break;
  9875. }
  9876. }
  9877. return fResult;
  9878. }
  9879. //+-------------------------------------------------------------------------
  9880. // Get or set the caller properties for a store or KeyId element.
  9881. //
  9882. // Upon entry/exit, properties are locked by caller.
  9883. //--------------------------------------------------------------------------
  9884. STATIC BOOL GetCallerProperty(
  9885. IN PPROP_ELEMENT pPropHead,
  9886. IN DWORD dwPropId,
  9887. BOOL fAlloc,
  9888. OUT void *pvData,
  9889. IN OUT DWORD *pcbData
  9890. )
  9891. {
  9892. BOOL fResult;
  9893. PPROP_ELEMENT pPropEle;
  9894. DWORD cbData;
  9895. void *pvDstData = NULL;
  9896. DWORD cbDstData;
  9897. if (NULL == (pPropEle = FindPropElement(pPropHead, dwPropId)))
  9898. goto PropertyNotFound;
  9899. if (dwPropId == CERT_KEY_CONTEXT_PROP_ID ||
  9900. dwPropId == CERT_KEY_PROV_HANDLE_PROP_ID)
  9901. goto InvalidPropId;
  9902. cbData = pPropEle->cbData;
  9903. if (fAlloc) {
  9904. if (dwPropId == CERT_KEY_PROV_INFO_PROP_ID) {
  9905. if (!DecodeKeyProvInfo(
  9906. (PSERIALIZED_KEY_PROV_INFO) pPropEle->pbData,
  9907. cbData,
  9908. NULL, // pInfo
  9909. &cbDstData
  9910. ))
  9911. goto DecodeKeyProvInfoError;
  9912. } else
  9913. cbDstData = cbData;
  9914. if (cbDstData) {
  9915. if (NULL == (pvDstData = PkiDefaultCryptAlloc(cbDstData)))
  9916. goto OutOfMemory;
  9917. }
  9918. *((void **) pvData) = pvDstData;
  9919. } else {
  9920. pvDstData = pvData;
  9921. if (NULL == pvData)
  9922. cbDstData = 0;
  9923. else
  9924. cbDstData = *pcbData;
  9925. }
  9926. if (dwPropId == CERT_KEY_PROV_INFO_PROP_ID) {
  9927. fResult = DecodeKeyProvInfo(
  9928. (PSERIALIZED_KEY_PROV_INFO) pPropEle->pbData,
  9929. cbData,
  9930. (PCRYPT_KEY_PROV_INFO) pvDstData,
  9931. &cbDstData
  9932. );
  9933. } else {
  9934. fResult = TRUE;
  9935. if (pvDstData) {
  9936. if (cbDstData < cbData) {
  9937. SetLastError((DWORD) ERROR_MORE_DATA);
  9938. fResult = FALSE;
  9939. } else if (cbData) {
  9940. memcpy((BYTE *) pvDstData, pPropEle->pbData, cbData);
  9941. }
  9942. }
  9943. cbDstData = cbData;
  9944. }
  9945. if (!fResult && fAlloc)
  9946. goto UnexpectedError;
  9947. CommonReturn:
  9948. *pcbData = cbDstData;
  9949. return fResult;
  9950. ErrorReturn:
  9951. if (fAlloc) {
  9952. *((void **) pvData) = NULL;
  9953. PkiDefaultCryptFree(pvDstData);
  9954. }
  9955. cbDstData = 0;
  9956. fResult = FALSE;
  9957. goto CommonReturn;
  9958. SET_ERROR(PropertyNotFound, CRYPT_E_NOT_FOUND)
  9959. SET_ERROR(InvalidPropId, E_INVALIDARG)
  9960. TRACE_ERROR(OutOfMemory)
  9961. TRACE_ERROR(DecodeKeyProvInfoError)
  9962. SET_ERROR(UnexpectedError, E_UNEXPECTED)
  9963. }
  9964. BOOL SetCallerProperty(
  9965. IN OUT PPROP_ELEMENT *ppPropHead,
  9966. IN DWORD dwPropId,
  9967. IN DWORD dwFlags,
  9968. IN const void *pvData
  9969. )
  9970. {
  9971. BOOL fResult;
  9972. if (pvData != NULL) {
  9973. DWORD cbEncoded = 0;
  9974. BYTE *pbEncoded = NULL;
  9975. PPROP_ELEMENT pPropEle;
  9976. // First, delete the property
  9977. DeleteProperty(ppPropHead, dwPropId);
  9978. if (dwPropId == CERT_KEY_CONTEXT_PROP_ID ||
  9979. dwPropId == CERT_KEY_PROV_HANDLE_PROP_ID) {
  9980. goto InvalidPropId;
  9981. } else if (dwPropId == CERT_KEY_PROV_INFO_PROP_ID) {
  9982. if (!AllocAndEncodeKeyProvInfo(
  9983. (PCRYPT_KEY_PROV_INFO) pvData,
  9984. &pbEncoded,
  9985. &cbEncoded
  9986. )) goto AllocAndEncodeKeyProvInfoError;
  9987. } else {
  9988. PCRYPT_DATA_BLOB pDataBlob = (PCRYPT_DATA_BLOB) pvData;
  9989. cbEncoded = pDataBlob->cbData;
  9990. if (cbEncoded) {
  9991. if (NULL == (pbEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  9992. goto OutOfMemory;
  9993. memcpy(pbEncoded, pDataBlob->pbData, cbEncoded);
  9994. }
  9995. }
  9996. if (NULL == (pPropEle = CreatePropElement(
  9997. dwPropId,
  9998. dwFlags,
  9999. pbEncoded,
  10000. cbEncoded))) {
  10001. PkiFree(pbEncoded);
  10002. goto CreatePropElementError;
  10003. }
  10004. AddPropElement(ppPropHead, pPropEle);
  10005. } else
  10006. // Delete the property
  10007. DeleteProperty(ppPropHead, dwPropId);
  10008. fResult = TRUE;
  10009. CommonReturn:
  10010. return fResult;
  10011. ErrorReturn:
  10012. fResult = FALSE;
  10013. goto CommonReturn;
  10014. SET_ERROR(InvalidPropId, E_INVALIDARG)
  10015. TRACE_ERROR(AllocAndEncodeKeyProvInfoError)
  10016. TRACE_ERROR(OutOfMemory)
  10017. TRACE_ERROR(CreatePropElementError)
  10018. }
  10019. //+-------------------------------------------------------------------------
  10020. // CRYPT_KEY_PROV_INFO: Encode and Decode Functions
  10021. //--------------------------------------------------------------------------
  10022. STATIC BOOL AllocAndEncodeKeyProvInfo(
  10023. IN PCRYPT_KEY_PROV_INFO pKeyProvInfo,
  10024. OUT BYTE **ppbEncoded,
  10025. OUT DWORD *pcbEncoded
  10026. )
  10027. {
  10028. BYTE *pbEncoded;
  10029. DWORD cbEncoded;
  10030. DWORD cbContainerName;
  10031. DWORD cbProvName;
  10032. PCRYPT_KEY_PROV_PARAM pParam;
  10033. PSERIALIZED_KEY_PROV_INFO pDstInfo;
  10034. DWORD Off;
  10035. DWORD cParam;
  10036. // Get overall length
  10037. cbEncoded = sizeof(SERIALIZED_KEY_PROV_INFO) +
  10038. pKeyProvInfo->cProvParam * sizeof(SERIALIZED_KEY_PROV_PARAM);
  10039. for (cParam = pKeyProvInfo->cProvParam, pParam = pKeyProvInfo->rgProvParam;
  10040. cParam > 0; cParam--, pParam++) {
  10041. if (pParam->cbData)
  10042. cbEncoded += ENCODE_LEN_ALIGN(pParam->cbData);
  10043. }
  10044. if (pKeyProvInfo->pwszContainerName) {
  10045. cbContainerName = (wcslen(pKeyProvInfo->pwszContainerName) + 1) *
  10046. sizeof(WCHAR);
  10047. cbEncoded += ENCODE_LEN_ALIGN(cbContainerName);
  10048. } else
  10049. cbContainerName = 0;
  10050. if (pKeyProvInfo->pwszProvName) {
  10051. cbProvName = (wcslen(pKeyProvInfo->pwszProvName) + 1) *
  10052. sizeof(WCHAR);
  10053. cbEncoded += ENCODE_LEN_ALIGN(cbProvName);
  10054. } else
  10055. cbProvName = 0;
  10056. assert(cbEncoded <= MAX_FILE_ELEMENT_DATA_LEN);
  10057. // Allocate
  10058. pbEncoded = (BYTE *) PkiZeroAlloc(cbEncoded);
  10059. if (pbEncoded == NULL) {
  10060. *ppbEncoded = NULL;
  10061. *pcbEncoded = 0;
  10062. return FALSE;
  10063. }
  10064. Off = sizeof(SERIALIZED_KEY_PROV_INFO);
  10065. pDstInfo = (PSERIALIZED_KEY_PROV_INFO) pbEncoded;
  10066. // pDstInfo->offwszContainerName
  10067. // pDstInfo->offwszProvName;
  10068. pDstInfo->dwProvType = pKeyProvInfo->dwProvType;
  10069. pDstInfo->dwFlags = pKeyProvInfo->dwFlags;
  10070. pDstInfo->cProvParam = pKeyProvInfo->cProvParam;
  10071. // pDstInfo->offrgProvParam;
  10072. pDstInfo->dwKeySpec = pKeyProvInfo->dwKeySpec;
  10073. if (pKeyProvInfo->cProvParam) {
  10074. PSERIALIZED_KEY_PROV_PARAM pDstParam;
  10075. pDstParam = (PSERIALIZED_KEY_PROV_PARAM) (pbEncoded + Off);
  10076. pDstInfo->offrgProvParam = Off;
  10077. Off += pKeyProvInfo->cProvParam * sizeof(SERIALIZED_KEY_PROV_PARAM);
  10078. for (cParam = pKeyProvInfo->cProvParam,
  10079. pParam = pKeyProvInfo->rgProvParam;
  10080. cParam > 0;
  10081. cParam--, pParam++, pDstParam++) {
  10082. pDstParam->dwParam = pParam->dwParam;
  10083. // pDstParam->offbData
  10084. pDstParam->cbData = pParam->cbData;
  10085. pDstParam->dwFlags = pParam->dwFlags;
  10086. if (pParam->cbData) {
  10087. memcpy(pbEncoded + Off, pParam->pbData, pParam->cbData);
  10088. pDstParam->offbData = Off;
  10089. Off += ENCODE_LEN_ALIGN(pParam->cbData);
  10090. }
  10091. }
  10092. }
  10093. if (cbContainerName) {
  10094. memcpy(pbEncoded + Off, (BYTE *) pKeyProvInfo->pwszContainerName,
  10095. cbContainerName);
  10096. pDstInfo->offwszContainerName = Off;
  10097. Off += ENCODE_LEN_ALIGN(cbContainerName);
  10098. }
  10099. if (cbProvName) {
  10100. memcpy(pbEncoded + Off, (BYTE *) pKeyProvInfo->pwszProvName,
  10101. cbProvName);
  10102. pDstInfo->offwszProvName = Off;
  10103. Off += ENCODE_LEN_ALIGN(cbProvName);
  10104. }
  10105. assert(Off == cbEncoded);
  10106. *ppbEncoded = pbEncoded;
  10107. *pcbEncoded = cbEncoded;
  10108. return TRUE;
  10109. }
  10110. STATIC BOOL DecodeKeyProvInfoString(
  10111. IN BYTE *pbSerialized,
  10112. IN DWORD cbSerialized,
  10113. IN DWORD off,
  10114. OUT LPWSTR *ppwsz,
  10115. IN OUT BYTE **ppbExtra,
  10116. IN OUT LONG *plRemain
  10117. )
  10118. {
  10119. BOOL fResult;
  10120. LONG lRemain = *plRemain;
  10121. LPWSTR pwszDst = (LPWSTR) *ppbExtra;
  10122. if (0 != off) {
  10123. LPWSTR pwszSrc = (LPWSTR) (pbSerialized + off);
  10124. LPWSTR pwszEnd = (LPWSTR) (pbSerialized + cbSerialized);
  10125. if (0 <= lRemain)
  10126. *ppwsz = pwszDst;
  10127. while (TRUE) {
  10128. if (pwszSrc + 1 > pwszEnd)
  10129. goto InvalidData;
  10130. lRemain -= sizeof(WCHAR);
  10131. if (0 <= lRemain)
  10132. *pwszDst++ = *pwszSrc;
  10133. if (L'\0' == *pwszSrc++)
  10134. break;
  10135. }
  10136. } else if (0 <= lRemain)
  10137. *ppwsz = NULL;
  10138. fResult = TRUE;
  10139. CommonReturn:
  10140. *ppbExtra = (BYTE *) pwszDst;
  10141. *plRemain = lRemain;
  10142. return fResult;
  10143. ErrorReturn:
  10144. fResult = FALSE;
  10145. goto CommonReturn;
  10146. SET_ERROR(InvalidData, ERROR_INVALID_DATA)
  10147. }
  10148. STATIC BOOL DecodeKeyProvInfo(
  10149. IN PSERIALIZED_KEY_PROV_INFO pSerializedInfo,
  10150. IN DWORD cbSerialized,
  10151. OUT PCRYPT_KEY_PROV_INFO pInfo,
  10152. OUT DWORD *pcbInfo
  10153. )
  10154. {
  10155. BOOL fResult;
  10156. DWORD cParam;
  10157. DWORD cbInfo;
  10158. BYTE *pbSerialized;
  10159. LONG lRemain;
  10160. BYTE *pbExtra;
  10161. DWORD dwExceptionCode;
  10162. __try {
  10163. if (sizeof(SERIALIZED_KEY_PROV_INFO) > cbSerialized)
  10164. goto InvalidData;
  10165. if (NULL == pInfo)
  10166. cbInfo = 0;
  10167. else
  10168. cbInfo = *pcbInfo;
  10169. lRemain = cbInfo;
  10170. cParam = pSerializedInfo->cProvParam;
  10171. pbSerialized = (BYTE *) pSerializedInfo;
  10172. lRemain -= sizeof(CRYPT_KEY_PROV_INFO);
  10173. if (0 <= lRemain) {
  10174. pbExtra = (BYTE *) pInfo + sizeof(CRYPT_KEY_PROV_INFO);
  10175. memset(pInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
  10176. // pInfo->pwszContainerName
  10177. // pInfo->pwszProvName
  10178. pInfo->dwProvType = pSerializedInfo->dwProvType;
  10179. pInfo->dwFlags = pSerializedInfo->dwFlags;
  10180. pInfo->cProvParam = cParam;
  10181. // pInfo->rgProvParam
  10182. pInfo->dwKeySpec = pSerializedInfo->dwKeySpec;
  10183. } else
  10184. pbExtra = NULL;
  10185. if (0 < cParam) {
  10186. DWORD off;
  10187. PCRYPT_KEY_PROV_PARAM pParam;
  10188. PSERIALIZED_KEY_PROV_PARAM pSerializedParam;
  10189. off = pSerializedInfo->offrgProvParam;
  10190. if (MAX_PROV_PARAM < cParam ||
  10191. off > cbSerialized ||
  10192. (off + cParam * sizeof(SERIALIZED_KEY_PROV_PARAM)) >
  10193. cbSerialized)
  10194. goto InvalidData;
  10195. lRemain -= cParam * sizeof(CRYPT_KEY_PROV_PARAM);
  10196. if (0 <= lRemain) {
  10197. pParam = (PCRYPT_KEY_PROV_PARAM) pbExtra;
  10198. pInfo->rgProvParam = pParam;
  10199. pbExtra += cParam * sizeof(CRYPT_KEY_PROV_PARAM);
  10200. } else
  10201. pParam = NULL;
  10202. pSerializedParam =
  10203. (PSERIALIZED_KEY_PROV_PARAM) (pbSerialized + off);
  10204. for (; 0 < cParam; cParam--, pParam++, pSerializedParam++) {
  10205. DWORD cbParamData = pSerializedParam->cbData;
  10206. if (0 <= lRemain) {
  10207. pParam->dwParam = pSerializedParam->dwParam;
  10208. pParam->pbData = NULL;
  10209. pParam->cbData = cbParamData;
  10210. pParam->dwFlags = pSerializedParam->dwFlags;
  10211. }
  10212. if (0 < cbParamData) {
  10213. LONG lAlignExtra;
  10214. off = pSerializedParam->offbData;
  10215. if (MAX_PROV_PARAM_CBDATA < cbParamData ||
  10216. off > cbSerialized ||
  10217. (off + cbParamData) > cbSerialized)
  10218. goto InvalidData;
  10219. lAlignExtra = ENCODE_LEN_ALIGN(cbParamData);
  10220. lRemain -= lAlignExtra;
  10221. if (0 <= lRemain) {
  10222. pParam->pbData = pbExtra;
  10223. memcpy(pbExtra, pbSerialized + off, cbParamData);
  10224. pbExtra += lAlignExtra;
  10225. }
  10226. }
  10227. }
  10228. }
  10229. if (!DecodeKeyProvInfoString(
  10230. pbSerialized,
  10231. cbSerialized,
  10232. pSerializedInfo->offwszContainerName,
  10233. &pInfo->pwszContainerName,
  10234. &pbExtra,
  10235. &lRemain
  10236. ))
  10237. goto InvalidData;
  10238. if (!DecodeKeyProvInfoString(
  10239. pbSerialized,
  10240. cbSerialized,
  10241. pSerializedInfo->offwszProvName,
  10242. &pInfo->pwszProvName,
  10243. &pbExtra,
  10244. &lRemain
  10245. ))
  10246. goto InvalidData;
  10247. if (0 > lRemain && pInfo) {
  10248. SetLastError((DWORD) ERROR_MORE_DATA);
  10249. fResult = FALSE;
  10250. } else
  10251. fResult = TRUE;
  10252. cbInfo = (DWORD) ((LONG) cbInfo - lRemain);
  10253. } __except(EXCEPTION_EXECUTE_HANDLER) {
  10254. dwExceptionCode = GetExceptionCode();
  10255. goto ExceptionError;
  10256. }
  10257. CommonReturn:
  10258. *pcbInfo = cbInfo;
  10259. return fResult;
  10260. ErrorReturn:
  10261. cbInfo = 0;
  10262. fResult = FALSE;
  10263. goto CommonReturn;
  10264. SET_ERROR(InvalidData, ERROR_INVALID_DATA)
  10265. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  10266. }
  10267. //+-------------------------------------------------------------------------
  10268. // Creates a CTL entry whose attributes are the certificate context's
  10269. // properties.
  10270. //
  10271. // The SubjectIdentifier in the CTL entry is the SHA1 hash of the certificate.
  10272. //
  10273. // The certificate properties are added as attributes. The property attribute
  10274. // OID is the decimal PROP_ID preceded by szOID_CERT_PROP_ID_PREFIX. Each
  10275. // property value is copied as a single attribute value.
  10276. //
  10277. // Any additional attributes to be included in the CTL entry can be passed
  10278. // in via the cOptAttr and pOptAttr parameters.
  10279. //
  10280. // CTL_ENTRY_FROM_PROP_CHAIN_FLAG can be set in dwFlags, to force the
  10281. // inclusion of the chain building hash properties as attributes.
  10282. //--------------------------------------------------------------------------
  10283. BOOL
  10284. WINAPI
  10285. CertCreateCTLEntryFromCertificateContextProperties(
  10286. IN PCCERT_CONTEXT pCertContext,
  10287. IN DWORD cOptAttr,
  10288. IN OPTIONAL PCRYPT_ATTRIBUTE rgOptAttr,
  10289. IN DWORD dwFlags,
  10290. IN OPTIONAL void *pvReserved,
  10291. OUT OPTIONAL PCTL_ENTRY pCtlEntry,
  10292. IN OUT DWORD *pcbCtlEntry
  10293. )
  10294. {
  10295. BOOL fResult;
  10296. DWORD cbCtlEntry;
  10297. LONG lRemainExtra;
  10298. BYTE *pbExtra;
  10299. DWORD cbData;
  10300. DWORD dwPropId;
  10301. DWORD cProp;
  10302. DWORD cAttr;
  10303. DWORD cValue;
  10304. DWORD cOptValue;
  10305. DWORD iAttr;
  10306. PCRYPT_ATTRIBUTE pAttr;
  10307. PCRYPT_ATTR_BLOB pValue;
  10308. DWORD rgdwChainHashPropId[] = {
  10309. CERT_KEY_IDENTIFIER_PROP_ID,
  10310. // CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID,
  10311. // CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID,
  10312. CERT_SUBJECT_NAME_MD5_HASH_PROP_ID,
  10313. };
  10314. #define CHAIN_HASH_PROP_CNT (sizeof(rgdwChainHashPropId) / \
  10315. sizeof(rgdwChainHashPropId[0]))
  10316. if (NULL == pCtlEntry) {
  10317. cbCtlEntry = 0;
  10318. lRemainExtra = 0;
  10319. } else {
  10320. cbCtlEntry = *pcbCtlEntry;
  10321. lRemainExtra = (LONG) cbCtlEntry;
  10322. }
  10323. // Ensure the certificate has the SHA1 hash property
  10324. if (!CertGetCertificateContextProperty(
  10325. pCertContext,
  10326. CERT_SHA1_HASH_PROP_ID,
  10327. NULL, // pvData
  10328. &cbData
  10329. ) || SHA1_HASH_LEN != cbData)
  10330. goto GetSha1HashPropError;
  10331. if (dwFlags & CTL_ENTRY_FROM_PROP_CHAIN_FLAG) {
  10332. DWORD i;
  10333. // Ensure the certificate has all of the properties needed for
  10334. // chain building
  10335. for (i = 0; i < CHAIN_HASH_PROP_CNT; i++) {
  10336. if (!CertGetCertificateContextProperty(
  10337. pCertContext,
  10338. rgdwChainHashPropId[i],
  10339. NULL, // pvData
  10340. &cbData
  10341. ))
  10342. goto GetChainHashPropError;
  10343. }
  10344. }
  10345. // Get the property count
  10346. cProp = 0;
  10347. dwPropId = 0;
  10348. while (dwPropId = CertEnumCertificateContextProperties(
  10349. pCertContext, dwPropId)) {
  10350. // We won't copy the hCryptProv, KeySpec or SHA1 hash properties to
  10351. // the attributes
  10352. if (CERT_KEY_CONTEXT_PROP_ID == dwPropId ||
  10353. CERT_SHA1_HASH_PROP_ID == dwPropId)
  10354. continue;
  10355. cProp++;
  10356. }
  10357. // Get the optional value count
  10358. cOptValue = 0;
  10359. for (iAttr = 0; iAttr < cOptAttr; iAttr++) {
  10360. PCRYPT_ATTRIBUTE pOptAttr = &rgOptAttr[iAttr];
  10361. cOptValue += pOptAttr->cValue;
  10362. }
  10363. // Calculate total attribute count. One attribute per property. Include
  10364. // optional attributes passed in.
  10365. cAttr = cOptAttr + cProp;
  10366. // Calculate total value count. One value per property. Include optional
  10367. // attribute values passed in.
  10368. cValue = cOptValue + cProp;
  10369. // Allocate memory for the CTL_ENTRY. array of attributes, all of the
  10370. // attribute value blobs and the SubjectIdentifier hash.
  10371. lRemainExtra -= sizeof(CTL_ENTRY) +
  10372. cAttr * sizeof(CRYPT_ATTRIBUTE) +
  10373. cValue * sizeof(CRYPT_ATTR_BLOB) +
  10374. SHA1_HASH_LEN;
  10375. if (0 <= lRemainExtra) {
  10376. // Initialize the attribute, value and byte pointers
  10377. pAttr = (PCRYPT_ATTRIBUTE) &pCtlEntry[1];
  10378. pValue = (PCRYPT_ATTR_BLOB) &pAttr[cAttr];
  10379. pbExtra = (BYTE *) &pValue[cValue];
  10380. // Update the CTL_ENTRY fields
  10381. pCtlEntry->SubjectIdentifier.cbData = SHA1_HASH_LEN;
  10382. pCtlEntry->SubjectIdentifier.pbData = pbExtra;
  10383. if (!CertGetCertificateContextProperty(
  10384. pCertContext,
  10385. CERT_SHA1_HASH_PROP_ID,
  10386. pCtlEntry->SubjectIdentifier.pbData,
  10387. &pCtlEntry->SubjectIdentifier.cbData
  10388. ) || SHA1_HASH_LEN != pCtlEntry->SubjectIdentifier.cbData)
  10389. goto GetSha1HashPropError;
  10390. pbExtra += SHA1_HASH_LEN;
  10391. pCtlEntry->cAttribute = cAttr;
  10392. pCtlEntry->rgAttribute = pAttr;
  10393. } else {
  10394. pAttr = NULL;
  10395. pValue = NULL;
  10396. pbExtra = NULL;
  10397. }
  10398. // Copy over the optional attributes and attribute values
  10399. for (iAttr = 0; iAttr < cOptAttr; iAttr++, pAttr++) {
  10400. PCRYPT_ATTRIBUTE pOptAttr = &rgOptAttr[iAttr];
  10401. DWORD cbOID = strlen(pOptAttr->pszObjId) + 1;
  10402. DWORD iValue;
  10403. lRemainExtra -= cbOID;
  10404. if (0 <= lRemainExtra) {
  10405. memcpy(pbExtra, pOptAttr->pszObjId, cbOID);
  10406. pAttr->pszObjId = (LPSTR) pbExtra;
  10407. pbExtra += cbOID;
  10408. pAttr->cValue = pOptAttr->cValue;
  10409. pAttr->rgValue = pValue;
  10410. }
  10411. for (iValue = 0; iValue < pOptAttr->cValue; iValue++, pValue++) {
  10412. PCRYPT_ATTR_BLOB pOptValue = &pOptAttr->rgValue[iValue];
  10413. assert(0 < cOptValue);
  10414. if (0 == cOptValue)
  10415. goto UnexpectedError;
  10416. cOptValue--;
  10417. lRemainExtra -= pOptValue->cbData;
  10418. if (0 <= lRemainExtra) {
  10419. pValue->cbData = pOptValue->cbData;
  10420. pValue->pbData = pbExtra;
  10421. if (0 < pValue->cbData)
  10422. memcpy(pValue->pbData, pOptValue->pbData, pValue->cbData);
  10423. pbExtra += pValue->cbData;
  10424. }
  10425. }
  10426. }
  10427. assert(0 == cOptValue);
  10428. if (0 != cOptValue)
  10429. goto UnexpectedError;
  10430. // Iterate through the properties and create an attribute and attribute
  10431. // value for each
  10432. dwPropId = 0;
  10433. while (dwPropId = CertEnumCertificateContextProperties(
  10434. pCertContext, dwPropId)) {
  10435. CRYPT_DATA_BLOB OctetBlob;
  10436. BYTE *pbEncoded = NULL;
  10437. DWORD cbEncoded;
  10438. char szPropId[33];
  10439. DWORD cbPrefixOID;
  10440. DWORD cbPropOID;
  10441. DWORD cbOID;
  10442. // We won't copy the hCryptProv, KeySpec or SHA1 hash properties to
  10443. // the attributes
  10444. if (CERT_KEY_CONTEXT_PROP_ID == dwPropId ||
  10445. CERT_SHA1_HASH_PROP_ID == dwPropId)
  10446. continue;
  10447. assert(0 < cProp);
  10448. if (0 == cProp)
  10449. goto UnexpectedError;
  10450. cProp--;
  10451. OctetBlob.cbData = 0;
  10452. OctetBlob.pbData = NULL;
  10453. if (!CertGetCertificateContextProperty(
  10454. pCertContext,
  10455. dwPropId,
  10456. NULL, // pvData
  10457. &OctetBlob.cbData
  10458. ))
  10459. goto GetPropError;
  10460. if (OctetBlob.cbData) {
  10461. if (NULL == (OctetBlob.pbData =
  10462. (BYTE *) PkiNonzeroAlloc(OctetBlob.cbData)))
  10463. goto OutOfMemory;
  10464. if (!CertGetCertificateContextProperty(
  10465. pCertContext,
  10466. dwPropId,
  10467. OctetBlob.pbData,
  10468. &OctetBlob.cbData
  10469. )) {
  10470. PkiFree(OctetBlob.pbData);
  10471. goto GetPropError;
  10472. }
  10473. if (CERT_KEY_PROV_INFO_PROP_ID == dwPropId) {
  10474. // Need to serialize the KeyProvInfo data structure
  10475. BYTE *pbEncodedKeyProvInfo;
  10476. DWORD cbEncodedKeyProvInfo;
  10477. fResult = AllocAndEncodeKeyProvInfo(
  10478. (PCRYPT_KEY_PROV_INFO) OctetBlob.pbData,
  10479. &pbEncodedKeyProvInfo,
  10480. &cbEncodedKeyProvInfo
  10481. );
  10482. PkiFree(OctetBlob.pbData);
  10483. if (!fResult)
  10484. goto SerializeKeyProvInfoError;
  10485. OctetBlob.pbData = pbEncodedKeyProvInfo;
  10486. OctetBlob.cbData = cbEncodedKeyProvInfo;
  10487. }
  10488. }
  10489. // Encode the property as an octet string
  10490. fResult = CryptEncodeObjectEx(
  10491. pCertContext->dwCertEncodingType,
  10492. X509_OCTET_STRING,
  10493. &OctetBlob,
  10494. CRYPT_ENCODE_ALLOC_FLAG,
  10495. &PkiEncodePara,
  10496. (void *) &pbEncoded,
  10497. &cbEncoded
  10498. );
  10499. PkiFree(OctetBlob.pbData);
  10500. if (!fResult)
  10501. goto EncodeError;
  10502. // Convert PropId to OID
  10503. _ltoa(dwPropId, szPropId, 10);
  10504. cbPropOID = strlen(szPropId) + 1;
  10505. cbPrefixOID = strlen(szOID_CERT_PROP_ID_PREFIX);
  10506. // Total length of attribute OID
  10507. cbOID = cbPrefixOID + cbPropOID;
  10508. lRemainExtra -= cbOID + cbEncoded;
  10509. if (0 <= lRemainExtra) {
  10510. // Update the attribute and value
  10511. pAttr->pszObjId = (LPSTR) pbExtra;
  10512. memcpy(pbExtra, szOID_CERT_PROP_ID_PREFIX, cbPrefixOID);
  10513. memcpy(pbExtra + cbPrefixOID, szPropId, cbPropOID);
  10514. pbExtra += cbOID;
  10515. assert(0 != cbEncoded);
  10516. pAttr->cValue = 1;
  10517. pAttr->rgValue = pValue;
  10518. pValue->cbData = cbEncoded;
  10519. pValue->pbData = pbExtra;
  10520. memcpy(pbExtra, pbEncoded, cbEncoded);
  10521. pbExtra += cbEncoded;
  10522. pAttr++;
  10523. pValue++;
  10524. }
  10525. PkiFree(pbEncoded);
  10526. }
  10527. assert(0 == cProp);
  10528. if (0 != cProp)
  10529. goto UnexpectedError;
  10530. if (0 <= lRemainExtra) {
  10531. cbCtlEntry = cbCtlEntry - (DWORD) lRemainExtra;
  10532. } else {
  10533. cbCtlEntry = cbCtlEntry + (DWORD) -lRemainExtra;
  10534. if (pCtlEntry) {
  10535. SetLastError((DWORD) ERROR_MORE_DATA);
  10536. fResult = FALSE;
  10537. goto CommonReturn;
  10538. }
  10539. }
  10540. fResult = TRUE;
  10541. CommonReturn:
  10542. *pcbCtlEntry = cbCtlEntry;
  10543. return fResult;
  10544. ErrorReturn:
  10545. cbCtlEntry = 0;
  10546. fResult = FALSE;
  10547. goto CommonReturn;
  10548. TRACE_ERROR(GetSha1HashPropError)
  10549. TRACE_ERROR(GetChainHashPropError)
  10550. SET_ERROR(UnexpectedError, E_UNEXPECTED)
  10551. TRACE_ERROR(GetPropError)
  10552. TRACE_ERROR(OutOfMemory)
  10553. TRACE_ERROR(SerializeKeyProvInfoError)
  10554. TRACE_ERROR(EncodeError)
  10555. }
  10556. //+-------------------------------------------------------------------------
  10557. // Sets properties on the certificate context using the attributes in
  10558. // the CTL entry.
  10559. //
  10560. // The property attribute OID is the decimal PROP_ID preceded by
  10561. // szOID_CERT_PROP_ID_PREFIX. Only attributes containing such an OID are
  10562. // copied.
  10563. //
  10564. // CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG may be set in dwFlags.
  10565. //--------------------------------------------------------------------------
  10566. BOOL
  10567. WINAPI
  10568. CertSetCertificateContextPropertiesFromCTLEntry(
  10569. IN PCCERT_CONTEXT pCertContext,
  10570. IN PCTL_ENTRY pCtlEntry,
  10571. IN DWORD dwFlags
  10572. )
  10573. {
  10574. BOOL fResult;
  10575. BOOL fValidPropData;
  10576. DWORD cAttr;
  10577. PCRYPT_ATTRIBUTE pAttr;
  10578. size_t cchPropPrefix;
  10579. if (SHA1_HASH_LEN != pCtlEntry->SubjectIdentifier.cbData)
  10580. goto InvalidCtlEntry;
  10581. if (!CertSetCertificateContextProperty(
  10582. pCertContext,
  10583. CERT_SHA1_HASH_PROP_ID,
  10584. dwFlags,
  10585. &pCtlEntry->SubjectIdentifier
  10586. ))
  10587. goto SetSha1HashPropError;
  10588. cchPropPrefix = strlen(szOID_CERT_PROP_ID_PREFIX);
  10589. fValidPropData = TRUE;
  10590. // Loop through the attributes.
  10591. for (cAttr = pCtlEntry->cAttribute,
  10592. pAttr = pCtlEntry->rgAttribute; cAttr > 0; cAttr--, pAttr++) {
  10593. DWORD dwPropId;
  10594. PCRYPT_ATTR_BLOB pValue;
  10595. CRYPT_DATA_BLOB PropBlob;
  10596. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  10597. void *pvData;
  10598. // Skip any non-property attributes
  10599. if (0 != strncmp(pAttr->pszObjId, szOID_CERT_PROP_ID_PREFIX,
  10600. cchPropPrefix))
  10601. continue;
  10602. dwPropId = (DWORD) strtoul(pAttr->pszObjId + cchPropPrefix, NULL, 10);
  10603. if (0 == dwPropId)
  10604. continue;
  10605. // Check that we have a single valued attribute encoded as an
  10606. // OCTET STRING
  10607. if (1 != pAttr->cValue) {
  10608. fValidPropData = FALSE;
  10609. continue;
  10610. }
  10611. pValue = pAttr->rgValue;
  10612. if (2 > pValue->cbData ||
  10613. ASN1UTIL_TAG_OCTETSTRING != pValue->pbData[0]) {
  10614. fValidPropData = FALSE;
  10615. continue;
  10616. }
  10617. // Extract the property bytes from the encoded OCTET STRING
  10618. if (0 >= Asn1UtilExtractContent(
  10619. pValue->pbData,
  10620. pValue->cbData,
  10621. &PropBlob.cbData,
  10622. (const BYTE **) &PropBlob.pbData
  10623. ) || CMSG_INDEFINITE_LENGTH == PropBlob.cbData) {
  10624. fValidPropData = FALSE;
  10625. continue;
  10626. }
  10627. if (CERT_KEY_PROV_INFO_PROP_ID == dwPropId) {
  10628. BYTE *pbAlignedData = NULL;
  10629. DWORD cbData;
  10630. DWORD cbInfo;
  10631. cbData = PropBlob.cbData;
  10632. if (0 == cbData) {
  10633. fValidPropData = FALSE;
  10634. continue;
  10635. }
  10636. if (NULL == (pbAlignedData = (BYTE *) PkiNonzeroAlloc(cbData)))
  10637. goto OutOfMemory;
  10638. memcpy(pbAlignedData, PropBlob.pbData, cbData);
  10639. if (!DecodeKeyProvInfo(
  10640. (PSERIALIZED_KEY_PROV_INFO) pbAlignedData,
  10641. cbData,
  10642. NULL, // pInfo
  10643. &cbInfo
  10644. )) {
  10645. PkiFree(pbAlignedData);
  10646. fValidPropData = FALSE;
  10647. continue;
  10648. }
  10649. if (NULL == (pKeyProvInfo =
  10650. (PCRYPT_KEY_PROV_INFO) PkiNonzeroAlloc(cbInfo))) {
  10651. PkiFree(pbAlignedData);
  10652. goto OutOfMemory;
  10653. }
  10654. if (!DecodeKeyProvInfo(
  10655. (PSERIALIZED_KEY_PROV_INFO) pbAlignedData,
  10656. cbData,
  10657. pKeyProvInfo,
  10658. &cbInfo
  10659. )) {
  10660. PkiFree(pbAlignedData);
  10661. PkiFree(pKeyProvInfo);
  10662. fValidPropData = FALSE;
  10663. continue;
  10664. }
  10665. PkiFree(pbAlignedData);
  10666. pvData = (void *) pKeyProvInfo;
  10667. } else
  10668. pvData = (void *) &PropBlob;
  10669. fResult = CertSetCertificateContextProperty(
  10670. pCertContext,
  10671. dwPropId,
  10672. dwFlags,
  10673. pvData
  10674. );
  10675. if (pKeyProvInfo)
  10676. PkiFree(pKeyProvInfo);
  10677. if (!fResult)
  10678. goto SetPropError;
  10679. }
  10680. if (!fValidPropData)
  10681. goto InvalidPropData;
  10682. fResult = TRUE;
  10683. CommonReturn:
  10684. return fResult;
  10685. ErrorReturn:
  10686. fResult = FALSE;
  10687. goto CommonReturn;
  10688. SET_ERROR(InvalidCtlEntry, E_INVALIDARG)
  10689. TRACE_ERROR(SetSha1HashPropError)
  10690. TRACE_ERROR(OutOfMemory)
  10691. TRACE_ERROR(SetPropError)
  10692. SET_ERROR(InvalidPropData, ERROR_INVALID_DATA)
  10693. }
  10694. //+=========================================================================
  10695. // KEYID_ELEMENT Functions
  10696. //==========================================================================
  10697. // pbKeyIdEncoded has already been allocated
  10698. STATIC PKEYID_ELEMENT CreateKeyIdElement(
  10699. IN BYTE *pbKeyIdEncoded,
  10700. IN DWORD cbKeyIdEncoded
  10701. )
  10702. {
  10703. PKEYID_ELEMENT pEle = NULL;
  10704. // Allocate and initialize the prop element structure
  10705. pEle = (PKEYID_ELEMENT) PkiZeroAlloc(sizeof(KEYID_ELEMENT));
  10706. if (pEle == NULL) return NULL;
  10707. pEle->KeyIdentifier.pbData = pbKeyIdEncoded;
  10708. pEle->KeyIdentifier.cbData = cbKeyIdEncoded;
  10709. return pEle;
  10710. }
  10711. STATIC void FreeKeyIdElement(IN PKEYID_ELEMENT pEle)
  10712. {
  10713. PPROP_ELEMENT pPropEle;
  10714. if (NULL == pEle)
  10715. return;
  10716. PkiFree(pEle->KeyIdentifier.pbData);
  10717. // Free the Key Identifier's property elements
  10718. while (pPropEle = pEle->pPropHead) {
  10719. RemovePropElement(&pEle->pPropHead, pPropEle);
  10720. FreePropElement(pPropEle);
  10721. }
  10722. PkiFree(pEle);
  10723. }
  10724. //+-------------------------------------------------------------------------
  10725. // Open Message Store Provider
  10726. //
  10727. // Get Certs and CRLs from the message. pvPara contains the HCRYPTMSG
  10728. // to read.
  10729. //
  10730. // Note for an error return, the caller will free any certs or CRLs
  10731. // successfully added to the store.
  10732. //--------------------------------------------------------------------------
  10733. STATIC BOOL WINAPI OpenMsgStoreProv(
  10734. IN LPCSTR lpszStoreProvider,
  10735. IN DWORD dwEncodingType,
  10736. IN HCRYPTPROV hCryptProv,
  10737. IN DWORD dwFlags,
  10738. IN const void *pvPara,
  10739. IN HCERTSTORE hCertStore,
  10740. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  10741. )
  10742. {
  10743. PCERT_STORE pStore = (PCERT_STORE) hCertStore;
  10744. HCRYPTMSG hCryptMsg = (HCRYPTMSG) pvPara;
  10745. BOOL fResult;
  10746. BYTE *pbEncoded = NULL;
  10747. DWORD cCert;
  10748. DWORD cCrl;
  10749. DWORD cbData;
  10750. DWORD dwIndex;
  10751. PCONTEXT_ELEMENT pCertEle;
  10752. PCONTEXT_ELEMENT pCrlEle;
  10753. if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG) {
  10754. SetLastError((DWORD) E_INVALIDARG);
  10755. goto ErrorReturn;
  10756. }
  10757. if (0 == GET_CERT_ENCODING_TYPE(dwEncodingType))
  10758. dwEncodingType |= X509_ASN_ENCODING;
  10759. // Get count of certificates and CRLs in the message
  10760. cCert = 0;
  10761. cbData = sizeof(cCert);
  10762. fResult = CryptMsgGetParam(
  10763. hCryptMsg,
  10764. CMSG_CERT_COUNT_PARAM,
  10765. 0, // dwIndex
  10766. &cCert,
  10767. &cbData
  10768. );
  10769. if (!fResult) goto ErrorReturn;
  10770. cCrl = 0;
  10771. cbData = sizeof(cCrl);
  10772. fResult = CryptMsgGetParam(
  10773. hCryptMsg,
  10774. CMSG_CRL_COUNT_PARAM,
  10775. 0, // dwIndex
  10776. &cCrl,
  10777. &cbData
  10778. );
  10779. if (!fResult) goto ErrorReturn;
  10780. for (dwIndex = 0; dwIndex < cCert; dwIndex++) {
  10781. if (NULL == (pbEncoded = (BYTE *) AllocAndGetMsgParam(
  10782. hCryptMsg,
  10783. CMSG_CERT_PARAM,
  10784. dwIndex,
  10785. &cbData))) goto ErrorReturn;
  10786. pCertEle = CreateCertElement(
  10787. pStore,
  10788. dwEncodingType,
  10789. pbEncoded,
  10790. cbData,
  10791. NULL // pShareEle
  10792. );
  10793. if (pCertEle == NULL)
  10794. goto ErrorReturn;
  10795. else {
  10796. pbEncoded = NULL;
  10797. AddContextElement(pCertEle);
  10798. }
  10799. }
  10800. for (dwIndex = 0; dwIndex < cCrl; dwIndex++) {
  10801. if (NULL == (pbEncoded = (BYTE *) AllocAndGetMsgParam(
  10802. hCryptMsg,
  10803. CMSG_CRL_PARAM,
  10804. dwIndex,
  10805. &cbData))) goto ErrorReturn;
  10806. pCrlEle = CreateCrlElement(
  10807. pStore,
  10808. dwEncodingType,
  10809. pbEncoded,
  10810. cbData,
  10811. NULL // pShareEle
  10812. );
  10813. if (pCrlEle == NULL)
  10814. goto ErrorReturn;
  10815. else {
  10816. pbEncoded = NULL;
  10817. AddContextElement(pCrlEle);
  10818. }
  10819. }
  10820. pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_NO_PERSIST_FLAG;
  10821. fResult = TRUE;
  10822. CommonReturn:
  10823. return fResult;
  10824. ErrorReturn:
  10825. PkiFree(pbEncoded);
  10826. fResult = FALSE;
  10827. goto CommonReturn;
  10828. }
  10829. //+-------------------------------------------------------------------------
  10830. // Open PKCS #7 Signed Message Store Provider
  10831. //
  10832. // Get Certs and CRLs from the message. pvPara points to a CRYPT_DATA_BLOB
  10833. // containing the signed message.
  10834. //
  10835. // Note for an error return, the caller will free any certs or CRLs
  10836. // successfully added to the store.
  10837. //--------------------------------------------------------------------------
  10838. STATIC BOOL WINAPI OpenPKCS7StoreProv(
  10839. IN LPCSTR lpszStoreProvider,
  10840. IN DWORD dwEncodingType,
  10841. IN HCRYPTPROV hCryptProv,
  10842. IN DWORD dwFlags,
  10843. IN const void *pvPara,
  10844. IN HCERTSTORE hCertStore,
  10845. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  10846. )
  10847. {
  10848. BOOL fResult;
  10849. PCRYPT_DATA_BLOB pMsg = (PCRYPT_DATA_BLOB) pvPara;
  10850. HCRYPTMSG hMsg = NULL;
  10851. DWORD dwMsgType;
  10852. if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG)
  10853. goto UnsafeOpenPKCS7Error;
  10854. if (0 == GET_CERT_ENCODING_TYPE(dwEncodingType))
  10855. dwEncodingType |= X509_ASN_ENCODING;
  10856. if (0 == GET_CMSG_ENCODING_TYPE(dwEncodingType))
  10857. dwEncodingType |= PKCS_7_ASN_ENCODING;
  10858. if (Asn1UtilIsPKCS7WithoutContentType(pMsg->pbData, pMsg->cbData))
  10859. dwMsgType = CMSG_SIGNED;
  10860. else
  10861. dwMsgType = 0;
  10862. if (NULL == (hMsg = CryptMsgOpenToDecode(
  10863. dwEncodingType,
  10864. 0, // dwFlags
  10865. dwMsgType,
  10866. 0, // hCryptProv,
  10867. NULL, // pRecipientInfo
  10868. NULL // pStreamInfo
  10869. ))) goto MsgOpenToDecodeError;
  10870. if (!CryptMsgUpdate(
  10871. hMsg,
  10872. pMsg->pbData,
  10873. pMsg->cbData,
  10874. TRUE // fFinal
  10875. )) goto MsgUpdateError;
  10876. fResult = OpenMsgStoreProv(
  10877. lpszStoreProvider,
  10878. dwEncodingType,
  10879. hCryptProv,
  10880. dwFlags,
  10881. (const void *) hMsg,
  10882. hCertStore,
  10883. pStoreProvInfo
  10884. );
  10885. // Set in above call
  10886. // pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_NO_PERSIST_FLAG;
  10887. CommonReturn:
  10888. if (hMsg)
  10889. CryptMsgClose(hMsg);
  10890. return fResult;
  10891. ErrorReturn:
  10892. fResult = FALSE;
  10893. goto CommonReturn;
  10894. SET_ERROR(UnsafeOpenPKCS7Error, E_INVALIDARG)
  10895. TRACE_ERROR(MsgOpenToDecodeError)
  10896. TRACE_ERROR(MsgUpdateError)
  10897. }
  10898. STATIC BOOL LoadSerializedStore(
  10899. IN HANDLE h,
  10900. IN PFNREAD pfnRead,
  10901. IN PFNSKIP pfnSkip,
  10902. IN DWORD cbReadSize,
  10903. IN PCERT_STORE pStore
  10904. )
  10905. {
  10906. FILE_HDR FileHdr;
  10907. DWORD csStatus;
  10908. if (!pfnRead(
  10909. h,
  10910. &FileHdr,
  10911. sizeof(FileHdr)))
  10912. return FALSE;
  10913. if (FileHdr.dwVersion != CERT_FILE_VERSION_0 ||
  10914. FileHdr.dwMagic != CERT_MAGIC) {
  10915. SetLastError((DWORD) CRYPT_E_FILE_ERROR);
  10916. return(FALSE);
  10917. }
  10918. while (CSContinue == (csStatus = LoadStoreElement(
  10919. h,
  10920. pfnRead,
  10921. pfnSkip,
  10922. cbReadSize,
  10923. pStore,
  10924. CERT_STORE_ADD_ALWAYS,
  10925. CERT_STORE_ALL_CONTEXT_FLAG,
  10926. NULL, // pdwContextType
  10927. NULL))) // ppvContext
  10928. ;
  10929. if(csStatus == CSError)
  10930. return(FALSE);
  10931. return(TRUE);
  10932. }
  10933. //+-------------------------------------------------------------------------
  10934. // Add the serialized store to the store.
  10935. //
  10936. // Called from logstor.cpp for serialized registry stores
  10937. //--------------------------------------------------------------------------
  10938. BOOL WINAPI I_CertAddSerializedStore(
  10939. IN HCERTSTORE hCertStore,
  10940. IN BYTE *pbStore,
  10941. IN DWORD cbStore
  10942. )
  10943. {
  10944. MEMINFO MemInfo;
  10945. MemInfo.pByte = pbStore;
  10946. MemInfo.cb = cbStore;
  10947. MemInfo.cbSeek = 0;
  10948. return LoadSerializedStore(
  10949. (HANDLE) &MemInfo,
  10950. ReadFromMemory,
  10951. SkipInMemory,
  10952. cbStore,
  10953. (PCERT_STORE) hCertStore
  10954. );
  10955. }
  10956. //+-------------------------------------------------------------------------
  10957. // Open Serialized Store Provider
  10958. //
  10959. // pvPara points to a CRYPT_DATA_BLOB containing an in memory serialized
  10960. // Store.
  10961. //
  10962. // Note for an error return, the caller will free any certs or CRLs
  10963. // successfully added to the store.
  10964. //--------------------------------------------------------------------------
  10965. STATIC BOOL WINAPI OpenSerializedStoreProv(
  10966. IN LPCSTR lpszStoreProvider,
  10967. IN DWORD dwEncodingType,
  10968. IN HCRYPTPROV hCryptProv,
  10969. IN DWORD dwFlags,
  10970. IN const void *pvPara,
  10971. IN HCERTSTORE hCertStore,
  10972. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  10973. )
  10974. {
  10975. PCRYPT_DATA_BLOB pData = (PCRYPT_DATA_BLOB) pvPara;
  10976. if (dwFlags & CERT_STORE_UNSAFE_PHYSICAL_FLAG) {
  10977. SetLastError((DWORD) E_INVALIDARG);
  10978. return FALSE;
  10979. }
  10980. pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_NO_PERSIST_FLAG;
  10981. assert(pData);
  10982. return I_CertAddSerializedStore(
  10983. hCertStore,
  10984. pData->pbData,
  10985. pData->cbData
  10986. );
  10987. }
  10988. //+=========================================================================
  10989. // File Store Provider Functions
  10990. //==========================================================================
  10991. #define OPEN_FILE_FLAGS_MASK (CERT_STORE_CREATE_NEW_FLAG | \
  10992. CERT_STORE_OPEN_EXISTING_FLAG | \
  10993. CERT_STORE_MAXIMUM_ALLOWED_FLAG | \
  10994. CERT_STORE_SHARE_CONTEXT_FLAG | \
  10995. CERT_STORE_SHARE_STORE_FLAG | \
  10996. CERT_STORE_BACKUP_RESTORE_FLAG | \
  10997. CERT_STORE_READONLY_FLAG | \
  10998. CERT_STORE_MANIFOLD_FLAG | \
  10999. CERT_STORE_UPDATE_KEYID_FLAG | \
  11000. CERT_STORE_ENUM_ARCHIVED_FLAG | \
  11001. CERT_STORE_NO_CRYPT_RELEASE_FLAG | \
  11002. CERT_STORE_SET_LOCALIZED_NAME_FLAG | \
  11003. CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
  11004. //+-------------------------------------------------------------------------
  11005. // File Store Provider handle information. Only applicable when the store
  11006. // was opened with CERT_FILE_STORE_COMMIT_ENABLE_FLAG set in dwFlags.
  11007. //--------------------------------------------------------------------------
  11008. typedef struct _FILE_STORE {
  11009. HCERTSTORE hCertStore; // not duplicated
  11010. CRITICAL_SECTION CriticalSection;
  11011. HANDLE hFile;
  11012. DWORD dwLoFilePointer;
  11013. LONG lHiFilePointer;
  11014. DWORD dwEncodingType;
  11015. DWORD dwSaveAs;
  11016. BOOL fTouched; // set for write, delete or set property
  11017. } FILE_STORE, *PFILE_STORE;
  11018. //+-------------------------------------------------------------------------
  11019. // Lock and unlock file functions
  11020. //--------------------------------------------------------------------------
  11021. static inline void LockFileStore(IN PFILE_STORE pFileStore)
  11022. {
  11023. EnterCriticalSection(&pFileStore->CriticalSection);
  11024. }
  11025. static inline void UnlockFileStore(IN PFILE_STORE pFileStore)
  11026. {
  11027. LeaveCriticalSection(&pFileStore->CriticalSection);
  11028. }
  11029. STATIC BOOL CommitFile(
  11030. IN PFILE_STORE pFileStore,
  11031. IN DWORD dwFlags
  11032. )
  11033. {
  11034. BOOL fResult;
  11035. BOOL fTouched;
  11036. assert(pFileStore);
  11037. LockFileStore(pFileStore);
  11038. if (dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG)
  11039. fTouched = TRUE;
  11040. else if (dwFlags & CERT_STORE_CTRL_COMMIT_CLEAR_FLAG)
  11041. fTouched = FALSE;
  11042. else
  11043. fTouched = pFileStore->fTouched;
  11044. if (fTouched) {
  11045. HANDLE hFile = pFileStore->hFile;
  11046. DWORD dwLoFilePointer;
  11047. LONG lHiFilePointer = pFileStore->lHiFilePointer;
  11048. // Start the file overwrite at the same location as we started
  11049. // the store read from the file.
  11050. assert(hFile);
  11051. dwLoFilePointer = SetFilePointer(
  11052. hFile,
  11053. (LONG) pFileStore->dwLoFilePointer,
  11054. &lHiFilePointer,
  11055. FILE_BEGIN
  11056. );
  11057. if (0xFFFFFFFF == dwLoFilePointer && NO_ERROR != GetLastError())
  11058. goto SetFilePointerError;
  11059. if (!CertSaveStore(
  11060. pFileStore->hCertStore,
  11061. pFileStore->dwEncodingType,
  11062. pFileStore->dwSaveAs,
  11063. CERT_STORE_SAVE_TO_FILE,
  11064. (void *) hFile,
  11065. 0)) // dwFlags
  11066. goto SaveStoreError;
  11067. if (!SetEndOfFile(hFile))
  11068. goto SetEndOfFileError;
  11069. }
  11070. pFileStore->fTouched = FALSE;
  11071. fResult = TRUE;
  11072. CommonReturn:
  11073. UnlockFileStore(pFileStore);
  11074. return fResult;
  11075. ErrorReturn:
  11076. fResult = FALSE;
  11077. goto CommonReturn;
  11078. TRACE_ERROR(SetFilePointerError)
  11079. TRACE_ERROR(SaveStoreError)
  11080. TRACE_ERROR(SetEndOfFileError)
  11081. }
  11082. //+-------------------------------------------------------------------------
  11083. // File Store Provider Functions for stores opened with
  11084. // CERT_FILE_STORE_COMMIT_ENABLE_FLAG set in dwFlags.
  11085. //
  11086. // Note, since the CRL and CTL callbacks have the same signature as the
  11087. // certificate callbacks and since we don't need to access the context
  11088. // information, we can also use the certificate callbacks for CRLs and
  11089. // CTLs.
  11090. //--------------------------------------------------------------------------
  11091. STATIC void WINAPI FileStoreProvClose(
  11092. IN HCERTSTOREPROV hStoreProv,
  11093. IN DWORD dwFlags
  11094. )
  11095. {
  11096. PFILE_STORE pFileStore = (PFILE_STORE) hStoreProv;
  11097. if (pFileStore) {
  11098. if (pFileStore->fTouched)
  11099. CommitFile(
  11100. pFileStore,
  11101. 0 // dwFlags
  11102. );
  11103. if (pFileStore->hFile)
  11104. CloseHandle(pFileStore->hFile);
  11105. DeleteCriticalSection(&pFileStore->CriticalSection);
  11106. PkiFree(pFileStore);
  11107. }
  11108. }
  11109. STATIC BOOL WINAPI FileStoreProvWriteCert(
  11110. IN HCERTSTOREPROV hStoreProv,
  11111. IN PCCERT_CONTEXT pCertContext,
  11112. IN DWORD dwFlags
  11113. )
  11114. {
  11115. PFILE_STORE pFileStore = (PFILE_STORE) hStoreProv;
  11116. assert(pFileStore);
  11117. pFileStore->fTouched = TRUE;
  11118. return TRUE;
  11119. }
  11120. STATIC BOOL WINAPI FileStoreProvDeleteCert(
  11121. IN HCERTSTOREPROV hStoreProv,
  11122. IN PCCERT_CONTEXT pCertContext,
  11123. IN DWORD dwFlags
  11124. )
  11125. {
  11126. PFILE_STORE pFileStore = (PFILE_STORE) hStoreProv;
  11127. assert(pFileStore);
  11128. pFileStore->fTouched = TRUE;
  11129. return TRUE;
  11130. }
  11131. STATIC BOOL WINAPI FileStoreProvSetCertProperty(
  11132. IN HCERTSTOREPROV hStoreProv,
  11133. IN PCCERT_CONTEXT pCertContext,
  11134. IN DWORD dwPropId,
  11135. IN DWORD dwFlags,
  11136. IN const void *pvData
  11137. )
  11138. {
  11139. PFILE_STORE pFileStore = (PFILE_STORE) hStoreProv;
  11140. assert(pFileStore);
  11141. pFileStore->fTouched = TRUE;
  11142. return TRUE;
  11143. }
  11144. STATIC BOOL WINAPI FileStoreProvControl(
  11145. IN HCERTSTOREPROV hStoreProv,
  11146. IN DWORD dwFlags,
  11147. IN DWORD dwCtrlType,
  11148. IN void const *pvCtrlPara
  11149. )
  11150. {
  11151. BOOL fResult;
  11152. PFILE_STORE pFileStore = (PFILE_STORE) hStoreProv;
  11153. switch (dwCtrlType) {
  11154. case CERT_STORE_CTRL_COMMIT:
  11155. fResult = CommitFile(pFileStore, dwFlags);
  11156. break;
  11157. default:
  11158. goto NotSupported;
  11159. }
  11160. CommonReturn:
  11161. return fResult;
  11162. ErrorReturn:
  11163. fResult = FALSE;
  11164. goto CommonReturn;
  11165. SET_ERROR(NotSupported, ERROR_CALL_NOT_IMPLEMENTED)
  11166. }
  11167. static void * const rgpvFileStoreProvFunc[] = {
  11168. // CERT_STORE_PROV_CLOSE_FUNC 0
  11169. FileStoreProvClose,
  11170. // CERT_STORE_PROV_READ_CERT_FUNC 1
  11171. NULL,
  11172. // CERT_STORE_PROV_WRITE_CERT_FUNC 2
  11173. FileStoreProvWriteCert,
  11174. // CERT_STORE_PROV_DELETE_CERT_FUNC 3
  11175. FileStoreProvDeleteCert,
  11176. // CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC 4
  11177. FileStoreProvSetCertProperty,
  11178. // CERT_STORE_PROV_READ_CRL_FUNC 5
  11179. NULL,
  11180. // CERT_STORE_PROV_WRITE_CRL_FUNC 6
  11181. FileStoreProvWriteCert,
  11182. // CERT_STORE_PROV_DELETE_CRL_FUNC 7
  11183. FileStoreProvDeleteCert,
  11184. // CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC 8
  11185. FileStoreProvSetCertProperty,
  11186. // CERT_STORE_PROV_READ_CTL_FUNC 9
  11187. NULL,
  11188. // CERT_STORE_PROV_WRITE_CTL_FUNC 10
  11189. FileStoreProvWriteCert,
  11190. // CERT_STORE_PROV_DELETE_CTL_FUNC 11
  11191. FileStoreProvDeleteCert,
  11192. // CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC 12
  11193. FileStoreProvSetCertProperty,
  11194. // CERT_STORE_PROV_CONTROL_FUNC 13
  11195. FileStoreProvControl
  11196. };
  11197. #define FILE_STORE_PROV_FUNC_COUNT (sizeof(rgpvFileStoreProvFunc) / \
  11198. sizeof(rgpvFileStoreProvFunc[0]))
  11199. STATIC BOOL OpenFileForCommit(
  11200. IN HANDLE hFile,
  11201. IN DWORD dwLoFilePointer,
  11202. IN LONG lHiFilePointer,
  11203. IN HCERTSTORE hCertStore,
  11204. IN DWORD dwEncodingType,
  11205. IN DWORD dwSaveAs,
  11206. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  11207. )
  11208. {
  11209. BOOL fResult;
  11210. PFILE_STORE pFileStore;
  11211. if (NULL == (pFileStore = (PFILE_STORE) PkiZeroAlloc(sizeof(FILE_STORE))))
  11212. return FALSE;
  11213. if (!Pki_InitializeCriticalSection(&pFileStore->CriticalSection)) {
  11214. PkiFree(pFileStore);
  11215. return FALSE;
  11216. }
  11217. // Duplicate the file HANDLE
  11218. if (!DuplicateHandle(
  11219. GetCurrentProcess(),
  11220. hFile,
  11221. GetCurrentProcess(),
  11222. &pFileStore->hFile,
  11223. GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess
  11224. FALSE, // bInheritHandle
  11225. 0 // dwOptions
  11226. ) || NULL == pFileStore->hFile)
  11227. goto DuplicateFileError;
  11228. pFileStore->hCertStore = hCertStore;
  11229. pFileStore->dwLoFilePointer = dwLoFilePointer;
  11230. pFileStore->lHiFilePointer = lHiFilePointer;
  11231. pFileStore->dwEncodingType = dwEncodingType;
  11232. pFileStore->dwSaveAs = dwSaveAs;
  11233. pStoreProvInfo->cStoreProvFunc = FILE_STORE_PROV_FUNC_COUNT;
  11234. pStoreProvInfo->rgpvStoreProvFunc = (void **) rgpvFileStoreProvFunc;
  11235. pStoreProvInfo->hStoreProv = (HCERTSTOREPROV) pFileStore;
  11236. fResult = TRUE;
  11237. CommonReturn:
  11238. return fResult;
  11239. ErrorReturn:
  11240. PkiFree(pFileStore);
  11241. fResult = FALSE;
  11242. goto CommonReturn;
  11243. TRACE_ERROR(DuplicateFileError)
  11244. }
  11245. //+-------------------------------------------------------------------------
  11246. // Open File Store Provider
  11247. //
  11248. // Get Certs and CRLs from the opened file. pvPara contains the opened
  11249. // HANDLE of the file to read.
  11250. //
  11251. // Note for an error return, the caller will free any certs or CRLs
  11252. // successfully added to the store.
  11253. //
  11254. // Opening an empty file is tolerated.
  11255. //--------------------------------------------------------------------------
  11256. STATIC BOOL WINAPI OpenFileStoreProv(
  11257. IN LPCSTR lpszStoreProvider,
  11258. IN DWORD dwEncodingType,
  11259. IN HCRYPTPROV hCryptProv,
  11260. IN DWORD dwFlags,
  11261. IN const void *pvPara,
  11262. IN HCERTSTORE hCertStore,
  11263. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  11264. )
  11265. {
  11266. BOOL fResult;
  11267. HANDLE hFile = (HANDLE) pvPara;
  11268. DWORD dwLoFilePointer = 0;
  11269. LONG lHiFilePointer = 0;
  11270. DWORD cbReadSize;
  11271. if (dwFlags & ~OPEN_FILE_FLAGS_MASK)
  11272. goto InvalidArg;
  11273. if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG) {
  11274. if (dwFlags & CERT_STORE_READONLY_FLAG)
  11275. goto InvalidArg;
  11276. // Get current file location. This is where we will start the
  11277. // commits.
  11278. lHiFilePointer = 0;
  11279. dwLoFilePointer = SetFilePointer(
  11280. hFile,
  11281. 0, // lDistanceToMove
  11282. &lHiFilePointer,
  11283. FILE_CURRENT
  11284. );
  11285. if (0xFFFFFFFF == dwLoFilePointer && NO_ERROR != GetLastError())
  11286. goto SetFilePointerError;
  11287. }
  11288. cbReadSize = GetFileSize(hFile, NULL);
  11289. if (0xFFFFFFFF == cbReadSize) goto FileError;
  11290. fResult = LoadSerializedStore(
  11291. hFile,
  11292. ReadFromFile,
  11293. SkipInFile,
  11294. cbReadSize,
  11295. (PCERT_STORE) hCertStore
  11296. );
  11297. if (!fResult) {
  11298. if (0 == GetFileSize(hFile, NULL))
  11299. // Empty file
  11300. fResult = TRUE;
  11301. }
  11302. if (fResult && (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
  11303. fResult = OpenFileForCommit(
  11304. hFile,
  11305. dwLoFilePointer,
  11306. lHiFilePointer,
  11307. hCertStore,
  11308. dwEncodingType,
  11309. CERT_STORE_SAVE_AS_STORE,
  11310. pStoreProvInfo
  11311. );
  11312. else
  11313. pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_NO_PERSIST_FLAG;
  11314. CommonReturn:
  11315. return fResult;
  11316. ErrorReturn:
  11317. fResult = FALSE;
  11318. goto CommonReturn;
  11319. SET_ERROR(InvalidArg, E_INVALIDARG)
  11320. TRACE_ERROR(SetFilePointerError)
  11321. TRACE_ERROR(FileError)
  11322. }
  11323. //+-------------------------------------------------------------------------
  11324. // Open Filename Store Provider (Unicode version)
  11325. //
  11326. // Attempt to open a file containing a Store, a PKCS #7 signed
  11327. // message or a single encoded certificate.
  11328. //
  11329. // pvPara contains a LPCWSTR of the Filename.
  11330. //
  11331. // Note for an error return, the caller will free any certs or CRLs
  11332. // successfully added to the store.
  11333. //
  11334. // Opening an empty file is tolerated.
  11335. //--------------------------------------------------------------------------
  11336. STATIC BOOL WINAPI OpenFilenameStoreProvW(
  11337. IN LPCSTR lpszStoreProvider,
  11338. IN DWORD dwEncodingType,
  11339. IN HCRYPTPROV hCryptProv,
  11340. IN DWORD dwFlags,
  11341. IN const void *pvPara,
  11342. IN HCERTSTORE hCertStore,
  11343. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  11344. )
  11345. {
  11346. BOOL fResult;
  11347. LPWSTR pwszFile = (LPWSTR) pvPara;
  11348. HANDLE hFile = INVALID_HANDLE_VALUE;
  11349. CRYPT_DATA_BLOB FileData;
  11350. memset(&FileData, 0, sizeof(FileData));
  11351. DWORD cbBytesRead;
  11352. DWORD dwSaveAs = 0;
  11353. HCERTSTORE hSpecialCertStore = NULL;
  11354. assert(pwszFile);
  11355. dwFlags &= ~CERT_STORE_UNSAFE_PHYSICAL_FLAG;
  11356. if (dwFlags & ~OPEN_FILE_FLAGS_MASK)
  11357. goto InvalidArg;
  11358. if (dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG)
  11359. ILS_EnableBackupRestorePrivileges();
  11360. if (0 == GET_CERT_ENCODING_TYPE(dwEncodingType))
  11361. dwEncodingType |= X509_ASN_ENCODING;
  11362. if (0 == GET_CMSG_ENCODING_TYPE(dwEncodingType))
  11363. dwEncodingType |= PKCS_7_ASN_ENCODING;
  11364. if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG) {
  11365. DWORD dwCreate;
  11366. if (dwFlags & CERT_STORE_READONLY_FLAG)
  11367. goto InvalidArg;
  11368. if (dwFlags & CERT_STORE_CREATE_NEW_FLAG)
  11369. dwCreate = CREATE_NEW;
  11370. else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
  11371. dwCreate = OPEN_EXISTING;
  11372. else
  11373. dwCreate = OPEN_ALWAYS;
  11374. if (INVALID_HANDLE_VALUE == (hFile = CreateFileU(
  11375. pwszFile,
  11376. GENERIC_READ | GENERIC_WRITE,
  11377. FILE_SHARE_READ,
  11378. NULL, // lpsa
  11379. dwCreate,
  11380. FILE_ATTRIBUTE_NORMAL |
  11381. ((dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
  11382. FILE_FLAG_BACKUP_SEMANTICS : 0),
  11383. NULL // hTemplateFile
  11384. )))
  11385. goto CreateFileError;
  11386. // Default to saving as a serialized store
  11387. dwSaveAs = CERT_STORE_SAVE_AS_STORE;
  11388. if (0 == GetFileSize(hFile, NULL)) {
  11389. // Use file extension to determine dwSaveAs
  11390. LPWSTR pwszExt;
  11391. pwszExt = pwszFile + wcslen(pwszFile);
  11392. while (pwszExt-- > pwszFile) {
  11393. if (L'.' == *pwszExt) {
  11394. pwszExt++;
  11395. if (0 == _wcsicmp(pwszExt, L"p7c") ||
  11396. 0 == _wcsicmp(pwszExt, L"spc"))
  11397. dwSaveAs = CERT_STORE_SAVE_AS_PKCS7;
  11398. break;
  11399. }
  11400. }
  11401. goto CommitReturn;
  11402. }
  11403. } else {
  11404. WIN32_FILE_ATTRIBUTE_DATA FileAttr;
  11405. if (!GetFileAttributesExW(
  11406. pwszFile,
  11407. GetFileExInfoStandard,
  11408. &FileAttr
  11409. ))
  11410. goto GetFileAttributesError;
  11411. if (INVALID_HANDLE_VALUE == (hFile = CreateFileU(
  11412. pwszFile,
  11413. GENERIC_READ,
  11414. FILE_SHARE_READ,
  11415. NULL, // lpsa
  11416. OPEN_EXISTING,
  11417. FILE_ATTRIBUTE_NORMAL |
  11418. ((dwFlags & CERT_STORE_BACKUP_RESTORE_FLAG) ?
  11419. FILE_FLAG_BACKUP_SEMANTICS : 0),
  11420. NULL // hTemplateFile
  11421. )))
  11422. goto CreateFileError;
  11423. }
  11424. if (OpenFileStoreProv(
  11425. lpszStoreProvider,
  11426. dwEncodingType,
  11427. hCryptProv,
  11428. dwFlags,
  11429. (const void *) hFile,
  11430. hCertStore,
  11431. pStoreProvInfo)) {
  11432. // For commit, we have already called OpenFileForCommit
  11433. fResult = TRUE;
  11434. goto OpenReturn;
  11435. }
  11436. // Read the entire file. Will attempt to process as either a
  11437. // PKCS #7 or as a single cert.
  11438. //
  11439. // Will first try as binary. If that fails will try as base64 encoded.
  11440. if (0 != SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
  11441. goto FileError;
  11442. FileData.cbData = GetFileSize(hFile, NULL);
  11443. if (0xFFFFFFFF == FileData.cbData) goto FileError;
  11444. if (0 == FileData.cbData)
  11445. // Empty file
  11446. goto CommitReturn;
  11447. if (NULL == (FileData.pbData = (BYTE *) PkiNonzeroAlloc(FileData.cbData)))
  11448. goto OutOfMemory;
  11449. if (!ReadFile(
  11450. hFile,
  11451. FileData.pbData,
  11452. FileData.cbData,
  11453. &cbBytesRead,
  11454. NULL // lpOverlapped
  11455. )) goto FileError;
  11456. if (OpenPKCS7StoreProv(
  11457. lpszStoreProvider,
  11458. dwEncodingType,
  11459. hCryptProv,
  11460. dwFlags,
  11461. (const void *) &FileData,
  11462. hCertStore,
  11463. pStoreProvInfo)) {
  11464. dwSaveAs = CERT_STORE_SAVE_AS_PKCS7;
  11465. goto CommitReturn;
  11466. }
  11467. // Try to process as a single encoded certificate
  11468. if (CertAddEncodedCertificateToStore(
  11469. hCertStore,
  11470. dwEncodingType,
  11471. FileData.pbData,
  11472. FileData.cbData,
  11473. CERT_STORE_ADD_USE_EXISTING,
  11474. NULL)) {
  11475. if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
  11476. goto CanNotCommitX509CertFileError;
  11477. else
  11478. goto CommitReturn;
  11479. }
  11480. // Try to process as an encoded PKCS7, X509 or CERT_PAIR in any
  11481. // format
  11482. if (CryptQueryObject(
  11483. CERT_QUERY_OBJECT_BLOB,
  11484. &FileData,
  11485. CERT_QUERY_CONTENT_FLAG_CERT |
  11486. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
  11487. CERT_QUERY_CONTENT_FLAG_CERT_PAIR,
  11488. CERT_QUERY_FORMAT_FLAG_ALL,
  11489. 0, // dwFlags
  11490. NULL, // pdwMsgAndCertEncodingType
  11491. NULL, // pdwContentType
  11492. NULL, // pdwFormatType
  11493. &hSpecialCertStore,
  11494. NULL, // phMsg
  11495. NULL // ppvContext
  11496. )) {
  11497. fResult = I_CertUpdateStore(hCertStore, hSpecialCertStore, 0, NULL);
  11498. CertCloseStore(hSpecialCertStore, 0);
  11499. if (!fResult)
  11500. goto UpdateStoreError;
  11501. if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
  11502. goto CanNotCommitSpecialFileError;
  11503. else
  11504. goto CommitReturn;
  11505. }
  11506. goto NoStoreOrPKCS7OrCertFileError;
  11507. CommitReturn:
  11508. if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
  11509. fResult = OpenFileForCommit(
  11510. hFile,
  11511. 0, // dwLoFilePointer
  11512. 0, // lHiFilePointer
  11513. hCertStore,
  11514. dwEncodingType,
  11515. dwSaveAs,
  11516. pStoreProvInfo
  11517. );
  11518. else {
  11519. pStoreProvInfo->dwStoreProvFlags |= CERT_STORE_PROV_NO_PERSIST_FLAG;
  11520. fResult = TRUE;
  11521. }
  11522. OpenReturn:
  11523. if (dwFlags & CERT_STORE_SET_LOCALIZED_NAME_FLAG) {
  11524. CRYPT_DATA_BLOB Property;
  11525. Property.pbData = (BYTE *) pwszFile;
  11526. Property.cbData = (wcslen(pwszFile) + 1) * sizeof(WCHAR);
  11527. CertSetStoreProperty(
  11528. hCertStore,
  11529. CERT_STORE_LOCALIZED_NAME_PROP_ID,
  11530. 0, // dwFlags
  11531. (const void *) &Property
  11532. );
  11533. }
  11534. CommonReturn:
  11535. if (INVALID_HANDLE_VALUE != hFile)
  11536. CloseHandle(hFile);
  11537. if (FileData.pbData)
  11538. PkiFree(FileData.pbData);
  11539. return fResult;
  11540. ErrorReturn:
  11541. fResult = FALSE;
  11542. goto CommonReturn;
  11543. SET_ERROR(InvalidArg, E_INVALIDARG)
  11544. TRACE_ERROR(GetFileAttributesError)
  11545. TRACE_ERROR(CreateFileError)
  11546. TRACE_ERROR(FileError)
  11547. TRACE_ERROR(OutOfMemory)
  11548. SET_ERROR(CanNotCommitX509CertFileError, ERROR_ACCESS_DENIED)
  11549. SET_ERROR(CanNotCommitSpecialFileError, ERROR_ACCESS_DENIED)
  11550. SET_ERROR(NoStoreOrPKCS7OrCertFileError, CRYPT_E_FILE_ERROR)
  11551. TRACE_ERROR(UpdateStoreError)
  11552. }
  11553. //+-------------------------------------------------------------------------
  11554. // Open Filename Store Provider (ASCII version)
  11555. //
  11556. // Attempt to open a file containing a Store, a PKCS #7 signed
  11557. // message or a single encoded certificate.
  11558. //
  11559. // pvPara contains a LPCWSTR of the Filename.
  11560. //
  11561. // Note for an error return, the caller will free any certs or CRLs
  11562. // successfully added to the store.
  11563. //
  11564. // Opening an empty file is tolerated.
  11565. //--------------------------------------------------------------------------
  11566. STATIC BOOL WINAPI OpenFilenameStoreProvA(
  11567. IN LPCSTR lpszStoreProvider,
  11568. IN DWORD dwEncodingType,
  11569. IN HCRYPTPROV hCryptProv,
  11570. IN DWORD dwFlags,
  11571. IN const void *pvPara,
  11572. IN HCERTSTORE hCertStore,
  11573. IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
  11574. )
  11575. {
  11576. BOOL fResult;
  11577. LPWSTR pwszFilename;
  11578. assert(pvPara);
  11579. if (NULL == (pwszFilename = MkWStr((LPSTR) pvPara)))
  11580. fResult = FALSE;
  11581. else {
  11582. fResult = OpenFilenameStoreProvW(
  11583. lpszStoreProvider,
  11584. dwEncodingType,
  11585. hCryptProv,
  11586. dwFlags,
  11587. (const void *) pwszFilename,
  11588. hCertStore,
  11589. pStoreProvInfo
  11590. );
  11591. FreeWStr(pwszFilename);
  11592. }
  11593. return fResult;
  11594. }
  11595. //+=========================================================================
  11596. // CryptAcquireCertificatePrivateKey Support Functions
  11597. //==========================================================================
  11598. // Upon entry/exit, the Cache Store is locked.
  11599. //
  11600. // OUTs are only updated for success.
  11601. STATIC BOOL GetCacheKeyContext(
  11602. IN PCONTEXT_ELEMENT pCacheEle,
  11603. OUT HCRYPTPROV *phCryptProv,
  11604. OUT OPTIONAL DWORD *pdwKeySpec
  11605. )
  11606. {
  11607. BOOL fResult = FALSE;
  11608. PPROP_ELEMENT pPropEle;
  11609. if (pPropEle = FindPropElement(pCacheEle, CERT_KEY_CONTEXT_PROP_ID)) {
  11610. PCERT_KEY_CONTEXT pKeyContext =
  11611. (PCERT_KEY_CONTEXT) pPropEle->pbData;
  11612. assert(pKeyContext);
  11613. assert(pPropEle->cbData >= sizeof(CERT_KEY_CONTEXT));
  11614. if (pKeyContext->hCryptProv) {
  11615. *phCryptProv = pKeyContext->hCryptProv;
  11616. if (pdwKeySpec)
  11617. *pdwKeySpec = pKeyContext->dwKeySpec;
  11618. fResult = TRUE;
  11619. }
  11620. }
  11621. return fResult;
  11622. }
  11623. STATIC PCRYPT_KEY_PROV_INFO GetKeyIdentifierKeyProvInfo(
  11624. IN PCONTEXT_ELEMENT pCacheEle
  11625. )
  11626. {
  11627. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  11628. DWORD cbKeyProvInfo;
  11629. BYTE rgbKeyId[MAX_HASH_LEN];
  11630. DWORD cbKeyId;
  11631. CRYPT_HASH_BLOB KeyIdentifier;
  11632. cbKeyId = sizeof(rgbKeyId);
  11633. if(!GetProperty(
  11634. pCacheEle,
  11635. CERT_KEY_IDENTIFIER_PROP_ID,
  11636. rgbKeyId,
  11637. &cbKeyId
  11638. ))
  11639. return NULL;
  11640. KeyIdentifier.pbData = rgbKeyId;
  11641. KeyIdentifier.cbData = cbKeyId;
  11642. if (CryptGetKeyIdentifierProperty(
  11643. &KeyIdentifier,
  11644. CERT_KEY_PROV_INFO_PROP_ID,
  11645. CRYPT_KEYID_ALLOC_FLAG,
  11646. NULL, // pwszComputerName
  11647. NULL, // pvReserved
  11648. (void *) &pKeyProvInfo,
  11649. &cbKeyProvInfo
  11650. ))
  11651. return pKeyProvInfo;
  11652. // Try again, searching LocalMachine
  11653. if (CryptGetKeyIdentifierProperty(
  11654. &KeyIdentifier,
  11655. CERT_KEY_PROV_INFO_PROP_ID,
  11656. CRYPT_KEYID_ALLOC_FLAG | CRYPT_KEYID_MACHINE_FLAG,
  11657. NULL, // pwszComputerName
  11658. NULL, // pvReserved
  11659. (void *) &pKeyProvInfo,
  11660. &cbKeyProvInfo
  11661. ))
  11662. return pKeyProvInfo;
  11663. else
  11664. return NULL;
  11665. }
  11666. STATIC BOOL AcquireKeyContext(
  11667. IN PCCERT_CONTEXT pCert,
  11668. IN DWORD dwFlags,
  11669. IN PCRYPT_KEY_PROV_INFO pKeyProvInfo,
  11670. IN OUT PCERT_KEY_CONTEXT pKeyContext,
  11671. IN OUT BOOL *pfBadPubKey
  11672. )
  11673. {
  11674. BOOL fResult;
  11675. DWORD dwAcquireFlags;
  11676. DWORD dwIdx;
  11677. dwAcquireFlags = pKeyProvInfo->dwFlags & ~CERT_SET_KEY_CONTEXT_PROP_ID;
  11678. if (dwFlags & CRYPT_ACQUIRE_SILENT_FLAG)
  11679. dwAcquireFlags |= CRYPT_SILENT;
  11680. pKeyContext->dwKeySpec = pKeyProvInfo->dwKeySpec;
  11681. if (PROV_RSA_FULL == pKeyProvInfo->dwProvType &&
  11682. (NULL == pKeyProvInfo->pwszProvName ||
  11683. L'\0' == *pKeyProvInfo->pwszProvName ||
  11684. 0 == _wcsicmp(pKeyProvInfo->pwszProvName, MS_DEF_PROV_W)))
  11685. fResult = CryptAcquireContextU(
  11686. &pKeyContext->hCryptProv,
  11687. pKeyProvInfo->pwszContainerName,
  11688. MS_ENHANCED_PROV_W,
  11689. PROV_RSA_FULL,
  11690. dwAcquireFlags
  11691. );
  11692. else if (PROV_DSS_DH == pKeyProvInfo->dwProvType &&
  11693. (NULL == pKeyProvInfo->pwszProvName ||
  11694. L'\0' == *pKeyProvInfo->pwszProvName ||
  11695. 0 == _wcsicmp(pKeyProvInfo->pwszProvName,
  11696. MS_DEF_DSS_DH_PROV_W)))
  11697. fResult = CryptAcquireContextU(
  11698. &pKeyContext->hCryptProv,
  11699. pKeyProvInfo->pwszContainerName,
  11700. MS_ENH_DSS_DH_PROV_W,
  11701. PROV_DSS_DH,
  11702. dwAcquireFlags
  11703. );
  11704. else
  11705. fResult = FALSE;
  11706. if (!fResult) {
  11707. if (!CryptAcquireContextU(
  11708. &pKeyContext->hCryptProv,
  11709. pKeyProvInfo->pwszContainerName,
  11710. pKeyProvInfo->pwszProvName,
  11711. pKeyProvInfo->dwProvType,
  11712. dwAcquireFlags
  11713. )) {
  11714. pKeyContext->hCryptProv = 0;
  11715. goto AcquireContextError;
  11716. }
  11717. }
  11718. for (dwIdx = 0; dwIdx < pKeyProvInfo->cProvParam; dwIdx++) {
  11719. PCRYPT_KEY_PROV_PARAM pKeyProvParam = &pKeyProvInfo->rgProvParam[dwIdx];
  11720. if (!CryptSetProvParam(
  11721. pKeyContext->hCryptProv,
  11722. pKeyProvParam->dwParam,
  11723. pKeyProvParam->pbData,
  11724. pKeyProvParam->dwFlags
  11725. ))
  11726. goto SetProvParamError;
  11727. }
  11728. if (dwFlags & CRYPT_ACQUIRE_COMPARE_KEY_FLAG) {
  11729. if (!I_CertCompareCertAndProviderPublicKey(
  11730. pCert,
  11731. pKeyContext->hCryptProv,
  11732. pKeyContext->dwKeySpec
  11733. )) {
  11734. *pfBadPubKey = TRUE;
  11735. goto BadPublicKey;
  11736. }
  11737. }
  11738. fResult = TRUE;
  11739. CommonReturn:
  11740. return fResult;
  11741. ErrorReturn:
  11742. if (pKeyContext->hCryptProv) {
  11743. DWORD dwErr = GetLastError();
  11744. CryptReleaseContext(pKeyContext->hCryptProv, 0);
  11745. SetLastError(dwErr);
  11746. pKeyContext->hCryptProv = 0;
  11747. }
  11748. fResult = FALSE;
  11749. goto CommonReturn;
  11750. TRACE_ERROR(AcquireContextError)
  11751. TRACE_ERROR(SetProvParamError)
  11752. SET_ERROR(BadPublicKey, NTE_BAD_PUBLIC_KEY)
  11753. }
  11754. //+-------------------------------------------------------------------------
  11755. // Acquire a HCRYPTPROV handle and dwKeySpec for the specified certificate
  11756. // context. Uses the certificate's CERT_KEY_PROV_INFO_PROP_ID property.
  11757. // The returned HCRYPTPROV handle may optionally be cached using the
  11758. // certificate's CERT_KEY_CONTEXT_PROP_ID property.
  11759. //
  11760. // If CRYPT_ACQUIRE_CACHE_FLAG is set, then, if an already acquired and
  11761. // cached HCRYPTPROV exists for the certificate, its returned. Otherwise,
  11762. // a HCRYPTPROV is acquired and then cached via the certificate's
  11763. // CERT_KEY_CONTEXT_PROP_ID.
  11764. //
  11765. // The CRYPT_ACQUIRE_USE_PROV_INFO_FLAG can be set to use the dwFlags field of
  11766. // the certificate's CERT_KEY_PROV_INFO_PROP_ID property's CRYPT_KEY_PROV_INFO
  11767. // data structure to determine if the returned HCRYPTPROV should be cached.
  11768. // HCRYPTPROV caching is enabled if the CERT_SET_KEY_CONTEXT_PROP_ID flag was
  11769. // set.
  11770. //
  11771. // If CRYPT_ACQUIRE_COMPARE_KEY_FLAG is set, then,
  11772. // the public key in the certificate is compared with the public
  11773. // key returned by the cryptographic provider. If the keys don't match, the
  11774. // acquire fails and LastError is set to NTE_BAD_PUBLIC_KEY. Note, if
  11775. // a cached HCRYPTPROV is returned, the comparison isn't done. We assume the
  11776. // comparison was done on the initial acquire.
  11777. //
  11778. // The CRYPT_ACQUIRE_SILENT_FLAG can be set to suppress any UI by the CSP.
  11779. // See CryptAcquireContext's CRYPT_SILENT flag for more details.
  11780. //
  11781. // *pfCallerFreeProv is returned set to FALSE for:
  11782. // - Acquire or public key comparison fails.
  11783. // - CRYPT_ACQUIRE_CACHE_FLAG is set.
  11784. // - CRYPT_ACQUIRE_USE_PROV_INFO_FLAG is set AND
  11785. // CERT_SET_KEY_CONTEXT_PROP_ID flag is set in the dwFlags field of the
  11786. // certificate's CERT_KEY_PROV_INFO_PROP_ID property's
  11787. // CRYPT_KEY_PROV_INFO data structure.
  11788. // When *pfCallerFreeProv is FALSE, the caller must not release. The
  11789. // returned HCRYPTPROV will be released on the last free of the certificate
  11790. // context.
  11791. //
  11792. // Otherwise, *pfCallerFreeProv is TRUE and the returned HCRYPTPROV must
  11793. // be released by the caller by calling CryptReleaseContext.
  11794. //--------------------------------------------------------------------------
  11795. BOOL
  11796. WINAPI
  11797. CryptAcquireCertificatePrivateKey(
  11798. IN PCCERT_CONTEXT pCert,
  11799. IN DWORD dwFlags,
  11800. IN void *pvReserved,
  11801. OUT HCRYPTPROV *phCryptProv,
  11802. OUT OPTIONAL DWORD *pdwKeySpec,
  11803. OUT OPTIONAL BOOL *pfCallerFreeProv
  11804. )
  11805. {
  11806. BOOL fResult;
  11807. BOOL fCallerFreeProv;
  11808. PCONTEXT_ELEMENT pCacheEle;
  11809. PCERT_STORE pCacheStore;
  11810. CERT_KEY_CONTEXT KeyContext;
  11811. memset(&KeyContext, 0, sizeof(KeyContext));
  11812. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  11813. DWORD cbData;
  11814. BOOL fKeyIdentifier = FALSE;
  11815. BOOL fBadPubKey = FALSE;
  11816. if (NULL == (pCacheEle = GetCacheElement(ToContextElement(pCert))))
  11817. goto InvalidCert;
  11818. pCacheStore = pCacheEle->pStore;
  11819. if (dwFlags &
  11820. (CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)) {
  11821. // Attempt to use existing CERT_KEY_CONTEXT_PROP_ID property
  11822. LockStore(pCacheStore);
  11823. if (GetCacheKeyContext(
  11824. pCacheEle,
  11825. phCryptProv,
  11826. pdwKeySpec
  11827. )) {
  11828. if (pfCallerFreeProv)
  11829. *pfCallerFreeProv = FALSE;
  11830. UnlockStore(pCacheStore);
  11831. return TRUE;
  11832. }
  11833. UnlockStore(pCacheStore);
  11834. }
  11835. if (!AllocAndGetProperty(
  11836. pCacheEle,
  11837. CERT_KEY_PROV_INFO_PROP_ID,
  11838. (void **) &pKeyProvInfo,
  11839. &cbData)) {
  11840. fKeyIdentifier = TRUE;
  11841. if (NULL == (pKeyProvInfo = GetKeyIdentifierKeyProvInfo(pCacheEle)))
  11842. goto NoKeyProperty;
  11843. }
  11844. if (!AcquireKeyContext(
  11845. pCert,
  11846. dwFlags,
  11847. pKeyProvInfo,
  11848. &KeyContext,
  11849. &fBadPubKey
  11850. )) {
  11851. DWORD dwLastErr;
  11852. if (fKeyIdentifier)
  11853. goto AcquireKeyContextError;
  11854. dwLastErr = GetLastError();
  11855. if (ERROR_CANCELLED == dwLastErr ||
  11856. SCARD_W_CANCELLED_BY_USER == dwLastErr ||
  11857. HRESULT_FROM_WIN32(ERROR_CANCELLED) == dwLastErr)
  11858. goto AcquireKeyContextError;
  11859. PkiFree(pKeyProvInfo);
  11860. fKeyIdentifier = TRUE;
  11861. if (NULL == (pKeyProvInfo = GetKeyIdentifierKeyProvInfo(pCacheEle)))
  11862. goto NoKeyProperty;
  11863. if (!AcquireKeyContext(
  11864. pCert,
  11865. dwFlags,
  11866. pKeyProvInfo,
  11867. &KeyContext,
  11868. &fBadPubKey
  11869. ))
  11870. goto AcquireKeyContextError;
  11871. }
  11872. fResult = TRUE;
  11873. if ((dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
  11874. ||
  11875. ((dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG) &&
  11876. (pKeyProvInfo->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID))) {
  11877. // Cache the context.
  11878. HCRYPTPROV hCryptProv;
  11879. DWORD dwKeySpec;
  11880. LockStore(pCacheStore);
  11881. // First check that another thread hasn't already cached the context.
  11882. if (GetCacheKeyContext(
  11883. pCacheEle,
  11884. &hCryptProv,
  11885. &dwKeySpec
  11886. )) {
  11887. CryptReleaseContext(KeyContext.hCryptProv, 0);
  11888. KeyContext.hCryptProv = hCryptProv;
  11889. KeyContext.dwKeySpec = dwKeySpec;
  11890. } else {
  11891. KeyContext.cbSize = sizeof(KeyContext);
  11892. fResult = SetProperty(
  11893. pCacheEle,
  11894. CERT_KEY_CONTEXT_PROP_ID,
  11895. 0, // dwFlags
  11896. (void *) &KeyContext,
  11897. TRUE // fInhibitProvSet
  11898. );
  11899. }
  11900. UnlockStore(pCacheStore);
  11901. if (!fResult) goto SetKeyContextPropertyError;
  11902. fCallerFreeProv = FALSE;
  11903. } else
  11904. fCallerFreeProv = TRUE;
  11905. CommonReturn:
  11906. if (pKeyProvInfo) {
  11907. if (fKeyIdentifier)
  11908. PkiDefaultCryptFree(pKeyProvInfo);
  11909. else
  11910. PkiFree(pKeyProvInfo);
  11911. }
  11912. *phCryptProv = KeyContext.hCryptProv;
  11913. if (pdwKeySpec)
  11914. *pdwKeySpec = KeyContext.dwKeySpec;
  11915. if (pfCallerFreeProv)
  11916. *pfCallerFreeProv = fCallerFreeProv;
  11917. return fResult;
  11918. ErrorReturn:
  11919. if (fBadPubKey)
  11920. SetLastError((DWORD) NTE_BAD_PUBLIC_KEY);
  11921. if (KeyContext.hCryptProv) {
  11922. DWORD dwErr = GetLastError();
  11923. CryptReleaseContext(KeyContext.hCryptProv, 0);
  11924. SetLastError(dwErr);
  11925. KeyContext.hCryptProv = 0;
  11926. }
  11927. fResult = FALSE;
  11928. fCallerFreeProv = FALSE;
  11929. goto CommonReturn;
  11930. SET_ERROR(InvalidCert, E_INVALIDARG)
  11931. SET_ERROR(NoKeyProperty, CRYPT_E_NO_KEY_PROPERTY)
  11932. TRACE_ERROR(AcquireKeyContextError)
  11933. TRACE_ERROR(SetKeyContextPropertyError)
  11934. }
  11935. //+=========================================================================
  11936. // I_CertSyncStore and I_CertSyncStoreEx Support Functions
  11937. //==========================================================================
  11938. // Returns FALSE if unable to do the find. For instance, OutOfMemory error.
  11939. STATIC BOOL FindElementInOtherStore(
  11940. IN PCERT_STORE pOtherStore,
  11941. IN DWORD dwContextType,
  11942. IN PCONTEXT_ELEMENT pEle,
  11943. OUT PCONTEXT_ELEMENT *ppOtherEle
  11944. )
  11945. {
  11946. PCONTEXT_ELEMENT pOtherEle;
  11947. BYTE rgbHash[SHA1_HASH_LEN];
  11948. DWORD cbHash;
  11949. *ppOtherEle = NULL;
  11950. cbHash = SHA1_HASH_LEN;
  11951. if (!GetProperty(
  11952. pEle,
  11953. CERT_SHA1_HASH_PROP_ID,
  11954. rgbHash,
  11955. &cbHash
  11956. ) || SHA1_HASH_LEN != cbHash)
  11957. return FALSE;
  11958. assert(STORE_TYPE_CACHE == pOtherStore->dwStoreType);
  11959. pOtherEle = NULL;
  11960. // Enable fForceEnumArchived
  11961. while (pOtherEle = FindElementInCacheStore(pOtherStore, dwContextType,
  11962. &FindAnyInfo, pOtherEle, TRUE)) {
  11963. BYTE rgbOtherHash[SHA1_HASH_LEN];
  11964. DWORD cbOtherHash;
  11965. cbOtherHash = SHA1_HASH_LEN;
  11966. if (!GetProperty(
  11967. pOtherEle,
  11968. CERT_SHA1_HASH_PROP_ID,
  11969. rgbOtherHash,
  11970. &cbOtherHash
  11971. ) || SHA1_HASH_LEN != cbOtherHash)
  11972. return FALSE;
  11973. if (0 == memcmp(rgbOtherHash, rgbHash, SHA1_HASH_LEN)) {
  11974. *ppOtherEle = pOtherEle;
  11975. return TRUE;
  11976. }
  11977. }
  11978. return TRUE;
  11979. }
  11980. STATIC void AppendElementToDeleteList(
  11981. IN PCONTEXT_ELEMENT pEle,
  11982. IN OUT DWORD *pcDeleteList,
  11983. IN OUT PCONTEXT_ELEMENT **pppDeleteList
  11984. )
  11985. {
  11986. DWORD cDeleteList = *pcDeleteList;
  11987. PCONTEXT_ELEMENT *ppDeleteList = *pppDeleteList;
  11988. if (ppDeleteList = (PCONTEXT_ELEMENT *) PkiRealloc(ppDeleteList,
  11989. (cDeleteList + 1) * sizeof(PCONTEXT_ELEMENT))) {
  11990. AddRefContextElement(pEle);
  11991. ppDeleteList[cDeleteList] = pEle;
  11992. *pcDeleteList = cDeleteList + 1;
  11993. *pppDeleteList = ppDeleteList;
  11994. }
  11995. }
  11996. //+-------------------------------------------------------------------------
  11997. // Synchronize the original store with the new store.
  11998. //
  11999. // Assumptions: Both are cache stores. The new store is temporary
  12000. // and local to the caller. The new store's contexts can be deleted or
  12001. // moved to the original store.
  12002. //
  12003. // Setting ICERT_SYNC_STORE_INHIBIT_SYNC_PROPERTY_IN_FLAG in dwInFlags
  12004. // inhibits the syncing of properties.
  12005. //
  12006. // ICERT_SYNC_STORE_CHANGED_OUT_FLAG is returned and set in *pdwOutFlags
  12007. // if any contexts were added or deleted from the original store.
  12008. //--------------------------------------------------------------------------
  12009. BOOL
  12010. WINAPI
  12011. I_CertSyncStoreEx(
  12012. IN OUT HCERTSTORE hOriginalStore,
  12013. IN OUT HCERTSTORE hNewStore,
  12014. IN DWORD dwInFlags,
  12015. OUT OPTIONAL DWORD *pdwOutFlags,
  12016. IN OUT OPTIONAL void *pvReserved
  12017. )
  12018. {
  12019. PCERT_STORE pOrigStore = (PCERT_STORE) hOriginalStore;
  12020. PCERT_STORE pNewStore = (PCERT_STORE) hNewStore;
  12021. DWORD dwOutFlags = 0;
  12022. DWORD cDeleteList = 0;
  12023. PCONTEXT_ELEMENT *ppDeleteList = NULL;
  12024. DWORD i;
  12025. assert(STORE_TYPE_CACHE == pOrigStore->dwStoreType &&
  12026. STORE_TYPE_CACHE == pNewStore->dwStoreType);
  12027. if (STORE_TYPE_CACHE != pOrigStore->dwStoreType ||
  12028. STORE_TYPE_CACHE != pNewStore->dwStoreType) {
  12029. SetLastError((DWORD) E_INVALIDARG);
  12030. return FALSE;
  12031. }
  12032. if (pOrigStore->dwFlags & CERT_STORE_MANIFOLD_FLAG)
  12033. ArchiveManifoldCertificatesInStore(pNewStore);
  12034. // Loop through the original store's elements. If the context exists
  12035. // in the new store, copy the new store's properties and delete from
  12036. // the new store. Otherwise, put the original store's context on a
  12037. // deferred delete list.
  12038. for (i = 0; i < CONTEXT_COUNT; i++) {
  12039. PCONTEXT_ELEMENT pOrigEle = NULL;
  12040. // Enable fForceEnumArchived
  12041. while (pOrigEle = FindElementInCacheStore(pOrigStore, i, &FindAnyInfo,
  12042. pOrigEle, TRUE)) {
  12043. PCONTEXT_ELEMENT pNewEle;
  12044. if (FindElementInOtherStore(pNewStore, i, pOrigEle, &pNewEle)) {
  12045. if (pNewEle) {
  12046. if (0 == (dwInFlags &
  12047. ICERT_SYNC_STORE_INHIBIT_SYNC_PROPERTY_IN_FLAG))
  12048. CopyProperties(
  12049. pNewEle,
  12050. pOrigEle,
  12051. COPY_PROPERTY_INHIBIT_PROV_SET_FLAG |
  12052. COPY_PROPERTY_SYNC_FLAG
  12053. );
  12054. DeleteContextElement(pNewEle);
  12055. } else {
  12056. dwOutFlags |= ICERT_SYNC_STORE_CHANGED_OUT_FLAG;
  12057. AppendElementToDeleteList(pOrigEle, &cDeleteList,
  12058. &ppDeleteList);
  12059. }
  12060. }
  12061. //
  12062. // else
  12063. // Find failed due to OutOfMemory
  12064. }
  12065. }
  12066. LockStore(pOrigStore);
  12067. // Move any remaining contexts in the new store to the original store.
  12068. // Note, append at the end of list and not at the beginning. Another
  12069. // thread might have been enumerating the store. Its better to find
  12070. // 2 copies of a renewed context instead of none.
  12071. for (i = 0; i < CONTEXT_COUNT; i++) {
  12072. PCONTEXT_ELEMENT pNewEle;
  12073. if (pNewEle = pNewStore->rgpContextListHead[i]) {
  12074. PCONTEXT_ELEMENT pOrigEle;
  12075. dwOutFlags |= ICERT_SYNC_STORE_CHANGED_OUT_FLAG;
  12076. if (pOrigEle = pOrigStore->rgpContextListHead[i]) {
  12077. // Append at end of original store
  12078. while (pOrigEle->pNext)
  12079. pOrigEle = pOrigEle->pNext;
  12080. pOrigEle->pNext = pNewEle;
  12081. pNewEle->pPrev = pOrigEle;
  12082. } else {
  12083. // New entries in original store
  12084. pOrigStore->rgpContextListHead[i] = pNewEle;
  12085. pNewEle->pPrev = NULL;
  12086. }
  12087. for ( ; pNewEle; pNewEle = pNewEle->pNext) {
  12088. // Update the elements obtained from the new store to
  12089. // point to the original store
  12090. pNewEle->pStore = pOrigStore;
  12091. pNewEle->pProvStore = pOrigStore;
  12092. SetStoreHandle(pNewEle);
  12093. }
  12094. // No contexts remain in new store
  12095. pNewStore->rgpContextListHead[i] = NULL;
  12096. }
  12097. }
  12098. UnlockStore(pOrigStore);
  12099. // Delete any contexts in the deferred delete list from the original store
  12100. while (cDeleteList--)
  12101. DeleteContextElement(ppDeleteList[cDeleteList]);
  12102. PkiFree(ppDeleteList);
  12103. if (pdwOutFlags)
  12104. *pdwOutFlags = dwOutFlags;
  12105. return TRUE;
  12106. }
  12107. //+-------------------------------------------------------------------------
  12108. // Synchronize the original store with the new store.
  12109. //
  12110. // Assumptions: Both are cache stores. The new store is temporary
  12111. // and local to the caller. The new store's contexts can be deleted or
  12112. // moved to the original store.
  12113. //--------------------------------------------------------------------------
  12114. BOOL
  12115. WINAPI
  12116. I_CertSyncStore(
  12117. IN OUT HCERTSTORE hOriginalStore,
  12118. IN OUT HCERTSTORE hNewStore
  12119. )
  12120. {
  12121. return I_CertSyncStoreEx(
  12122. hOriginalStore,
  12123. hNewStore,
  12124. 0, // dwInFlags
  12125. NULL, // pdwOutFlags
  12126. NULL // pvReserved
  12127. );
  12128. }
  12129. //+-------------------------------------------------------------------------
  12130. // Update the original store with contexts from the new store.
  12131. //
  12132. // Assumptions: Both are cache stores. The new store is temporary
  12133. // and local to the caller. The new store's contexts can be deleted or
  12134. // moved to the original store.
  12135. //--------------------------------------------------------------------------
  12136. BOOL
  12137. WINAPI
  12138. I_CertUpdateStore(
  12139. IN OUT HCERTSTORE hOriginalStore,
  12140. IN OUT HCERTSTORE hNewStore,
  12141. IN DWORD dwReserved,
  12142. IN OUT void *pvReserved
  12143. )
  12144. {
  12145. PCERT_STORE pOrigStore = (PCERT_STORE) hOriginalStore;
  12146. PCERT_STORE pNewStore = (PCERT_STORE) hNewStore;
  12147. DWORD i;
  12148. assert(STORE_TYPE_CACHE == pOrigStore->dwStoreType &&
  12149. STORE_TYPE_CACHE == pNewStore->dwStoreType);
  12150. if (STORE_TYPE_CACHE != pOrigStore->dwStoreType ||
  12151. STORE_TYPE_CACHE != pNewStore->dwStoreType) {
  12152. SetLastError((DWORD) E_INVALIDARG);
  12153. return FALSE;
  12154. }
  12155. LockStore(pOrigStore);
  12156. // Move contexts in the new store to the original store.
  12157. for (i = 0; i < CONTEXT_COUNT; i++) {
  12158. PCONTEXT_ELEMENT pNewEle;
  12159. if (pNewEle = pNewStore->rgpContextListHead[i]) {
  12160. PCONTEXT_ELEMENT pNewTailEle = NULL;
  12161. PCONTEXT_ELEMENT pOrigEle;
  12162. PCONTEXT_ELEMENT pEle;
  12163. for (pEle = pNewEle ; pEle; pEle = pEle->pNext) {
  12164. // Update the elements obtained from the new store to
  12165. // point to the original store
  12166. pEle->pStore = pOrigStore;
  12167. pEle->pProvStore = pOrigStore;
  12168. SetStoreHandle(pEle);
  12169. // Remember the last element in the linked list
  12170. pNewTailEle = pEle;
  12171. }
  12172. assert(pNewTailEle);
  12173. assert(NULL == pNewEle->pPrev);
  12174. assert(NULL == pNewTailEle->pNext);
  12175. // Insert new store's linked list of contexts at the
  12176. // beginning of the original store
  12177. if (pOrigEle = pOrigStore->rgpContextListHead[i]) {
  12178. assert(NULL == pOrigEle->pPrev);
  12179. pOrigEle->pPrev = pNewTailEle;
  12180. pNewTailEle->pNext = pOrigEle;
  12181. }
  12182. pOrigStore->rgpContextListHead[i] = pNewEle;
  12183. // No contexts remain in new store
  12184. pNewStore->rgpContextListHead[i] = NULL;
  12185. }
  12186. }
  12187. UnlockStore(pOrigStore);
  12188. return TRUE;
  12189. }
  12190. //+=========================================================================
  12191. // SortedCTL APIs.
  12192. //==========================================================================
  12193. static const BYTE rgbSeqTag[] = {ASN1UTIL_TAG_SEQ, 0};
  12194. static const BYTE rgbSetTag[] = {ASN1UTIL_TAG_SET, 0};
  12195. static const BYTE rgbOIDTag[] = {ASN1UTIL_TAG_OID, 0};
  12196. static const BYTE rgbIntegerTag[] = {ASN1UTIL_TAG_INTEGER, 0};
  12197. static const BYTE rgbBooleanTag[] = {ASN1UTIL_TAG_BOOLEAN, 0};
  12198. static const BYTE rgbOctetStringTag[] = {ASN1UTIL_TAG_OCTETSTRING, 0};
  12199. static const BYTE rgbConstructedContext0Tag[] =
  12200. {ASN1UTIL_TAG_CONSTRUCTED_CONTEXT_0, 0};
  12201. static const BYTE rgbChoiceOfTimeTag[] =
  12202. {ASN1UTIL_TAG_UTC_TIME, ASN1UTIL_TAG_GENERALIZED_TIME, 0};
  12203. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractCtlPara[] = {
  12204. // 0 - CertificateTrustList ::= SEQUENCE {
  12205. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12206. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  12207. // 1 - version CTLVersion DEFAULT v1,
  12208. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbIntegerTag,
  12209. // 2 - subjectUsage SubjectUsage,
  12210. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag,
  12211. // 3 - listIdentifier ListIdentifier OPTIONAL,
  12212. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbOctetStringTag,
  12213. // 4 - sequenceNumber HUGEINTEGER OPTIONAL,
  12214. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbIntegerTag,
  12215. // 5 - ctlThisUpdate ChoiceOfTime,
  12216. ASN1UTIL_STEP_OVER_VALUE_OP, rgbChoiceOfTimeTag,
  12217. // 6 - ctlNextUpdate ChoiceOfTime OPTIONAL,
  12218. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbChoiceOfTimeTag,
  12219. // 7 - subjectAlgorithm AlgorithmIdentifier,
  12220. ASN1UTIL_RETURN_VALUE_BLOB_FLAG |
  12221. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSeqTag,
  12222. // 8 - trustedSubjects TrustedSubjects OPTIONAL,
  12223. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12224. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbSeqTag,
  12225. // 9 - ctlExtensions [0] EXPLICIT Extensions OPTIONAL
  12226. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12227. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbConstructedContext0Tag,
  12228. };
  12229. #define CTL_SEQ_VALUE_INDEX 0
  12230. #define CTL_SUBJECT_ALG_VALUE_INDEX 7
  12231. #define CTL_SUBJECTS_VALUE_INDEX 8
  12232. #define CTL_EXTENSIONS_VALUE_INDEX 9
  12233. #define CTL_VALUE_COUNT \
  12234. (sizeof(rgExtractCtlPara) / sizeof(rgExtractCtlPara[0]))
  12235. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractExtPara[] = {
  12236. // 0 - Extension ::= SEQUENCE {
  12237. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  12238. // 1 - extnId OBJECT IDENTIFIER,
  12239. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12240. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOIDTag,
  12241. // 2 - critical BOOLEAN DEFAULT FALSE,
  12242. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbBooleanTag,
  12243. // 3 - extnValue OCTETSTRING
  12244. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12245. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOctetStringTag,
  12246. };
  12247. #define EXT_OID_VALUE_INDEX 1
  12248. #define EXT_OCTETS_VALUE_INDEX 3
  12249. #define EXT_VALUE_COUNT \
  12250. (sizeof(rgExtractExtPara) / sizeof(rgExtractExtPara[0]))
  12251. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractTrustedSubjectPara[] = {
  12252. // 0 - TrustedSubject ::= SEQUENCE {
  12253. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  12254. // 1 - subjectIdentifier SubjectIdentifier,
  12255. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12256. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOctetStringTag,
  12257. // 2 - subjectAttributes Attributes OPTIONAL
  12258. ASN1UTIL_RETURN_VALUE_BLOB_FLAG |
  12259. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbSetTag,
  12260. };
  12261. #define TRUSTED_SUBJECT_IDENTIFIER_VALUE_INDEX 1
  12262. #define TRUSTED_SUBJECT_ATTRIBUTES_VALUE_INDEX 2
  12263. #define TRUSTED_SUBJECT_VALUE_COUNT \
  12264. (sizeof(rgExtractTrustedSubjectPara) / \
  12265. sizeof(rgExtractTrustedSubjectPara[0]))
  12266. // same as above, however, return content blob for subjectAttributes instead
  12267. // of its value blob
  12268. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractTrustedSubjectPara2[] = {
  12269. // 0 - TrustedSubject ::= SEQUENCE {
  12270. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  12271. // 1 - subjectIdentifier SubjectIdentifier,
  12272. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12273. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOctetStringTag,
  12274. // 2 - subjectAttributes Attributes OPTIONAL
  12275. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12276. ASN1UTIL_OPTIONAL_STEP_OVER_VALUE_OP, rgbSetTag,
  12277. };
  12278. static const ASN1UTIL_EXTRACT_VALUE_PARA rgExtractAttributePara[] = {
  12279. // 0 - Attribute ::= SEQUENCE {
  12280. ASN1UTIL_STEP_INTO_VALUE_OP, rgbSeqTag,
  12281. // 1 - type
  12282. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12283. ASN1UTIL_STEP_OVER_VALUE_OP, rgbOIDTag,
  12284. // 2 - values AttributeSetValue
  12285. ASN1UTIL_RETURN_CONTENT_BLOB_FLAG |
  12286. ASN1UTIL_STEP_OVER_VALUE_OP, rgbSetTag,
  12287. };
  12288. #define ATTRIBUTE_OID_VALUE_INDEX 1
  12289. #define ATTRIBUTE_VALUES_VALUE_INDEX 2
  12290. #define ATTRIBUTE_VALUE_COUNT \
  12291. (sizeof(rgExtractAttributePara) / sizeof(rgExtractAttributePara[0]))
  12292. static const DWORD rgdwPrime[] = {
  12293. // Bits - cHashBucket
  12294. 1, // 0 - 0x00001 (1)
  12295. 2, // 1 - 0x00002 (2)
  12296. 3, // 2 - 0x00004 (4)
  12297. 7, // 3 - 0x00008 (8)
  12298. 13, // 4 - 0x00010 (16)
  12299. 31, // 5 - 0x00020 (32)
  12300. 61, // 6 - 0x00040 (64)
  12301. 127, // 7 - 0x00080 (128)
  12302. 251, // 8 - 0x00100 (256)
  12303. 509, // 9 - 0x00200 (512)
  12304. 1021, // 10 - 0x00400 (1024)
  12305. 2039, // 11 - 0x00800 (2048)
  12306. 4093, // 12 - 0x01000 (4096)
  12307. 8191, // 13 - 0x02000 (8192)
  12308. 16381, // 14 - 0x04000 (16384)
  12309. 32749, // 15 - 0x08000 (32768)
  12310. 65521, // 16 - 0x10000 (65536)
  12311. };
  12312. #define MIN_HASH_BUCKET_BITS 6
  12313. #define MIN_HASH_BUCKET_COUNT (1 << MIN_HASH_BUCKET_BITS)
  12314. #define MAX_HASH_BUCKET_BITS 16
  12315. #define MAX_HASH_BUCKET_COUNT (1 << MAX_HASH_BUCKET_BITS)
  12316. #define DEFAULT_BYTES_PER_CTL_ENTRY 100
  12317. #define DEFAULT_CTL_ENTRY_COUNT 256
  12318. STATIC DWORD GetHashBucketCount(
  12319. IN DWORD cCtlEntry
  12320. )
  12321. {
  12322. DWORD cBits;
  12323. if (MAX_HASH_BUCKET_COUNT <= cCtlEntry)
  12324. cBits = MAX_HASH_BUCKET_BITS;
  12325. else {
  12326. DWORD cHashBucket = MIN_HASH_BUCKET_COUNT;
  12327. cBits = MIN_HASH_BUCKET_BITS;
  12328. while (cCtlEntry > cHashBucket) {
  12329. cHashBucket = cHashBucket << 1;
  12330. cBits++;
  12331. }
  12332. assert(cBits <= MAX_HASH_BUCKET_BITS);
  12333. }
  12334. return rgdwPrime[cBits];
  12335. }
  12336. STATIC DWORD GetHashBucketIndex(
  12337. IN DWORD cHashBucket,
  12338. IN BOOL fHashedIdentifier,
  12339. IN const CRYPT_DATA_BLOB *pIdentifier
  12340. )
  12341. {
  12342. DWORD dwIndex;
  12343. const BYTE *pb = pIdentifier->pbData;
  12344. DWORD cb = pIdentifier->cbData;
  12345. if (fHashedIdentifier) {
  12346. if (4 <= cb)
  12347. memcpy(&dwIndex, pb, 4);
  12348. else
  12349. dwIndex = 0;
  12350. } else {
  12351. dwIndex = 0;
  12352. while (cb--) {
  12353. if (dwIndex & 0x80000000)
  12354. dwIndex = (dwIndex << 1) | 1;
  12355. else
  12356. dwIndex = dwIndex << 1;
  12357. dwIndex += *pb++;
  12358. }
  12359. }
  12360. if (0 == cHashBucket)
  12361. return 0;
  12362. else
  12363. return dwIndex % cHashBucket;
  12364. }
  12365. // #define szOID_CTL "1.3.6.1.4.1.311.10.1"
  12366. static const BYTE rgbOIDCtl[] =
  12367. {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0A, 0x01};
  12368. static const CRYPT_DER_BLOB EncodedOIDCtl = {
  12369. sizeof(rgbOIDCtl), (BYTE *) rgbOIDCtl
  12370. };
  12371. // #define szOID_SORTED_CTL "1.3.6.1.4.1.311.10.1.1"
  12372. static const BYTE rgbOIDSortedCtlExt[] =
  12373. {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x0A, 0x01, 0x01};
  12374. static const CRYPT_DER_BLOB EncodedOIDSortedCtlExt = {
  12375. sizeof(rgbOIDSortedCtlExt), (BYTE *) rgbOIDSortedCtlExt
  12376. };
  12377. // The encoded OID only includes the content octets. Excludes the tag and
  12378. // length octets.
  12379. STATIC BOOL CompareEncodedOID(
  12380. IN const CRYPT_DER_BLOB *pEncodedOID1,
  12381. IN const CRYPT_DER_BLOB *pEncodedOID2
  12382. )
  12383. {
  12384. if (pEncodedOID1->cbData == pEncodedOID2->cbData &&
  12385. 0 == memcmp(pEncodedOID1->pbData, pEncodedOID2->pbData,
  12386. pEncodedOID1->cbData))
  12387. return TRUE;
  12388. else
  12389. return FALSE;
  12390. }
  12391. STATIC BOOL ExtractSortedCtlExtValue(
  12392. IN const CRYPT_DER_BLOB rgCtlValueBlob[CTL_VALUE_COUNT],
  12393. OUT const BYTE **ppbSortedCtlExtValue,
  12394. OUT DWORD *pcbSortedCtlExtValue,
  12395. OUT const BYTE **ppbRemainExt,
  12396. OUT DWORD *pcbRemainExt
  12397. )
  12398. {
  12399. BOOL fResult;
  12400. const BYTE *pbEncodedExtensions;
  12401. DWORD cbEncodedExtensions;
  12402. const BYTE *pbEncodedSortedCtlExt;
  12403. DWORD cbEncodedSortedCtlExt;
  12404. DWORD cValue;
  12405. CRYPT_DER_BLOB rgValueBlob[EXT_VALUE_COUNT];
  12406. LONG lSkipped;
  12407. // Following points to the outer Extensions sequence
  12408. pbEncodedExtensions = rgCtlValueBlob[CTL_EXTENSIONS_VALUE_INDEX].pbData;
  12409. cbEncodedExtensions = rgCtlValueBlob[CTL_EXTENSIONS_VALUE_INDEX].cbData;
  12410. if (0 == cbEncodedExtensions)
  12411. goto NoExtensions;
  12412. // Step into the Extension sequence and get pointer to the first extension.
  12413. // The returned cbEncodedSortedCtlExt includes all of the
  12414. // extensions in the sequence.
  12415. if (0 >= (lSkipped = Asn1UtilExtractContent(
  12416. pbEncodedExtensions,
  12417. cbEncodedExtensions,
  12418. &cbEncodedSortedCtlExt,
  12419. &pbEncodedSortedCtlExt
  12420. )) || CMSG_INDEFINITE_LENGTH == cbEncodedSortedCtlExt ||
  12421. (DWORD) lSkipped + cbEncodedSortedCtlExt !=
  12422. cbEncodedExtensions)
  12423. goto InvalidExtensions;
  12424. // Decode the first extension
  12425. cValue = EXT_VALUE_COUNT;
  12426. if (0 >= (lSkipped = Asn1UtilExtractValues(
  12427. pbEncodedSortedCtlExt,
  12428. cbEncodedSortedCtlExt,
  12429. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  12430. &cValue,
  12431. rgExtractExtPara,
  12432. rgValueBlob
  12433. )))
  12434. goto ExtractValuesError;
  12435. // Check that the first extension is the SortedCtl extension
  12436. if (!CompareEncodedOID(
  12437. &rgValueBlob[EXT_OID_VALUE_INDEX],
  12438. &EncodedOIDSortedCtlExt
  12439. ))
  12440. goto NoSortedCtlExtension;
  12441. *ppbSortedCtlExtValue = rgValueBlob[EXT_OCTETS_VALUE_INDEX].pbData;
  12442. *pcbSortedCtlExtValue = rgValueBlob[EXT_OCTETS_VALUE_INDEX].cbData;
  12443. *ppbRemainExt = pbEncodedSortedCtlExt + lSkipped;
  12444. *pcbRemainExt = cbEncodedSortedCtlExt - lSkipped;
  12445. fResult = TRUE;
  12446. CommonReturn:
  12447. return fResult;
  12448. ErrorReturn:
  12449. *ppbSortedCtlExtValue = NULL;
  12450. *pcbSortedCtlExtValue = 0;
  12451. *ppbRemainExt = NULL;
  12452. *pcbRemainExt = 0;
  12453. fResult = FALSE;
  12454. goto CommonReturn;
  12455. SET_ERROR(NoExtensions, ERROR_INVALID_DATA)
  12456. SET_ERROR(InvalidExtensions, ERROR_INVALID_DATA)
  12457. TRACE_ERROR(ExtractValuesError)
  12458. SET_ERROR(NoSortedCtlExtension, ERROR_INVALID_DATA)
  12459. }
  12460. BOOL
  12461. WINAPI
  12462. SortedCtlInfoEncodeEx(
  12463. IN DWORD dwCertEncodingType,
  12464. IN LPCSTR lpszStructType,
  12465. IN PCTL_INFO pOrigCtlInfo,
  12466. IN DWORD dwFlags,
  12467. IN OPTIONAL PCRYPT_ENCODE_PARA pEncodePara,
  12468. OUT OPTIONAL void *pvEncoded,
  12469. IN OUT DWORD *pcbEncoded
  12470. )
  12471. {
  12472. BOOL fResult;
  12473. PCTL_INFO pSortedCtlInfo = NULL;
  12474. BYTE *pbEncoded = NULL;
  12475. DWORD cbEncoded;
  12476. DWORD cCtlEntry;
  12477. PCTL_ENTRY pSortedCtlEntry = NULL;
  12478. DWORD cHashBucket = 0;
  12479. PHASH_BUCKET_ENTRY *ppHashBucketHead = NULL;
  12480. PHASH_BUCKET_ENTRY pHashBucketEntry = NULL;
  12481. DWORD cSortedExtension;
  12482. PCERT_EXTENSION pSortedExtension = NULL;
  12483. BYTE *pbSortedCtlExtValue = NULL;
  12484. DWORD cbSortedCtlExtValue = 0;
  12485. if (0 == (dwFlags & CRYPT_ENCODE_ALLOC_FLAG))
  12486. goto InvalidArg;
  12487. // Make a copy of the CtlInfo. We're going to re-order the CTL entries
  12488. // and insert a szOID_SORTED_CTL extension.
  12489. if (NULL == (pSortedCtlInfo = (PCTL_INFO) PkiNonzeroAlloc(
  12490. sizeof(CTL_INFO))))
  12491. goto OutOfMemory;
  12492. memcpy(pSortedCtlInfo, pOrigCtlInfo, sizeof(CTL_INFO));
  12493. cCtlEntry = pSortedCtlInfo->cCTLEntry;
  12494. if (0 < cCtlEntry) {
  12495. DWORD i;
  12496. DWORD j;
  12497. PCTL_ENTRY pCtlEntry;
  12498. DWORD cOrigExtension;
  12499. PCERT_EXTENSION pOrigExtension;
  12500. BOOL fHashedIdentifier =
  12501. dwFlags & CRYPT_SORTED_CTL_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;
  12502. DWORD dwSortedCtlExtFlags = fHashedIdentifier ?
  12503. SORTED_CTL_EXT_HASHED_SUBJECT_IDENTIFIER_FLAG : 0;
  12504. DWORD dwMaxCollision = 0;
  12505. cHashBucket = GetHashBucketCount(cCtlEntry);
  12506. if (NULL == (ppHashBucketHead = (PHASH_BUCKET_ENTRY *) PkiZeroAlloc(
  12507. sizeof(PHASH_BUCKET_ENTRY) * cHashBucket)))
  12508. goto OutOfMemory;
  12509. if (NULL == (pHashBucketEntry = (PHASH_BUCKET_ENTRY) PkiNonzeroAlloc(
  12510. sizeof(HASH_BUCKET_ENTRY) * cCtlEntry)))
  12511. goto OutOfMemory;
  12512. // Iterate through the CTL entries and add to the appropriate
  12513. // hash bucket.
  12514. pCtlEntry = pSortedCtlInfo->rgCTLEntry;
  12515. for (i = 0; i < cCtlEntry; i++) {
  12516. DWORD HashBucketIndex;
  12517. HashBucketIndex = GetHashBucketIndex(
  12518. cHashBucket,
  12519. fHashedIdentifier,
  12520. &pCtlEntry[i].SubjectIdentifier
  12521. );
  12522. pHashBucketEntry[i].dwEntryIndex = i;
  12523. pHashBucketEntry[i].pNext = ppHashBucketHead[HashBucketIndex];
  12524. ppHashBucketHead[HashBucketIndex] = &pHashBucketEntry[i];
  12525. }
  12526. // Sort the entries according to the HashBucket order
  12527. if (NULL == (pSortedCtlEntry = (PCTL_ENTRY) PkiNonzeroAlloc(
  12528. sizeof(CTL_ENTRY) * cCtlEntry)))
  12529. goto OutOfMemory;
  12530. j = 0;
  12531. for (i = 0; i < cHashBucket; i++) {
  12532. DWORD dwCollision = 0;
  12533. PHASH_BUCKET_ENTRY p;
  12534. for (p = ppHashBucketHead[i]; p; p = p->pNext) {
  12535. pSortedCtlEntry[j++] = pCtlEntry[p->dwEntryIndex];
  12536. dwCollision++;
  12537. }
  12538. if (dwCollision > dwMaxCollision)
  12539. dwMaxCollision = dwCollision;
  12540. }
  12541. #if DBG
  12542. DbgPrintf(DBG_SS_CRYPT32,
  12543. "SortedCtlInfoEncodeEx:: cHashBucket: %d MaxCollision: %d Flags:: 0x%x\n",
  12544. cHashBucket, dwMaxCollision, dwSortedCtlExtFlags);
  12545. #endif
  12546. assert(j == cCtlEntry);
  12547. pSortedCtlInfo->rgCTLEntry = pSortedCtlEntry;
  12548. // Insert a SortedCtl extension
  12549. cOrigExtension = pSortedCtlInfo->cExtension;
  12550. pOrigExtension = pSortedCtlInfo->rgExtension;
  12551. // Check if the first extension is the SortedCtl extension
  12552. if (cOrigExtension && 0 == strcmp(pOrigExtension[0].pszObjId,
  12553. szOID_SORTED_CTL)) {
  12554. cOrigExtension--;
  12555. pOrigExtension++;
  12556. }
  12557. cSortedExtension = cOrigExtension + 1;
  12558. if (NULL == (pSortedExtension = (PCERT_EXTENSION) PkiNonzeroAlloc(
  12559. sizeof(CERT_EXTENSION) * cSortedExtension)))
  12560. goto OutOfMemory;
  12561. if (cOrigExtension)
  12562. memcpy(&pSortedExtension[1], pOrigExtension,
  12563. sizeof(CERT_EXTENSION) * cOrigExtension);
  12564. cbSortedCtlExtValue = SORTED_CTL_EXT_HASH_BUCKET_OFFSET +
  12565. sizeof(DWORD) * (cHashBucket + 1);
  12566. if (NULL == (pbSortedCtlExtValue = (BYTE *) PkiNonzeroAlloc(
  12567. cbSortedCtlExtValue)))
  12568. goto OutOfMemory;
  12569. memcpy(pbSortedCtlExtValue + SORTED_CTL_EXT_FLAGS_OFFSET,
  12570. &dwSortedCtlExtFlags, sizeof(DWORD));
  12571. memcpy(pbSortedCtlExtValue + SORTED_CTL_EXT_COUNT_OFFSET,
  12572. &cHashBucket, sizeof(DWORD));
  12573. memcpy(pbSortedCtlExtValue + SORTED_CTL_EXT_MAX_COLLISION_OFFSET,
  12574. &dwMaxCollision, sizeof(DWORD));
  12575. pSortedExtension[0].pszObjId = szOID_SORTED_CTL;
  12576. pSortedExtension[0].fCritical = FALSE;
  12577. pSortedExtension[0].Value.pbData = pbSortedCtlExtValue;
  12578. pSortedExtension[0].Value.cbData = cbSortedCtlExtValue;
  12579. pSortedCtlInfo->cExtension = cSortedExtension;
  12580. pSortedCtlInfo->rgExtension = pSortedExtension;
  12581. }
  12582. if (!CryptEncodeObjectEx(
  12583. dwCertEncodingType,
  12584. PKCS_CTL,
  12585. pSortedCtlInfo,
  12586. dwFlags,
  12587. pEncodePara,
  12588. (void *) &pbEncoded,
  12589. &cbEncoded
  12590. ))
  12591. goto CtlInfoEncodeError;
  12592. if (0 < cCtlEntry) {
  12593. // Update the SortedCtl extension's array of hash bucket offsets
  12594. // First, extract values for the encoded sequence of subjects
  12595. // and extensions.
  12596. DWORD i;
  12597. DWORD cCtlValue;
  12598. CRYPT_DER_BLOB rgCtlValueBlob[CTL_VALUE_COUNT];
  12599. const BYTE *pbEncodedSubject;
  12600. DWORD cbEncodedSubject;
  12601. const BYTE *pbEncodedSortedCtlExtValue;
  12602. DWORD cbEncodedSortedCtlExtValue;
  12603. const BYTE *pbRemainExt;
  12604. DWORD cbRemainExt;
  12605. BYTE *pbEncodedHashBucketOffset;
  12606. DWORD dwEncodedHashBucketOffset;
  12607. cCtlValue = CTL_VALUE_COUNT;
  12608. if (0 >= Asn1UtilExtractValues(
  12609. pbEncoded,
  12610. cbEncoded,
  12611. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  12612. &cCtlValue,
  12613. rgExtractCtlPara,
  12614. rgCtlValueBlob
  12615. ))
  12616. goto ExtractCtlValuesError;
  12617. pbEncodedSubject = rgCtlValueBlob[CTL_SUBJECTS_VALUE_INDEX].pbData;
  12618. cbEncodedSubject = rgCtlValueBlob[CTL_SUBJECTS_VALUE_INDEX].cbData;
  12619. assert(pbEncodedSubject > pbEncoded);
  12620. assert(cbEncodedSubject);
  12621. assert(rgCtlValueBlob[CTL_EXTENSIONS_VALUE_INDEX].pbData);
  12622. if (!ExtractSortedCtlExtValue(
  12623. rgCtlValueBlob,
  12624. &pbEncodedSortedCtlExtValue,
  12625. &cbEncodedSortedCtlExtValue,
  12626. &pbRemainExt,
  12627. &cbRemainExt
  12628. ))
  12629. goto ExtractSortedCtlExtValueError;
  12630. assert(cbEncodedSortedCtlExtValue == cbSortedCtlExtValue);
  12631. pbEncodedHashBucketOffset = (BYTE *) pbEncodedSortedCtlExtValue +
  12632. SORTED_CTL_EXT_HASH_BUCKET_OFFSET;
  12633. for (i = 0; i < cHashBucket; i++) {
  12634. PHASH_BUCKET_ENTRY p;
  12635. dwEncodedHashBucketOffset = (DWORD)(pbEncodedSubject - pbEncoded);
  12636. memcpy(pbEncodedHashBucketOffset, &dwEncodedHashBucketOffset,
  12637. sizeof(DWORD));
  12638. pbEncodedHashBucketOffset += sizeof(DWORD);
  12639. // Advance through the encoded subjects for the current
  12640. // hash bucket index
  12641. for (p = ppHashBucketHead[i]; p; p = p->pNext) {
  12642. LONG lTagLength;
  12643. DWORD cbContent;
  12644. const BYTE *pbContent;
  12645. DWORD cbSubject;
  12646. lTagLength = Asn1UtilExtractContent(
  12647. pbEncodedSubject,
  12648. cbEncodedSubject,
  12649. &cbContent,
  12650. &pbContent
  12651. );
  12652. assert(lTagLength > 0 && CMSG_INDEFINITE_LENGTH != cbContent);
  12653. cbSubject = cbContent + lTagLength;
  12654. assert(cbEncodedSubject >= cbSubject);
  12655. pbEncodedSubject += cbSubject;
  12656. cbEncodedSubject -= cbSubject;
  12657. }
  12658. }
  12659. assert(0 == cbEncodedSubject);
  12660. assert(pbEncodedSubject ==
  12661. rgCtlValueBlob[CTL_SUBJECTS_VALUE_INDEX].pbData +
  12662. rgCtlValueBlob[CTL_SUBJECTS_VALUE_INDEX].cbData);
  12663. assert(pbEncodedHashBucketOffset + sizeof(DWORD) ==
  12664. pbEncodedSortedCtlExtValue + cbEncodedSortedCtlExtValue);
  12665. dwEncodedHashBucketOffset = (DWORD)(pbEncodedSubject - pbEncoded);
  12666. memcpy(pbEncodedHashBucketOffset, &dwEncodedHashBucketOffset,
  12667. sizeof(DWORD));
  12668. }
  12669. *((BYTE **) pvEncoded) = pbEncoded;
  12670. *pcbEncoded = cbEncoded;
  12671. fResult = TRUE;
  12672. CommonReturn:
  12673. PkiFree(pSortedCtlInfo);
  12674. PkiFree(pSortedCtlEntry);
  12675. PkiFree(ppHashBucketHead);
  12676. PkiFree(pHashBucketEntry);
  12677. PkiFree(pSortedExtension);
  12678. PkiFree(pbSortedCtlExtValue);
  12679. return fResult;
  12680. ErrorReturn:
  12681. if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) {
  12682. if (pbEncoded) {
  12683. PFN_CRYPT_FREE pfnFree = PkiGetEncodeFreeFunction(pEncodePara);
  12684. pfnFree(pbEncoded);
  12685. }
  12686. *((BYTE **) pvEncoded) = NULL;
  12687. }
  12688. *pcbEncoded = 0;
  12689. fResult = FALSE;
  12690. goto CommonReturn;
  12691. SET_ERROR(InvalidArg, E_INVALIDARG)
  12692. TRACE_ERROR(OutOfMemory)
  12693. TRACE_ERROR(CtlInfoEncodeError)
  12694. TRACE_ERROR(ExtractCtlValuesError)
  12695. TRACE_ERROR(ExtractSortedCtlExtValueError)
  12696. }
  12697. STATIC BOOL CreateSortedCtlHashBuckets(
  12698. IN OUT PSORTED_CTL_FIND_INFO pSortedCtlFindInfo
  12699. )
  12700. {
  12701. BOOL fResult;
  12702. DWORD cHashBucket;
  12703. DWORD *pdwHashBucketHead = NULL;
  12704. PHASH_BUCKET_ENTRY pHashBucketEntry = NULL;
  12705. DWORD cAllocEntry = 0;
  12706. DWORD cEntry = 0;
  12707. const BYTE *pbEncoded;
  12708. DWORD cbEncoded;
  12709. #if DBG
  12710. DWORD dwMaxCollision = 0;
  12711. #endif
  12712. DWORD dwExceptionCode;
  12713. // Handle MappedFile Exceptions
  12714. __try {
  12715. pbEncoded = pSortedCtlFindInfo->pbEncodedSubjects;
  12716. cbEncoded = pSortedCtlFindInfo->cbEncodedSubjects;
  12717. cHashBucket = GetHashBucketCount(cbEncoded / DEFAULT_BYTES_PER_CTL_ENTRY);
  12718. if (NULL == (pdwHashBucketHead = (DWORD *) PkiZeroAlloc(
  12719. sizeof(DWORD) * cHashBucket)))
  12720. goto OutOfMemory;
  12721. // Loop through the encoded trusted subjects. For each subject, create
  12722. // hash bucket entry, calculate hash bucket index and insert.
  12723. while (cbEncoded) {
  12724. DWORD cValue;
  12725. LONG lAllValues;
  12726. DWORD HashBucketIndex;
  12727. CRYPT_DER_BLOB rgValueBlob[TRUSTED_SUBJECT_VALUE_COUNT];
  12728. cValue = TRUSTED_SUBJECT_VALUE_COUNT;
  12729. if (0 >= (lAllValues = Asn1UtilExtractValues(
  12730. pbEncoded,
  12731. cbEncoded,
  12732. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  12733. &cValue,
  12734. rgExtractTrustedSubjectPara,
  12735. rgValueBlob
  12736. )))
  12737. goto ExtractValuesError;
  12738. if (cEntry == cAllocEntry) {
  12739. PHASH_BUCKET_ENTRY pNewHashBucketEntry;
  12740. cAllocEntry += DEFAULT_CTL_ENTRY_COUNT;
  12741. if (NULL == (pNewHashBucketEntry = (PHASH_BUCKET_ENTRY) PkiRealloc(
  12742. pHashBucketEntry, sizeof(HASH_BUCKET_ENTRY) * cAllocEntry)))
  12743. goto OutOfMemory;
  12744. pHashBucketEntry = pNewHashBucketEntry;
  12745. }
  12746. if (0 == cEntry)
  12747. // Entry[0] is used to indicate no entries for the indexed
  12748. // HashBucket
  12749. cEntry++;
  12750. HashBucketIndex = GetHashBucketIndex(
  12751. cHashBucket,
  12752. FALSE, // fHashedIdentifier,
  12753. &rgValueBlob[TRUSTED_SUBJECT_IDENTIFIER_VALUE_INDEX]
  12754. );
  12755. #if DBG
  12756. {
  12757. DWORD dwEntryIndex = pdwHashBucketHead[HashBucketIndex];
  12758. DWORD dwCollision = 1;
  12759. while (dwEntryIndex) {
  12760. dwCollision++;
  12761. dwEntryIndex = pHashBucketEntry[dwEntryIndex].iNext;
  12762. }
  12763. if (dwCollision > dwMaxCollision)
  12764. dwMaxCollision = dwCollision;
  12765. }
  12766. #endif
  12767. pHashBucketEntry[cEntry].iNext = pdwHashBucketHead[HashBucketIndex];
  12768. pHashBucketEntry[cEntry].pbEntry = pbEncoded;
  12769. pdwHashBucketHead[HashBucketIndex] = cEntry;
  12770. cEntry++;
  12771. cbEncoded -= lAllValues;
  12772. pbEncoded += lAllValues;
  12773. }
  12774. } __except(EXCEPTION_EXECUTE_HANDLER) {
  12775. dwExceptionCode = GetExceptionCode();
  12776. goto ExceptionError;
  12777. }
  12778. #if DBG
  12779. DbgPrintf(DBG_SS_CRYPT32,
  12780. "CreateSortedCtlHashBuckets:: cEntry: %d cHashBucket: %d MaxCollision: %d\n",
  12781. cEntry, cHashBucket, dwMaxCollision);
  12782. #endif
  12783. pSortedCtlFindInfo->cHashBucket = cHashBucket;
  12784. pSortedCtlFindInfo->pdwHashBucketHead = pdwHashBucketHead;
  12785. pSortedCtlFindInfo->pHashBucketEntry = pHashBucketEntry;
  12786. fResult = TRUE;
  12787. CommonReturn:
  12788. return fResult;
  12789. ErrorReturn:
  12790. PkiFree(pdwHashBucketHead);
  12791. PkiFree(pHashBucketEntry);
  12792. fResult = FALSE;
  12793. goto CommonReturn;
  12794. TRACE_ERROR(ExtractValuesError)
  12795. TRACE_ERROR(OutOfMemory)
  12796. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  12797. }
  12798. STATIC BOOL FastDecodeCtlSubjects(
  12799. IN const BYTE *pbEncodedSubjects,
  12800. IN DWORD cbEncodedSubjects,
  12801. OUT DWORD *pcCTLEntry,
  12802. OUT PCTL_ENTRY *ppCTLEntry
  12803. )
  12804. {
  12805. BOOL fResult;
  12806. PCTL_ENTRY pAllocEntry = NULL;
  12807. DWORD cAllocEntry;
  12808. DWORD cbAllocEntry;
  12809. DWORD cEntry = 0;
  12810. PCTL_ENTRY pEntry;
  12811. DWORD cbEntryEncoded;
  12812. const BYTE *pbEntryEncoded;
  12813. DWORD cAttr = 0;
  12814. PCRYPT_ATTRIBUTE pAttr;
  12815. DWORD cAttrValue = 0;
  12816. PCRYPT_ATTR_BLOB pAttrValue;
  12817. DWORD cValue;
  12818. LONG lAllValues;
  12819. DWORD dwExceptionCode;
  12820. // Handle MappedFile Exceptions
  12821. __try {
  12822. // First: Loop through the encoded trusted subjects. Get total count of
  12823. // Entries, Attributes and Values.
  12824. cbEntryEncoded = cbEncodedSubjects;
  12825. pbEntryEncoded = pbEncodedSubjects;
  12826. while (cbEntryEncoded) {
  12827. CRYPT_DER_BLOB rgEntryValueBlob[TRUSTED_SUBJECT_VALUE_COUNT];
  12828. DWORD cbAttrEncoded;
  12829. const BYTE *pbAttrEncoded;
  12830. cValue = TRUSTED_SUBJECT_VALUE_COUNT;
  12831. if (0 >= (lAllValues = Asn1UtilExtractValues(
  12832. pbEntryEncoded,
  12833. cbEntryEncoded,
  12834. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  12835. &cValue,
  12836. rgExtractTrustedSubjectPara2,
  12837. rgEntryValueBlob
  12838. )))
  12839. goto ExtractEntryError;
  12840. cEntry++;
  12841. cbEntryEncoded -= lAllValues;
  12842. pbEntryEncoded += lAllValues;
  12843. cbAttrEncoded =
  12844. rgEntryValueBlob[TRUSTED_SUBJECT_ATTRIBUTES_VALUE_INDEX].cbData;
  12845. pbAttrEncoded =
  12846. rgEntryValueBlob[TRUSTED_SUBJECT_ATTRIBUTES_VALUE_INDEX].pbData;
  12847. while (cbAttrEncoded) {
  12848. CRYPT_DER_BLOB rgAttrValueBlob[ATTRIBUTE_VALUE_COUNT];
  12849. DWORD cbAttrValueEncoded;
  12850. const BYTE *pbAttrValueEncoded;
  12851. cValue = ATTRIBUTE_VALUE_COUNT;
  12852. if (0 >= (lAllValues = Asn1UtilExtractValues(
  12853. pbAttrEncoded,
  12854. cbAttrEncoded,
  12855. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  12856. &cValue,
  12857. rgExtractAttributePara,
  12858. rgAttrValueBlob
  12859. )))
  12860. goto ExtractAttrError;
  12861. cAttr++;
  12862. cbAttrEncoded -= lAllValues;
  12863. pbAttrEncoded += lAllValues;
  12864. cbAttrValueEncoded =
  12865. rgAttrValueBlob[ATTRIBUTE_VALUES_VALUE_INDEX].cbData;
  12866. pbAttrValueEncoded =
  12867. rgAttrValueBlob[ATTRIBUTE_VALUES_VALUE_INDEX].pbData;
  12868. while (cbAttrValueEncoded) {
  12869. LONG lTagLength;
  12870. DWORD cbAttrValue;
  12871. const BYTE *pbContent;
  12872. lTagLength = Asn1UtilExtractContent(
  12873. pbAttrValueEncoded,
  12874. cbAttrValueEncoded,
  12875. &cbAttrValue,
  12876. &pbContent
  12877. );
  12878. if (0 >= lTagLength ||
  12879. CMSG_INDEFINITE_LENGTH == cbAttrValue)
  12880. goto ExtractValueError;
  12881. cbAttrValue += (DWORD) lTagLength;
  12882. if (cbAttrValue > cbAttrValueEncoded)
  12883. goto ExtractValueError;
  12884. cAttrValue++;
  12885. cbAttrValueEncoded -= cbAttrValue;
  12886. pbAttrValueEncoded += cbAttrValue;
  12887. }
  12888. }
  12889. }
  12890. cAllocEntry = cEntry;
  12891. if (0 == cEntry)
  12892. goto SuccessReturn;
  12893. cbAllocEntry = cEntry * sizeof(CTL_ENTRY) +
  12894. cAttr * sizeof(CRYPT_ATTRIBUTE) +
  12895. cAttrValue * sizeof(CRYPT_ATTR_BLOB);
  12896. if (NULL == (pAllocEntry = (PCTL_ENTRY) PkiZeroAlloc(cbAllocEntry)))
  12897. goto OutOfMemory;
  12898. pEntry = pAllocEntry;
  12899. pAttr = (PCRYPT_ATTRIBUTE) (pEntry + cEntry);
  12900. pAttrValue = (PCRYPT_ATTR_BLOB) (pAttr + cAttr);
  12901. // Second: Loop through the encoded trusted subjects. Update the
  12902. // allocated Entries, Attributes and Values data structures
  12903. cbEntryEncoded = cbEncodedSubjects;
  12904. pbEntryEncoded = pbEncodedSubjects;
  12905. while (cbEntryEncoded) {
  12906. CRYPT_DER_BLOB rgEntryValueBlob[TRUSTED_SUBJECT_VALUE_COUNT];
  12907. DWORD cbAttrEncoded;
  12908. const BYTE *pbAttrEncoded;
  12909. cValue = TRUSTED_SUBJECT_VALUE_COUNT;
  12910. if (0 >= (lAllValues = Asn1UtilExtractValues(
  12911. pbEntryEncoded,
  12912. cbEntryEncoded,
  12913. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  12914. &cValue,
  12915. rgExtractTrustedSubjectPara2,
  12916. rgEntryValueBlob
  12917. )))
  12918. goto ExtractEntryError;
  12919. cbEntryEncoded -= lAllValues;
  12920. pbEntryEncoded += lAllValues;
  12921. assert(0 != cEntry);
  12922. if (0 == cEntry--)
  12923. goto InvalidCountError;
  12924. pEntry->SubjectIdentifier =
  12925. rgEntryValueBlob[TRUSTED_SUBJECT_IDENTIFIER_VALUE_INDEX];
  12926. cbAttrEncoded =
  12927. rgEntryValueBlob[TRUSTED_SUBJECT_ATTRIBUTES_VALUE_INDEX].cbData;
  12928. pbAttrEncoded =
  12929. rgEntryValueBlob[TRUSTED_SUBJECT_ATTRIBUTES_VALUE_INDEX].pbData;
  12930. while (cbAttrEncoded) {
  12931. CRYPT_DER_BLOB rgAttrValueBlob[ATTRIBUTE_VALUE_COUNT];
  12932. DWORD cbAttrValueEncoded;
  12933. const BYTE *pbAttrValueEncoded;
  12934. ASN1encodedOID_t EncodedOid;
  12935. BYTE *pbExtra;
  12936. LONG lRemainExtra;
  12937. cValue = ATTRIBUTE_VALUE_COUNT;
  12938. if (0 >= (lAllValues = Asn1UtilExtractValues(
  12939. pbAttrEncoded,
  12940. cbAttrEncoded,
  12941. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  12942. &cValue,
  12943. rgExtractAttributePara,
  12944. rgAttrValueBlob
  12945. )))
  12946. goto ExtractAttrError;
  12947. cbAttrEncoded -= lAllValues;
  12948. pbAttrEncoded += lAllValues;
  12949. assert(0 != cAttr);
  12950. if (0 == cAttr--)
  12951. goto InvalidCountError;
  12952. if (0 == pEntry->cAttribute) {
  12953. pEntry->cAttribute = 1;
  12954. pEntry->rgAttribute = pAttr;
  12955. } else
  12956. pEntry->cAttribute++;
  12957. EncodedOid.length = (ASN1uint16_t)
  12958. rgAttrValueBlob[ATTRIBUTE_OID_VALUE_INDEX].cbData;
  12959. EncodedOid.value =
  12960. rgAttrValueBlob[ATTRIBUTE_OID_VALUE_INDEX].pbData;
  12961. pbExtra = NULL;
  12962. lRemainExtra = 0;
  12963. I_CryptGetEncodedOID(
  12964. &EncodedOid,
  12965. CRYPT_DECODE_SHARE_OID_STRING_FLAG,
  12966. &pAttr->pszObjId,
  12967. &pbExtra,
  12968. &lRemainExtra
  12969. );
  12970. cbAttrValueEncoded =
  12971. rgAttrValueBlob[ATTRIBUTE_VALUES_VALUE_INDEX].cbData;
  12972. pbAttrValueEncoded =
  12973. rgAttrValueBlob[ATTRIBUTE_VALUES_VALUE_INDEX].pbData;
  12974. while (cbAttrValueEncoded) {
  12975. LONG lTagLength;
  12976. DWORD cbAttrValue;
  12977. const BYTE *pbContent;
  12978. lTagLength = Asn1UtilExtractContent(
  12979. pbAttrValueEncoded,
  12980. cbAttrValueEncoded,
  12981. &cbAttrValue,
  12982. &pbContent
  12983. );
  12984. if (0 >= lTagLength ||
  12985. CMSG_INDEFINITE_LENGTH == cbAttrValue)
  12986. goto ExtractValueError;
  12987. cbAttrValue += (DWORD) lTagLength;
  12988. if (cbAttrValue > cbAttrValueEncoded)
  12989. goto ExtractValueError;
  12990. assert(0 != cAttrValue);
  12991. if (0 == cAttrValue--)
  12992. goto InvalidCountError;
  12993. if (0 == pAttr->cValue) {
  12994. pAttr->cValue = 1;
  12995. pAttr->rgValue = pAttrValue;
  12996. } else
  12997. pAttr->cValue++;
  12998. pAttrValue->cbData = cbAttrValue;
  12999. pAttrValue->pbData = (BYTE *) pbAttrValueEncoded;
  13000. pAttrValue++;
  13001. cbAttrValueEncoded -= cbAttrValue;
  13002. pbAttrValueEncoded += cbAttrValue;
  13003. }
  13004. pAttr++;
  13005. }
  13006. pEntry++;
  13007. }
  13008. assert(0 == cEntry && 0 == cAttr && 0 == cAttrValue);
  13009. } __except(EXCEPTION_EXECUTE_HANDLER) {
  13010. dwExceptionCode = GetExceptionCode();
  13011. goto ExceptionError;
  13012. }
  13013. SuccessReturn:
  13014. fResult = TRUE;
  13015. CommonReturn:
  13016. *pcCTLEntry = cAllocEntry;
  13017. *ppCTLEntry = pAllocEntry;
  13018. return fResult;
  13019. ErrorReturn:
  13020. PkiFree(pAllocEntry);
  13021. pAllocEntry = NULL;
  13022. cAllocEntry = 0;
  13023. fResult = FALSE;
  13024. goto CommonReturn;
  13025. SET_ERROR(ExtractEntryError, ERROR_INVALID_DATA)
  13026. SET_ERROR(ExtractAttrError, ERROR_INVALID_DATA)
  13027. SET_ERROR(ExtractValueError, ERROR_INVALID_DATA)
  13028. SET_ERROR(InvalidCountError, ERROR_INVALID_DATA)
  13029. TRACE_ERROR(OutOfMemory)
  13030. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  13031. }
  13032. // pbCtlEncoded has already been allocated
  13033. STATIC PCONTEXT_ELEMENT FastCreateCtlElement(
  13034. IN PCERT_STORE pStore,
  13035. IN DWORD dwMsgAndCertEncodingType,
  13036. IN const BYTE *pbCtlEncoded,
  13037. IN DWORD cbCtlEncoded,
  13038. IN OPTIONAL PSHARE_ELEMENT pShareEle,
  13039. IN DWORD dwFlags
  13040. )
  13041. {
  13042. DWORD dwEncodingType;
  13043. const BYTE *pbContent; // not allocated
  13044. DWORD cbContent;
  13045. PCTL_INFO pInfo = NULL;
  13046. PCONTEXT_ELEMENT pEle = NULL;
  13047. PCTL_CONTEXT pCtl;
  13048. PCTL_CONTEXT_SUFFIX pCtlSuffix; // not allocated
  13049. PSORTED_CTL_FIND_INFO pSortedCtlFindInfo; // not allocated
  13050. const BYTE *pbCtlEncodedHdr; // not allocated
  13051. DWORD cbCtlEncodedHdr;
  13052. BYTE *pbCtlReencodedHdr = NULL;
  13053. DWORD cbCtlReencodedHdr;
  13054. DWORD cCtlValue;
  13055. CRYPT_DER_BLOB rgCtlValueBlob[CTL_VALUE_COUNT];
  13056. const BYTE *pbEncodedSubjects; // not allocated
  13057. DWORD cbEncodedSubjects;
  13058. const BYTE *pbSortedCtlExtValue; // not allocated
  13059. DWORD cbSortedCtlExtValue;
  13060. const BYTE *pbRemainExt; // not allocated
  13061. DWORD cbRemainExt;
  13062. PCERT_EXTENSIONS pExtInfo = NULL;
  13063. BYTE *pbAllocReencodedExt = NULL;
  13064. BYTE *pbReencodedExt = NULL; // not allocated
  13065. DWORD cbReencodedExt;
  13066. HCRYPTMSG hMsg = NULL;
  13067. PCTL_ENTRY pCTLEntry = NULL;
  13068. DWORD cCTLEntry;
  13069. DWORD dwExceptionCode;
  13070. // Handle MappedFile Exceptions
  13071. __try {
  13072. if (0 == (dwMsgAndCertEncodingType = GetCtlEncodingType(
  13073. dwMsgAndCertEncodingType)))
  13074. goto InvalidArg;
  13075. // The message encoding type takes precedence
  13076. dwEncodingType = (dwMsgAndCertEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
  13077. // Advance to the encoded CTL_INFO
  13078. if (0 >= Asn1UtilExtractPKCS7SignedDataContent(
  13079. pbCtlEncoded,
  13080. cbCtlEncoded,
  13081. &EncodedOIDCtl,
  13082. &cbContent,
  13083. &pbContent
  13084. ))
  13085. goto ExtractSignedDataContentError;
  13086. if (CMSG_INDEFINITE_LENGTH == cbContent)
  13087. goto UnsupportedIndefiniteLength;
  13088. // Get pointers to the encoded CTL_INFO values
  13089. cCtlValue = CTL_VALUE_COUNT;
  13090. if (0 >= Asn1UtilExtractValues(
  13091. pbContent,
  13092. cbContent,
  13093. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  13094. &cCtlValue,
  13095. rgExtractCtlPara,
  13096. rgCtlValueBlob
  13097. ))
  13098. goto ExtractCtlValuesError;
  13099. pbEncodedSubjects = rgCtlValueBlob[CTL_SUBJECTS_VALUE_INDEX].pbData;
  13100. cbEncodedSubjects = rgCtlValueBlob[CTL_SUBJECTS_VALUE_INDEX].cbData;
  13101. // Initialize pointer to and length of the Extensions sequence
  13102. pbReencodedExt = rgCtlValueBlob[CTL_EXTENSIONS_VALUE_INDEX].pbData;
  13103. cbReencodedExt = rgCtlValueBlob[CTL_EXTENSIONS_VALUE_INDEX].cbData;
  13104. // Get pointer to the first value in the CTL sequence. Get length
  13105. // through the subjectAlgorithm value. Don't include the TrustedSubjects
  13106. // or Extensions.
  13107. pbCtlEncodedHdr = rgCtlValueBlob[CTL_SEQ_VALUE_INDEX].pbData;
  13108. cbCtlEncodedHdr = (DWORD)(rgCtlValueBlob[CTL_SUBJECT_ALG_VALUE_INDEX].pbData +
  13109. rgCtlValueBlob[CTL_SUBJECT_ALG_VALUE_INDEX].cbData -
  13110. pbCtlEncodedHdr);
  13111. // Re-encode the CTL excluding the TrustedSubjects and Extensions.
  13112. // Re-encode the CTL sequence to have an indefinite length and terminated
  13113. // with a NULL tag and length.
  13114. cbCtlReencodedHdr = cbCtlEncodedHdr + 2 + 2;
  13115. if (NULL == (pbCtlReencodedHdr = (BYTE *) PkiNonzeroAlloc(
  13116. cbCtlReencodedHdr)))
  13117. goto OutOfMemory;
  13118. pbCtlReencodedHdr[0] = ASN1UTIL_TAG_SEQ;
  13119. pbCtlReencodedHdr[1] = ASN1UTIL_LENGTH_INDEFINITE;
  13120. memcpy(pbCtlReencodedHdr + 2, pbCtlEncodedHdr, cbCtlEncodedHdr);
  13121. pbCtlReencodedHdr[cbCtlEncodedHdr + 2] = ASN1UTIL_TAG_NULL;
  13122. pbCtlReencodedHdr[cbCtlEncodedHdr + 3] = ASN1UTIL_LENGTH_NULL;
  13123. // Decode CTL_INFO excluding the TrustedSubjects and Extensions
  13124. if (NULL == (pInfo = (PCTL_INFO) AllocAndDecodeObject(
  13125. dwEncodingType,
  13126. PKCS_CTL,
  13127. pbCtlReencodedHdr,
  13128. cbCtlReencodedHdr,
  13129. 0 // dwFlags
  13130. ))) goto DecodeCtlError;
  13131. // Allocate and initialize the CTL element structure
  13132. if (NULL == (pEle = (PCONTEXT_ELEMENT) PkiZeroAlloc(
  13133. sizeof(CONTEXT_ELEMENT) +
  13134. sizeof(CTL_CONTEXT) + sizeof(CTL_CONTEXT_SUFFIX) +
  13135. sizeof(SORTED_CTL_FIND_INFO))))
  13136. goto OutOfMemory;
  13137. pEle->dwElementType = ELEMENT_TYPE_CACHE;
  13138. pEle->dwContextType = CERT_STORE_CTL_CONTEXT - 1;
  13139. pEle->lRefCnt = 1;
  13140. pEle->pEle = pEle;
  13141. pEle->pStore = pStore;
  13142. pEle->pProvStore = pStore;
  13143. pEle->pShareEle = pShareEle;
  13144. pCtl = (PCTL_CONTEXT) ToCtlContext(pEle);
  13145. pCtl->dwMsgAndCertEncodingType =
  13146. dwMsgAndCertEncodingType;
  13147. pCtl->pbCtlEncoded = (BYTE *) pbCtlEncoded;
  13148. pCtl->cbCtlEncoded = cbCtlEncoded;
  13149. pCtl->pCtlInfo = pInfo;
  13150. pCtl->hCertStore = (HCERTSTORE) pStore;
  13151. // pCtl->hCryptMsg = NULL;
  13152. pCtl->pbCtlContent = (BYTE *) pbContent;
  13153. pCtl->cbCtlContent = cbContent;
  13154. pCtlSuffix = ToCtlContextSuffix(pEle);
  13155. // pCtlSuffix->ppSortedEntry = NULL;
  13156. pCtlSuffix->fFastCreate = TRUE;
  13157. if (0 == (dwFlags & CERT_CREATE_CONTEXT_SORTED_FLAG)) {
  13158. if (0 == (dwFlags & CERT_CREATE_CONTEXT_NO_ENTRY_FLAG)) {
  13159. if (!FastDecodeCtlSubjects(
  13160. pbEncodedSubjects,
  13161. cbEncodedSubjects,
  13162. &cCTLEntry,
  13163. &pCTLEntry
  13164. ))
  13165. goto FastDecodeCtlSubjectsError;
  13166. pInfo->cCTLEntry = cCTLEntry;
  13167. pInfo->rgCTLEntry = pCTLEntry;
  13168. pCtlSuffix->pCTLEntry = pCTLEntry;
  13169. }
  13170. if (0 == (dwFlags & CERT_CREATE_CONTEXT_NO_HCRYPTMSG_FLAG)) {
  13171. BOOL fResult;
  13172. DWORD dwLastErr = 0;
  13173. HCRYPTPROV hProv = 0;
  13174. DWORD dwProvFlags = 0;
  13175. // Attempt to get the store's crypt provider. Serialize crypto
  13176. // operations.
  13177. hProv = GetCryptProv(pStore, &dwProvFlags);
  13178. hMsg = CryptMsgOpenToDecode(
  13179. dwMsgAndCertEncodingType,
  13180. 0, // dwFlags
  13181. 0, // dwMsgType
  13182. hProv,
  13183. NULL, // pRecipientInfo
  13184. NULL // pStreamInfo
  13185. );
  13186. if (hMsg && CryptMsgUpdate(
  13187. hMsg,
  13188. pbCtlEncoded,
  13189. cbCtlEncoded,
  13190. TRUE // fFinal
  13191. ))
  13192. fResult = TRUE;
  13193. else {
  13194. fResult = FALSE;
  13195. dwLastErr = GetLastError();
  13196. }
  13197. // For the store's crypt provider, release reference count. Leave
  13198. // crypto operations critical section.
  13199. ReleaseCryptProv(pStore, dwProvFlags);
  13200. if (!fResult) {
  13201. SetLastError(dwLastErr);
  13202. goto MsgError;
  13203. }
  13204. pCtl->hCryptMsg = hMsg;
  13205. }
  13206. } else {
  13207. pSortedCtlFindInfo = (PSORTED_CTL_FIND_INFO) ((BYTE *) pCtlSuffix +
  13208. sizeof(CTL_CONTEXT_SUFFIX));
  13209. pCtlSuffix->pSortedCtlFindInfo = pSortedCtlFindInfo;
  13210. pSortedCtlFindInfo->pbEncodedSubjects = pbEncodedSubjects;
  13211. pSortedCtlFindInfo->cbEncodedSubjects = cbEncodedSubjects;
  13212. // Check if the CTL had the SORTED_CTL extension. If it does, update
  13213. // the find info to point to the extension's hash bucket entry
  13214. // offsets.
  13215. if (ExtractSortedCtlExtValue(
  13216. rgCtlValueBlob,
  13217. &pbSortedCtlExtValue,
  13218. &cbSortedCtlExtValue,
  13219. &pbRemainExt,
  13220. &cbRemainExt
  13221. )) {
  13222. DWORD dwCtlExtFlags;
  13223. if (SORTED_CTL_EXT_HASH_BUCKET_OFFSET > cbSortedCtlExtValue)
  13224. goto InvalidSortedCtlExtension;
  13225. memcpy(&dwCtlExtFlags,
  13226. pbSortedCtlExtValue + SORTED_CTL_EXT_FLAGS_OFFSET,
  13227. sizeof(DWORD));
  13228. pSortedCtlFindInfo->fHashedIdentifier =
  13229. dwCtlExtFlags & SORTED_CTL_EXT_HASHED_SUBJECT_IDENTIFIER_FLAG;
  13230. memcpy(&pSortedCtlFindInfo->cHashBucket,
  13231. pbSortedCtlExtValue + SORTED_CTL_EXT_COUNT_OFFSET,
  13232. sizeof(DWORD));
  13233. pSortedCtlFindInfo->pbEncodedHashBucket =
  13234. pbSortedCtlExtValue + SORTED_CTL_EXT_HASH_BUCKET_OFFSET;
  13235. if (MAX_HASH_BUCKET_COUNT < pSortedCtlFindInfo->cHashBucket ||
  13236. SORTED_CTL_EXT_HASH_BUCKET_OFFSET +
  13237. (pSortedCtlFindInfo->cHashBucket + 1) * sizeof(DWORD) >
  13238. cbSortedCtlExtValue)
  13239. goto InvalidSortedCtlExtension;
  13240. if (0 == cbRemainExt)
  13241. cbReencodedExt = 0;
  13242. else {
  13243. // Reencode the remaining extensions.
  13244. // Re-encode the Extensions sequence to have an indefinite
  13245. // length and terminated with a NULL tag and length.
  13246. cbReencodedExt = cbRemainExt + 2 + 2;
  13247. if (NULL == (pbAllocReencodedExt =
  13248. (BYTE *) PkiNonzeroAlloc(cbReencodedExt)))
  13249. goto OutOfMemory;
  13250. pbReencodedExt = pbAllocReencodedExt;
  13251. pbReencodedExt[0] = ASN1UTIL_TAG_SEQ;
  13252. pbReencodedExt[1] = ASN1UTIL_LENGTH_INDEFINITE;
  13253. memcpy(pbReencodedExt + 2, pbRemainExt, cbRemainExt);
  13254. pbReencodedExt[cbRemainExt + 2] = ASN1UTIL_TAG_NULL;
  13255. pbReencodedExt[cbRemainExt + 3] = ASN1UTIL_LENGTH_NULL;
  13256. }
  13257. } else if (cbEncodedSubjects) {
  13258. if (!CreateSortedCtlHashBuckets(pSortedCtlFindInfo))
  13259. goto CreateSortedCtlHashBucketsError;
  13260. }
  13261. }
  13262. if (cbReencodedExt) {
  13263. if (NULL == (pExtInfo = (PCERT_EXTENSIONS) AllocAndDecodeObject(
  13264. dwEncodingType,
  13265. X509_EXTENSIONS,
  13266. pbReencodedExt,
  13267. cbReencodedExt,
  13268. 0 // dwFlags
  13269. ))) goto DecodeExtError;
  13270. pInfo->cExtension = pExtInfo->cExtension;
  13271. pInfo->rgExtension = pExtInfo->rgExtension;
  13272. pCtlSuffix->pExtInfo = pExtInfo;
  13273. }
  13274. } __except(EXCEPTION_EXECUTE_HANDLER) {
  13275. dwExceptionCode = GetExceptionCode();
  13276. goto ExceptionError;
  13277. }
  13278. if (NULL == pShareEle) {
  13279. CertPerfIncrementCtlElementCurrentCount();
  13280. CertPerfIncrementCtlElementTotalCount();
  13281. }
  13282. CommonReturn:
  13283. PkiFree(pbCtlReencodedHdr);
  13284. PkiFree(pbAllocReencodedExt);
  13285. return pEle;
  13286. ErrorReturn:
  13287. if (hMsg)
  13288. CryptMsgClose(hMsg);
  13289. PkiFree(pInfo);
  13290. PkiFree(pExtInfo);
  13291. PkiFree(pCTLEntry);
  13292. if (pEle) {
  13293. PkiFree(pEle);
  13294. pEle = NULL;
  13295. }
  13296. goto CommonReturn;
  13297. SET_ERROR(InvalidArg, E_INVALIDARG)
  13298. TRACE_ERROR(ExtractSignedDataContentError)
  13299. SET_ERROR(UnsupportedIndefiniteLength, ERROR_INVALID_DATA)
  13300. TRACE_ERROR(ExtractCtlValuesError)
  13301. TRACE_ERROR(OutOfMemory)
  13302. TRACE_ERROR(DecodeCtlError)
  13303. TRACE_ERROR(DecodeExtError)
  13304. SET_ERROR(InvalidSortedCtlExtension, ERROR_INVALID_DATA)
  13305. TRACE_ERROR(CreateSortedCtlHashBucketsError)
  13306. TRACE_ERROR(FastDecodeCtlSubjectsError)
  13307. TRACE_ERROR(MsgError)
  13308. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  13309. }
  13310. //+-------------------------------------------------------------------------
  13311. // Creates the specified context from the encoded bytes. The created
  13312. // context isn't put in a store.
  13313. //
  13314. // dwContextType values:
  13315. // CERT_STORE_CERTIFICATE_CONTEXT
  13316. // CERT_STORE_CRL_CONTEXT
  13317. // CERT_STORE_CTL_CONTEXT
  13318. //
  13319. // If CERT_CREATE_CONTEXT_NOCOPY_FLAG is set, the created context points
  13320. // directly to the pbEncoded instead of an allocated copy. See flag
  13321. // definition for more details.
  13322. //
  13323. // If CERT_CREATE_CONTEXT_SORTED_FLAG is set, the context is created
  13324. // with sorted entries. This flag may only be set for CERT_STORE_CTL_CONTEXT.
  13325. // Setting this flag implicitly sets CERT_CREATE_CONTEXT_NO_HCRYPTMSG_FLAG and
  13326. // CERT_CREATE_CONTEXT_NO_ENTRY_FLAG. See flag definition for
  13327. // more details.
  13328. //
  13329. // If CERT_CREATE_CONTEXT_NO_HCRYPTMSG_FLAG is set, the context is created
  13330. // without creating a HCRYPTMSG handle for the context. This flag may only be
  13331. // set for CERT_STORE_CTL_CONTEXT. See flag definition for more details.
  13332. //
  13333. // If CERT_CREATE_CONTEXT_NO_ENTRY_FLAG is set, the context is created
  13334. // without decoding the entries. This flag may only be set for
  13335. // CERT_STORE_CTL_CONTEXT. See flag definition for more details.
  13336. //
  13337. // If unable to decode and create the context, NULL is returned.
  13338. // Otherwise, a pointer to a read only CERT_CONTEXT, CRL_CONTEXT or
  13339. // CTL_CONTEXT is returned. The context must be freed by the appropriate
  13340. // free context API. The context can be duplicated by calling the
  13341. // appropriate duplicate context API.
  13342. //--------------------------------------------------------------------------
  13343. const void *
  13344. WINAPI
  13345. CertCreateContext(
  13346. IN DWORD dwContextType,
  13347. IN DWORD dwEncodingType,
  13348. IN const BYTE *pbEncoded,
  13349. IN DWORD cbEncoded,
  13350. IN DWORD dwFlags,
  13351. IN OPTIONAL PCERT_CREATE_CONTEXT_PARA pCreatePara
  13352. )
  13353. {
  13354. BYTE *pbAllocEncoded = NULL;
  13355. PCONTEXT_ELEMENT pEle = NULL;
  13356. PCONTEXT_NOCOPY_INFO pNoCopyInfo = NULL;
  13357. PCONTEXT_ELEMENT pStoreEle; // not allocated
  13358. DWORD dwExceptionCode;
  13359. // Handle MappedFile Exceptions
  13360. __try {
  13361. dwContextType--;
  13362. if (CONTEXT_COUNT <= dwContextType)
  13363. goto InvalidContextType;
  13364. if (dwFlags & CERT_CREATE_CONTEXT_NOCOPY_FLAG) {
  13365. if (NULL == (pNoCopyInfo = (PCONTEXT_NOCOPY_INFO) PkiZeroAlloc(
  13366. sizeof(CONTEXT_NOCOPY_INFO))))
  13367. goto OutOfMemory;
  13368. if (pCreatePara && pCreatePara->cbSize >=
  13369. offsetof(CERT_CREATE_CONTEXT_PARA, pfnFree) +
  13370. sizeof(pCreatePara->pfnFree)) {
  13371. pNoCopyInfo->pfnFree = pCreatePara->pfnFree;
  13372. if (pCreatePara->cbSize >=
  13373. offsetof(CERT_CREATE_CONTEXT_PARA, pvFree) +
  13374. sizeof(pCreatePara->pvFree) &&
  13375. pCreatePara->pvFree)
  13376. pNoCopyInfo->pvFree = pCreatePara->pvFree;
  13377. else
  13378. pNoCopyInfo->pvFree = (void *) pbEncoded;
  13379. }
  13380. } else {
  13381. if (NULL == (pbAllocEncoded = (BYTE *) PkiNonzeroAlloc(cbEncoded)))
  13382. goto OutOfMemory;
  13383. memcpy(pbAllocEncoded, pbEncoded, cbEncoded);
  13384. pbEncoded = pbAllocEncoded;
  13385. }
  13386. if (CERT_STORE_CTL_CONTEXT - 1 == dwContextType)
  13387. pEle = FastCreateCtlElement(
  13388. &NullCertStore,
  13389. dwEncodingType,
  13390. pbEncoded,
  13391. cbEncoded,
  13392. NULL, // pShareEle
  13393. dwFlags
  13394. );
  13395. else
  13396. pEle = rgpfnCreateElement[dwContextType](
  13397. &NullCertStore,
  13398. dwEncodingType,
  13399. (BYTE *) pbEncoded,
  13400. cbEncoded,
  13401. NULL // pShareEle
  13402. );
  13403. if (NULL == pEle)
  13404. goto CreateElementError;
  13405. pEle->pNoCopyInfo = pNoCopyInfo;
  13406. if (!AddElementToStore(
  13407. &NullCertStore,
  13408. pEle,
  13409. CERT_STORE_ADD_ALWAYS,
  13410. &pStoreEle
  13411. ))
  13412. goto AddElementError;
  13413. } __except(EXCEPTION_EXECUTE_HANDLER) {
  13414. dwExceptionCode = GetExceptionCode();
  13415. goto ExceptionError;
  13416. }
  13417. CommonReturn:
  13418. // Any To*Context would work
  13419. return ToCertContext(pStoreEle);
  13420. ErrorReturn:
  13421. if (pEle)
  13422. FreeContextElement(pEle);
  13423. else if (pNoCopyInfo) {
  13424. if (pNoCopyInfo->pfnFree)
  13425. pNoCopyInfo->pfnFree(pNoCopyInfo->pvFree);
  13426. PkiFree(pNoCopyInfo);
  13427. } else
  13428. PkiFree(pbAllocEncoded);
  13429. pStoreEle = NULL;
  13430. goto CommonReturn;
  13431. SET_ERROR(InvalidContextType, E_INVALIDARG)
  13432. TRACE_ERROR(OutOfMemory)
  13433. TRACE_ERROR(CreateElementError)
  13434. TRACE_ERROR(AddElementError)
  13435. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  13436. }
  13437. STATIC BOOL IsTrustedSubject(
  13438. IN PCRYPT_DATA_BLOB pSubjectIdentifier,
  13439. IN OUT const BYTE **ppbEncoded,
  13440. IN OUT DWORD *pcbEncoded,
  13441. OUT BOOL *pfTrusted,
  13442. OUT OPTIONAL PCRYPT_DATA_BLOB pEncodedAttributes
  13443. )
  13444. {
  13445. const BYTE *pbEncoded = *ppbEncoded;
  13446. DWORD cbEncoded = *pcbEncoded;
  13447. DWORD cValue;
  13448. LONG lAllValues;
  13449. CRYPT_DER_BLOB rgValueBlob[TRUSTED_SUBJECT_VALUE_COUNT];
  13450. cValue = TRUSTED_SUBJECT_VALUE_COUNT;
  13451. if (0 >= (lAllValues = Asn1UtilExtractValues(
  13452. pbEncoded,
  13453. cbEncoded,
  13454. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  13455. &cValue,
  13456. rgExtractTrustedSubjectPara,
  13457. rgValueBlob
  13458. ))) {
  13459. *pfTrusted = FALSE;
  13460. return FALSE;
  13461. }
  13462. if (pSubjectIdentifier->cbData ==
  13463. rgValueBlob[TRUSTED_SUBJECT_IDENTIFIER_VALUE_INDEX].cbData
  13464. &&
  13465. 0 == memcmp(pSubjectIdentifier->pbData,
  13466. rgValueBlob[
  13467. TRUSTED_SUBJECT_IDENTIFIER_VALUE_INDEX].pbData,
  13468. pSubjectIdentifier->cbData)) {
  13469. *pfTrusted = TRUE;
  13470. if (pEncodedAttributes)
  13471. *pEncodedAttributes =
  13472. rgValueBlob[TRUSTED_SUBJECT_ATTRIBUTES_VALUE_INDEX];
  13473. } else {
  13474. cbEncoded -= lAllValues;
  13475. *pcbEncoded = cbEncoded;
  13476. pbEncoded += lAllValues;
  13477. *ppbEncoded = pbEncoded;
  13478. *pfTrusted = FALSE;
  13479. }
  13480. return TRUE;
  13481. }
  13482. //+-------------------------------------------------------------------------
  13483. // Returns TRUE if the SubjectIdentifier exists in the CTL. Optionally
  13484. // returns a pointer to and byte count of the Subject's encoded attributes.
  13485. //--------------------------------------------------------------------------
  13486. BOOL
  13487. WINAPI
  13488. CertFindSubjectInSortedCTL(
  13489. IN PCRYPT_DATA_BLOB pSubjectIdentifier,
  13490. IN PCCTL_CONTEXT pCtlContext,
  13491. IN DWORD dwFlags,
  13492. IN void *pvReserved,
  13493. OUT OPTIONAL PCRYPT_DER_BLOB pEncodedAttributes
  13494. )
  13495. {
  13496. PCONTEXT_ELEMENT pCacheEle; // not allocated
  13497. PSORTED_CTL_FIND_INFO pSortedCtlFindInfo; // not allocated
  13498. DWORD HashBucketIndex;
  13499. BOOL fTrusted;
  13500. if (NULL == (pCacheEle = GetCacheElement(ToContextElement(pCtlContext))))
  13501. goto NoCacheElementError;
  13502. if (NULL == (pSortedCtlFindInfo =
  13503. ToCtlContextSuffix(pCacheEle)->pSortedCtlFindInfo))
  13504. goto NotSortedCtlContext;
  13505. HashBucketIndex = GetHashBucketIndex(
  13506. pSortedCtlFindInfo->cHashBucket,
  13507. pSortedCtlFindInfo->fHashedIdentifier,
  13508. pSubjectIdentifier
  13509. );
  13510. if (pSortedCtlFindInfo->pbEncodedHashBucket) {
  13511. DWORD dwEntryOffset[2];
  13512. DWORD cbEncoded;
  13513. const BYTE *pbEncoded;
  13514. memcpy(dwEntryOffset, pSortedCtlFindInfo->pbEncodedHashBucket +
  13515. sizeof(DWORD) * HashBucketIndex, sizeof(DWORD) * 2);
  13516. if (dwEntryOffset[1] < dwEntryOffset[0] ||
  13517. dwEntryOffset[1] > pCtlContext->cbCtlContent)
  13518. goto InvalidSortedCtlExtension;
  13519. // Iterate through the encoded TrustedSubjects until a match
  13520. // or reached a TrustedSubject in the next HashBucket.
  13521. cbEncoded = dwEntryOffset[1] - dwEntryOffset[0];
  13522. pbEncoded = pCtlContext->pbCtlContent + dwEntryOffset[0];
  13523. while (cbEncoded) {
  13524. if (!IsTrustedSubject(
  13525. pSubjectIdentifier,
  13526. &pbEncoded,
  13527. &cbEncoded,
  13528. &fTrusted,
  13529. pEncodedAttributes))
  13530. goto IsTrustedSubjectError;
  13531. if (fTrusted)
  13532. goto CommonReturn;
  13533. }
  13534. } else if (pSortedCtlFindInfo->pdwHashBucketHead) {
  13535. DWORD dwEntryIndex;
  13536. dwEntryIndex = pSortedCtlFindInfo->pdwHashBucketHead[HashBucketIndex];
  13537. while (dwEntryIndex) {
  13538. PHASH_BUCKET_ENTRY pHashBucketEntry;
  13539. DWORD cbEncoded;
  13540. const BYTE *pbEncoded;
  13541. pHashBucketEntry =
  13542. &pSortedCtlFindInfo->pHashBucketEntry[dwEntryIndex];
  13543. pbEncoded = pHashBucketEntry->pbEntry;
  13544. assert(pbEncoded >= pSortedCtlFindInfo->pbEncodedSubjects &&
  13545. pbEncoded < pSortedCtlFindInfo->pbEncodedSubjects +
  13546. pSortedCtlFindInfo->cbEncodedSubjects);
  13547. cbEncoded = (DWORD)(pSortedCtlFindInfo->cbEncodedSubjects -
  13548. (pbEncoded - pSortedCtlFindInfo->pbEncodedSubjects));
  13549. assert(cbEncoded);
  13550. if (!IsTrustedSubject(
  13551. pSubjectIdentifier,
  13552. &pbEncoded,
  13553. &cbEncoded,
  13554. &fTrusted,
  13555. pEncodedAttributes))
  13556. goto IsTrustedSubjectError;
  13557. if (fTrusted)
  13558. goto CommonReturn;
  13559. dwEntryIndex = pHashBucketEntry->iNext;
  13560. }
  13561. }
  13562. goto NotFoundError;
  13563. CommonReturn:
  13564. return fTrusted;
  13565. NotFoundError:
  13566. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  13567. ErrorReturn:
  13568. fTrusted = FALSE;
  13569. goto CommonReturn;
  13570. TRACE_ERROR(NoCacheElementError)
  13571. SET_ERROR(NotSortedCtlContext, E_INVALIDARG)
  13572. SET_ERROR(InvalidSortedCtlExtension, ERROR_INVALID_DATA)
  13573. TRACE_ERROR(IsTrustedSubjectError)
  13574. }
  13575. //+-------------------------------------------------------------------------
  13576. // Enumerates through the sequence of TrustedSubjects in a CTL context
  13577. // created with CERT_CREATE_CONTEXT_SORTED_FLAG set.
  13578. //
  13579. // To start the enumeration, *ppvNextSubject must be NULL. Upon return,
  13580. // *ppvNextSubject is updated to point to the next TrustedSubject in
  13581. // the encoded sequence.
  13582. //
  13583. // Returns FALSE for no more subjects or invalid arguments.
  13584. //
  13585. // Note, the returned DER_BLOBs point directly into the encoded
  13586. // bytes (not allocated, and must not be freed).
  13587. //--------------------------------------------------------------------------
  13588. BOOL
  13589. WINAPI
  13590. CertEnumSubjectInSortedCTL(
  13591. IN PCCTL_CONTEXT pCtlContext,
  13592. IN OUT void **ppvNextSubject,
  13593. OUT OPTIONAL PCRYPT_DER_BLOB pSubjectIdentifier,
  13594. OUT OPTIONAL PCRYPT_DER_BLOB pEncodedAttributes
  13595. )
  13596. {
  13597. BOOL fResult;
  13598. PCONTEXT_ELEMENT pCacheEle; // not allocated
  13599. PSORTED_CTL_FIND_INFO pSortedCtlFindInfo; // not allocated
  13600. const BYTE *pbEncodedSubjects;
  13601. const BYTE *pbEncoded;
  13602. DWORD cbEncoded;
  13603. DWORD cValue;
  13604. LONG lAllValues;
  13605. CRYPT_DER_BLOB rgValueBlob[TRUSTED_SUBJECT_VALUE_COUNT];
  13606. if (NULL == (pCacheEle = GetCacheElement(ToContextElement(pCtlContext))))
  13607. goto NoCacheElementError;
  13608. if (NULL == (pSortedCtlFindInfo =
  13609. ToCtlContextSuffix(pCacheEle)->pSortedCtlFindInfo))
  13610. goto NotSortedCtlContext;
  13611. cbEncoded = pSortedCtlFindInfo->cbEncodedSubjects;
  13612. if (0 == cbEncoded)
  13613. goto NotFoundError;
  13614. pbEncodedSubjects = pSortedCtlFindInfo->pbEncodedSubjects;
  13615. pbEncoded = *((const BYTE **) ppvNextSubject);
  13616. if (NULL == pbEncoded)
  13617. pbEncoded = pbEncodedSubjects;
  13618. else if (pbEncoded < pbEncodedSubjects ||
  13619. pbEncoded >= pbEncodedSubjects + cbEncoded)
  13620. goto NotFoundError;
  13621. else
  13622. cbEncoded -= (DWORD)(pbEncoded - pbEncodedSubjects);
  13623. cValue = TRUSTED_SUBJECT_VALUE_COUNT;
  13624. if (0 >= (lAllValues = Asn1UtilExtractValues(
  13625. pbEncoded,
  13626. cbEncoded,
  13627. ASN1UTIL_DEFINITE_LENGTH_FLAG,
  13628. &cValue,
  13629. rgExtractTrustedSubjectPara,
  13630. rgValueBlob
  13631. )))
  13632. goto ExtractValuesError;
  13633. if (pSubjectIdentifier)
  13634. *pSubjectIdentifier =
  13635. rgValueBlob[TRUSTED_SUBJECT_IDENTIFIER_VALUE_INDEX];
  13636. if (pEncodedAttributes)
  13637. *pEncodedAttributes =
  13638. rgValueBlob[TRUSTED_SUBJECT_ATTRIBUTES_VALUE_INDEX];
  13639. pbEncoded += lAllValues;
  13640. *((const BYTE **) ppvNextSubject) = pbEncoded;
  13641. fResult = TRUE;
  13642. CommonReturn:
  13643. return fResult;
  13644. NotFoundError:
  13645. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  13646. ErrorReturn:
  13647. *ppvNextSubject = NULL;
  13648. fResult = FALSE;
  13649. goto CommonReturn;
  13650. TRACE_ERROR(NoCacheElementError)
  13651. SET_ERROR(NotSortedCtlContext, E_INVALIDARG)
  13652. TRACE_ERROR(ExtractValuesError)
  13653. }
  13654. //+=========================================================================
  13655. // Key Identifier Property Functions
  13656. //==========================================================================
  13657. //+-------------------------------------------------------------------------
  13658. // Decode the Key Identifier and its properties.
  13659. //--------------------------------------------------------------------------
  13660. STATIC PKEYID_ELEMENT DecodeKeyIdElement(
  13661. IN const BYTE *pbElement,
  13662. IN DWORD cbElement
  13663. )
  13664. {
  13665. PKEYID_ELEMENT pEle = NULL;
  13666. DWORD csStatus;
  13667. MEMINFO MemInfo;
  13668. MemInfo.pByte = (BYTE *) pbElement;
  13669. MemInfo.cb = cbElement;
  13670. MemInfo.cbSeek = 0;
  13671. csStatus = LoadStoreElement(
  13672. (HANDLE) &MemInfo,
  13673. ReadFromMemory,
  13674. SkipInMemory,
  13675. cbElement,
  13676. NULL, // pStore
  13677. 0, // dwAddDisposition
  13678. 0, // dwContextTypeFlags
  13679. NULL, // pdwContextType
  13680. (const void **) &pEle,
  13681. TRUE // fKeyIdAllowed
  13682. );
  13683. if (NULL == pEle && CSError != csStatus)
  13684. SetLastError((DWORD) CRYPT_E_FILE_ERROR);
  13685. return pEle;
  13686. }
  13687. STATIC BOOL SerializeKeyIdElement(
  13688. IN HANDLE h,
  13689. IN PFNWRITE pfn,
  13690. IN PKEYID_ELEMENT pEle
  13691. )
  13692. {
  13693. BOOL fResult;
  13694. PPROP_ELEMENT pPropEle;
  13695. for (pPropEle = pEle->pPropHead; pPropEle; pPropEle = pPropEle->pNext) {
  13696. if (pPropEle->dwPropId != CERT_KEY_CONTEXT_PROP_ID) {
  13697. if (!WriteStoreElement(
  13698. h,
  13699. pfn,
  13700. 0, // dwEncodingType
  13701. pPropEle->dwPropId,
  13702. pPropEle->pbData,
  13703. pPropEle->cbData
  13704. ))
  13705. goto WriteElementError;
  13706. }
  13707. }
  13708. if (!WriteStoreElement(
  13709. h,
  13710. pfn,
  13711. 0, // dwEncodingType
  13712. FILE_ELEMENT_KEYID_TYPE,
  13713. pEle->KeyIdentifier.pbData,
  13714. pEle->KeyIdentifier.cbData
  13715. ))
  13716. goto WriteElementError;
  13717. fResult = TRUE;
  13718. CommonReturn:
  13719. return fResult;
  13720. ErrorReturn:
  13721. fResult = FALSE;
  13722. goto CommonReturn;
  13723. TRACE_ERROR(WriteElementError);
  13724. }
  13725. //+-------------------------------------------------------------------------
  13726. // Encode the Key Identifier and its properties.
  13727. //--------------------------------------------------------------------------
  13728. STATIC BOOL EncodeKeyIdElement(
  13729. IN PKEYID_ELEMENT pEle,
  13730. OUT BYTE **ppbElement,
  13731. OUT DWORD *pcbElement
  13732. )
  13733. {
  13734. BOOL fResult;
  13735. MEMINFO MemInfo;
  13736. BYTE *pbElement = NULL;
  13737. DWORD cbElement = 0;
  13738. memset(&MemInfo, 0, sizeof(MemInfo));
  13739. if (!SerializeKeyIdElement(
  13740. (HANDLE) &MemInfo,
  13741. WriteToMemory,
  13742. pEle
  13743. ))
  13744. goto SerializeKeyIdElementError;
  13745. cbElement = MemInfo.cbSeek;
  13746. if (NULL == (pbElement = (BYTE *) PkiNonzeroAlloc(cbElement)))
  13747. goto OutOfMemory;
  13748. MemInfo.pByte = pbElement;
  13749. MemInfo.cb = cbElement;
  13750. MemInfo.cbSeek = 0;
  13751. if (!SerializeKeyIdElement(
  13752. (HANDLE) &MemInfo,
  13753. WriteToMemory,
  13754. pEle
  13755. ))
  13756. goto SerializeKeyIdElementError;
  13757. fResult = TRUE;
  13758. CommonReturn:
  13759. *ppbElement = pbElement;
  13760. *pcbElement = cbElement;
  13761. return fResult;
  13762. ErrorReturn:
  13763. PkiFree(pbElement);
  13764. pbElement = NULL;
  13765. cbElement = 0;
  13766. fResult = FALSE;
  13767. goto CommonReturn;
  13768. TRACE_ERROR(SerializeKeyIdElementError)
  13769. TRACE_ERROR(OutOfMemory)
  13770. }
  13771. //+-------------------------------------------------------------------------
  13772. // Get the property for the specified Key Identifier.
  13773. //
  13774. // The Key Identifier is the SHA1 hash of the encoded CERT_PUBLIC_KEY_INFO.
  13775. // The Key Identifier for a certificate can be obtained by getting the
  13776. // certificate's CERT_KEY_IDENTIFIER_PROP_ID. The
  13777. // CryptCreateKeyIdentifierFromCSP API can be called to create the Key
  13778. // Identifier from a CSP Public Key Blob.
  13779. //
  13780. // A Key Identifier can have the same properties as a certificate context.
  13781. // CERT_KEY_PROV_INFO_PROP_ID is the property of most interest.
  13782. // For CERT_KEY_PROV_INFO_PROP_ID, pvData points to a CRYPT_KEY_PROV_INFO
  13783. // structure. Elements pointed to by fields in the pvData structure follow the
  13784. // structure. Therefore, *pcbData will exceed the size of the structure.
  13785. //
  13786. // If CRYPT_KEYID_ALLOC_FLAG is set, then, *pvData is updated with a
  13787. // pointer to allocated memory. LocalFree() must be called to free the
  13788. // allocated memory.
  13789. //
  13790. // By default, searches the CurrentUser's list of Key Identifiers.
  13791. // CRYPT_KEYID_MACHINE_FLAG can be set to search the LocalMachine's list
  13792. // of Key Identifiers. When CRYPT_KEYID_MACHINE_FLAG is set, pwszComputerName
  13793. // can also be set to specify the name of a remote computer to be searched
  13794. // instead of the local machine.
  13795. //--------------------------------------------------------------------------
  13796. BOOL
  13797. WINAPI
  13798. CryptGetKeyIdentifierProperty(
  13799. IN const CRYPT_HASH_BLOB *pKeyIdentifier,
  13800. IN DWORD dwPropId,
  13801. IN DWORD dwFlags,
  13802. IN OPTIONAL LPCWSTR pwszComputerName,
  13803. IN OPTIONAL void *pvReserved,
  13804. OUT void *pvData,
  13805. IN OUT DWORD *pcbData
  13806. )
  13807. {
  13808. BOOL fResult;
  13809. BYTE *pbElement = NULL;
  13810. DWORD cbElement = 0;
  13811. PKEYID_ELEMENT pKeyIdEle = NULL;
  13812. if (!ILS_ReadKeyIdElement(
  13813. pKeyIdentifier,
  13814. dwFlags & CRYPT_KEYID_MACHINE_FLAG ? TRUE : FALSE,
  13815. pwszComputerName,
  13816. &pbElement,
  13817. &cbElement
  13818. ))
  13819. goto ReadKeyIdElementError;
  13820. if (NULL == (pKeyIdEle = DecodeKeyIdElement(
  13821. pbElement,
  13822. cbElement
  13823. )))
  13824. goto DecodeKeyIdElementError;
  13825. fResult = GetCallerProperty(
  13826. pKeyIdEle->pPropHead,
  13827. dwPropId,
  13828. dwFlags & CRYPT_KEYID_ALLOC_FLAG ? TRUE : FALSE,
  13829. pvData,
  13830. pcbData
  13831. );
  13832. CommonReturn:
  13833. FreeKeyIdElement(pKeyIdEle);
  13834. PkiFree(pbElement);
  13835. return fResult;
  13836. ErrorReturn:
  13837. if (dwFlags & CRYPT_KEYID_ALLOC_FLAG)
  13838. *((void **) pvData) = NULL;
  13839. *pcbData = 0;
  13840. fResult = FALSE;
  13841. goto CommonReturn;
  13842. TRACE_ERROR(ReadKeyIdElementError)
  13843. TRACE_ERROR(DecodeKeyIdElementError)
  13844. }
  13845. //+-------------------------------------------------------------------------
  13846. // Set the property for the specified Key Identifier.
  13847. //
  13848. // For CERT_KEY_PROV_INFO_PROP_ID pvData points to the
  13849. // CRYPT_KEY_PROV_INFO data structure. For all other properties, pvData
  13850. // points to a CRYPT_DATA_BLOB.
  13851. //
  13852. // Setting pvData == NULL, deletes the property.
  13853. //
  13854. // Set CRYPT_KEYID_MACHINE_FLAG to set the property for a LocalMachine
  13855. // Key Identifier. Set pwszComputerName, to select a remote computer.
  13856. //
  13857. // If CRYPT_KEYID_DELETE_FLAG is set, the Key Identifier and all its
  13858. // properties is deleted.
  13859. //
  13860. // If CRYPT_KEYID_SET_NEW_FLAG is set, the set fails if the property already
  13861. // exists. For an existing property, FALSE is returned with LastError set to
  13862. // CRYPT_E_EXISTS.
  13863. //--------------------------------------------------------------------------
  13864. BOOL
  13865. WINAPI
  13866. CryptSetKeyIdentifierProperty(
  13867. IN const CRYPT_HASH_BLOB *pKeyIdentifier,
  13868. IN DWORD dwPropId,
  13869. IN DWORD dwFlags,
  13870. IN OPTIONAL LPCWSTR pwszComputerName,
  13871. IN OPTIONAL void *pvReserved,
  13872. IN const void *pvData
  13873. )
  13874. {
  13875. BOOL fResult;
  13876. BYTE *pbElement = NULL;
  13877. DWORD cbElement = 0;
  13878. PKEYID_ELEMENT pKeyIdEle = NULL;
  13879. if (dwFlags & CRYPT_KEYID_DELETE_FLAG) {
  13880. return ILS_DeleteKeyIdElement(
  13881. pKeyIdentifier,
  13882. dwFlags & CRYPT_KEYID_MACHINE_FLAG ? TRUE : FALSE,
  13883. pwszComputerName
  13884. );
  13885. }
  13886. if (!ILS_ReadKeyIdElement(
  13887. pKeyIdentifier,
  13888. dwFlags & CRYPT_KEYID_MACHINE_FLAG ? TRUE : FALSE,
  13889. pwszComputerName,
  13890. &pbElement,
  13891. &cbElement
  13892. )) {
  13893. if (ERROR_FILE_NOT_FOUND != GetLastError())
  13894. goto ReadKeyIdElementError;
  13895. }
  13896. if (NULL == pbElement) {
  13897. BYTE *pbKeyIdEncoded;
  13898. if (NULL == (pbKeyIdEncoded = (BYTE *) PkiNonzeroAlloc(
  13899. pKeyIdentifier->cbData)))
  13900. goto OutOfMemory;
  13901. if (NULL == (pKeyIdEle = CreateKeyIdElement(
  13902. pbKeyIdEncoded,
  13903. pKeyIdentifier->cbData
  13904. )))
  13905. goto OutOfMemory;
  13906. } else {
  13907. if (NULL == (pKeyIdEle = DecodeKeyIdElement(
  13908. pbElement,
  13909. cbElement
  13910. )))
  13911. goto DecodeKeyIdElementError;
  13912. }
  13913. if (dwFlags & CRYPT_KEYID_SET_NEW_FLAG) {
  13914. if (FindPropElement(pKeyIdEle->pPropHead, dwPropId))
  13915. goto KeyIdExists;
  13916. }
  13917. if (!SetCallerProperty(
  13918. &pKeyIdEle->pPropHead,
  13919. dwPropId,
  13920. dwFlags,
  13921. pvData
  13922. ))
  13923. goto SetCallerPropertyError;
  13924. PkiFree(pbElement);
  13925. pbElement = NULL;
  13926. if (!EncodeKeyIdElement(
  13927. pKeyIdEle,
  13928. &pbElement,
  13929. &cbElement
  13930. ))
  13931. goto EncodeKeyIdElementError;
  13932. if (!ILS_WriteKeyIdElement(
  13933. pKeyIdentifier,
  13934. dwFlags & CRYPT_KEYID_MACHINE_FLAG ? TRUE : FALSE,
  13935. pwszComputerName,
  13936. pbElement,
  13937. cbElement
  13938. ))
  13939. goto WriteKeyIdElementError;
  13940. fResult = TRUE;
  13941. CommonReturn:
  13942. FreeKeyIdElement(pKeyIdEle);
  13943. PkiFree(pbElement);
  13944. return fResult;
  13945. ErrorReturn:
  13946. fResult = FALSE;
  13947. goto CommonReturn;
  13948. TRACE_ERROR(ReadKeyIdElementError)
  13949. TRACE_ERROR(OutOfMemory)
  13950. SET_ERROR(KeyIdExists, CRYPT_E_EXISTS)
  13951. TRACE_ERROR(DecodeKeyIdElementError)
  13952. TRACE_ERROR(SetCallerPropertyError)
  13953. TRACE_ERROR(EncodeKeyIdElementError)
  13954. TRACE_ERROR(WriteKeyIdElementError)
  13955. }
  13956. typedef struct _KEYID_ELEMENT_CALLBACK_ARG {
  13957. DWORD dwPropId;
  13958. DWORD dwFlags;
  13959. void *pvArg;
  13960. PFN_CRYPT_ENUM_KEYID_PROP pfnEnum;
  13961. } KEYID_ELEMENT_CALLBACK_ARG, *PKEYID_ELEMENT_CALLBACK_ARG;
  13962. STATIC BOOL KeyIdElementCallback(
  13963. IN const CRYPT_HASH_BLOB *pKeyIdentifier,
  13964. IN const BYTE *pbElement,
  13965. IN DWORD cbElement,
  13966. IN void *pvArg
  13967. )
  13968. {
  13969. BOOL fResult = TRUE;
  13970. PKEYID_ELEMENT_CALLBACK_ARG pKeyIdArg =
  13971. (PKEYID_ELEMENT_CALLBACK_ARG) pvArg;
  13972. PKEYID_ELEMENT pKeyIdEle = NULL;
  13973. PPROP_ELEMENT pPropEle;
  13974. DWORD iProp;
  13975. DWORD cProp = 0;
  13976. DWORD *pdwPropId = NULL;
  13977. void **ppvData = NULL;
  13978. DWORD *pcbData = NULL;
  13979. if (NULL == (pKeyIdEle = DecodeKeyIdElement(
  13980. pbElement,
  13981. cbElement
  13982. )))
  13983. goto DecodeKeyIdElementError;
  13984. // Get number of properties
  13985. cProp = 0;
  13986. pPropEle = pKeyIdEle->pPropHead;
  13987. for ( ; pPropEle; pPropEle = pPropEle->pNext) {
  13988. if (pKeyIdArg->dwPropId) {
  13989. if (pKeyIdArg->dwPropId == pPropEle->dwPropId) {
  13990. cProp = 1;
  13991. break;
  13992. }
  13993. } else
  13994. cProp++;
  13995. }
  13996. if (0 == cProp) {
  13997. if (0 == pKeyIdArg->dwPropId)
  13998. fResult = pKeyIdArg->pfnEnum(
  13999. pKeyIdentifier,
  14000. 0, // dwFlags
  14001. NULL, // pvReserved
  14002. pKeyIdArg->pvArg,
  14003. 0, // cProp
  14004. NULL, // rgdwPropId
  14005. NULL, // rgpvData
  14006. NULL // rgcbData
  14007. );
  14008. } else {
  14009. pdwPropId = (DWORD *) PkiZeroAlloc(cProp * sizeof(DWORD));
  14010. ppvData = (void **) PkiZeroAlloc(cProp * sizeof(void *));
  14011. pcbData = (DWORD *) PkiZeroAlloc(cProp * sizeof(DWORD));
  14012. if (NULL == pdwPropId || NULL == ppvData || NULL == pcbData)
  14013. goto OutOfMemory;
  14014. iProp = 0;
  14015. pPropEle = pKeyIdEle->pPropHead;
  14016. for ( ; pPropEle; pPropEle = pPropEle->pNext) {
  14017. if (pKeyIdArg->dwPropId &&
  14018. pKeyIdArg->dwPropId != pPropEle->dwPropId)
  14019. continue;
  14020. if (GetCallerProperty(
  14021. pPropEle,
  14022. pPropEle->dwPropId,
  14023. TRUE, // fAlloc
  14024. (void *) &ppvData[iProp],
  14025. &pcbData[iProp]
  14026. )) {
  14027. pdwPropId[iProp] = pPropEle->dwPropId;
  14028. iProp++;
  14029. if (iProp == cProp)
  14030. break;
  14031. }
  14032. }
  14033. if (0 == iProp)
  14034. goto CommonReturn;
  14035. fResult = pKeyIdArg->pfnEnum(
  14036. pKeyIdentifier,
  14037. 0, // dwFlags
  14038. NULL, // pvReserved
  14039. pKeyIdArg->pvArg,
  14040. iProp,
  14041. pdwPropId,
  14042. ppvData,
  14043. pcbData
  14044. );
  14045. }
  14046. CommonReturn:
  14047. FreeKeyIdElement(pKeyIdEle);
  14048. if (ppvData) {
  14049. while (cProp--)
  14050. PkiDefaultCryptFree(ppvData[cProp]);
  14051. PkiFree(ppvData);
  14052. }
  14053. PkiFree(pdwPropId);
  14054. PkiFree(pcbData);
  14055. return fResult;
  14056. ErrorReturn:
  14057. goto CommonReturn;
  14058. TRACE_ERROR(DecodeKeyIdElementError)
  14059. TRACE_ERROR(OutOfMemory)
  14060. }
  14061. //+-------------------------------------------------------------------------
  14062. // Enumerate the Key Identifiers.
  14063. //
  14064. // If pKeyIdentifier is NULL, enumerates all Key Identifers. Otherwise,
  14065. // calls the callback for the specified KeyIdentifier. If dwPropId is
  14066. // 0, calls the callback with all the properties. Otherwise, only calls
  14067. // the callback with the specified property (cProp = 1).
  14068. // Furthermore, when dwPropId is specified, skips KeyIdentifiers not
  14069. // having the property.
  14070. //
  14071. // Set CRYPT_KEYID_MACHINE_FLAG to enumerate the LocalMachine
  14072. // Key Identifiers. Set pwszComputerName, to enumerate Key Identifiers on
  14073. // a remote computer.
  14074. //--------------------------------------------------------------------------
  14075. BOOL
  14076. WINAPI
  14077. CryptEnumKeyIdentifierProperties(
  14078. IN OPTIONAL const CRYPT_HASH_BLOB *pKeyIdentifier,
  14079. IN DWORD dwPropId,
  14080. IN DWORD dwFlags,
  14081. IN OPTIONAL LPCWSTR pwszComputerName,
  14082. IN OPTIONAL void *pvReserved,
  14083. IN OPTIONAL void *pvArg,
  14084. IN PFN_CRYPT_ENUM_KEYID_PROP pfnEnum
  14085. )
  14086. {
  14087. BOOL fResult;
  14088. KEYID_ELEMENT_CALLBACK_ARG KeyIdArg =
  14089. { dwPropId, dwFlags, pvArg, pfnEnum };
  14090. if (pKeyIdentifier) {
  14091. BYTE *pbElement = NULL;
  14092. DWORD cbElement;
  14093. fResult = ILS_ReadKeyIdElement(
  14094. pKeyIdentifier,
  14095. dwFlags & CRYPT_KEYID_MACHINE_FLAG ? TRUE : FALSE,
  14096. pwszComputerName,
  14097. &pbElement,
  14098. &cbElement
  14099. );
  14100. if (fResult)
  14101. fResult = KeyIdElementCallback(
  14102. pKeyIdentifier,
  14103. pbElement,
  14104. cbElement,
  14105. (void *) &KeyIdArg
  14106. );
  14107. PkiFree(pbElement);
  14108. } else
  14109. fResult = ILS_OpenAllKeyIdElements(
  14110. dwFlags & CRYPT_KEYID_MACHINE_FLAG ? TRUE : FALSE,
  14111. pwszComputerName,
  14112. (void *) &KeyIdArg,
  14113. KeyIdElementCallback
  14114. );
  14115. return fResult;
  14116. }
  14117. //+-------------------------------------------------------------------------
  14118. // For either the CERT_KEY_IDENTIFIER_PROP_ID or CERT_KEY_PROV_INFO_PROP_ID
  14119. // set the Crypt KeyIdentifier CERT_KEY_PROV_INFO_PROP_ID property if the
  14120. // other property already exists.
  14121. //
  14122. // If dwPropId == 0, does an implicit GetProperty(KEY_PROV_INFO)
  14123. //--------------------------------------------------------------------------
  14124. STATIC void SetCryptKeyIdentifierKeyProvInfoProperty(
  14125. IN PCONTEXT_ELEMENT pEle,
  14126. IN DWORD dwPropId, // may be 0
  14127. IN const void *pvData
  14128. )
  14129. {
  14130. PCRYPT_HASH_BLOB pKeyIdentifier = NULL;
  14131. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  14132. DWORD cbKeyProvInfo;
  14133. void *pvOtherData = NULL;
  14134. DWORD cbOtherData;
  14135. CRYPT_HASH_BLOB OtherKeyIdentifier;
  14136. if ((CERT_STORE_CERTIFICATE_CONTEXT - 1) != pEle->dwContextType)
  14137. return;
  14138. if (0 == dwPropId) {
  14139. if (AllocAndGetProperty(
  14140. pEle,
  14141. CERT_KEY_PROV_INFO_PROP_ID,
  14142. (void **) &pKeyProvInfo,
  14143. &cbKeyProvInfo
  14144. ) && cbKeyProvInfo) {
  14145. SetCryptKeyIdentifierKeyProvInfoProperty(
  14146. pEle,
  14147. CERT_KEY_PROV_INFO_PROP_ID,
  14148. pKeyProvInfo
  14149. );
  14150. PkiFree(pKeyProvInfo);
  14151. }
  14152. return;
  14153. } else if (NULL == pvData)
  14154. return;
  14155. switch (dwPropId) {
  14156. case CERT_KEY_IDENTIFIER_PROP_ID:
  14157. AllocAndGetProperty(
  14158. pEle,
  14159. CERT_KEY_PROV_INFO_PROP_ID,
  14160. &pvOtherData,
  14161. &cbOtherData
  14162. );
  14163. if (pvOtherData) {
  14164. pKeyIdentifier = (PCRYPT_HASH_BLOB) pvData;
  14165. pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) pvOtherData;
  14166. }
  14167. break;
  14168. case CERT_KEY_PROV_INFO_PROP_ID:
  14169. AllocAndGetProperty(
  14170. pEle,
  14171. CERT_KEY_IDENTIFIER_PROP_ID,
  14172. &pvOtherData,
  14173. &cbOtherData
  14174. );
  14175. if (pvOtherData) {
  14176. pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) pvData;
  14177. OtherKeyIdentifier.cbData = cbOtherData;
  14178. OtherKeyIdentifier.pbData = (BYTE *)pvOtherData;
  14179. pKeyIdentifier = &OtherKeyIdentifier;
  14180. }
  14181. break;
  14182. default:
  14183. return;
  14184. }
  14185. if (pvOtherData) {
  14186. DWORD dwFlags = CRYPT_KEYID_SET_NEW_FLAG;
  14187. if (pKeyProvInfo->dwFlags & CRYPT_MACHINE_KEYSET)
  14188. dwFlags |= CRYPT_KEYID_MACHINE_FLAG;
  14189. CryptSetKeyIdentifierProperty(
  14190. pKeyIdentifier,
  14191. CERT_KEY_PROV_INFO_PROP_ID,
  14192. dwFlags,
  14193. NULL, // pwszComputerName
  14194. NULL, // pvReserved
  14195. (const void *) pKeyProvInfo
  14196. );
  14197. PkiFree(pvOtherData);
  14198. }
  14199. }
  14200. //+-------------------------------------------------------------------------
  14201. // Get the Key Identifier property for the specified element.
  14202. //
  14203. // Only supported for certificates.
  14204. //--------------------------------------------------------------------------
  14205. STATIC BOOL GetKeyIdProperty(
  14206. IN PCONTEXT_ELEMENT pEle,
  14207. IN DWORD dwPropId,
  14208. OUT void *pvData,
  14209. IN OUT DWORD *pcbData
  14210. )
  14211. {
  14212. BOOL fResult;
  14213. PCCERT_CONTEXT pCert;
  14214. PCERT_INFO pCertInfo;
  14215. PCERT_EXTENSION pExt;
  14216. CRYPT_HASH_BLOB KeyIdentifier = { 0, NULL };
  14217. BYTE rgbHash[MAX_HASH_LEN];
  14218. if ((CERT_STORE_CERTIFICATE_CONTEXT - 1) != pEle->dwContextType)
  14219. goto InvalidPropId;
  14220. pCert = ToCertContext(pEle);
  14221. pCertInfo = pCert->pCertInfo;
  14222. if (pExt = CertFindExtension(
  14223. szOID_SUBJECT_KEY_IDENTIFIER,
  14224. pCertInfo->cExtension,
  14225. pCertInfo->rgExtension
  14226. )) {
  14227. // Skip by the octet tag, length bytes
  14228. Asn1UtilExtractContent(
  14229. pExt->Value.pbData,
  14230. pExt->Value.cbData,
  14231. &KeyIdentifier.cbData,
  14232. (const BYTE **) &KeyIdentifier.pbData
  14233. );
  14234. }
  14235. if (0 == KeyIdentifier.cbData) {
  14236. const BYTE *pbPublicKeyInfo;
  14237. DWORD cbPublicKeyInfo;
  14238. if (!Asn1UtilExtractCertificatePublicKeyInfo(
  14239. pCert->pbCertEncoded,
  14240. pCert->cbCertEncoded,
  14241. &cbPublicKeyInfo,
  14242. &pbPublicKeyInfo
  14243. ))
  14244. goto ExtractPublicKeyInfoError;
  14245. KeyIdentifier.cbData = sizeof(rgbHash);
  14246. KeyIdentifier.pbData = rgbHash;
  14247. if (!CryptHashCertificate(
  14248. 0, // hCryptProv
  14249. CALG_SHA1,
  14250. 0, // dwFlags
  14251. pbPublicKeyInfo,
  14252. cbPublicKeyInfo,
  14253. rgbHash,
  14254. &KeyIdentifier.cbData
  14255. ))
  14256. goto HashPublicKeyInfoError;
  14257. }
  14258. if (!SetProperty(
  14259. pEle,
  14260. dwPropId,
  14261. CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG,
  14262. &KeyIdentifier
  14263. ))
  14264. goto SetKeyIdPropertyError;
  14265. fResult = GetProperty(
  14266. pEle,
  14267. dwPropId,
  14268. pvData,
  14269. pcbData
  14270. );
  14271. CommonReturn:
  14272. return fResult;
  14273. ErrorReturn:
  14274. fResult = FALSE;
  14275. *pcbData = 0;
  14276. goto CommonReturn;
  14277. SET_ERROR(InvalidPropId, E_INVALIDARG)
  14278. TRACE_ERROR(ExtractPublicKeyInfoError)
  14279. TRACE_ERROR(HashPublicKeyInfoError)
  14280. TRACE_ERROR(SetKeyIdPropertyError)
  14281. }
  14282. #ifdef CMS_PKCS7
  14283. //+-------------------------------------------------------------------------
  14284. // If the verify signature fails with CRYPT_E_MISSING_PUBKEY_PARA,
  14285. // build a certificate chain. Retry. Hopefully, the issuer's
  14286. // CERT_PUBKEY_ALG_PARA_PROP_ID property gets set while building the chain.
  14287. //--------------------------------------------------------------------------
  14288. STATIC BOOL VerifyCertificateSignatureWithChainPubKeyParaInheritance(
  14289. IN HCRYPTPROV hCryptProv,
  14290. IN DWORD dwCertEncodingType,
  14291. IN DWORD dwSubjectType,
  14292. IN void *pvSubject,
  14293. IN PCCERT_CONTEXT pIssuer
  14294. )
  14295. {
  14296. if (CryptVerifyCertificateSignatureEx(
  14297. hCryptProv,
  14298. dwCertEncodingType,
  14299. dwSubjectType,
  14300. pvSubject,
  14301. CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
  14302. (void *) pIssuer,
  14303. 0, // dwFlags
  14304. NULL // pvReserved
  14305. ))
  14306. return TRUE;
  14307. else if (CRYPT_E_MISSING_PUBKEY_PARA != GetLastError())
  14308. return FALSE;
  14309. else {
  14310. PCCERT_CHAIN_CONTEXT pChainContext;
  14311. CERT_CHAIN_PARA ChainPara;
  14312. // Build a chain. Hopefully, the issuer inherit's its public key
  14313. // parameters from up the chain
  14314. memset(&ChainPara, 0, sizeof(ChainPara));
  14315. ChainPara.cbSize = sizeof(ChainPara);
  14316. if (CertGetCertificateChain(
  14317. NULL, // hChainEngine
  14318. pIssuer,
  14319. NULL, // pTime
  14320. pIssuer->hCertStore,
  14321. &ChainPara,
  14322. CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL,
  14323. NULL, // pvReserved
  14324. &pChainContext
  14325. ))
  14326. CertFreeCertificateChain(pChainContext);
  14327. // Try again. Hopefully the above chain building updated the issuer's
  14328. // context property with the missing public key parameters
  14329. return CryptVerifyCertificateSignatureEx(
  14330. hCryptProv,
  14331. dwCertEncodingType,
  14332. dwSubjectType,
  14333. pvSubject,
  14334. CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
  14335. (void *) pIssuer,
  14336. 0, // dwFlags
  14337. NULL // pvReserved
  14338. );
  14339. }
  14340. }
  14341. #endif // CMS_PKCS7