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

10492 lines
326 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT Security
  4. // Copyright (C) Microsoft Corporation, 1997 - 1999
  5. //
  6. // File: chain.cpp
  7. //
  8. // Contents: Certificate Chaining Infrastructure
  9. //
  10. // History: 15-Jan-98 kirtd Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <global.hxx>
  14. #include <dbgdef.h>
  15. //+===========================================================================
  16. // CCertObject methods
  17. //============================================================================
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Member: CCertObject::CCertObject, public
  21. //
  22. // Synopsis: Constructor
  23. //
  24. // Leaves the engine's critical section to create an object of
  25. // dwObjectType = CERT_END_OBJECT_TYPE. For a self-signed root
  26. // may also leave the critical section to retrieve and validate
  27. // the AuthRoot Auto Update CTL and add such a root to the
  28. // AuthRoot store.
  29. //
  30. // Assumption: Chain engine is locked once in the calling thread.
  31. //
  32. //----------------------------------------------------------------------------
  33. CCertObject::CCertObject (
  34. IN DWORD dwObjectType,
  35. IN PCCHAINCALLCONTEXT pCallContext,
  36. IN PCCERT_CONTEXT pCertContext,
  37. IN BYTE rgbCertHash[CHAINHASHLEN],
  38. OUT BOOL& rfResult
  39. )
  40. {
  41. BOOL fLocked = TRUE;
  42. CRYPT_DATA_BLOB DataBlob;
  43. DWORD cbData;
  44. if (CERT_END_OBJECT_TYPE == dwObjectType) {
  45. pCallContext->ChainEngine()->UnlockEngine();
  46. fLocked = FALSE;
  47. }
  48. m_dwObjectType = dwObjectType;
  49. m_cRefs = 1;
  50. // NOTE: The chain engine is NOT addref'd
  51. m_pChainEngine = pCallContext->ChainEngine();
  52. m_dwIssuerMatchFlags = 0;
  53. m_dwCachedMatchFlags = 0;
  54. m_dwIssuerStatusFlags = 0;
  55. m_dwInfoFlags = 0;
  56. m_pCtlCacheHead = NULL;
  57. m_pCertContext = CertDuplicateCertificateContext( pCertContext );
  58. memset(&m_PoliciesInfo, 0, sizeof(m_PoliciesInfo));
  59. m_pBasicConstraintsInfo = NULL;
  60. m_pKeyUsage = NULL;
  61. m_pIssuerNameConstraintsInfo = NULL;
  62. m_fAvailableSubjectNameConstraintsInfo = FALSE;
  63. memset(&m_SubjectNameConstraintsInfo, 0,
  64. sizeof(m_SubjectNameConstraintsInfo));
  65. m_pAuthKeyIdentifier = NULL;
  66. // m_ObjectIdentifier;
  67. memcpy(m_rgbCertHash, rgbCertHash, CHAINHASHLEN);
  68. m_cbKeyIdentifier = 0;
  69. m_pbKeyIdentifier = NULL;
  70. // m_rgbPublicKeyHash[ CHAINHASHLEN ];
  71. // m_rgbIssuerPublicKeyHash[ CHAINHASHLEN ];
  72. // m_rgbIssuerExactMatchHash[ CHAINHASHLEN ];
  73. // m_rgbIssuerNameMatchHash[ CHAINHASHLEN ];
  74. m_hHashEntry = NULL;
  75. m_hIdentifierEntry = NULL;
  76. m_hSubjectNameEntry = NULL;
  77. m_hKeyIdEntry = NULL;
  78. m_hPublicKeyHashEntry = NULL;
  79. m_hEndHashEntry = NULL;
  80. if (!CertGetCertificateContextProperty(
  81. pCertContext,
  82. CERT_KEY_IDENTIFIER_PROP_ID,
  83. NULL,
  84. &m_cbKeyIdentifier
  85. ))
  86. goto GetKeyIdentifierPropertyError;
  87. m_pbKeyIdentifier = new BYTE [ m_cbKeyIdentifier ];
  88. if (NULL == m_pbKeyIdentifier)
  89. goto OutOfMemory;
  90. if (!CertGetCertificateContextProperty(
  91. pCertContext,
  92. CERT_KEY_IDENTIFIER_PROP_ID,
  93. m_pbKeyIdentifier,
  94. &m_cbKeyIdentifier
  95. ))
  96. goto GetKeyIdentifierPropertyError;
  97. cbData = CHAINHASHLEN;
  98. if (!CertGetCertificateContextProperty(
  99. pCertContext,
  100. CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID,
  101. m_rgbPublicKeyHash,
  102. &cbData
  103. ) || CHAINHASHLEN != cbData)
  104. goto GetSubjectPublicKeyHashPropertyError;
  105. cbData = CHAINHASHLEN;
  106. if (CertGetCertificateContextProperty(
  107. pCertContext,
  108. CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID,
  109. m_rgbIssuerPublicKeyHash,
  110. &cbData
  111. ) && CHAINHASHLEN == cbData)
  112. m_dwIssuerStatusFlags |= CERT_ISSUER_PUBKEY_FLAG;
  113. ChainGetPoliciesInfo(pCertContext, &m_PoliciesInfo);
  114. if (!ChainGetBasicConstraintsInfo(pCertContext, &m_pBasicConstraintsInfo))
  115. m_dwInfoFlags |= CHAIN_INVALID_BASIC_CONSTRAINTS_INFO_FLAG;
  116. if (!ChainGetKeyUsage(pCertContext, &m_pKeyUsage))
  117. m_dwInfoFlags |= CHAIN_INVALID_KEY_USAGE_FLAG;
  118. if (!ChainGetIssuerNameConstraintsInfo(pCertContext,
  119. &m_pIssuerNameConstraintsInfo))
  120. m_dwInfoFlags |= CHAIN_INVALID_ISSUER_NAME_CONSTRAINTS_INFO_FLAG;
  121. if (CERT_CACHED_ISSUER_OBJECT_TYPE == dwObjectType) {
  122. DataBlob.cbData = CHAINHASHLEN;
  123. DataBlob.pbData = m_rgbCertHash;
  124. if (!I_CryptCreateLruEntry(
  125. m_pChainEngine->CertObjectCache()->HashIndex(),
  126. &DataBlob,
  127. this,
  128. &m_hHashEntry
  129. ))
  130. goto CreateHashLruEntryError;
  131. // Need to double check this, only needed for issuer caching ???
  132. ChainCreateCertificateObjectIdentifier(
  133. &pCertContext->pCertInfo->Issuer,
  134. &pCertContext->pCertInfo->SerialNumber,
  135. m_ObjectIdentifier
  136. );
  137. DataBlob.cbData = sizeof( CERT_OBJECT_IDENTIFIER );
  138. DataBlob.pbData = m_ObjectIdentifier;
  139. if (!I_CryptCreateLruEntry(
  140. m_pChainEngine->CertObjectCache()->IdentifierIndex(),
  141. &DataBlob,
  142. this,
  143. &m_hIdentifierEntry
  144. ))
  145. goto CreateIdentifierLruEntryError;
  146. DataBlob.cbData = pCertContext->pCertInfo->Subject.cbData;
  147. DataBlob.pbData = pCertContext->pCertInfo->Subject.pbData;
  148. if (!I_CryptCreateLruEntry(
  149. m_pChainEngine->CertObjectCache()->SubjectNameIndex(),
  150. &DataBlob,
  151. this,
  152. &m_hSubjectNameEntry
  153. ))
  154. goto CreateSubjectNameLruEntryError;
  155. DataBlob.cbData = m_cbKeyIdentifier;
  156. DataBlob.pbData = m_pbKeyIdentifier;
  157. if (!I_CryptCreateLruEntry(
  158. m_pChainEngine->CertObjectCache()->KeyIdIndex(),
  159. &DataBlob,
  160. this,
  161. &m_hKeyIdEntry
  162. ))
  163. goto CreateKeyIdLruEntryError;
  164. DataBlob.cbData = CHAINHASHLEN;
  165. DataBlob.pbData = m_rgbPublicKeyHash;
  166. if (!I_CryptCreateLruEntry(
  167. m_pChainEngine->CertObjectCache()->PublicKeyHashIndex(),
  168. &DataBlob,
  169. this,
  170. &m_hPublicKeyHashEntry
  171. ))
  172. goto CreatePublicKeyHashLruEntryError;
  173. }
  174. ChainGetIssuerMatchInfo(
  175. pCertContext,
  176. &m_dwIssuerMatchFlags,
  177. &m_pAuthKeyIdentifier
  178. );
  179. ChainGetSelfSignedStatus(pCallContext, this, &m_dwIssuerStatusFlags);
  180. if (m_dwIssuerStatusFlags & CERT_ISSUER_SELF_SIGNED_FLAG) {
  181. //
  182. // NOTE: This means that only self-signed roots are supported
  183. //
  184. if (!fLocked) {
  185. pCallContext->ChainEngine()->LockEngine();
  186. fLocked = TRUE;
  187. }
  188. ChainGetRootStoreStatus(
  189. m_pChainEngine->RootStore(),
  190. m_pChainEngine->RealRootStore(),
  191. rgbCertHash,
  192. &m_dwIssuerStatusFlags
  193. );
  194. if (!(m_dwIssuerStatusFlags & CERT_ISSUER_TRUSTED_ROOT_FLAG)) {
  195. if (!ChainGetAuthRootAutoUpdateStatus(
  196. pCallContext,
  197. this,
  198. &m_dwIssuerStatusFlags
  199. ))
  200. goto AuthRootAutoUpdateError;
  201. }
  202. if (!(m_dwIssuerStatusFlags & CERT_ISSUER_TRUSTED_ROOT_FLAG)) {
  203. // Get all cached CTLs we are a member of
  204. CERT_OBJECT_CTL_CACHE_ENUM_DATA EnumData;
  205. memset(&EnumData, 0, sizeof(EnumData));
  206. EnumData.fResult = TRUE;
  207. EnumData.pCertObject = this;
  208. m_pChainEngine->SSCtlObjectCache()->EnumObjects(
  209. ChainFillCertObjectCtlCacheEnumFn,
  210. &EnumData
  211. );
  212. if (!EnumData.fResult) {
  213. SetLastError(EnumData.dwLastError);
  214. goto FillCertObjectCtlCacheError;
  215. }
  216. }
  217. }
  218. rfResult = TRUE;
  219. CommonReturn:
  220. if (!fLocked)
  221. pCallContext->ChainEngine()->LockEngine();
  222. return;
  223. ErrorReturn:
  224. rfResult = FALSE;
  225. goto CommonReturn;
  226. TRACE_ERROR(GetKeyIdentifierPropertyError)
  227. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  228. TRACE_ERROR(GetSubjectPublicKeyHashPropertyError)
  229. TRACE_ERROR(CreateHashLruEntryError)
  230. TRACE_ERROR(CreateIdentifierLruEntryError)
  231. TRACE_ERROR(CreateSubjectNameLruEntryError)
  232. TRACE_ERROR(CreateKeyIdLruEntryError)
  233. TRACE_ERROR(CreatePublicKeyHashLruEntryError)
  234. TRACE_ERROR(AuthRootAutoUpdateError)
  235. TRACE_ERROR(FillCertObjectCtlCacheError)
  236. }
  237. //+---------------------------------------------------------------------------
  238. //
  239. // Member: CCertObject::~CCertObject, public
  240. //
  241. // Synopsis: Destructor
  242. //
  243. //----------------------------------------------------------------------------
  244. CCertObject::~CCertObject ()
  245. {
  246. if ( m_hKeyIdEntry != NULL )
  247. {
  248. I_CryptReleaseLruEntry( m_hKeyIdEntry );
  249. }
  250. if ( m_hSubjectNameEntry != NULL )
  251. {
  252. I_CryptReleaseLruEntry( m_hSubjectNameEntry );
  253. }
  254. if ( m_hIdentifierEntry != NULL )
  255. {
  256. I_CryptReleaseLruEntry( m_hIdentifierEntry );
  257. }
  258. if ( m_hPublicKeyHashEntry != NULL )
  259. {
  260. I_CryptReleaseLruEntry( m_hPublicKeyHashEntry );
  261. }
  262. if ( m_hHashEntry != NULL )
  263. {
  264. I_CryptReleaseLruEntry( m_hHashEntry );
  265. }
  266. if ( m_hEndHashEntry != NULL )
  267. {
  268. I_CryptReleaseLruEntry( m_hEndHashEntry );
  269. }
  270. ChainFreeCertObjectCtlCache(m_pCtlCacheHead);
  271. delete m_pbKeyIdentifier;
  272. ChainFreeAuthorityKeyIdentifier( m_pAuthKeyIdentifier );
  273. ChainFreePoliciesInfo( &m_PoliciesInfo );
  274. ChainFreeBasicConstraintsInfo( m_pBasicConstraintsInfo );
  275. ChainFreeKeyUsage( m_pKeyUsage );
  276. ChainFreeIssuerNameConstraintsInfo( m_pIssuerNameConstraintsInfo );
  277. ChainFreeSubjectNameConstraintsInfo( &m_SubjectNameConstraintsInfo );
  278. CertFreeCertificateContext( m_pCertContext );
  279. }
  280. //+---------------------------------------------------------------------------
  281. //
  282. // Member: CCertObject::CacheEndObject, public
  283. //
  284. // Synopsis: Convert a CERT_END_OBJECT_TYPE to a CERT_CACHED_END_OBJECT_TYPE.
  285. //
  286. //----------------------------------------------------------------------------
  287. BOOL
  288. CCertObject::CacheEndObject(
  289. IN PCCHAINCALLCONTEXT pCallContext
  290. )
  291. {
  292. BOOL fResult;
  293. CRYPT_DATA_BLOB DataBlob;
  294. assert(CERT_END_OBJECT_TYPE == m_dwObjectType);
  295. DataBlob.cbData = CHAINHASHLEN;
  296. DataBlob.pbData = m_rgbCertHash;
  297. fResult = I_CryptCreateLruEntry(
  298. m_pChainEngine->CertObjectCache()->EndHashIndex(),
  299. &DataBlob,
  300. this,
  301. &m_hEndHashEntry
  302. );
  303. if (fResult)
  304. m_dwObjectType = CERT_CACHED_END_OBJECT_TYPE;
  305. return fResult;
  306. }
  307. //+---------------------------------------------------------------------------
  308. //
  309. // Member: CCertObject::SubjectNameConstraintsInfo, public
  310. //
  311. // Synopsis: return the subject name constraints info
  312. //
  313. // allocation and getting of info is deferred until the
  314. // first name constraint check is done.
  315. //
  316. // Assumption: chain engine isn't locked upon entry.
  317. //
  318. //----------------------------------------------------------------------------
  319. PCHAIN_SUBJECT_NAME_CONSTRAINTS_INFO
  320. CCertObject::SubjectNameConstraintsInfo ()
  321. {
  322. if (!m_fAvailableSubjectNameConstraintsInfo) {
  323. CHAIN_SUBJECT_NAME_CONSTRAINTS_INFO Info;
  324. memset(&Info, 0, sizeof(Info));
  325. ChainGetSubjectNameConstraintsInfo(m_pCertContext, &Info);
  326. // Must do the update while holding the engine's critical section
  327. m_pChainEngine->LockEngine();
  328. if (m_fAvailableSubjectNameConstraintsInfo)
  329. // Another thread already did the update
  330. ChainFreeSubjectNameConstraintsInfo(&Info);
  331. else {
  332. memcpy(&m_SubjectNameConstraintsInfo, &Info,
  333. sizeof(m_SubjectNameConstraintsInfo));
  334. // Must be set last!!!
  335. m_fAvailableSubjectNameConstraintsInfo = TRUE;
  336. }
  337. m_pChainEngine->UnlockEngine();
  338. }
  339. return &m_SubjectNameConstraintsInfo;
  340. }
  341. //+---------------------------------------------------------------------------
  342. //
  343. // Member: CCertObject::GetIssuerExactMatchHash, public
  344. //
  345. // Synopsis: if the cert has an Authority Key Info extension with
  346. // the optional issuer and serial number, returns the count and
  347. // pointer to the MD5 hash of the issuer name and serial number.
  348. // Otherwise, pMatchHash->cbData is set to 0.
  349. //
  350. // MD5 hash calculation is deferred until the first call.
  351. //
  352. // Assumption: Chain engine is locked once in the calling thread.
  353. //
  354. //----------------------------------------------------------------------------
  355. VOID
  356. CCertObject::GetIssuerExactMatchHash(
  357. OUT PCRYPT_DATA_BLOB pMatchHash
  358. )
  359. {
  360. if (!(m_dwIssuerStatusFlags & CERT_ISSUER_EXACT_MATCH_HASH_FLAG)) {
  361. PCERT_AUTHORITY_KEY_ID_INFO pAKI = m_pAuthKeyIdentifier;
  362. if (pAKI && 0 != pAKI->CertIssuer.cbData &&
  363. 0 != pAKI->CertSerialNumber.cbData) {
  364. ChainCreateCertificateObjectIdentifier(
  365. &pAKI->CertIssuer,
  366. &pAKI->CertSerialNumber,
  367. m_rgbIssuerExactMatchHash
  368. );
  369. m_dwIssuerStatusFlags |= CERT_ISSUER_EXACT_MATCH_HASH_FLAG;
  370. } else {
  371. pMatchHash->cbData = 0;
  372. pMatchHash->pbData = NULL;
  373. return;
  374. }
  375. }
  376. // else
  377. // We have already calculated the MD5 hash
  378. pMatchHash->cbData = CHAINHASHLEN;
  379. pMatchHash->pbData = m_rgbIssuerExactMatchHash;
  380. }
  381. //+---------------------------------------------------------------------------
  382. //
  383. // Member: CCertObject::GetIssuerKeyMatchHash, public
  384. //
  385. // Synopsis: if the cert has an Authority Key Info extension with
  386. // the optional key id, returns the key id.
  387. // Otherwise, pMatchHash->cbData is set to 0.
  388. //
  389. //----------------------------------------------------------------------------
  390. VOID
  391. CCertObject::GetIssuerKeyMatchHash(
  392. OUT PCRYPT_DATA_BLOB pMatchHash
  393. )
  394. {
  395. PCERT_AUTHORITY_KEY_ID_INFO pAKI = m_pAuthKeyIdentifier;
  396. if (pAKI)
  397. *pMatchHash = pAKI->KeyId;
  398. else {
  399. pMatchHash->cbData = 0;
  400. pMatchHash->pbData = NULL;
  401. }
  402. }
  403. //+---------------------------------------------------------------------------
  404. //
  405. // Member: CCertObject::GetIssuerNameMatchHash, public
  406. //
  407. // Synopsis: if the cert has an issuer name, returns the count and
  408. // pointer to the MD5 hash of the issuer name.
  409. // Otherwise, pMatchHash->cbData is set to 0.
  410. //
  411. // MD5 hash calculation is deferred until the first call.
  412. //
  413. // Assumption: Chain engine is locked once in the calling thread.
  414. //
  415. //----------------------------------------------------------------------------
  416. VOID
  417. CCertObject::GetIssuerNameMatchHash(
  418. OUT PCRYPT_DATA_BLOB pMatchHash
  419. )
  420. {
  421. if (!(m_dwIssuerStatusFlags & CERT_ISSUER_NAME_MATCH_HASH_FLAG)) {
  422. PCERT_INFO pCertInfo = m_pCertContext->pCertInfo;
  423. if (0 != pCertInfo->Issuer.cbData) {
  424. MD5_CTX md5ctx;
  425. MD5Init( &md5ctx );
  426. MD5Update( &md5ctx, pCertInfo->Issuer.pbData,
  427. pCertInfo->Issuer.cbData );
  428. MD5Final( &md5ctx );
  429. assert(CHAINHASHLEN == MD5DIGESTLEN);
  430. memcpy(m_rgbIssuerNameMatchHash, md5ctx.digest, CHAINHASHLEN);
  431. m_dwIssuerStatusFlags |= CERT_ISSUER_NAME_MATCH_HASH_FLAG;
  432. } else {
  433. pMatchHash->cbData = 0;
  434. pMatchHash->pbData = NULL;
  435. return;
  436. }
  437. }
  438. pMatchHash->cbData = CHAINHASHLEN;
  439. pMatchHash->pbData = m_rgbIssuerNameMatchHash;
  440. }
  441. //+===========================================================================
  442. // CChainPathObject methods
  443. //============================================================================
  444. //+---------------------------------------------------------------------------
  445. //
  446. // Member: CChainPathObject::CChainPathObject, public
  447. //
  448. // Synopsis: Constructor
  449. //
  450. // Once successfully added to the call context cache, rfAddedToCreationCache
  451. // is set. This object will be deleted when CChainCallContext gets destroyed.
  452. //
  453. // Since this object is per call, no AddRef'ing is required.
  454. //
  455. //----------------------------------------------------------------------------
  456. CChainPathObject::CChainPathObject (
  457. IN PCCHAINCALLCONTEXT pCallContext,
  458. IN BOOL fCyclic,
  459. IN LPVOID pvObject, // fCyclic : pPathObject ? pCertObject
  460. IN OPTIONAL HCERTSTORE hAdditionalStore,
  461. OUT BOOL& rfResult,
  462. OUT BOOL& rfAddedToCreationCache
  463. )
  464. {
  465. PCCERTOBJECT pCertObject;
  466. PCCHAINPATHOBJECT pPathObject;
  467. DWORD dwIssuerStatusFlags;
  468. rfAddedToCreationCache = FALSE;
  469. if (fCyclic) {
  470. pPathObject = (PCCHAINPATHOBJECT) pvObject;
  471. pCertObject = pPathObject->CertObject();
  472. } else {
  473. pPathObject = NULL;
  474. pCertObject = (PCCERTOBJECT) pvObject;
  475. }
  476. m_pCertObject = pCertObject;
  477. pCertObject->AddRef();
  478. memset( &m_TrustStatus, 0, sizeof( m_TrustStatus ) );
  479. m_dwPass1Quality = 0;
  480. m_dwChainIndex = 0;
  481. m_dwElementIndex = 0;
  482. m_pDownIssuerElement = NULL;
  483. m_pDownPathObject = NULL;
  484. m_pUpIssuerElement = NULL;
  485. m_fHasAdditionalStatus = FALSE;
  486. memset( &m_AdditionalStatus, 0, sizeof( m_AdditionalStatus ) );
  487. m_fHasRevocationInfo = FALSE;
  488. memset( &m_RevocationInfo, 0, sizeof( m_RevocationInfo ) );
  489. memset( &m_RevocationCrlInfo, 0, sizeof( m_RevocationCrlInfo ) );
  490. m_pIssuerList = NULL;
  491. m_pwszExtendedErrorInfo = NULL;
  492. m_fCompleted = FALSE;
  493. if (!ChainCreateIssuerList( this, &m_pIssuerList ))
  494. goto CreateIssuerListError;
  495. if (!pCallContext->AddPathObjectToCreationCache( this ))
  496. goto AddPathObjectToCreationCacheError;
  497. rfAddedToCreationCache = TRUE;
  498. if (fCyclic) {
  499. m_TrustStatus = pPathObject->m_TrustStatus;
  500. m_TrustStatus.dwInfoStatus |= ChainGetMatchInfoStatusForNoIssuer(
  501. pCertObject->IssuerMatchFlags());
  502. m_TrustStatus.dwErrorStatus |= CERT_TRUST_IS_CYCLIC;
  503. goto SuccessReturn;
  504. }
  505. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  506. if (dwIssuerStatusFlags & CERT_ISSUER_SELF_SIGNED_FLAG) {
  507. m_TrustStatus.dwInfoStatus |= CERT_TRUST_IS_SELF_SIGNED;
  508. ChainGetMatchInfoStatus(pCertObject, pCertObject,
  509. &m_TrustStatus.dwInfoStatus);
  510. m_dwPass1Quality |= CERT_QUALITY_COMPLETE_CHAIN |
  511. CERT_QUALITY_NOT_CYCLIC;
  512. if (dwIssuerStatusFlags & CERT_ISSUER_VALID_SIGNATURE_FLAG) {
  513. m_dwPass1Quality |= CERT_QUALITY_SIGNATURE_VALID;
  514. } else {
  515. m_TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_SIGNATURE_VALID;
  516. m_TrustStatus.dwInfoStatus &= ~CERT_TRUST_HAS_PREFERRED_ISSUER;
  517. }
  518. if (dwIssuerStatusFlags & CERT_ISSUER_TRUSTED_ROOT_FLAG) {
  519. m_dwPass1Quality |= CERT_QUALITY_HAS_TRUSTED_ROOT;
  520. // Check if we have a time valid root. This is an extra
  521. // check necessary to determine if we will need to do
  522. // AuthRoot Auto Update.
  523. FILETIME RequestedTime;
  524. PCERT_INFO pCertInfo = pCertObject->CertContext()->pCertInfo;
  525. pCallContext->RequestedTime(&RequestedTime);
  526. if ((0 == (pCallContext->CallFlags() &
  527. CERT_CHAIN_TIMESTAMP_TIME)) &&
  528. 0 == CertVerifyTimeValidity(&RequestedTime, pCertInfo)) {
  529. m_dwPass1Quality |= CERT_QUALITY_HAS_TIME_VALID_TRUSTED_ROOT;
  530. } else {
  531. // Use current time for timestamping or try again using the
  532. // current time. This is necessary for cross certificate
  533. // chains.
  534. FILETIME CurrentTime;
  535. pCallContext->CurrentTime(&CurrentTime);
  536. if (0 == CertVerifyTimeValidity(&CurrentTime, pCertInfo)) {
  537. m_dwPass1Quality |=
  538. CERT_QUALITY_HAS_TIME_VALID_TRUSTED_ROOT;
  539. }
  540. }
  541. } else {
  542. m_TrustStatus.dwErrorStatus |= CERT_TRUST_IS_UNTRUSTED_ROOT;
  543. if (!FindAndAddCtlIssuersFromCache(pCallContext, hAdditionalStore))
  544. goto FindAndCtlIssuersFromCacheError;
  545. if (hAdditionalStore) {
  546. if (!FindAndAddCtlIssuersFromAdditionalStore(
  547. pCallContext,
  548. hAdditionalStore
  549. ))
  550. goto FindAndCtlIssuersFromAdditionalStoreError;
  551. }
  552. if (!(dwIssuerStatusFlags & CERT_ISSUER_VALID_SIGNATURE_FLAG))
  553. m_dwPass1Quality &= ~CERT_QUALITY_SIGNATURE_VALID;
  554. }
  555. } else {
  556. if (!FindAndAddIssuers (
  557. pCallContext,
  558. hAdditionalStore,
  559. NULL // hIssuerUrlStore
  560. ))
  561. goto FindAndAddIssuersError;
  562. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  563. if (m_pIssuerList->IsEmpty()
  564. ||
  565. (!(dwIssuerStatusFlags & CERT_ISSUER_URL_FLAG)
  566. &&
  567. (!(dwIssuerStatusFlags &
  568. CERT_ISSUER_VALID_SIGNATURE_FLAG) ||
  569. !(m_dwPass1Quality & CERT_QUALITY_SIGNATURE_VALID)))) {
  570. DWORD i;
  571. // Try the following 2 URL cases:
  572. // 0 - AIA cache
  573. // 1 - AIA wire
  574. // Continue through the cases until finding a "good" issuer.
  575. for (i = 0; i <= 1; i++) {
  576. HCERTSTORE hIssuerUrlStore = NULL;
  577. DWORD dwRetrievalFlags;
  578. if (0 == i)
  579. dwRetrievalFlags = CRYPT_CACHE_ONLY_RETRIEVAL;
  580. else {
  581. if (!pCallContext->IsOnline())
  582. break;
  583. dwRetrievalFlags = CRYPT_WIRE_ONLY_RETRIEVAL;
  584. }
  585. // The following leaves the engine's critical section to do
  586. // URL fetching. If the engine was touched by another
  587. // thread, it fails with LastError set to
  588. // ERROR_CAN_NOT_COMPLETE.
  589. if (!pCallContext->ChainEngine()->GetIssuerUrlStore(
  590. pCallContext,
  591. pCertObject->CertContext(),
  592. dwRetrievalFlags,
  593. &hIssuerUrlStore
  594. ))
  595. goto GetIssuerUrlStoreError;
  596. if (hIssuerUrlStore) {
  597. BOOL fResult;
  598. fResult = FindAndAddIssuers (
  599. pCallContext,
  600. hAdditionalStore,
  601. hIssuerUrlStore
  602. );
  603. CertCloseStore(hIssuerUrlStore, 0);
  604. if (!fResult)
  605. goto FindAndAddIssuersFromUrlStoreError;
  606. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  607. if (!m_pIssuerList->IsEmpty() &&
  608. (dwIssuerStatusFlags &
  609. CERT_ISSUER_VALID_SIGNATURE_FLAG)) {
  610. assert(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG);
  611. // Try to find all issuers having the same public key.
  612. if (!FindAndAddIssuersByMatchType(
  613. CERT_PUBKEY_ISSUER_MATCH_TYPE,
  614. pCallContext,
  615. hAdditionalStore,
  616. NULL // hIssuerUrlStore
  617. ))
  618. goto FindIssuersByPubKeyError;
  619. if (m_dwPass1Quality & CERT_QUALITY_SIGNATURE_VALID)
  620. break;
  621. }
  622. }
  623. }
  624. pCertObject->OrIssuerStatusFlags(CERT_ISSUER_URL_FLAG);
  625. }
  626. // Check if we have a time valid, signature valid, trusted root
  627. if ((CERT_QUALITY_HAS_TIME_VALID_TRUSTED_ROOT |
  628. CERT_QUALITY_SIGNATURE_VALID) !=
  629. (m_dwPass1Quality &
  630. (CERT_QUALITY_HAS_TIME_VALID_TRUSTED_ROOT |
  631. CERT_QUALITY_SIGNATURE_VALID))
  632. &&
  633. pCallContext->IsOnline()) {
  634. HCERTSTORE hIssuerUrlStore = NULL;
  635. // The following leaves the engine's critical section to do
  636. // URL fetching. If the engine was touched by another
  637. // thread, it fails with LastError set to
  638. // ERROR_CAN_NOT_COMPLETE.
  639. // Note, we only hit the wire to fetch AuthRoots stored
  640. // on Microsoft's web server
  641. if (!GetAuthRootAutoUpdateUrlStore(
  642. pCallContext,
  643. &hIssuerUrlStore
  644. ))
  645. goto GetAuthRootAutoUpdateUrlStoreError;
  646. if (hIssuerUrlStore) {
  647. BOOL fResult;
  648. fResult = FindAndAddIssuers (
  649. pCallContext,
  650. hAdditionalStore,
  651. hIssuerUrlStore
  652. );
  653. CertCloseStore(hIssuerUrlStore, 0);
  654. if (!fResult)
  655. goto FindAndAddIssuersFromUrlStoreError;
  656. }
  657. }
  658. if (m_pIssuerList->IsEmpty()) {
  659. m_TrustStatus.dwInfoStatus |= ChainGetMatchInfoStatusForNoIssuer(
  660. pCertObject->IssuerMatchFlags());
  661. assert(0 == (m_dwPass1Quality &
  662. (CERT_QUALITY_HAS_TRUSTED_ROOT |
  663. CERT_QUALITY_COMPLETE_CHAIN)));
  664. // Unable to verify our signature, default to being valid.
  665. // Also, we can't be cyclic.
  666. m_dwPass1Quality |= CERT_QUALITY_SIGNATURE_VALID |
  667. CERT_QUALITY_NOT_CYCLIC;
  668. }
  669. }
  670. SuccessReturn:
  671. rfResult = TRUE;
  672. CommonReturn:
  673. m_fCompleted = TRUE;
  674. return;
  675. ErrorReturn:
  676. rfResult = FALSE;
  677. goto CommonReturn;
  678. TRACE_ERROR(CreateIssuerListError)
  679. TRACE_ERROR(AddPathObjectToCreationCacheError)
  680. TRACE_ERROR(FindAndCtlIssuersFromCacheError)
  681. TRACE_ERROR(FindAndCtlIssuersFromAdditionalStoreError)
  682. TRACE_ERROR(FindAndAddIssuersError)
  683. TRACE_ERROR(GetIssuerUrlStoreError)
  684. TRACE_ERROR(GetAuthRootAutoUpdateUrlStoreError)
  685. TRACE_ERROR(FindAndAddIssuersFromUrlStoreError)
  686. TRACE_ERROR(FindIssuersByPubKeyError)
  687. }
  688. //+---------------------------------------------------------------------------
  689. //
  690. // Member: CChainPathObject::~CChainPathObject, public
  691. //
  692. // Synopsis: Destructor
  693. //
  694. //----------------------------------------------------------------------------
  695. CChainPathObject::~CChainPathObject ()
  696. {
  697. if (m_pCertObject)
  698. m_pCertObject->Release();
  699. if (m_fHasRevocationInfo) {
  700. if (m_RevocationCrlInfo.pBaseCrlContext)
  701. CertFreeCRLContext(m_RevocationCrlInfo.pBaseCrlContext);
  702. if (m_RevocationCrlInfo.pDeltaCrlContext)
  703. CertFreeCRLContext(m_RevocationCrlInfo.pDeltaCrlContext);
  704. }
  705. if (m_pIssuerList)
  706. ChainFreeIssuerList( m_pIssuerList );
  707. if (m_pwszExtendedErrorInfo)
  708. PkiFree(m_pwszExtendedErrorInfo);
  709. }
  710. //+---------------------------------------------------------------------------
  711. //
  712. // Member: CChainPathObject::FindAndAddIssuers, public
  713. //
  714. // Synopsis: find and add issuers for all matching types
  715. //
  716. //----------------------------------------------------------------------------
  717. BOOL
  718. CChainPathObject::FindAndAddIssuers (
  719. IN PCCHAINCALLCONTEXT pCallContext,
  720. IN OPTIONAL HCERTSTORE hAdditionalStore,
  721. IN OPTIONAL HCERTSTORE hIssuerUrlStore
  722. )
  723. {
  724. BOOL fResult;
  725. PCCERTOBJECT pCertObject = m_pCertObject;
  726. DWORD dwIssuerMatchFlags;
  727. DWORD i;
  728. static const rgdwMatchType[] = {
  729. CERT_EXACT_ISSUER_MATCH_TYPE,
  730. CERT_KEYID_ISSUER_MATCH_TYPE,
  731. CERT_NAME_ISSUER_MATCH_TYPE
  732. };
  733. #define FIND_MATCH_TYPE_CNT (sizeof(rgdwMatchType) / sizeof(rgdwMatchType[0]))
  734. if (pCertObject->IssuerStatusFlags() & CERT_ISSUER_PUBKEY_FLAG) {
  735. // We know the issuer's public key. First, attempt to find all issuers
  736. // having that public key.
  737. if (!FindAndAddIssuersByMatchType(
  738. CERT_PUBKEY_ISSUER_MATCH_TYPE,
  739. pCallContext,
  740. hAdditionalStore,
  741. hIssuerUrlStore
  742. ))
  743. goto FindIssuersByPubKeyError;
  744. if (!m_pIssuerList->IsEmpty() &&
  745. (pCertObject->IssuerStatusFlags() &
  746. CERT_ISSUER_VALID_SIGNATURE_FLAG))
  747. goto SuccessReturn;
  748. }
  749. dwIssuerMatchFlags = pCertObject->IssuerMatchFlags();
  750. for (i = 0; i < FIND_MATCH_TYPE_CNT; i++) {
  751. if (dwIssuerMatchFlags & CERT_MATCH_TYPE_TO_FLAG(rgdwMatchType[i])) {
  752. DWORD dwIssuerStatusFlags;
  753. if (!FindAndAddIssuersByMatchType(
  754. rgdwMatchType[i],
  755. pCallContext,
  756. hAdditionalStore,
  757. hIssuerUrlStore
  758. ))
  759. goto FindIssuersByMatchTypeError;
  760. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  761. if (!m_pIssuerList->IsEmpty() &&
  762. (dwIssuerStatusFlags & CERT_ISSUER_VALID_SIGNATURE_FLAG)) {
  763. assert(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG);
  764. // We can now find all issuers having the same public key.
  765. if (!FindAndAddIssuersByMatchType(
  766. CERT_PUBKEY_ISSUER_MATCH_TYPE,
  767. pCallContext,
  768. hAdditionalStore,
  769. hIssuerUrlStore
  770. ))
  771. goto FindIssuersByPubKeyError;
  772. break;
  773. }
  774. }
  775. }
  776. SuccessReturn:
  777. fResult = TRUE;
  778. CommonReturn:
  779. return fResult;
  780. ErrorReturn:
  781. fResult = FALSE;
  782. goto CommonReturn;
  783. TRACE_ERROR(FindIssuersByPubKeyError)
  784. TRACE_ERROR(FindIssuersByMatchTypeError)
  785. }
  786. //+---------------------------------------------------------------------------
  787. //
  788. // Member: CChainPathObject::FindAndAddIssuersByMatchType, public
  789. //
  790. // Synopsis: find and add issuers for the specified match type
  791. //
  792. //----------------------------------------------------------------------------
  793. BOOL
  794. CChainPathObject::FindAndAddIssuersByMatchType(
  795. IN DWORD dwMatchType,
  796. IN PCCHAINCALLCONTEXT pCallContext,
  797. IN OPTIONAL HCERTSTORE hAdditionalStore,
  798. IN OPTIONAL HCERTSTORE hIssuerUrlStore
  799. )
  800. {
  801. BOOL fResult;
  802. PCCERTOBJECT pCertObject = m_pCertObject;
  803. if (NULL == hIssuerUrlStore) {
  804. DWORD dwIssuerStatusFlags;
  805. DWORD dwCachedMatchFlags;
  806. // Note, we need to get the cached match flags before finding
  807. // in the cache. Due to recursive, doing a find further up the
  808. // chain may result in another issuer being inserted at the beginning
  809. // of the cache bucket list. Pretty remote, but possible.
  810. dwCachedMatchFlags = pCertObject->CachedMatchFlags();
  811. if (!FindAndAddIssuersFromCacheByMatchType(
  812. dwMatchType,
  813. pCallContext,
  814. hAdditionalStore
  815. ))
  816. goto FindIssuersFromCacheError;
  817. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  818. if (CERT_PUBKEY_ISSUER_MATCH_TYPE != dwMatchType &&
  819. !m_pIssuerList->IsEmpty() &&
  820. (dwIssuerStatusFlags & CERT_ISSUER_VALID_SIGNATURE_FLAG)) {
  821. assert(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG);
  822. // We will be called again using the PUBKEY match
  823. goto SuccessReturn;
  824. }
  825. if (!(dwCachedMatchFlags & CERT_MATCH_TYPE_TO_FLAG(dwMatchType))) {
  826. if (!FindAndAddIssuersFromStoreByMatchType(
  827. dwMatchType,
  828. pCallContext,
  829. FALSE, // fExternalStore
  830. hAdditionalStore,
  831. NULL // hIssuerUrlStore
  832. ))
  833. goto FindIssuersFromEngineStoreError;
  834. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  835. if (CERT_PUBKEY_ISSUER_MATCH_TYPE != dwMatchType &&
  836. !m_pIssuerList->IsEmpty() &&
  837. (dwIssuerStatusFlags &
  838. CERT_ISSUER_VALID_SIGNATURE_FLAG)) {
  839. assert(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG);
  840. // We will be called again using the PUBKEY match
  841. goto SuccessReturn;
  842. }
  843. }
  844. }
  845. if (NULL != hAdditionalStore || NULL != hIssuerUrlStore) {
  846. if (!FindAndAddIssuersFromStoreByMatchType(
  847. dwMatchType,
  848. pCallContext,
  849. TRUE, // fExternalStore
  850. hAdditionalStore,
  851. hIssuerUrlStore
  852. ))
  853. goto FindIssuersFromAdditionalOrUrlStoreError;
  854. }
  855. SuccessReturn:
  856. fResult = TRUE;
  857. CommonReturn:
  858. return fResult;
  859. ErrorReturn:
  860. fResult = FALSE;
  861. goto CommonReturn;
  862. TRACE_ERROR(FindIssuersFromCacheError)
  863. TRACE_ERROR(FindIssuersFromEngineStoreError)
  864. TRACE_ERROR(FindIssuersFromAdditionalOrUrlStoreError)
  865. }
  866. //+---------------------------------------------------------------------------
  867. //
  868. // Member: CChainPathObject::FindAndAddIssuersFromCacheByMatchType, public
  869. //
  870. // Synopsis: find and add cached issuers for the specified match type
  871. //
  872. //----------------------------------------------------------------------------
  873. BOOL
  874. CChainPathObject::FindAndAddIssuersFromCacheByMatchType(
  875. IN DWORD dwMatchType,
  876. IN PCCHAINCALLCONTEXT pCallContext,
  877. IN OPTIONAL HCERTSTORE hAdditionalStore
  878. )
  879. {
  880. BOOL fResult;
  881. PCCERTOBJECT pCertObject = m_pCertObject;
  882. PCCERTCHAINENGINE pChainEngine = pCertObject->ChainEngine();
  883. PCCERTOBJECTCACHE pCertObjectCache = pChainEngine->CertObjectCache();
  884. PCCERTOBJECT pIssuer = NULL;
  885. HLRUCACHE hCache;
  886. HLRUENTRY hEntry;
  887. PCRYPT_DATA_BLOB pIdentifier;
  888. CRYPT_DATA_BLOB DataBlob;
  889. PCERT_AUTHORITY_KEY_ID_INFO pAuthKeyIdentifier;
  890. switch (dwMatchType) {
  891. case CERT_EXACT_ISSUER_MATCH_TYPE:
  892. hCache = pCertObjectCache->IdentifierIndex();
  893. pCertObject->GetIssuerExactMatchHash(&DataBlob);
  894. pIdentifier = &DataBlob;
  895. break;
  896. case CERT_KEYID_ISSUER_MATCH_TYPE:
  897. hCache = pCertObjectCache->KeyIdIndex();
  898. pAuthKeyIdentifier = pCertObject->AuthorityKeyIdentifier();
  899. pIdentifier = &pAuthKeyIdentifier->KeyId;
  900. break;
  901. case CERT_NAME_ISSUER_MATCH_TYPE:
  902. hCache = pCertObjectCache->SubjectNameIndex();
  903. pIdentifier = &pCertObject->CertContext()->pCertInfo->Issuer;
  904. break;
  905. case CERT_PUBKEY_ISSUER_MATCH_TYPE:
  906. hCache = pCertObjectCache->PublicKeyHashIndex();
  907. DataBlob.cbData = CHAINHASHLEN;
  908. DataBlob.pbData = pCertObject->IssuerPublicKeyHash();
  909. pIdentifier = &DataBlob;
  910. break;
  911. default:
  912. goto InvalidMatchType;
  913. }
  914. pIssuer = pCertObjectCache->FindIssuerObject(hCache, pIdentifier);
  915. while (pIssuer) {
  916. DWORD dwIssuerStatusFlags;
  917. if (!m_pIssuerList->AddIssuer(
  918. pCallContext,
  919. hAdditionalStore,
  920. pIssuer
  921. ))
  922. goto AddIssuerError;
  923. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  924. if (CERT_PUBKEY_ISSUER_MATCH_TYPE != dwMatchType &&
  925. (dwIssuerStatusFlags & CERT_ISSUER_VALID_SIGNATURE_FLAG)) {
  926. assert(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG);
  927. // We will be called again using the PUBKEY match
  928. goto SuccessReturn;
  929. }
  930. switch (dwMatchType) {
  931. case CERT_EXACT_ISSUER_MATCH_TYPE:
  932. hEntry = pIssuer->IdentifierIndexEntry();
  933. break;
  934. case CERT_KEYID_ISSUER_MATCH_TYPE:
  935. hEntry = pIssuer->KeyIdIndexEntry();
  936. break;
  937. case CERT_NAME_ISSUER_MATCH_TYPE:
  938. hEntry = pIssuer->SubjectNameIndexEntry();
  939. break;
  940. case CERT_PUBKEY_ISSUER_MATCH_TYPE:
  941. hEntry = pIssuer->PublicKeyHashIndexEntry();
  942. break;
  943. default:
  944. goto InvalidMatchType;
  945. }
  946. pIssuer = pCertObjectCache->NextMatchingIssuerObject(hEntry, pIssuer);
  947. }
  948. SuccessReturn:
  949. fResult = TRUE;
  950. CommonReturn:
  951. if (pIssuer) {
  952. DWORD dwErr = GetLastError();
  953. pIssuer->Release();
  954. SetLastError(dwErr);
  955. }
  956. return fResult;
  957. ErrorReturn:
  958. fResult = FALSE;
  959. goto CommonReturn;
  960. SET_ERROR(InvalidMatchType, E_UNEXPECTED)
  961. TRACE_ERROR(AddIssuerError)
  962. }
  963. //+---------------------------------------------------------------------------
  964. //
  965. // Member: CChainPathObject::FindAndAddIssuersFromStoreByMatchType, public
  966. //
  967. // Synopsis: find and add issuers from either the engine's or an
  968. // external store for the specified match type
  969. //
  970. //----------------------------------------------------------------------------
  971. BOOL
  972. CChainPathObject::FindAndAddIssuersFromStoreByMatchType(
  973. IN DWORD dwMatchType,
  974. IN PCCHAINCALLCONTEXT pCallContext,
  975. IN BOOL fExternalStore,
  976. IN OPTIONAL HCERTSTORE hAdditionalStore,
  977. IN OPTIONAL HCERTSTORE hIssuerUrlStore
  978. )
  979. {
  980. BOOL fResult;
  981. PCCERTOBJECT pCertObject = m_pCertObject;
  982. PCCERTCHAINENGINE pChainEngine = pCertObject->ChainEngine();
  983. HCERTSTORE hAdditionalStoreToUse = NULL;
  984. HCERTSTORE hStore = NULL;
  985. PCCERT_CONTEXT pCertContext = NULL;
  986. DWORD dwFindType;
  987. const void *pvFindPara;
  988. CRYPT_DATA_BLOB DataBlob;
  989. CERT_INFO CertInfo;
  990. PCERT_AUTHORITY_KEY_ID_INFO pAuthKeyIdentifier;
  991. if (fExternalStore) {
  992. if (hIssuerUrlStore) {
  993. hStore = CertDuplicateStore(hIssuerUrlStore);
  994. if (hAdditionalStore) {
  995. hAdditionalStoreToUse = CertOpenStore(
  996. CERT_STORE_PROV_COLLECTION,
  997. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  998. NULL,
  999. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  1000. NULL
  1001. );
  1002. if (NULL == hAdditionalStoreToUse)
  1003. goto OpenCollectionStoreError;
  1004. if (!CertAddStoreToCollection(hAdditionalStoreToUse,
  1005. hIssuerUrlStore, 0, 0))
  1006. goto AddToCollectionStoreError;
  1007. if (!CertAddStoreToCollection(hAdditionalStoreToUse,
  1008. hAdditionalStore, 0, 0))
  1009. goto AddToCollectionStoreError;
  1010. } else
  1011. hAdditionalStoreToUse = CertDuplicateStore(hIssuerUrlStore);
  1012. } else {
  1013. assert(hAdditionalStore);
  1014. hStore = CertDuplicateStore(hAdditionalStore);
  1015. hAdditionalStoreToUse = CertDuplicateStore(hAdditionalStore);
  1016. }
  1017. } else {
  1018. hStore = CertDuplicateStore(pChainEngine->OtherStore());
  1019. if (hAdditionalStore)
  1020. hAdditionalStoreToUse = CertDuplicateStore(hAdditionalStore);
  1021. }
  1022. switch (dwMatchType) {
  1023. case CERT_EXACT_ISSUER_MATCH_TYPE:
  1024. dwFindType = CERT_FIND_SUBJECT_CERT;
  1025. pAuthKeyIdentifier = pCertObject->AuthorityKeyIdentifier();
  1026. CertInfo.Issuer = pAuthKeyIdentifier->CertIssuer;
  1027. CertInfo.SerialNumber = pAuthKeyIdentifier->CertSerialNumber;
  1028. pvFindPara = (const void *) &CertInfo;
  1029. break;
  1030. case CERT_KEYID_ISSUER_MATCH_TYPE:
  1031. dwFindType = CERT_FIND_KEY_IDENTIFIER;
  1032. pAuthKeyIdentifier = pCertObject->AuthorityKeyIdentifier();
  1033. pvFindPara = (const void *) &pAuthKeyIdentifier->KeyId;
  1034. break;
  1035. case CERT_NAME_ISSUER_MATCH_TYPE:
  1036. dwFindType = CERT_FIND_SUBJECT_NAME;
  1037. pvFindPara =
  1038. (const void *) &pCertObject->CertContext()->pCertInfo->Issuer;
  1039. break;
  1040. case CERT_PUBKEY_ISSUER_MATCH_TYPE:
  1041. dwFindType = CERT_FIND_PUBKEY_MD5_HASH;
  1042. DataBlob.cbData = CHAINHASHLEN;
  1043. DataBlob.pbData = pCertObject->IssuerPublicKeyHash();
  1044. pvFindPara = (const void *) &DataBlob;
  1045. break;
  1046. default:
  1047. goto InvalidMatchType;
  1048. }
  1049. while (pCertContext = CertFindCertificateInStore(
  1050. hStore,
  1051. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1052. 0, // dwFindFlags
  1053. dwFindType,
  1054. pvFindPara,
  1055. pCertContext
  1056. )) {
  1057. DWORD dwIssuerStatusFlags;
  1058. PCCERTOBJECT pIssuer = NULL;
  1059. if (!ChainCreateCertObject (
  1060. fExternalStore ? CERT_EXTERNAL_ISSUER_OBJECT_TYPE :
  1061. CERT_CACHED_ISSUER_OBJECT_TYPE,
  1062. pCallContext,
  1063. pCertContext,
  1064. NULL, // rgbCertHash
  1065. &pIssuer
  1066. ))
  1067. goto CreateIssuerObjectError;
  1068. fResult = m_pIssuerList->AddIssuer(
  1069. pCallContext,
  1070. hAdditionalStoreToUse,
  1071. pIssuer
  1072. );
  1073. pIssuer->Release();
  1074. if (!fResult)
  1075. goto AddIssuerError;
  1076. dwIssuerStatusFlags = pCertObject->IssuerStatusFlags();
  1077. if (CERT_PUBKEY_ISSUER_MATCH_TYPE != dwMatchType &&
  1078. (dwIssuerStatusFlags & CERT_ISSUER_VALID_SIGNATURE_FLAG)) {
  1079. assert(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG);
  1080. // We will be called again using the PUBKEY match
  1081. goto SuccessReturn;
  1082. }
  1083. }
  1084. if (CRYPT_E_NOT_FOUND != GetLastError())
  1085. goto FindCertificateInStoreError;
  1086. if (!fExternalStore)
  1087. // All matching issuers from the engine's store should be in
  1088. // the cache now.
  1089. pCertObject->OrCachedMatchFlags(CERT_MATCH_TYPE_TO_FLAG(dwMatchType));
  1090. SuccessReturn:
  1091. fResult = TRUE;
  1092. CommonReturn:
  1093. if (pCertContext)
  1094. CertFreeCertificateContext(pCertContext);
  1095. if (hAdditionalStoreToUse)
  1096. CertCloseStore(hAdditionalStoreToUse, 0);
  1097. if (hStore)
  1098. CertCloseStore(hStore, 0);
  1099. return fResult;
  1100. ErrorReturn:
  1101. fResult = FALSE;
  1102. goto CommonReturn;
  1103. TRACE_ERROR(OpenCollectionStoreError)
  1104. TRACE_ERROR(AddToCollectionStoreError)
  1105. SET_ERROR(InvalidMatchType, E_UNEXPECTED)
  1106. TRACE_ERROR(CreateIssuerObjectError)
  1107. TRACE_ERROR(AddIssuerError)
  1108. TRACE_ERROR(FindCertificateInStoreError)
  1109. }
  1110. //+---------------------------------------------------------------------------
  1111. //
  1112. // Member: CChainPathObject::FindAndAddCtlIssuersFromCache, public
  1113. //
  1114. // Synopsis: find and add matching CTL issuers from the cache
  1115. //
  1116. //----------------------------------------------------------------------------
  1117. BOOL
  1118. CChainPathObject::FindAndAddCtlIssuersFromCache (
  1119. IN PCCHAINCALLCONTEXT pCallContext,
  1120. IN OPTIONAL HCERTSTORE hAdditionalStore
  1121. )
  1122. {
  1123. PCERT_OBJECT_CTL_CACHE_ENTRY pEntry;
  1124. assert(m_pCertObject->IssuerStatusFlags() &
  1125. CERT_ISSUER_SELF_SIGNED_FLAG);
  1126. assert(!(m_pCertObject->IssuerStatusFlags() &
  1127. CERT_ISSUER_TRUSTED_ROOT_FLAG));
  1128. pEntry = NULL;
  1129. while (pEntry = m_pCertObject->NextCtlCacheEntry(pEntry)) {
  1130. PCERT_TRUST_LIST_INFO pTrustListInfo = NULL;
  1131. if (!SSCtlAllocAndCopyTrustListInfo(
  1132. pEntry->pTrustListInfo,
  1133. &pTrustListInfo
  1134. ))
  1135. return FALSE;
  1136. if (!m_pIssuerList->AddCtlIssuer(
  1137. pCallContext,
  1138. hAdditionalStore,
  1139. pEntry->pSSCtlObject,
  1140. pTrustListInfo
  1141. ))
  1142. {
  1143. SSCtlFreeTrustListInfo(pTrustListInfo);
  1144. return FALSE;
  1145. }
  1146. }
  1147. return TRUE;
  1148. }
  1149. //+---------------------------------------------------------------------------
  1150. //
  1151. // Member: CChainPathObject::FindAndAddCtlIssuersFromAdditionalStore, public
  1152. //
  1153. // Synopsis: find and add matching Ctl issuers from an additional store
  1154. //
  1155. //----------------------------------------------------------------------------
  1156. BOOL
  1157. CChainPathObject::FindAndAddCtlIssuersFromAdditionalStore (
  1158. IN PCCHAINCALLCONTEXT pCallContext,
  1159. IN HCERTSTORE hAdditionalStore
  1160. )
  1161. {
  1162. BOOL fResult;
  1163. PCCTL_CONTEXT pCtlContext = NULL;
  1164. PCSSCTLOBJECT pSSCtlObject = NULL;
  1165. assert(hAdditionalStore);
  1166. while (pCtlContext = CertEnumCTLsInStore(hAdditionalStore, pCtlContext))
  1167. {
  1168. PCERT_TRUST_LIST_INFO pTrustListInfo = NULL;
  1169. pSSCtlObject = NULL;
  1170. if (!SSCtlCreateCtlObject(
  1171. m_pCertObject->ChainEngine(),
  1172. pCtlContext,
  1173. TRUE, // fAdditionalStore
  1174. &pSSCtlObject
  1175. ))
  1176. // Should look at the different errors
  1177. continue;
  1178. if (!pSSCtlObject->GetTrustListInfo(
  1179. m_pCertObject->CertContext(),
  1180. &pTrustListInfo
  1181. )) {
  1182. DWORD dwErr = GetLastError();
  1183. if (CRYPT_E_NOT_FOUND != dwErr)
  1184. goto GetTrustListInfoError;
  1185. else {
  1186. pSSCtlObject->Release();
  1187. continue;
  1188. }
  1189. }
  1190. if (!m_pIssuerList->AddCtlIssuer(
  1191. pCallContext,
  1192. hAdditionalStore,
  1193. pSSCtlObject,
  1194. pTrustListInfo
  1195. )) {
  1196. SSCtlFreeTrustListInfo(pTrustListInfo);
  1197. goto AddCtlIssuerError;
  1198. }
  1199. pSSCtlObject->Release();
  1200. }
  1201. fResult = TRUE;
  1202. CommonReturn:
  1203. return fResult;
  1204. ErrorReturn:
  1205. if (pCtlContext)
  1206. CertFreeCTLContext(pCtlContext);
  1207. if (pSSCtlObject)
  1208. pSSCtlObject->Release();
  1209. fResult = FALSE;
  1210. goto CommonReturn;
  1211. TRACE_ERROR(GetTrustListInfoError)
  1212. TRACE_ERROR(AddCtlIssuerError)
  1213. }
  1214. //+---------------------------------------------------------------------------
  1215. //
  1216. // Member: CChainPathObject::NextPath, public
  1217. //
  1218. // Synopsis: Get the next top path object for this end path object.
  1219. //
  1220. //----------------------------------------------------------------------------
  1221. PCCHAINPATHOBJECT
  1222. CChainPathObject::NextPath (
  1223. IN PCCHAINCALLCONTEXT pCallContext,
  1224. IN OPTIONAL PCCHAINPATHOBJECT pPrevTopPathObject
  1225. )
  1226. {
  1227. PCCHAINPATHOBJECT pTopPathObject;
  1228. PCERT_ISSUER_ELEMENT pSubjectIssuerElement;
  1229. PCCHAINPATHOBJECT pSubjectPathObject;
  1230. DWORD dwFlags = pCallContext->CallFlags();
  1231. if (NULL == pPrevTopPathObject) {
  1232. pSubjectIssuerElement = NULL;
  1233. pSubjectPathObject = NULL;
  1234. } else {
  1235. // Find the next issuer for the issuer's subject certificate.
  1236. // We iterate downward toward the end certificate
  1237. while (TRUE) {
  1238. pSubjectIssuerElement = pPrevTopPathObject->m_pDownIssuerElement;
  1239. pSubjectPathObject = pPrevTopPathObject->m_pDownPathObject;
  1240. // Set to NULL so it can be reused. Used to determine if
  1241. // cyclic.
  1242. pPrevTopPathObject->m_pDownPathObject = NULL;
  1243. pPrevTopPathObject->m_fHasAdditionalStatus = FALSE;
  1244. if (NULL == pSubjectPathObject) {
  1245. // We have reached the end certificate without having a
  1246. // next path
  1247. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  1248. goto NoPath;
  1249. }
  1250. assert(pSubjectIssuerElement);
  1251. if (pSubjectIssuerElement->pCyclicSaveIssuer) {
  1252. // Restore the issuer replaced by the cyclic issuer
  1253. pSubjectIssuerElement->pIssuer =
  1254. pSubjectIssuerElement->pCyclicSaveIssuer;
  1255. pSubjectIssuerElement->pCyclicSaveIssuer = NULL;
  1256. }
  1257. // Move on to the next issuer for the subject. Skip low
  1258. // quality issuers
  1259. while (pSubjectIssuerElement =
  1260. pSubjectPathObject->m_pIssuerList->NextElement(
  1261. pSubjectIssuerElement)) {
  1262. if ((dwFlags & CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING) ||
  1263. pSubjectIssuerElement->dwPass1Quality >=
  1264. pSubjectPathObject->m_dwPass1Quality)
  1265. break;
  1266. }
  1267. if (pSubjectIssuerElement)
  1268. // The subject has another issuer
  1269. break;
  1270. // Note, a untrusted self signed root without CTLs is equal and
  1271. // possibly higher quality than having untrusted CTLs
  1272. if ((pSubjectPathObject->m_TrustStatus.dwInfoStatus &
  1273. CERT_TRUST_IS_SELF_SIGNED) &&
  1274. (dwFlags & CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING) &&
  1275. !(pSubjectPathObject->m_dwPass1Quality &
  1276. CERT_QUALITY_HAS_TRUSTED_ROOT)) {
  1277. pTopPathObject = pSubjectPathObject;
  1278. pTopPathObject->m_pUpIssuerElement = NULL;
  1279. goto SelfSignedRootInsteadOfCtlPathReturn;
  1280. }
  1281. // Find the next issuer for my subject
  1282. pPrevTopPathObject = pSubjectPathObject;
  1283. }
  1284. }
  1285. // Iterate upward until the TopPathObject's issuer list is empty or
  1286. // we have detected a cyclic PathObject
  1287. while (TRUE) {
  1288. if (NULL == pSubjectIssuerElement) {
  1289. // End (bottom) certificate
  1290. pTopPathObject = this;
  1291. pTopPathObject->m_dwChainIndex = 0;
  1292. pTopPathObject->m_dwElementIndex = 0;
  1293. } else {
  1294. pTopPathObject = pSubjectIssuerElement->pIssuer;
  1295. // Determine if cyclic.
  1296. if (pTopPathObject->m_pDownPathObject ||
  1297. pTopPathObject == this) {
  1298. // The returned Cyclic path won't have any issuers
  1299. if (!ChainCreateCyclicPathObject(
  1300. pCallContext,
  1301. pTopPathObject,
  1302. &pTopPathObject
  1303. ))
  1304. goto CreateCyclicPathObjectError;
  1305. pSubjectIssuerElement->pCyclicSaveIssuer =
  1306. pSubjectIssuerElement->pIssuer;
  1307. pSubjectIssuerElement->pIssuer = pTopPathObject;
  1308. }
  1309. if (pSubjectPathObject->m_TrustStatus.dwInfoStatus &
  1310. CERT_TRUST_IS_SELF_SIGNED) {
  1311. pTopPathObject->m_dwChainIndex =
  1312. pSubjectPathObject->m_dwChainIndex + 1;
  1313. pTopPathObject->m_dwElementIndex = 0;
  1314. } else {
  1315. pTopPathObject->m_dwChainIndex =
  1316. pSubjectPathObject->m_dwChainIndex;
  1317. pTopPathObject->m_dwElementIndex =
  1318. pSubjectPathObject->m_dwElementIndex + 1;
  1319. }
  1320. pSubjectPathObject->m_pUpIssuerElement = pSubjectIssuerElement;
  1321. }
  1322. pTopPathObject->m_pDownIssuerElement = pSubjectIssuerElement;
  1323. pTopPathObject->m_pDownPathObject = pSubjectPathObject;
  1324. pSubjectPathObject = pTopPathObject;
  1325. // Find the first issuer having sufficient quality
  1326. pSubjectIssuerElement = NULL;
  1327. while (pSubjectIssuerElement =
  1328. pSubjectPathObject->m_pIssuerList->NextElement(
  1329. pSubjectIssuerElement)) {
  1330. if ((dwFlags & CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING) ||
  1331. pSubjectIssuerElement->dwPass1Quality >=
  1332. pSubjectPathObject->m_dwPass1Quality) {
  1333. // For a CTL, check that we have an issuer
  1334. if (NULL != pSubjectIssuerElement->pIssuer)
  1335. break;
  1336. else {
  1337. assert(pSubjectIssuerElement->fCtlIssuer);
  1338. }
  1339. }
  1340. }
  1341. if (NULL == pSubjectIssuerElement) {
  1342. pTopPathObject->m_pUpIssuerElement = NULL;
  1343. break;
  1344. }
  1345. }
  1346. SelfSignedRootInsteadOfCtlPathReturn:
  1347. CommonReturn:
  1348. return pTopPathObject;
  1349. NoPath:
  1350. ErrorReturn:
  1351. pTopPathObject = NULL;
  1352. goto CommonReturn;
  1353. TRACE_ERROR(CreateCyclicPathObjectError)
  1354. }
  1355. //+---------------------------------------------------------------------------
  1356. //
  1357. // Member: CChainPathObject::CalculateAdditionalStatus, public
  1358. //
  1359. // Synopsis: calculate additional status bits based on time, usage,
  1360. // revocation, ...
  1361. //
  1362. //----------------------------------------------------------------------------
  1363. VOID
  1364. CChainPathObject::CalculateAdditionalStatus (
  1365. IN PCCHAINCALLCONTEXT pCallContext,
  1366. IN HCERTSTORE hAllStore
  1367. )
  1368. {
  1369. PCERT_INFO pCertInfo = m_pCertObject->CertContext()->pCertInfo;
  1370. FILETIME RequestedTime;
  1371. FILETIME CurrentTime;
  1372. assert(!m_fHasAdditionalStatus);
  1373. memset(&m_AdditionalStatus, 0, sizeof(m_AdditionalStatus));
  1374. if (m_pwszExtendedErrorInfo) {
  1375. PkiFree(m_pwszExtendedErrorInfo);
  1376. m_pwszExtendedErrorInfo = NULL;
  1377. }
  1378. pCallContext->RequestedTime(&RequestedTime);
  1379. pCallContext->CurrentTime(&CurrentTime);
  1380. if (0 == m_dwChainIndex) {
  1381. // First simple chain
  1382. if (0 == m_dwElementIndex) {
  1383. // End cert
  1384. if (pCallContext->CallFlags() & CERT_CHAIN_TIMESTAMP_TIME) {
  1385. // For time stamping, the end certificate needs to be valid
  1386. // for both the time stamped and current times.
  1387. if (0 != CertVerifyTimeValidity(&RequestedTime, pCertInfo) ||
  1388. 0 != CertVerifyTimeValidity(&CurrentTime, pCertInfo))
  1389. m_AdditionalStatus.dwErrorStatus |=
  1390. CERT_TRUST_IS_NOT_TIME_VALID;
  1391. } else {
  1392. // End certificate needs to be valid for the requested time
  1393. if (0 != CertVerifyTimeValidity(&RequestedTime, pCertInfo))
  1394. m_AdditionalStatus.dwErrorStatus |=
  1395. CERT_TRUST_IS_NOT_TIME_VALID;
  1396. }
  1397. } else {
  1398. // CA or root
  1399. if (pCallContext->CallFlags() & CERT_CHAIN_TIMESTAMP_TIME) {
  1400. // For time stamping, the CA or root needs to be valid using
  1401. // current time
  1402. if (0 != CertVerifyTimeValidity(&CurrentTime, pCertInfo))
  1403. m_AdditionalStatus.dwErrorStatus |=
  1404. CERT_TRUST_IS_NOT_TIME_VALID;
  1405. } else {
  1406. // The CA or root needs to be valid using either the requested
  1407. // or current time. Allowing current time is necessary for
  1408. // cross certificate chains.
  1409. if (!(0 == CertVerifyTimeValidity(&RequestedTime, pCertInfo) ||
  1410. 0 == CertVerifyTimeValidity(&CurrentTime, pCertInfo)))
  1411. m_AdditionalStatus.dwErrorStatus |=
  1412. CERT_TRUST_IS_NOT_TIME_VALID;
  1413. }
  1414. }
  1415. } else {
  1416. // CTL signer chains. Must be valid using current time.
  1417. if (0 != CertVerifyTimeValidity(&CurrentTime, pCertInfo))
  1418. m_AdditionalStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_TIME_VALID;
  1419. }
  1420. if (m_pDownIssuerElement) {
  1421. PCERT_USAGE_MATCH pUsageToUse;
  1422. CERT_USAGE_MATCH CtlUsage;
  1423. LPSTR pszUsage = szOID_KP_CTL_USAGE_SIGNING;
  1424. // Update subject's issuer status
  1425. assert (m_pDownIssuerElement->pIssuer = this);
  1426. if (0 != m_pDownPathObject->m_dwChainIndex) {
  1427. // CTL path object
  1428. memset(&CtlUsage, 0, sizeof(CtlUsage));
  1429. CtlUsage.dwType = USAGE_MATCH_TYPE_AND;
  1430. CtlUsage.Usage.cUsageIdentifier = 1;
  1431. CtlUsage.Usage.rgpszUsageIdentifier = &pszUsage;
  1432. pUsageToUse = &CtlUsage;
  1433. } else
  1434. pUsageToUse = &pCallContext->ChainPara()->RequestedUsage;
  1435. if (m_pDownIssuerElement->fCtlIssuer) {
  1436. FILETIME CurrentTime;
  1437. memset(&m_pDownIssuerElement->SubjectStatus, 0,
  1438. sizeof(m_pDownIssuerElement->SubjectStatus));
  1439. pCallContext->CurrentTime(&CurrentTime);
  1440. m_pDownIssuerElement->pCtlIssuerData->pSSCtlObject->
  1441. CalculateStatus(
  1442. &CurrentTime,
  1443. pUsageToUse,
  1444. &m_pDownIssuerElement->SubjectStatus
  1445. );
  1446. } else {
  1447. CalculatePolicyConstraintsStatus();
  1448. CalculateBasicConstraintsStatus();
  1449. CalculateKeyUsageStatus();
  1450. CalculateNameConstraintsStatus(pUsageToUse);
  1451. }
  1452. }
  1453. if (pCallContext->CallFlags() & CERT_CHAIN_REVOCATION_CHECK_ALL) {
  1454. // For CTL signer chains, always use current time
  1455. CalculateRevocationStatus(
  1456. pCallContext,
  1457. hAllStore,
  1458. 0 == m_dwChainIndex ? &RequestedTime : &CurrentTime
  1459. );
  1460. }
  1461. m_fHasAdditionalStatus = TRUE;
  1462. }
  1463. //+---------------------------------------------------------------------------
  1464. //
  1465. // Member: CChainPathObject::CalculatePolicyConstraintsStatus, public
  1466. //
  1467. // Synopsis: calculate policy constraints additional status for this
  1468. // issuer
  1469. //
  1470. //----------------------------------------------------------------------------
  1471. VOID
  1472. CChainPathObject::CalculatePolicyConstraintsStatus ()
  1473. {
  1474. PCHAIN_POLICIES_INFO pPoliciesInfo;
  1475. DWORD i;
  1476. assert (0 != m_dwElementIndex);
  1477. pPoliciesInfo = m_pCertObject->PoliciesInfo();
  1478. for (i = 0; i < CHAIN_ISS_OR_APP_COUNT; i++ ) {
  1479. PCERT_POLICY_CONSTRAINTS_INFO pConstraints =
  1480. pPoliciesInfo->rgIssOrAppInfo[i].pConstraints;
  1481. DWORD dwRequireSkipCerts;
  1482. DWORD dwInhibitSkipCerts;
  1483. PCCHAINPATHOBJECT pPathObject;
  1484. if (NULL == pConstraints)
  1485. continue;
  1486. dwRequireSkipCerts = pConstraints->dwRequireExplicitPolicySkipCerts;
  1487. dwInhibitSkipCerts = pConstraints->dwInhibitPolicyMappingSkipCerts;
  1488. for (pPathObject = m_pDownPathObject;
  1489. NULL != pPathObject &&
  1490. pPathObject->m_dwChainIndex == m_dwChainIndex;
  1491. pPathObject = pPathObject->m_pDownPathObject) {
  1492. PCHAIN_POLICIES_INFO pSubjectPoliciesInfo;
  1493. pSubjectPoliciesInfo = pPathObject->m_pCertObject->PoliciesInfo();
  1494. if (pConstraints->fRequireExplicitPolicy) {
  1495. if (0 < dwRequireSkipCerts)
  1496. dwRequireSkipCerts--;
  1497. else {
  1498. if (NULL == pSubjectPoliciesInfo->rgIssOrAppInfo[i].pPolicy)
  1499. {
  1500. m_AdditionalStatus.dwErrorStatus |=
  1501. CERT_TRUST_INVALID_POLICY_CONSTRAINTS;
  1502. goto RequireExplicitPolicyError;
  1503. }
  1504. }
  1505. }
  1506. if (pConstraints->fInhibitPolicyMapping) {
  1507. if (0 < dwInhibitSkipCerts)
  1508. dwInhibitSkipCerts--;
  1509. else {
  1510. if (pSubjectPoliciesInfo->rgIssOrAppInfo[i].pMappings)
  1511. {
  1512. m_AdditionalStatus.dwErrorStatus |=
  1513. CERT_TRUST_INVALID_POLICY_CONSTRAINTS;
  1514. goto InhibitPolicyMappingError;
  1515. }
  1516. }
  1517. }
  1518. }
  1519. }
  1520. CommonReturn:
  1521. return;
  1522. ErrorReturn:
  1523. goto CommonReturn;
  1524. TRACE_ERROR(RequireExplicitPolicyError)
  1525. TRACE_ERROR(InhibitPolicyMappingError)
  1526. }
  1527. //+---------------------------------------------------------------------------
  1528. //
  1529. // Member: CChainPathObject::CalculateBasicConstraintsStatus, public
  1530. //
  1531. // Synopsis: calculate basic constraints additional status for this
  1532. // issuer
  1533. //
  1534. //----------------------------------------------------------------------------
  1535. VOID
  1536. CChainPathObject::CalculateBasicConstraintsStatus ()
  1537. {
  1538. PCERT_BASIC_CONSTRAINTS2_INFO pInfo;
  1539. assert (0 != m_dwElementIndex);
  1540. if (m_pCertObject->InfoFlags() &
  1541. CHAIN_INVALID_BASIC_CONSTRAINTS_INFO_FLAG) {
  1542. m_AdditionalStatus.dwErrorStatus |= CERT_TRUST_INVALID_EXTENSION |
  1543. CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
  1544. }
  1545. pInfo = m_pCertObject->BasicConstraintsInfo();
  1546. if (NULL == pInfo)
  1547. return;
  1548. if (!pInfo->fCA || (pInfo->fPathLenConstraint &&
  1549. m_dwElementIndex > pInfo->dwPathLenConstraint + 1)) {
  1550. m_AdditionalStatus.dwErrorStatus |=
  1551. CERT_TRUST_INVALID_BASIC_CONSTRAINTS;
  1552. goto BasicConstraintsError;
  1553. }
  1554. CommonReturn:
  1555. return;
  1556. ErrorReturn:
  1557. goto CommonReturn;
  1558. TRACE_ERROR(BasicConstraintsError)
  1559. }
  1560. //+---------------------------------------------------------------------------
  1561. //
  1562. // Member: CChainPathObject::CalculateKeyUsageStatus, public
  1563. //
  1564. // Synopsis: calculate key usage additional status for this
  1565. // issuer
  1566. //
  1567. //----------------------------------------------------------------------------
  1568. VOID
  1569. CChainPathObject::CalculateKeyUsageStatus ()
  1570. {
  1571. PCRYPT_BIT_BLOB pKeyUsage;
  1572. assert (0 != m_dwElementIndex);
  1573. if (m_pCertObject->InfoFlags() & CHAIN_INVALID_KEY_USAGE_FLAG) {
  1574. m_AdditionalStatus.dwErrorStatus |= CERT_TRUST_INVALID_EXTENSION |
  1575. CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
  1576. }
  1577. pKeyUsage = m_pCertObject->KeyUsage();
  1578. if (NULL == pKeyUsage)
  1579. return;
  1580. if (1 > pKeyUsage->cbData ||
  1581. 0 == (pKeyUsage->pbData[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)) {
  1582. m_AdditionalStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
  1583. goto KeyUsageError;
  1584. }
  1585. CommonReturn:
  1586. return;
  1587. ErrorReturn:
  1588. goto CommonReturn;
  1589. TRACE_ERROR(KeyUsageError)
  1590. }
  1591. //+---------------------------------------------------------------------------
  1592. //
  1593. // Member: CChainPathObject::CalculateNameConstraintsStatus, public
  1594. //
  1595. // Synopsis: calculate name constraints additional status for this
  1596. // issuer
  1597. //
  1598. //----------------------------------------------------------------------------
  1599. VOID
  1600. CChainPathObject::CalculateNameConstraintsStatus (
  1601. IN PCERT_USAGE_MATCH pUsageToUse
  1602. )
  1603. {
  1604. PCERT_NAME_CONSTRAINTS_INFO pIssuerInfo;
  1605. PCHAIN_SUBJECT_NAME_CONSTRAINTS_INFO pSubjectInfo;
  1606. PCERT_BASIC_CONSTRAINTS2_INFO pSubjectBasicInfo;
  1607. PCCHAINPATHOBJECT pSubjectObject;
  1608. DWORD dwErrorStatus = 0;
  1609. assert (0 != m_dwElementIndex);
  1610. if (m_pCertObject->InfoFlags() &
  1611. CHAIN_INVALID_ISSUER_NAME_CONSTRAINTS_INFO_FLAG) {
  1612. m_AdditionalStatus.dwErrorStatus |= CERT_TRUST_INVALID_EXTENSION |
  1613. CERT_TRUST_INVALID_NAME_CONSTRAINTS;
  1614. ChainFormatAndAppendExtendedErrorInfo(
  1615. &m_pwszExtendedErrorInfo,
  1616. IDS_INVALID_ISSUER_NAME_CONSTRAINT_EXT
  1617. );
  1618. }
  1619. pIssuerInfo = m_pCertObject->IssuerNameConstraintsInfo();
  1620. if (NULL == pIssuerInfo)
  1621. // No NameConstraint check
  1622. return;
  1623. // We only verify the name constraints on the end cert
  1624. for (pSubjectObject = m_pDownPathObject;
  1625. NULL != pSubjectObject && 0 != pSubjectObject->m_dwElementIndex;
  1626. pSubjectObject = pSubjectObject->m_pDownPathObject)
  1627. ;
  1628. assert(pSubjectObject);
  1629. assert(pSubjectObject->m_dwChainIndex == m_dwChainIndex);
  1630. if (NULL == pSubjectObject)
  1631. return;
  1632. pSubjectBasicInfo = pSubjectObject->m_pCertObject->BasicConstraintsInfo();
  1633. if (pSubjectBasicInfo && pSubjectBasicInfo->fCA)
  1634. // End cert is a CA.
  1635. return;
  1636. pSubjectInfo = pSubjectObject->m_pCertObject->SubjectNameConstraintsInfo();
  1637. if (pSubjectInfo->fInvalid) {
  1638. dwErrorStatus |= CERT_TRUST_INVALID_EXTENSION |
  1639. CERT_TRUST_INVALID_NAME_CONSTRAINTS;
  1640. ChainFormatAndAppendExtendedErrorInfo(
  1641. &m_pwszExtendedErrorInfo,
  1642. IDS_INVALID_SUBJECT_NAME_CONSTRAINT_INFO
  1643. );
  1644. goto InvalidNameConstraints;
  1645. }
  1646. if (pSubjectInfo->pAltNameInfo) {
  1647. // Loop through all the AltName entries. There needs to be a
  1648. // name constraint for each entry.
  1649. DWORD cEntry;
  1650. PCERT_ALT_NAME_ENTRY pEntry;
  1651. cEntry = pSubjectInfo->pAltNameInfo->cAltEntry;
  1652. pEntry = pSubjectInfo->pAltNameInfo->rgAltEntry;
  1653. for ( ; 0 < cEntry; cEntry--, pEntry++) {
  1654. BOOL fSupported;
  1655. // Check if a NameConstraint for this entry choice is supported
  1656. fSupported = FALSE;
  1657. switch (pEntry->dwAltNameChoice) {
  1658. case CERT_ALT_NAME_OTHER_NAME:
  1659. // Only support the UPN OID
  1660. if (0 == strcmp(pEntry->pOtherName->pszObjId,
  1661. szOID_NT_PRINCIPAL_NAME))
  1662. fSupported = TRUE;
  1663. break;
  1664. case CERT_ALT_NAME_RFC822_NAME:
  1665. case CERT_ALT_NAME_DNS_NAME:
  1666. case CERT_ALT_NAME_URL:
  1667. case CERT_ALT_NAME_DIRECTORY_NAME:
  1668. fSupported = TRUE;
  1669. break;
  1670. case CERT_ALT_NAME_IP_ADDRESS:
  1671. // Only support 4 or 16 byte IP addresses
  1672. if (4 == pEntry->IPAddress.cbData ||
  1673. 16 == pEntry->IPAddress.cbData)
  1674. fSupported = TRUE;
  1675. break;
  1676. case CERT_ALT_NAME_X400_ADDRESS:
  1677. case CERT_ALT_NAME_EDI_PARTY_NAME:
  1678. case CERT_ALT_NAME_REGISTERED_ID:
  1679. default:
  1680. // Not supported
  1681. break;
  1682. }
  1683. if (!fSupported) {
  1684. dwErrorStatus |= CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
  1685. ChainFormatAndAppendNameConstraintsAltNameEntryFixup(
  1686. &m_pwszExtendedErrorInfo,
  1687. pEntry,
  1688. IDS_NOT_SUPPORTED_ENTRY_NAME_CONSTRAINT
  1689. );
  1690. } else
  1691. dwErrorStatus |=
  1692. ChainCalculateNameConstraintsErrorStatusForAltNameEntry(
  1693. pEntry, pIssuerInfo, &m_pwszExtendedErrorInfo);
  1694. }
  1695. }
  1696. if (pSubjectInfo->pUnicodeNameInfo) {
  1697. // Check as a DIRECTORY_NAME AltNameEntry choice. The DIRECTORY_NAME
  1698. // fixup expects the DirectoryName.pbData to be the decoded and
  1699. // fixup'ed UnicodeNameInfo.
  1700. CERT_ALT_NAME_ENTRY Entry;
  1701. Entry.dwAltNameChoice = CERT_ALT_NAME_DIRECTORY_NAME;
  1702. Entry.DirectoryName.pbData = (BYTE *) pSubjectInfo->pUnicodeNameInfo;
  1703. dwErrorStatus |=
  1704. ChainCalculateNameConstraintsErrorStatusForAltNameEntry(
  1705. &Entry, pIssuerInfo, &m_pwszExtendedErrorInfo);
  1706. }
  1707. if (pSubjectInfo->pEmailAttr) {
  1708. // The SubjectAltName doesn't have an email choice. However, there is an
  1709. // email attribute in the Subject UnicodeNameInfo.
  1710. //
  1711. // Check as a CERT_ALT_NAME_RFC822_NAME AltNameEntry choice. The
  1712. // RFC822 fixup uses the DirectoryName.pbData and DirectoryName.cbData
  1713. // to contain the pointer to and length of the unicode string.
  1714. CERT_ALT_NAME_ENTRY Entry;
  1715. Entry.dwAltNameChoice = CERT_ALT_NAME_RFC822_NAME;
  1716. Entry.DirectoryName = pSubjectInfo->pEmailAttr->Value;
  1717. dwErrorStatus |=
  1718. ChainCalculateNameConstraintsErrorStatusForAltNameEntry(
  1719. &Entry, pIssuerInfo, &m_pwszExtendedErrorInfo);
  1720. }
  1721. if (!pSubjectInfo->fHasDnsAltNameEntry &&
  1722. NULL != pSubjectInfo->pUnicodeNameInfo &&
  1723. ChainIsOIDInUsage(szOID_PKIX_KP_SERVER_AUTH, &pUsageToUse->Usage)) {
  1724. // The SubjectAltName doesn't have a DNS choice and we are building
  1725. // a ServerAuth chain.
  1726. // Need to check all the CN components in the UnicodeNameInfo.
  1727. DWORD cRDN;
  1728. PCERT_RDN pRDN;
  1729. cRDN = pSubjectInfo->pUnicodeNameInfo->cRDN;
  1730. pRDN = pSubjectInfo->pUnicodeNameInfo->rgRDN;
  1731. for ( ; cRDN > 0; cRDN--, pRDN++) {
  1732. DWORD cAttr = pRDN->cRDNAttr;
  1733. PCERT_RDN_ATTR pAttr = pRDN->rgRDNAttr;
  1734. for ( ; cAttr > 0; cAttr--, pAttr++) {
  1735. if (!IS_CERT_RDN_CHAR_STRING(pAttr->dwValueType))
  1736. continue;
  1737. if (0 == strcmp(pAttr->pszObjId, szOID_COMMON_NAME)) {
  1738. //
  1739. // Check as a CERT_ALT_NAME_DNS_NAME AltNameEntry choice.
  1740. // The DNS fixup uses the DirectoryName.pbData and
  1741. // DirectoryName.cbData to contain the pointer to and
  1742. // length of the unicode string.
  1743. CERT_ALT_NAME_ENTRY Entry;
  1744. Entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
  1745. Entry.DirectoryName = pAttr->Value;
  1746. dwErrorStatus |=
  1747. ChainCalculateNameConstraintsErrorStatusForAltNameEntry(
  1748. &Entry, pIssuerInfo, &m_pwszExtendedErrorInfo);
  1749. }
  1750. }
  1751. }
  1752. }
  1753. CommonReturn:
  1754. if (0 == dwErrorStatus)
  1755. m_AdditionalStatus.dwInfoStatus |= CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS;
  1756. else
  1757. m_AdditionalStatus.dwErrorStatus |= dwErrorStatus;
  1758. return;
  1759. ErrorReturn:
  1760. goto CommonReturn;
  1761. TRACE_ERROR(InvalidNameConstraints)
  1762. }
  1763. //+---------------------------------------------------------------------------
  1764. //
  1765. // Member: CChainPathObject::CalculateRevocationStatus, public
  1766. //
  1767. // Synopsis: calculate additional status bits based on revocation
  1768. //
  1769. //----------------------------------------------------------------------------
  1770. VOID
  1771. CChainPathObject::CalculateRevocationStatus (
  1772. IN PCCHAINCALLCONTEXT pCallContext,
  1773. IN HCERTSTORE hCrlStore,
  1774. IN LPFILETIME pTime
  1775. )
  1776. {
  1777. CERT_REVOCATION_PARA RevPara;
  1778. CERT_REVOCATION_STATUS RevStatus;
  1779. DWORD dwRevFlags;
  1780. DWORD dwFlags = pCallContext->CallFlags();
  1781. PCERT_CHAIN_PARA pChainPara = pCallContext->ChainPara();
  1782. FILETIME CurrentTime;
  1783. assert(dwFlags & CERT_CHAIN_REVOCATION_CHECK_ALL);
  1784. memset( &RevPara, 0, sizeof( RevPara ) );
  1785. RevPara.cbSize = sizeof( RevPara );
  1786. RevPara.hCrlStore = hCrlStore;
  1787. RevPara.pftTimeToUse = pTime;
  1788. RevPara.dwUrlRetrievalTimeout =
  1789. pCallContext->RevocationUrlRetrievalTimeout();
  1790. RevPara.fCheckFreshnessTime = pChainPara->fCheckRevocationFreshnessTime;
  1791. RevPara.dwFreshnessTime = pChainPara->dwRevocationFreshnessTime;
  1792. pCallContext->CurrentTime(&CurrentTime);
  1793. RevPara.pftCurrentTime = &CurrentTime;
  1794. memset( &RevStatus, 0, sizeof( RevStatus ) );
  1795. RevStatus.cbSize = sizeof( RevStatus );
  1796. dwRevFlags = 0;
  1797. if (dwFlags & CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY)
  1798. dwRevFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION;
  1799. if (dwFlags & CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT)
  1800. dwRevFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG;
  1801. if (!m_fHasRevocationInfo) {
  1802. BOOL fHasRevocationInfo = FALSE;
  1803. if (m_TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
  1804. BOOL fDoRevocation = FALSE;
  1805. if (dwFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT) {
  1806. ;
  1807. } else if (dwFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT) {
  1808. if (0 == m_dwChainIndex && 0 == m_dwElementIndex)
  1809. fDoRevocation = TRUE;
  1810. } else {
  1811. assert(dwFlags & CERT_CHAIN_REVOCATION_CHECK_CHAIN);
  1812. fDoRevocation = TRUE;
  1813. }
  1814. if (fDoRevocation) {
  1815. PCCERT_CONTEXT pSubjectCert = m_pCertObject->CertContext();
  1816. RevPara.pIssuerCert = m_pCertObject->CertContext();
  1817. RevPara.pCrlInfo = &m_RevocationCrlInfo;
  1818. m_RevocationCrlInfo.cbSize = sizeof(m_RevocationCrlInfo);
  1819. RevStatus.dwError = (DWORD) CRYPT_E_REVOCATION_OFFLINE;
  1820. CertVerifyRevocation(
  1821. X509_ASN_ENCODING,
  1822. CERT_CONTEXT_REVOCATION_TYPE,
  1823. 1,
  1824. (LPVOID *) &pSubjectCert,
  1825. dwRevFlags,
  1826. &RevPara,
  1827. &RevStatus
  1828. );
  1829. fHasRevocationInfo = TRUE;
  1830. }
  1831. } else if (NULL == m_pUpIssuerElement) {
  1832. if (dwFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT) {
  1833. if (0 == m_dwChainIndex && 0 == m_dwElementIndex)
  1834. fHasRevocationInfo = TRUE;
  1835. } else {
  1836. fHasRevocationInfo = TRUE;
  1837. }
  1838. if (fHasRevocationInfo) {
  1839. RevStatus.dwError = (DWORD) CRYPT_E_REVOCATION_OFFLINE;
  1840. }
  1841. }
  1842. if (fHasRevocationInfo) {
  1843. ChainUpdateRevocationInfo(&RevStatus, &m_RevocationInfo,
  1844. &m_TrustStatus);
  1845. m_fHasRevocationInfo = TRUE;
  1846. memset( &RevStatus, 0, sizeof( RevStatus ) );
  1847. RevStatus.cbSize = sizeof( RevStatus );
  1848. }
  1849. }
  1850. if (m_pDownIssuerElement && !m_pDownIssuerElement->fCtlIssuer &&
  1851. !m_pDownIssuerElement->fHasRevocationInfo) {
  1852. BOOL fDoRevocation = FALSE;
  1853. if (dwFlags & CERT_CHAIN_REVOCATION_CHECK_END_CERT) {
  1854. if (0 == m_dwChainIndex && 1 == m_dwElementIndex)
  1855. fDoRevocation = TRUE;
  1856. } else {
  1857. fDoRevocation = TRUE;
  1858. }
  1859. if (fDoRevocation) {
  1860. PCCERT_CONTEXT pSubjectCert =
  1861. m_pDownPathObject->m_pCertObject->CertContext();
  1862. RevPara.pIssuerCert = m_pCertObject->CertContext();
  1863. RevPara.pCrlInfo = &m_pDownIssuerElement->RevocationCrlInfo;
  1864. m_pDownIssuerElement->RevocationCrlInfo.cbSize =
  1865. sizeof(m_pDownIssuerElement->RevocationCrlInfo);
  1866. RevStatus.dwError = (DWORD) CRYPT_E_REVOCATION_OFFLINE;
  1867. CertVerifyRevocation(
  1868. X509_ASN_ENCODING,
  1869. CERT_CONTEXT_REVOCATION_TYPE,
  1870. 1,
  1871. (LPVOID *) &pSubjectCert,
  1872. dwRevFlags,
  1873. &RevPara,
  1874. &RevStatus
  1875. );
  1876. ChainUpdateRevocationInfo(&RevStatus,
  1877. &m_pDownIssuerElement->RevocationInfo,
  1878. &m_pDownIssuerElement->SubjectStatus);
  1879. m_pDownIssuerElement->fHasRevocationInfo = TRUE;
  1880. }
  1881. }
  1882. }
  1883. //+---------------------------------------------------------------------------
  1884. //
  1885. // Member: CChainPathObject::CreateChainContextFromPath, public
  1886. //
  1887. // Synopsis: Create the chain context for chain path ending in the
  1888. // specified top path object. Also calculates the chain's
  1889. // quality value.
  1890. //
  1891. //----------------------------------------------------------------------------
  1892. PINTERNAL_CERT_CHAIN_CONTEXT
  1893. CChainPathObject::CreateChainContextFromPath (
  1894. IN PCCHAINCALLCONTEXT pCallContext,
  1895. IN PCCHAINPATHOBJECT pTopPathObject
  1896. )
  1897. {
  1898. // Single PkiZeroAlloc for all of the following:
  1899. PINTERNAL_CERT_CHAIN_CONTEXT pContext = NULL;
  1900. PCERT_SIMPLE_CHAIN *ppChain;
  1901. PCERT_SIMPLE_CHAIN pChain;
  1902. PCERT_CHAIN_ELEMENT *ppElement;
  1903. PCERT_CHAIN_ELEMENT pElement;
  1904. DWORD cChain;
  1905. DWORD cTotalElement;
  1906. DWORD cbTotal;
  1907. PCCHAINPATHOBJECT pPathObject;
  1908. DWORD dwQuality;
  1909. DWORD dwChainErrorStatus;
  1910. DWORD dwChainInfoStatus;
  1911. PCERT_ENHKEY_USAGE pAppUsage;
  1912. BOOL fHasContextRevocationFreshnessTime;
  1913. // Restricted usage info that gets propogated downward
  1914. CHAIN_RESTRICTED_USAGE_INFO RestrictedUsageInfo;
  1915. memset(&RestrictedUsageInfo, 0, sizeof(RestrictedUsageInfo));
  1916. cChain = pTopPathObject->m_dwChainIndex + 1;
  1917. if (1 == cChain) {
  1918. cTotalElement = pTopPathObject->m_dwElementIndex + 1;
  1919. } else {
  1920. cTotalElement = 0;
  1921. for (pPathObject = pTopPathObject; NULL != pPathObject;
  1922. pPathObject = pPathObject->m_pDownPathObject)
  1923. cTotalElement++;
  1924. }
  1925. cbTotal = sizeof(INTERNAL_CERT_CHAIN_CONTEXT) +
  1926. sizeof(PCERT_SIMPLE_CHAIN) * cChain +
  1927. sizeof(CERT_SIMPLE_CHAIN) * cChain +
  1928. sizeof(PCERT_CHAIN_ELEMENT) * cTotalElement +
  1929. sizeof(CERT_CHAIN_ELEMENT) * cTotalElement;
  1930. pContext = (PINTERNAL_CERT_CHAIN_CONTEXT) PkiZeroAlloc(cbTotal);
  1931. if (NULL == pContext)
  1932. goto OutOfMemory;
  1933. ppChain = (PCERT_SIMPLE_CHAIN *) &pContext[1];
  1934. pChain = (PCERT_SIMPLE_CHAIN) &ppChain[cChain];
  1935. ppElement = (PCERT_CHAIN_ELEMENT *) &pChain[cChain];
  1936. pElement = (PCERT_CHAIN_ELEMENT) &ppElement[cTotalElement];
  1937. pContext->cRefs = 1;
  1938. pContext->ChainContext.cbSize = sizeof(CERT_CHAIN_CONTEXT);
  1939. pContext->ChainContext.cChain = cChain;
  1940. pContext->ChainContext.rgpChain = ppChain;
  1941. if (1 < cChain )
  1942. pContext->ChainContext.TrustStatus.dwInfoStatus |=
  1943. CERT_TRUST_IS_COMPLEX_CHAIN;
  1944. // Default to having preferred issuers
  1945. pContext->ChainContext.TrustStatus.dwInfoStatus |=
  1946. CERT_TRUST_HAS_PREFERRED_ISSUER;
  1947. // Default to having revocation freshness time
  1948. fHasContextRevocationFreshnessTime = TRUE;
  1949. // Work our way from the top downward
  1950. pPathObject = pTopPathObject;
  1951. ppChain += cChain - 1;
  1952. pChain += cChain - 1;
  1953. ppElement += cTotalElement - 1;
  1954. pElement += cTotalElement - 1;
  1955. if (!(pTopPathObject->m_TrustStatus.dwInfoStatus &
  1956. CERT_TRUST_IS_SELF_SIGNED))
  1957. pChain->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_PARTIAL_CHAIN;
  1958. for ( ; 0 < cChain; cChain--, ppChain--, pChain--) {
  1959. BOOL fHasChainRevocationFreshnessTime;
  1960. DWORD cElement;
  1961. *ppChain = pChain;
  1962. pChain->cbSize = sizeof(CERT_SIMPLE_CHAIN);
  1963. // Default to having preferred issuers
  1964. pChain->TrustStatus.dwInfoStatus |= CERT_TRUST_HAS_PREFERRED_ISSUER;
  1965. // Default to having revocation freshness time
  1966. fHasChainRevocationFreshnessTime = TRUE;
  1967. cElement = pPathObject->m_dwElementIndex + 1;
  1968. pChain->cElement = cElement;
  1969. pChain->rgpElement = ppElement - (cElement - 1);
  1970. for ( ; 0 < cElement; cElement--, cTotalElement--,
  1971. ppElement--, pElement--,
  1972. pPathObject = pPathObject->m_pDownPathObject) {
  1973. assert(pPathObject);
  1974. *ppElement = pElement;
  1975. pElement->cbSize = sizeof(CERT_CHAIN_ELEMENT);
  1976. if (!pPathObject->UpdateChainContextUsageForPathObject (
  1977. pCallContext,
  1978. pChain,
  1979. pElement,
  1980. &RestrictedUsageInfo
  1981. ))
  1982. goto UpdateChainContextUsageForPathObjectError;
  1983. // This must be last. It updates the chain's TrustStatus
  1984. // from the element's TrustStatus.
  1985. if (!pPathObject->UpdateChainContextFromPathObject (
  1986. pCallContext,
  1987. pChain,
  1988. pElement
  1989. ))
  1990. goto UpdateChainContextFromPathObjectError;
  1991. // Remember the largest revocation freshness time for the
  1992. // simple chain and the chain context.
  1993. if (pElement->pRevocationInfo && fHasChainRevocationFreshnessTime) {
  1994. PCERT_REVOCATION_INFO pRevInfo = pElement->pRevocationInfo;
  1995. if (pRevInfo->fHasFreshnessTime) {
  1996. if (pRevInfo->dwFreshnessTime >
  1997. pChain->dwRevocationFreshnessTime)
  1998. pChain->dwRevocationFreshnessTime =
  1999. pRevInfo->dwFreshnessTime;
  2000. pChain->fHasRevocationFreshnessTime = TRUE;
  2001. if (fHasContextRevocationFreshnessTime) {
  2002. if (pRevInfo->dwFreshnessTime >
  2003. pContext->ChainContext.dwRevocationFreshnessTime)
  2004. pContext->ChainContext.dwRevocationFreshnessTime =
  2005. pRevInfo->dwFreshnessTime;
  2006. pContext->ChainContext.fHasRevocationFreshnessTime =
  2007. TRUE;
  2008. }
  2009. } else if (CRYPT_E_NO_REVOCATION_CHECK !=
  2010. pRevInfo->dwRevocationResult) {
  2011. fHasChainRevocationFreshnessTime = FALSE;
  2012. pChain->fHasRevocationFreshnessTime = FALSE;
  2013. fHasContextRevocationFreshnessTime = FALSE;
  2014. pContext->ChainContext.fHasRevocationFreshnessTime = FALSE;
  2015. }
  2016. }
  2017. CertPerfIncrementChainElementCount();
  2018. }
  2019. ChainUpdateSummaryStatusByTrustStatus(
  2020. &pContext->ChainContext.TrustStatus,
  2021. &pChain->TrustStatus);
  2022. ChainFreeAndClearRestrictedUsageInfo(&RestrictedUsageInfo);
  2023. }
  2024. assert(0 == cTotalElement);
  2025. // Calculate chain quality value
  2026. dwQuality = 0;
  2027. dwChainErrorStatus = pContext->ChainContext.TrustStatus.dwErrorStatus;
  2028. dwChainInfoStatus = pContext->ChainContext.TrustStatus.dwInfoStatus;
  2029. if (!(dwChainErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) &&
  2030. !(dwChainErrorStatus & CERT_TRUST_CTL_IS_NOT_TIME_VALID))
  2031. dwQuality |= CERT_QUALITY_TIME_VALID;
  2032. if (!(dwChainErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) &&
  2033. !(dwChainErrorStatus & CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE))
  2034. dwQuality |= CERT_QUALITY_MEETS_USAGE_CRITERIA;
  2035. pAppUsage =
  2036. pContext->ChainContext.rgpChain[0]->rgpElement[0]->pApplicationUsage;
  2037. if (NULL == pAppUsage || 0 != pAppUsage->cUsageIdentifier)
  2038. dwQuality |= CERT_QUALITY_HAS_APPLICATION_USAGE;
  2039. if (!(dwChainErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT))
  2040. dwQuality |= CERT_QUALITY_HAS_TRUSTED_ROOT;
  2041. if (!(dwChainErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) &&
  2042. !(dwChainErrorStatus & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID))
  2043. dwQuality |= CERT_QUALITY_SIGNATURE_VALID;
  2044. if (!(dwChainErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN))
  2045. dwQuality |= CERT_QUALITY_COMPLETE_CHAIN;
  2046. if (!(dwChainErrorStatus & CERT_TRUST_IS_REVOKED))
  2047. dwQuality |= CERT_QUALITY_NOT_REVOKED;
  2048. if (!(dwChainErrorStatus & CERT_TRUST_IS_OFFLINE_REVOCATION) &&
  2049. !(dwChainErrorStatus & CERT_TRUST_IS_REVOKED))
  2050. dwQuality |= CERT_QUALITY_ONLINE_REVOCATION;
  2051. if (!(dwChainErrorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) &&
  2052. !(dwChainErrorStatus & CERT_TRUST_IS_REVOKED))
  2053. dwQuality |= CERT_QUALITY_CHECK_REVOCATION;
  2054. if (!(dwChainInfoStatus & CERT_TRUST_IS_COMPLEX_CHAIN))
  2055. dwQuality |= CERT_QUALITY_SIMPLE_CHAIN;
  2056. if (dwChainInfoStatus & CERT_TRUST_HAS_PREFERRED_ISSUER)
  2057. dwQuality |= CERT_QUALITY_PREFERRED_ISSUER;
  2058. if (dwChainInfoStatus & CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY)
  2059. dwQuality |= CERT_QUALITY_HAS_ISSUANCE_CHAIN_POLICY;
  2060. if (!(dwChainErrorStatus &
  2061. (CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY |
  2062. CERT_TRUST_INVALID_POLICY_CONSTRAINTS)))
  2063. dwQuality |= CERT_QUALITY_POLICY_CONSTRAINTS_VALID;
  2064. if (!(dwChainErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS))
  2065. dwQuality |= CERT_QUALITY_BASIC_CONSTRAINTS_VALID;
  2066. if (dwChainInfoStatus & CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS)
  2067. dwQuality |= CERT_QUALITY_HAS_NAME_CONSTRAINTS;
  2068. if (!(dwChainErrorStatus & (CERT_TRUST_INVALID_NAME_CONSTRAINTS |
  2069. CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT |
  2070. CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT)))
  2071. dwQuality |= CERT_QUALITY_NAME_CONSTRAINTS_VALID;
  2072. if (!(dwChainErrorStatus & (CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT |
  2073. CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT)))
  2074. dwQuality |= CERT_QUALITY_NAME_CONSTRAINTS_MET;
  2075. pContext->dwQuality = dwQuality;
  2076. CertPerfIncrementChainCount();
  2077. CommonReturn:
  2078. return pContext;
  2079. ErrorReturn:
  2080. if (pContext) {
  2081. ChainReleaseInternalChainContext(pContext);
  2082. pContext = NULL;
  2083. }
  2084. ChainFreeAndClearRestrictedUsageInfo(&RestrictedUsageInfo);
  2085. goto CommonReturn;
  2086. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  2087. TRACE_ERROR(UpdateChainContextUsageForPathObjectError)
  2088. TRACE_ERROR(UpdateChainContextFromPathObjectError)
  2089. }
  2090. //+---------------------------------------------------------------------------
  2091. //
  2092. // Member: CChainPathObject::UpdateChainContextUsageForPathObject, public
  2093. //
  2094. // Synopsis: update the chain context usage information for this
  2095. // path object.
  2096. //
  2097. //----------------------------------------------------------------------------
  2098. BOOL
  2099. CChainPathObject::UpdateChainContextUsageForPathObject (
  2100. IN PCCHAINCALLCONTEXT pCallContext,
  2101. IN OUT PCERT_SIMPLE_CHAIN pChain,
  2102. IN OUT PCERT_CHAIN_ELEMENT pElement,
  2103. IN OUT PCHAIN_RESTRICTED_USAGE_INFO pRestrictedUsageInfo
  2104. )
  2105. {
  2106. BOOL fResult;
  2107. PCHAIN_POLICIES_INFO pPoliciesInfo = m_pCertObject->PoliciesInfo();
  2108. CERT_USAGE_MATCH CtlUsage;
  2109. PCERT_USAGE_MATCH pUsageToUse;
  2110. LPSTR pszUsage = szOID_KP_CTL_USAGE_SIGNING;
  2111. PCERT_ENHKEY_USAGE pIssUsage;
  2112. PCERT_ENHKEY_USAGE pAppUsage;
  2113. PCERT_ENHKEY_USAGE pPropUsage;
  2114. DWORD dwIssFlags;
  2115. DWORD dwAppFlags;
  2116. static const CERT_ENHKEY_USAGE NoUsage = { 0, NULL };
  2117. // Update the usage to use for the second and subsequent chains
  2118. if (0 != m_dwChainIndex) {
  2119. // CTL path object
  2120. memset(&CtlUsage, 0, sizeof(CtlUsage));
  2121. CtlUsage.dwType = USAGE_MATCH_TYPE_AND;
  2122. CtlUsage.Usage.cUsageIdentifier = 1;
  2123. CtlUsage.Usage.rgpszUsageIdentifier = &pszUsage;
  2124. pUsageToUse = &CtlUsage;
  2125. } else {
  2126. pUsageToUse = &pCallContext->ChainPara()->RequestedUsage;
  2127. }
  2128. dwIssFlags = pPoliciesInfo->rgIssOrAppInfo[CHAIN_ISS_INDEX].dwFlags;
  2129. dwAppFlags = pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].dwFlags;
  2130. // Update TrustStatus to reflect any policy decoding errors
  2131. if ((dwIssFlags & CHAIN_INVALID_POLICY_FLAG) ||
  2132. (dwAppFlags & CHAIN_INVALID_POLICY_FLAG))
  2133. pElement->TrustStatus.dwErrorStatus |= CERT_TRUST_INVALID_EXTENSION |
  2134. CERT_TRUST_INVALID_POLICY_CONSTRAINTS;
  2135. // Issuance :: restricted and mapped usage
  2136. pIssUsage = pPoliciesInfo->rgIssOrAppInfo[CHAIN_ISS_INDEX].pUsage;
  2137. if (NULL == pIssUsage) {
  2138. // NULL => Any Usage
  2139. // Only allow any usage for self signed roots or certs having
  2140. // the CertPolicies extension. Otherwise, treat as having no usage.
  2141. if (!(m_TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) &&
  2142. NULL == pPoliciesInfo->rgIssOrAppInfo[CHAIN_ISS_INDEX].pPolicy)
  2143. pIssUsage = (PCERT_ENHKEY_USAGE) &NoUsage;
  2144. }
  2145. if (!ChainCalculateRestrictedUsage (
  2146. pIssUsage,
  2147. pPoliciesInfo->rgIssOrAppInfo[CHAIN_ISS_INDEX].pMappings,
  2148. &pRestrictedUsageInfo->pIssuanceRestrictedUsage,
  2149. &pRestrictedUsageInfo->pIssuanceMappedUsage,
  2150. &pRestrictedUsageInfo->rgdwIssuanceMappedIndex
  2151. ))
  2152. goto CalculateIssuanceRestrictedUsageError;
  2153. if (!ChainAllocAndCopyUsage(
  2154. pRestrictedUsageInfo->pIssuanceRestrictedUsage,
  2155. &pElement->pIssuanceUsage
  2156. ))
  2157. goto AllocAndCopyUsageError;
  2158. if (0 != m_dwElementIndex) {
  2159. PCERT_POLICY_CONSTRAINTS_INFO pConstraints =
  2160. pPoliciesInfo->rgIssOrAppInfo[CHAIN_ISS_INDEX].pConstraints;
  2161. if (pConstraints && pConstraints->fRequireExplicitPolicy &&
  2162. m_dwElementIndex >
  2163. pConstraints->dwRequireExplicitPolicySkipCerts)
  2164. pRestrictedUsageInfo->fRequireIssuancePolicy = TRUE;
  2165. } else {
  2166. // For the end cert, update the require issuance chain policy
  2167. // TrustStatus. Also, check the requested issuance policy.
  2168. if (pRestrictedUsageInfo->fRequireIssuancePolicy) {
  2169. if (pRestrictedUsageInfo->pIssuanceRestrictedUsage &&
  2170. 0 == pRestrictedUsageInfo->pIssuanceRestrictedUsage->cUsageIdentifier) {
  2171. // Must have either ANY_POLICY or some policy OIDs
  2172. pChain->TrustStatus.dwErrorStatus |=
  2173. CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY;
  2174. } else if (pPoliciesInfo->rgIssOrAppInfo[CHAIN_ISS_INDEX].pPolicy) {
  2175. pChain->TrustStatus.dwInfoStatus |=
  2176. CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY;
  2177. }
  2178. }
  2179. pIssUsage = pElement->pIssuanceUsage;
  2180. if (pIssUsage) {
  2181. PCERT_USAGE_MATCH pRequestedIssuancePolicy =
  2182. &pCallContext->ChainPara()->RequestedIssuancePolicy;
  2183. ChainGetUsageStatus(
  2184. &pRequestedIssuancePolicy->Usage,
  2185. pIssUsage,
  2186. pRequestedIssuancePolicy->dwType,
  2187. &pElement->TrustStatus
  2188. );
  2189. }
  2190. }
  2191. if (USAGE_MATCH_TYPE_OR == pUsageToUse->dwType &&
  2192. 1 < pUsageToUse->Usage.cUsageIdentifier) {
  2193. // For "OR" match type request, we can't use restricted property usage
  2194. pPropUsage = pPoliciesInfo->pPropertyUsage;
  2195. // For "OR" match type request, we only use restricted application
  2196. // usage upon seeing policy mappings.
  2197. if (pRestrictedUsageInfo->pApplicationMappedUsage ||
  2198. pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].pMappings) {
  2199. if (!ChainCalculateRestrictedUsage (
  2200. pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].pUsage,
  2201. pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].pMappings,
  2202. &pRestrictedUsageInfo->pApplicationRestrictedUsage,
  2203. &pRestrictedUsageInfo->pApplicationMappedUsage,
  2204. &pRestrictedUsageInfo->rgdwApplicationMappedIndex
  2205. ))
  2206. goto CalculateApplicationRestrictedUsageError;
  2207. pAppUsage = pRestrictedUsageInfo->pApplicationRestrictedUsage;
  2208. } else
  2209. pAppUsage = pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].pUsage;
  2210. } else {
  2211. // Restricted property and application usage
  2212. PCERT_ENHKEY_USAGE pPropMappedUsage = NULL;
  2213. LPDWORD pdwPropMappedIndex = NULL;
  2214. fResult = ChainCalculateRestrictedUsage (
  2215. pPoliciesInfo->pPropertyUsage,
  2216. NULL, // pMappings
  2217. &pRestrictedUsageInfo->pPropertyRestrictedUsage,
  2218. &pPropMappedUsage,
  2219. &pdwPropMappedIndex
  2220. );
  2221. assert(NULL == pPropMappedUsage && NULL == pdwPropMappedIndex);
  2222. if (!fResult)
  2223. goto CalculatePropertyRestrictedUsageError;
  2224. pPropUsage = pRestrictedUsageInfo->pPropertyRestrictedUsage;
  2225. if (!ChainCalculateRestrictedUsage (
  2226. pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].pUsage,
  2227. pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].pMappings,
  2228. &pRestrictedUsageInfo->pApplicationRestrictedUsage,
  2229. &pRestrictedUsageInfo->pApplicationMappedUsage,
  2230. &pRestrictedUsageInfo->rgdwApplicationMappedIndex
  2231. ))
  2232. goto CalculateApplicationRestrictedUsageError;
  2233. pAppUsage = pRestrictedUsageInfo->pApplicationRestrictedUsage;
  2234. }
  2235. // The element's application usage includes the intersection with
  2236. // the property usage
  2237. if (NULL == pAppUsage) {
  2238. if (!ChainAllocAndCopyUsage(
  2239. pPropUsage,
  2240. &pElement->pApplicationUsage
  2241. ))
  2242. goto AllocAndCopyUsageError;
  2243. } else {
  2244. if (!ChainAllocAndCopyUsage(
  2245. pAppUsage,
  2246. &pElement->pApplicationUsage
  2247. ))
  2248. goto AllocAndCopyUsageError;
  2249. if (pPropUsage)
  2250. // Remove OIDs not also in the property usage
  2251. ChainIntersectUsages(pPropUsage, pElement->pApplicationUsage);
  2252. }
  2253. // Check the requested usage
  2254. pAppUsage = pElement->pApplicationUsage;
  2255. if (pAppUsage)
  2256. ChainGetUsageStatus(
  2257. &pUsageToUse->Usage,
  2258. pAppUsage,
  2259. pUsageToUse->dwType,
  2260. &pElement->TrustStatus
  2261. );
  2262. fResult = TRUE;
  2263. CommonReturn:
  2264. return fResult;
  2265. ErrorReturn:
  2266. fResult = FALSE;
  2267. goto CommonReturn;
  2268. TRACE_ERROR(CalculateIssuanceRestrictedUsageError)
  2269. TRACE_ERROR(AllocAndCopyUsageError)
  2270. TRACE_ERROR(CalculateApplicationRestrictedUsageError)
  2271. TRACE_ERROR(CalculatePropertyRestrictedUsageError)
  2272. }
  2273. //+---------------------------------------------------------------------------
  2274. //
  2275. // Member: CChainPathObject::UpdateChainContextFromPathObject, public
  2276. //
  2277. // Synopsis: update the chain context using information from this
  2278. // path object.
  2279. //
  2280. //----------------------------------------------------------------------------
  2281. BOOL
  2282. CChainPathObject::UpdateChainContextFromPathObject (
  2283. IN PCCHAINCALLCONTEXT pCallContext,
  2284. IN OUT PCERT_SIMPLE_CHAIN pChain,
  2285. IN OUT PCERT_CHAIN_ELEMENT pElement
  2286. )
  2287. {
  2288. BOOL fResult;
  2289. PCERT_REVOCATION_INFO pRevocationInfo = NULL;
  2290. PCERT_REVOCATION_CRL_INFO pRevocationCrlInfo = NULL;
  2291. ChainOrInStatusBits(&pElement->TrustStatus, &m_TrustStatus);
  2292. assert(m_fHasAdditionalStatus);
  2293. ChainOrInStatusBits(&pElement->TrustStatus, &m_AdditionalStatus);
  2294. if (m_pUpIssuerElement) {
  2295. if (m_pUpIssuerElement->fCtlIssuer) {
  2296. ChainOrInStatusBits(&pChain->TrustStatus,
  2297. &m_pUpIssuerElement->SubjectStatus);
  2298. assert(pElement->TrustStatus.dwErrorStatus &
  2299. CERT_TRUST_IS_UNTRUSTED_ROOT);
  2300. pElement->TrustStatus.dwErrorStatus &=
  2301. ~CERT_TRUST_IS_UNTRUSTED_ROOT;
  2302. if (!SSCtlAllocAndCopyTrustListInfo(
  2303. m_pUpIssuerElement->pCtlIssuerData->pTrustListInfo,
  2304. &pChain->pTrustListInfo
  2305. ))
  2306. goto AllocAndCopyTrustListInfoError;
  2307. } else {
  2308. ChainOrInStatusBits(&pElement->TrustStatus,
  2309. &m_pUpIssuerElement->SubjectStatus);
  2310. }
  2311. }
  2312. pRevocationInfo = NULL;
  2313. if (m_fHasRevocationInfo) {
  2314. pRevocationInfo = &m_RevocationInfo;
  2315. pRevocationCrlInfo = &m_RevocationCrlInfo;
  2316. } else if (m_pUpIssuerElement && m_pUpIssuerElement->fHasRevocationInfo) {
  2317. pRevocationInfo = &m_pUpIssuerElement->RevocationInfo;
  2318. pRevocationCrlInfo = &m_pUpIssuerElement->RevocationCrlInfo;
  2319. }
  2320. if (pRevocationInfo) {
  2321. pElement->pRevocationInfo = new CERT_REVOCATION_INFO;
  2322. if (NULL == pElement->pRevocationInfo)
  2323. goto OutOfMemory;
  2324. memset(pElement->pRevocationInfo, 0, sizeof(CERT_REVOCATION_INFO));
  2325. pElement->pRevocationInfo->cbSize = sizeof(CERT_REVOCATION_INFO);
  2326. pElement->pRevocationInfo->dwRevocationResult =
  2327. pRevocationInfo->dwRevocationResult;
  2328. pElement->pRevocationInfo->fHasFreshnessTime =
  2329. pRevocationInfo->fHasFreshnessTime;
  2330. pElement->pRevocationInfo->dwFreshnessTime =
  2331. pRevocationInfo->dwFreshnessTime;
  2332. if (NULL != pRevocationCrlInfo->pBaseCrlContext) {
  2333. PCERT_REVOCATION_CRL_INFO pCrlInfo;
  2334. pCrlInfo = new CERT_REVOCATION_CRL_INFO;
  2335. if (NULL == pCrlInfo)
  2336. goto OutOfMemory;
  2337. pElement->pRevocationInfo->pCrlInfo = pCrlInfo;
  2338. memcpy(pCrlInfo, pRevocationCrlInfo, sizeof(*pCrlInfo));
  2339. assert(pCrlInfo->cbSize = sizeof(*pCrlInfo));
  2340. pCrlInfo->pBaseCrlContext = CertDuplicateCRLContext(
  2341. pRevocationCrlInfo->pBaseCrlContext);
  2342. if (NULL != pRevocationCrlInfo->pDeltaCrlContext)
  2343. pCrlInfo->pDeltaCrlContext = CertDuplicateCRLContext(
  2344. pRevocationCrlInfo->pDeltaCrlContext);
  2345. }
  2346. }
  2347. if (m_pwszExtendedErrorInfo) {
  2348. DWORD cbExtendedErrorInfo;
  2349. LPWSTR pwszExtendedErrorInfo;
  2350. cbExtendedErrorInfo =
  2351. (wcslen(m_pwszExtendedErrorInfo) + 1) * sizeof(WCHAR);
  2352. if (NULL == (pwszExtendedErrorInfo = (LPWSTR) PkiNonzeroAlloc(
  2353. cbExtendedErrorInfo)))
  2354. goto OutOfMemory;
  2355. memcpy(pwszExtendedErrorInfo, m_pwszExtendedErrorInfo,
  2356. cbExtendedErrorInfo);
  2357. pElement->pwszExtendedErrorInfo = pwszExtendedErrorInfo;
  2358. }
  2359. pElement->pCertContext = CertDuplicateCertificateContext(
  2360. m_pCertObject->CertContext());
  2361. ChainUpdateSummaryStatusByTrustStatus(&pChain->TrustStatus,
  2362. &pElement->TrustStatus);
  2363. fResult = TRUE;
  2364. CommonReturn:
  2365. return fResult;
  2366. ErrorReturn:
  2367. fResult = FALSE;
  2368. goto CommonReturn;
  2369. TRACE_ERROR(AllocAndCopyTrustListInfoError)
  2370. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  2371. }
  2372. //+===========================================================================
  2373. // CCertIssuerList methods
  2374. //============================================================================
  2375. //+---------------------------------------------------------------------------
  2376. //
  2377. // Member: CCertIssuerList::CCertIssuerList, public
  2378. //
  2379. // Synopsis: Constructor
  2380. //
  2381. //----------------------------------------------------------------------------
  2382. CCertIssuerList::CCertIssuerList (IN PCCHAINPATHOBJECT pSubject)
  2383. {
  2384. m_pSubject = pSubject;
  2385. m_pHead = NULL;
  2386. }
  2387. //+---------------------------------------------------------------------------
  2388. //
  2389. // Member: CCertIssuerList::~CCertIssuerList, public
  2390. //
  2391. // Synopsis: Destructor
  2392. //
  2393. //----------------------------------------------------------------------------
  2394. CCertIssuerList::~CCertIssuerList ()
  2395. {
  2396. PCERT_ISSUER_ELEMENT pElement;
  2397. while ( ( pElement = NextElement( NULL ) ) != NULL )
  2398. {
  2399. RemoveElement( pElement );
  2400. DeleteElement( pElement );
  2401. }
  2402. }
  2403. //+---------------------------------------------------------------------------
  2404. //
  2405. // Member: CCertIssuerList::AddIssuer, public
  2406. //
  2407. // Synopsis: add an issuer to the list
  2408. //
  2409. //----------------------------------------------------------------------------
  2410. BOOL
  2411. CCertIssuerList::AddIssuer(
  2412. IN PCCHAINCALLCONTEXT pCallContext,
  2413. IN OPTIONAL HCERTSTORE hAdditionalStore,
  2414. IN PCCERTOBJECT pIssuer
  2415. )
  2416. {
  2417. BOOL fResult;
  2418. PCCHAINPATHOBJECT pIssuerPathObject = NULL;
  2419. PCERT_ISSUER_ELEMENT pElement = NULL;
  2420. if (CheckForDuplicateElement(pIssuer->CertHash(), FALSE))
  2421. return TRUE;
  2422. // Don't add ourself as an issuer.
  2423. if (0 == memcmp(m_pSubject->CertObject()->CertHash(),
  2424. pIssuer->CertHash(), CHAINHASHLEN))
  2425. return TRUE;
  2426. // Mainly for certs generated by tstore2.exe that mostly contain
  2427. // the same public key, need to add an additional filter to
  2428. // discard certs that only match via the public key, ie no
  2429. // AKI, name or basic constraints match.
  2430. if (!ChainIsValidPubKeyMatchForIssuer(pIssuer, m_pSubject->CertObject()))
  2431. return TRUE;
  2432. if (!ChainCreatePathObject(
  2433. pCallContext,
  2434. pIssuer,
  2435. hAdditionalStore,
  2436. &pIssuerPathObject
  2437. ))
  2438. return FALSE;
  2439. fResult = CreateElement(
  2440. pCallContext,
  2441. FALSE, // fCtlIssuer
  2442. pIssuerPathObject,
  2443. hAdditionalStore,
  2444. NULL, // pSSCtlObject
  2445. NULL, // pTrustListInfo
  2446. &pElement
  2447. );
  2448. if (!fResult)
  2449. {
  2450. return( FALSE );
  2451. }
  2452. AddElement( pElement );
  2453. return( TRUE );
  2454. }
  2455. //+---------------------------------------------------------------------------
  2456. //
  2457. // Member: CCertIssuerList::AddCtlIssuer, public
  2458. //
  2459. // Synopsis: add an issuer to the list
  2460. //
  2461. //----------------------------------------------------------------------------
  2462. BOOL
  2463. CCertIssuerList::AddCtlIssuer(
  2464. IN PCCHAINCALLCONTEXT pCallContext,
  2465. IN OPTIONAL HCERTSTORE hAdditionalStore,
  2466. IN PCSSCTLOBJECT pSSCtlObject,
  2467. IN PCERT_TRUST_LIST_INFO pTrustListInfo
  2468. )
  2469. {
  2470. PCERT_ISSUER_ELEMENT pElement = NULL;
  2471. if (CheckForDuplicateElement(pSSCtlObject->CtlHash(), TRUE))
  2472. return TRUE;
  2473. if (!CreateElement(
  2474. pCallContext,
  2475. TRUE, // fCtlIssuer
  2476. NULL, // pIssuerPathObject
  2477. hAdditionalStore,
  2478. pSSCtlObject,
  2479. pTrustListInfo,
  2480. &pElement
  2481. ))
  2482. return FALSE;
  2483. AddElement( pElement );
  2484. return( TRUE );
  2485. }
  2486. //+---------------------------------------------------------------------------
  2487. //
  2488. // Member: CCertIssuerList::CreateElement, public
  2489. //
  2490. // Synopsis: create an element
  2491. //
  2492. //----------------------------------------------------------------------------
  2493. BOOL
  2494. CCertIssuerList::CreateElement(
  2495. IN PCCHAINCALLCONTEXT pCallContext,
  2496. IN BOOL fCtlIssuer,
  2497. IN OPTIONAL PCCHAINPATHOBJECT pIssuer,
  2498. IN OPTIONAL HCERTSTORE hAdditionalStore,
  2499. IN OPTIONAL PCSSCTLOBJECT pSSCtlObject,
  2500. IN OPTIONAL PCERT_TRUST_LIST_INFO pTrustListInfo, // allocated by caller
  2501. OUT PCERT_ISSUER_ELEMENT* ppElement
  2502. )
  2503. {
  2504. BOOL fResult;
  2505. BOOL fCtlSignatureValid = FALSE;
  2506. PCERT_ISSUER_ELEMENT pElement;
  2507. pElement = new CERT_ISSUER_ELEMENT;
  2508. if (NULL == pElement)
  2509. goto OutOfMemory;
  2510. memset( pElement, 0, sizeof( CERT_ISSUER_ELEMENT ) );
  2511. pElement->fCtlIssuer = fCtlIssuer;
  2512. if (!fCtlIssuer) {
  2513. pElement->pIssuer = pIssuer;
  2514. // The following may leave the engine's critical section to verify the
  2515. // signature. If the engine was touched by another thread, it fails with
  2516. // LastError set to ERROR_CAN_NOT_COMPLETE.
  2517. if (!ChainGetSubjectStatus(
  2518. pCallContext,
  2519. pIssuer,
  2520. m_pSubject,
  2521. &pElement->SubjectStatus
  2522. ))
  2523. goto GetSubjectStatusError;
  2524. } else {
  2525. pElement->pCtlIssuerData = new CTL_ISSUER_DATA;
  2526. if (NULL == pElement->pCtlIssuerData)
  2527. goto OutOfMemory;
  2528. memset( pElement->pCtlIssuerData, 0, sizeof( CTL_ISSUER_DATA ) );
  2529. pSSCtlObject->AddRef();
  2530. pElement->pCtlIssuerData->pSSCtlObject = pSSCtlObject;
  2531. pElement->pCtlIssuerData->pTrustListInfo = pTrustListInfo;
  2532. // The following may leave the engine's critical section to verify a
  2533. // signature or do URL retrieval. If the engine was touched by
  2534. // another thread, it fails with LastError set to
  2535. // ERROR_CAN_NOT_COMPLETE.
  2536. if (!pSSCtlObject->GetSigner(
  2537. m_pSubject,
  2538. pCallContext,
  2539. hAdditionalStore,
  2540. &pElement->pIssuer,
  2541. &fCtlSignatureValid
  2542. )) {
  2543. if (GetLastError() != CRYPT_E_NOT_FOUND)
  2544. goto GetSignerError;
  2545. }
  2546. }
  2547. if (pElement->pIssuer) {
  2548. // If the Issuer hasn't completed yet, then, we are cyclic.
  2549. if (!pElement->pIssuer->IsCompleted())
  2550. pElement->dwPass1Quality = 0;
  2551. else {
  2552. pElement->dwPass1Quality = pElement->pIssuer->Pass1Quality();
  2553. if (!fCtlIssuer) {
  2554. if (pElement->SubjectStatus.dwErrorStatus &
  2555. CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
  2556. pElement->dwPass1Quality &= ~CERT_QUALITY_SIGNATURE_VALID;
  2557. }
  2558. } else if (!fCtlSignatureValid) {
  2559. pElement->dwPass1Quality &= ~CERT_QUALITY_SIGNATURE_VALID;
  2560. }
  2561. }
  2562. } else {
  2563. assert(fCtlIssuer);
  2564. pElement->dwPass1Quality = 0;
  2565. }
  2566. // Remember highest quality issuer
  2567. if (pElement->dwPass1Quality > m_pSubject->Pass1Quality())
  2568. m_pSubject->SetPass1Quality(pElement->dwPass1Quality);
  2569. fResult = TRUE;
  2570. CommonReturn:
  2571. *ppElement = pElement;
  2572. return fResult;
  2573. ErrorReturn:
  2574. if (pElement) {
  2575. DeleteElement(pElement);
  2576. pElement = NULL;
  2577. }
  2578. fResult = FALSE;
  2579. goto CommonReturn;
  2580. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  2581. TRACE_ERROR(GetSubjectStatusError)
  2582. TRACE_ERROR(GetSignerError)
  2583. }
  2584. //+---------------------------------------------------------------------------
  2585. //
  2586. // Member: CCertIssuerList::DeleteElement, public
  2587. //
  2588. // Synopsis: delete an element
  2589. //
  2590. //----------------------------------------------------------------------------
  2591. VOID
  2592. CCertIssuerList::DeleteElement (IN PCERT_ISSUER_ELEMENT pElement)
  2593. {
  2594. if ( pElement->pCtlIssuerData )
  2595. {
  2596. ChainFreeCtlIssuerData( pElement->pCtlIssuerData );
  2597. }
  2598. if (pElement->fHasRevocationInfo) {
  2599. if (pElement->RevocationCrlInfo.pBaseCrlContext)
  2600. CertFreeCRLContext(pElement->RevocationCrlInfo.pBaseCrlContext);
  2601. if (pElement->RevocationCrlInfo.pDeltaCrlContext)
  2602. CertFreeCRLContext(pElement->RevocationCrlInfo.pDeltaCrlContext);
  2603. }
  2604. delete pElement;
  2605. }
  2606. //+---------------------------------------------------------------------------
  2607. //
  2608. // Member: CCertIssuerList::CheckForDuplicateElement, public
  2609. //
  2610. // Synopsis: check for a duplicate element
  2611. //
  2612. //----------------------------------------------------------------------------
  2613. BOOL
  2614. CCertIssuerList::CheckForDuplicateElement (
  2615. IN BYTE rgbHash[ CHAINHASHLEN ],
  2616. IN BOOL fCtlIssuer
  2617. )
  2618. {
  2619. PCERT_ISSUER_ELEMENT pElement = NULL;
  2620. while ( ( pElement = NextElement( pElement ) ) != NULL )
  2621. {
  2622. if ( pElement->fCtlIssuer == fCtlIssuer )
  2623. {
  2624. if ( fCtlIssuer == FALSE )
  2625. {
  2626. if ( memcmp(
  2627. rgbHash,
  2628. pElement->pIssuer->CertObject()->CertHash(),
  2629. CHAINHASHLEN
  2630. ) == 0 )
  2631. {
  2632. return( TRUE );
  2633. }
  2634. }
  2635. else
  2636. {
  2637. if ( memcmp(
  2638. rgbHash,
  2639. pElement->pCtlIssuerData->pSSCtlObject->CtlHash(),
  2640. CHAINHASHLEN
  2641. ) == 0 )
  2642. {
  2643. return( TRUE );
  2644. }
  2645. }
  2646. }
  2647. }
  2648. return( FALSE );
  2649. }
  2650. //+===========================================================================
  2651. // CCertObjectCache methods
  2652. //============================================================================
  2653. //+---------------------------------------------------------------------------
  2654. //
  2655. // Member: CCertObjectCache::CCertObjectCache, public
  2656. //
  2657. // Synopsis: Constructor
  2658. //
  2659. //----------------------------------------------------------------------------
  2660. CCertObjectCache::CCertObjectCache (
  2661. IN DWORD MaxIndexEntries,
  2662. OUT BOOL& rfResult
  2663. )
  2664. {
  2665. LRU_CACHE_CONFIG Config;
  2666. memset( &Config, 0, sizeof( Config ) );
  2667. Config.dwFlags = LRU_CACHE_NO_SERIALIZE | LRU_CACHE_NO_COPY_IDENTIFIER;
  2668. Config.cBuckets = DEFAULT_CERT_OBJECT_CACHE_BUCKETS;
  2669. m_hHashIndex = NULL;
  2670. m_hIdentifierIndex = NULL;
  2671. m_hKeyIdIndex = NULL;
  2672. m_hSubjectNameIndex = NULL;
  2673. m_hPublicKeyHashIndex = NULL;
  2674. m_hEndHashIndex = NULL;
  2675. Config.pfnHash = CertObjectCacheHashNameIdentifier;
  2676. rfResult = I_CryptCreateLruCache( &Config, &m_hSubjectNameIndex );
  2677. Config.pfnHash = CertObjectCacheHashMd5Identifier;
  2678. if ( rfResult == TRUE )
  2679. {
  2680. rfResult = I_CryptCreateLruCache( &Config, &m_hIdentifierIndex );
  2681. }
  2682. if ( rfResult == TRUE )
  2683. {
  2684. rfResult = I_CryptCreateLruCache( &Config, &m_hKeyIdIndex );
  2685. }
  2686. if ( rfResult == TRUE )
  2687. {
  2688. rfResult = I_CryptCreateLruCache( &Config, &m_hPublicKeyHashIndex );
  2689. }
  2690. Config.pfnOnRemoval = CertObjectCacheOnRemovalFromPrimaryIndex;
  2691. if ( rfResult == TRUE )
  2692. {
  2693. rfResult = I_CryptCreateLruCache( &Config, &m_hHashIndex );
  2694. }
  2695. Config.MaxEntries = MaxIndexEntries;
  2696. Config.pfnOnRemoval = CertObjectCacheOnRemovalFromEndHashIndex;
  2697. if ( rfResult == TRUE )
  2698. {
  2699. rfResult = I_CryptCreateLruCache( &Config, &m_hEndHashIndex );
  2700. }
  2701. }
  2702. //+---------------------------------------------------------------------------
  2703. //
  2704. // Member: CCertObjectCache::~CCertObjectCache, public
  2705. //
  2706. // Synopsis: Destructor
  2707. //
  2708. //----------------------------------------------------------------------------
  2709. CCertObjectCache::~CCertObjectCache ()
  2710. {
  2711. I_CryptFreeLruCache(
  2712. m_hHashIndex,
  2713. 0,
  2714. NULL
  2715. );
  2716. I_CryptFreeLruCache(
  2717. m_hSubjectNameIndex,
  2718. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  2719. NULL
  2720. );
  2721. I_CryptFreeLruCache(
  2722. m_hIdentifierIndex,
  2723. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  2724. NULL
  2725. );
  2726. I_CryptFreeLruCache(
  2727. m_hKeyIdIndex,
  2728. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  2729. NULL
  2730. );
  2731. I_CryptFreeLruCache(
  2732. m_hPublicKeyHashIndex,
  2733. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  2734. NULL
  2735. );
  2736. I_CryptFreeLruCache(
  2737. m_hEndHashIndex,
  2738. 0,
  2739. NULL
  2740. );
  2741. }
  2742. //+---------------------------------------------------------------------------
  2743. //
  2744. // Member: CCertObjectCache::AddIssuerObject, public
  2745. //
  2746. // Synopsis: add an issuer object to the cache
  2747. // Increments engine's touch count
  2748. //
  2749. //----------------------------------------------------------------------------
  2750. VOID
  2751. CCertObjectCache::AddIssuerObject (
  2752. IN PCCHAINCALLCONTEXT pCallContext,
  2753. IN PCCERTOBJECT pCertObject
  2754. )
  2755. {
  2756. assert(CERT_CACHED_ISSUER_OBJECT_TYPE == pCertObject->ObjectType());
  2757. pCertObject->AddRef();
  2758. I_CryptInsertLruEntry( pCertObject->HashIndexEntry(), pCallContext );
  2759. I_CryptInsertLruEntry( pCertObject->IdentifierIndexEntry(), pCallContext );
  2760. I_CryptInsertLruEntry( pCertObject->SubjectNameIndexEntry(), pCallContext );
  2761. I_CryptInsertLruEntry( pCertObject->KeyIdIndexEntry(), pCallContext );
  2762. I_CryptInsertLruEntry( pCertObject->PublicKeyHashIndexEntry(),
  2763. pCallContext );
  2764. pCallContext->TouchEngine();
  2765. CertPerfIncrementChainCertCacheCount();
  2766. }
  2767. //+---------------------------------------------------------------------------
  2768. //
  2769. // Member: CCertObjectCache::AddEndObject, public
  2770. //
  2771. // Synopsis: add an end object to the cache
  2772. //
  2773. //----------------------------------------------------------------------------
  2774. VOID
  2775. CCertObjectCache::AddEndObject (
  2776. IN PCCHAINCALLCONTEXT pCallContext,
  2777. IN PCCERTOBJECT pCertObject
  2778. )
  2779. {
  2780. PCCERTOBJECT pDuplicate;
  2781. if (CERT_END_OBJECT_TYPE != pCertObject->ObjectType())
  2782. return;
  2783. pDuplicate = FindEndObjectByHash(pCertObject->CertHash());
  2784. if (pDuplicate) {
  2785. pDuplicate->Release();
  2786. return;
  2787. }
  2788. if (pCertObject->CacheEndObject(pCallContext)) {
  2789. pCertObject->AddRef();
  2790. I_CryptInsertLruEntry( pCertObject->EndHashIndexEntry(), pCallContext );
  2791. CertPerfIncrementChainCertCacheCount();
  2792. CertPerfIncrementChainCacheEndCertCount();
  2793. }
  2794. }
  2795. //+---------------------------------------------------------------------------
  2796. //
  2797. // Member: CCertObjectCache::FindIssuerObject, public
  2798. //
  2799. // Synopsis: find object
  2800. //
  2801. // Note, also called by FindEndObjectByHash
  2802. //
  2803. //----------------------------------------------------------------------------
  2804. PCCERTOBJECT
  2805. CCertObjectCache::FindIssuerObject (
  2806. IN HLRUCACHE hIndex,
  2807. IN PCRYPT_DATA_BLOB pIdentifier
  2808. )
  2809. {
  2810. HLRUENTRY hFound;
  2811. PCCERTOBJECT pFound = NULL;
  2812. hFound = I_CryptFindLruEntry( hIndex, pIdentifier );
  2813. if ( hFound != NULL )
  2814. {
  2815. pFound = (PCCERTOBJECT)I_CryptGetLruEntryData( hFound );
  2816. pFound->AddRef();
  2817. I_CryptReleaseLruEntry( hFound );
  2818. }
  2819. return( pFound );
  2820. }
  2821. //+---------------------------------------------------------------------------
  2822. //
  2823. // Member: CCertObjectCache::FindIssuerObjectByHash, public
  2824. //
  2825. // Synopsis: find object by hash
  2826. //
  2827. //----------------------------------------------------------------------------
  2828. PCCERTOBJECT
  2829. CCertObjectCache::FindIssuerObjectByHash (
  2830. IN BYTE rgbCertHash[ CHAINHASHLEN ]
  2831. )
  2832. {
  2833. CRYPT_DATA_BLOB DataBlob;
  2834. DataBlob.cbData = CHAINHASHLEN;
  2835. DataBlob.pbData = rgbCertHash;
  2836. return( FindIssuerObject( m_hHashIndex, &DataBlob ) );
  2837. }
  2838. //+---------------------------------------------------------------------------
  2839. //
  2840. // Member: CCertObjectCache::FindEndObjectByHash, public
  2841. //
  2842. // Synopsis: find object by hash
  2843. //
  2844. //----------------------------------------------------------------------------
  2845. PCCERTOBJECT
  2846. CCertObjectCache::FindEndObjectByHash (
  2847. IN BYTE rgbCertHash[ CHAINHASHLEN ]
  2848. )
  2849. {
  2850. CRYPT_DATA_BLOB DataBlob;
  2851. DataBlob.cbData = CHAINHASHLEN;
  2852. DataBlob.pbData = rgbCertHash;
  2853. return( FindIssuerObject( m_hEndHashIndex, &DataBlob ) );
  2854. }
  2855. //+---------------------------------------------------------------------------
  2856. //
  2857. // Member: CCertObjectCache::NextMatchingIssuerObject, public
  2858. //
  2859. // Synopsis: next matching issuer object
  2860. //
  2861. //----------------------------------------------------------------------------
  2862. PCCERTOBJECT
  2863. CCertObjectCache::NextMatchingIssuerObject (
  2864. IN HLRUENTRY hObjectEntry,
  2865. IN PCCERTOBJECT pCertObject
  2866. )
  2867. {
  2868. HLRUENTRY hFound;
  2869. PCCERTOBJECT pFound = NULL;
  2870. I_CryptAddRefLruEntry( hObjectEntry );
  2871. hFound = I_CryptEnumMatchingLruEntries( hObjectEntry );
  2872. if ( hFound != NULL )
  2873. {
  2874. pFound = (PCCERTOBJECT)I_CryptGetLruEntryData( hFound );
  2875. pFound->AddRef();
  2876. I_CryptReleaseLruEntry( hFound );
  2877. }
  2878. pCertObject->Release();
  2879. return( pFound );
  2880. }
  2881. //+===========================================================================
  2882. // CCertChainEngine methods
  2883. //============================================================================
  2884. //+---------------------------------------------------------------------------
  2885. //
  2886. // Member: CCertChainEngine::CCertChainEngine, public
  2887. //
  2888. // Synopsis: Constructor
  2889. //
  2890. //----------------------------------------------------------------------------
  2891. CCertChainEngine::CCertChainEngine (
  2892. IN PCERT_CHAIN_ENGINE_CONFIG pConfig,
  2893. IN BOOL fDefaultEngine,
  2894. OUT BOOL& rfResult
  2895. )
  2896. {
  2897. HCERTSTORE hWorld = NULL;
  2898. DWORD dwStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER;
  2899. assert( pConfig->cbSize == sizeof( CERT_CHAIN_ENGINE_CONFIG ) );
  2900. rfResult = TRUE;
  2901. m_cRefs = 1;
  2902. m_hRootStore = NULL;
  2903. m_hRealRootStore = NULL;
  2904. m_hTrustStore = NULL;
  2905. m_hOtherStore = NULL;
  2906. m_hCAStore = NULL;
  2907. m_hEngineStore = NULL;
  2908. m_hEngineStoreChangeEvent = NULL;
  2909. m_pCertObjectCache = NULL;
  2910. m_pSSCtlObjectCache = NULL;
  2911. m_dwFlags = pConfig->dwFlags;
  2912. if (0 == pConfig->dwUrlRetrievalTimeout)
  2913. {
  2914. m_dwUrlRetrievalTimeout = DEFAULT_ENGINE_URL_RETRIEVAL_TIMEOUT;
  2915. m_fDefaultUrlRetrievalTimeout = TRUE;
  2916. }
  2917. else
  2918. {
  2919. m_dwUrlRetrievalTimeout = pConfig->dwUrlRetrievalTimeout;
  2920. m_fDefaultUrlRetrievalTimeout = FALSE;
  2921. }
  2922. m_dwTouchEngineCount = 0;
  2923. m_pCrossCertDPEntry = NULL;
  2924. m_pCrossCertDPLink = NULL;
  2925. m_hCrossCertStore = NULL;
  2926. m_dwCrossCertDPResyncIndex = 0;
  2927. m_pAuthRootAutoUpdateInfo = NULL;
  2928. if ( !Pki_InitializeCriticalSection( &m_Lock ))
  2929. {
  2930. rfResult = FALSE;
  2931. return;
  2932. }
  2933. if ( pConfig->dwFlags & CERT_CHAIN_USE_LOCAL_MACHINE_STORE )
  2934. {
  2935. dwStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  2936. }
  2937. if ( pConfig->dwFlags & CERT_CHAIN_ENABLE_SHARE_STORE )
  2938. {
  2939. dwStoreFlags |= CERT_STORE_SHARE_STORE_FLAG;
  2940. }
  2941. dwStoreFlags |= CERT_STORE_SHARE_CONTEXT_FLAG;
  2942. m_hRealRootStore = CertOpenStore(
  2943. CERT_STORE_PROV_SYSTEM_W,
  2944. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  2945. NULL,
  2946. dwStoreFlags |
  2947. CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  2948. L"root"
  2949. );
  2950. if ( m_hRealRootStore == NULL )
  2951. {
  2952. rfResult = FALSE;
  2953. return;
  2954. }
  2955. m_hCAStore = CertOpenStore(
  2956. CERT_STORE_PROV_SYSTEM_W,
  2957. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  2958. NULL,
  2959. dwStoreFlags |
  2960. CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  2961. L"ca"
  2962. );
  2963. if ( pConfig->hRestrictedRoot != NULL )
  2964. {
  2965. if ( ChainIsProperRestrictedRoot(
  2966. m_hRealRootStore,
  2967. pConfig->hRestrictedRoot
  2968. ) == TRUE )
  2969. {
  2970. m_hRootStore = CertDuplicateStore( pConfig->hRestrictedRoot );
  2971. // Having restricted roots implicitly disables the auto
  2972. // updating of roots
  2973. m_dwFlags |= CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE;
  2974. }
  2975. }
  2976. else
  2977. {
  2978. m_hRootStore = CertDuplicateStore( m_hRealRootStore );
  2979. }
  2980. if ( m_hRootStore == NULL )
  2981. {
  2982. rfResult = FALSE;
  2983. return;
  2984. }
  2985. if ( ( pConfig->hRestrictedTrust == NULL ) ||
  2986. ( pConfig->hRestrictedOther == NULL ) )
  2987. {
  2988. rfResult = ChainCreateWorldStore(
  2989. m_hRootStore,
  2990. m_hCAStore,
  2991. pConfig->cAdditionalStore,
  2992. pConfig->rghAdditionalStore,
  2993. dwStoreFlags,
  2994. &hWorld
  2995. );
  2996. if ( rfResult == FALSE )
  2997. {
  2998. return;
  2999. }
  3000. }
  3001. if ( pConfig->hRestrictedTrust != NULL )
  3002. {
  3003. m_hTrustStore = CertDuplicateStore( pConfig->hRestrictedTrust );
  3004. }
  3005. else
  3006. {
  3007. m_hTrustStore = CertDuplicateStore( hWorld );
  3008. }
  3009. m_hOtherStore = CertOpenStore(
  3010. CERT_STORE_PROV_COLLECTION,
  3011. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  3012. NULL,
  3013. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  3014. NULL
  3015. );
  3016. if ( m_hOtherStore != NULL )
  3017. {
  3018. if ( pConfig->hRestrictedOther != NULL )
  3019. {
  3020. rfResult = CertAddStoreToCollection(
  3021. m_hOtherStore,
  3022. pConfig->hRestrictedOther,
  3023. 0,
  3024. 0
  3025. );
  3026. if ( rfResult == TRUE )
  3027. {
  3028. rfResult = CertAddStoreToCollection(
  3029. m_hOtherStore,
  3030. m_hRootStore,
  3031. 0,
  3032. 0
  3033. );
  3034. }
  3035. }
  3036. else
  3037. {
  3038. rfResult = CertAddStoreToCollection(
  3039. m_hOtherStore,
  3040. hWorld,
  3041. 0,
  3042. 0
  3043. );
  3044. if ( ( rfResult == TRUE ) && ( pConfig->hRestrictedTrust != NULL ) )
  3045. {
  3046. rfResult = CertAddStoreToCollection(
  3047. m_hOtherStore,
  3048. pConfig->hRestrictedTrust,
  3049. 0,
  3050. 0
  3051. );
  3052. }
  3053. }
  3054. }
  3055. else
  3056. {
  3057. rfResult = FALSE;
  3058. }
  3059. if ( hWorld != NULL )
  3060. {
  3061. CertCloseStore( hWorld, 0 );
  3062. }
  3063. if ( rfResult == TRUE )
  3064. {
  3065. rfResult = ChainCreateEngineStore(
  3066. m_hRootStore,
  3067. m_hTrustStore,
  3068. m_hOtherStore,
  3069. fDefaultEngine,
  3070. pConfig->dwFlags,
  3071. &m_hEngineStore,
  3072. &m_hEngineStoreChangeEvent
  3073. );
  3074. }
  3075. if ( rfResult == TRUE )
  3076. {
  3077. rfResult = ChainCreateCertificateObjectCache(
  3078. pConfig->MaximumCachedCertificates,
  3079. &m_pCertObjectCache
  3080. );
  3081. }
  3082. if ( rfResult == TRUE )
  3083. {
  3084. rfResult = SSCtlCreateObjectCache( &m_pSSCtlObjectCache );
  3085. }
  3086. if ( rfResult == TRUE )
  3087. {
  3088. rfResult = m_pSSCtlObjectCache->PopulateCache( this );
  3089. }
  3090. assert( m_hRootStore != NULL );
  3091. // Beginning of cross certificate stuff
  3092. if ( rfResult == FALSE )
  3093. {
  3094. return;
  3095. }
  3096. m_hCrossCertStore = CertOpenStore(
  3097. CERT_STORE_PROV_COLLECTION,
  3098. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  3099. NULL,
  3100. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  3101. NULL
  3102. );
  3103. if ( m_hCrossCertStore == NULL )
  3104. {
  3105. rfResult = FALSE;
  3106. return;
  3107. }
  3108. rfResult = GetCrossCertDistPointsForStore(
  3109. m_hEngineStore,
  3110. &m_pCrossCertDPLink
  3111. );
  3112. if ( rfResult == FALSE )
  3113. {
  3114. return;
  3115. }
  3116. rfResult = CertAddStoreToCollection(
  3117. m_hOtherStore,
  3118. m_hCrossCertStore,
  3119. 0,
  3120. 0
  3121. );
  3122. // End of cross certificate stuff
  3123. CertPerfIncrementChainEngineCurrentCount();
  3124. CertPerfIncrementChainEngineTotalCount();
  3125. }
  3126. //+---------------------------------------------------------------------------
  3127. //
  3128. // Member: CCertChainEngine::~CCertChainEngine, public
  3129. //
  3130. // Synopsis: Destructor
  3131. //
  3132. //----------------------------------------------------------------------------
  3133. CCertChainEngine::~CCertChainEngine ()
  3134. {
  3135. CertPerfDecrementChainEngineCurrentCount();
  3136. // Beginning of cross certificate stuff
  3137. FreeCrossCertDistPoints(
  3138. &m_pCrossCertDPLink
  3139. );
  3140. assert( NULL == m_pCrossCertDPLink );
  3141. assert( NULL == m_pCrossCertDPEntry );
  3142. if ( m_hCrossCertStore != NULL )
  3143. {
  3144. CertCloseStore( m_hCrossCertStore, 0 );
  3145. }
  3146. // End of cross certificate stuff
  3147. FreeAuthRootAutoUpdateInfo(m_pAuthRootAutoUpdateInfo);
  3148. ChainFreeCertificateObjectCache( m_pCertObjectCache );
  3149. SSCtlFreeObjectCache( m_pSSCtlObjectCache );
  3150. if ( m_hRootStore != NULL )
  3151. {
  3152. CertCloseStore( m_hRootStore, 0 );
  3153. }
  3154. if ( m_hRealRootStore != NULL )
  3155. {
  3156. CertCloseStore( m_hRealRootStore, 0 );
  3157. }
  3158. if ( m_hTrustStore != NULL )
  3159. {
  3160. CertCloseStore( m_hTrustStore, 0 );
  3161. }
  3162. if ( m_hOtherStore != NULL )
  3163. {
  3164. CertCloseStore( m_hOtherStore, 0 );
  3165. }
  3166. if ( m_hCAStore != NULL )
  3167. {
  3168. CertCloseStore( m_hCAStore, 0 );
  3169. }
  3170. if ( m_hEngineStore != NULL )
  3171. {
  3172. if ( m_hEngineStoreChangeEvent != NULL )
  3173. {
  3174. CertControlStore(
  3175. m_hEngineStore,
  3176. 0, // dwFlags
  3177. CERT_STORE_CTRL_CANCEL_NOTIFY,
  3178. &m_hEngineStoreChangeEvent
  3179. );
  3180. }
  3181. CertCloseStore( m_hEngineStore, 0 );
  3182. }
  3183. if ( m_hEngineStoreChangeEvent != NULL )
  3184. {
  3185. CloseHandle( m_hEngineStoreChangeEvent );
  3186. }
  3187. DeleteCriticalSection( &m_Lock );
  3188. }
  3189. // "CrossCA"
  3190. const BYTE rgbEncodedCrossCAUnicodeString[] = {
  3191. 0x1E, 0x0E,
  3192. 0x00, 0x43, 0x00, 0x72, 0x00, 0x6F, 0x00, 0x73,
  3193. 0x00, 0x73, 0x00, 0x43, 0x00, 0x41
  3194. };
  3195. //+---------------------------------------------------------------------------
  3196. //
  3197. // Member: CCertChainEngine::GetChainContext, public
  3198. //
  3199. // Synopsis: get a certificate chain context
  3200. //
  3201. // NOTE: This method acquires the engine lock
  3202. //
  3203. //----------------------------------------------------------------------------
  3204. BOOL
  3205. CCertChainEngine::GetChainContext (
  3206. IN PCCERT_CONTEXT pCertContext,
  3207. IN LPFILETIME pTime,
  3208. IN OPTIONAL HCERTSTORE hAdditionalStore,
  3209. IN OPTIONAL PCERT_CHAIN_PARA pChainPara,
  3210. IN DWORD dwFlags,
  3211. IN LPVOID pvReserved,
  3212. OUT PCCERT_CHAIN_CONTEXT* ppChainContext
  3213. )
  3214. {
  3215. BOOL fResult;
  3216. DWORD dwLastError = 0;
  3217. PCCHAINCALLCONTEXT pCallContext = NULL;
  3218. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  3219. if (!CallContextCreateCallObject(
  3220. this,
  3221. pTime,
  3222. pChainPara,
  3223. dwFlags,
  3224. &pCallContext
  3225. ))
  3226. goto CallContextCreateCallObjectError;
  3227. if (!CreateChainContextFromPathGraph(
  3228. pCallContext,
  3229. pCertContext,
  3230. hAdditionalStore,
  3231. &pChainContext
  3232. ))
  3233. goto CreateChainContextFromPathGraphError;
  3234. if ((pChainContext->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) &&
  3235. pCallContext->IsOnline()) {
  3236. // For a revoked CA, try to retrieve a newer CA cert via the subject's
  3237. // AIA extension.
  3238. //
  3239. // Note, will only try for the first revoked CA cert in the first
  3240. // simple chain.
  3241. HCERTSTORE hNewerIssuerUrlStore = NULL;
  3242. PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[0];
  3243. DWORD cEle = pChain->cElement;
  3244. PCERT_CHAIN_ELEMENT *ppEle = pChain->rgpElement;
  3245. DWORD i;
  3246. for (i = 1; i < cEle; i++) {
  3247. PCERT_CHAIN_ELEMENT pIssuerEle = ppEle[i];
  3248. if (pIssuerEle->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
  3249. // First Revoked CA
  3250. PCCERT_CONTEXT pIssuerCert = pIssuerEle->pCertContext;
  3251. PCERT_EXTENSION pExt;
  3252. // Ignore CrossCA's. If the CA cert has a Certificate
  3253. // Template Name extension we will check if its set to
  3254. // "CrossCA". Note, this is only a hint. Its not a
  3255. // requirement to have this extension for a cross cert.
  3256. pExt = CertFindExtension(
  3257. szOID_ENROLL_CERTTYPE_EXTENSION,
  3258. pIssuerCert->pCertInfo->cExtension,
  3259. pIssuerCert->pCertInfo->rgExtension
  3260. );
  3261. if (pExt && pExt->Value.cbData ==
  3262. sizeof(rgbEncodedCrossCAUnicodeString) &&
  3263. 0 == memcmp(pExt->Value.pbData,
  3264. rgbEncodedCrossCAUnicodeString,
  3265. sizeof(rgbEncodedCrossCAUnicodeString)))
  3266. break;
  3267. hNewerIssuerUrlStore = GetNewerIssuerUrlStore(
  3268. pCallContext,
  3269. ppEle[i - 1]->pCertContext, // Subject
  3270. pIssuerCert
  3271. );
  3272. break;
  3273. }
  3274. }
  3275. if (hNewerIssuerUrlStore) {
  3276. // Rebuild the chain using the newer AIA retrieved Issuer cert
  3277. HCERTSTORE hNewerAdditionalStore = NULL;
  3278. if (hAdditionalStore) {
  3279. hNewerAdditionalStore = CertOpenStore(
  3280. CERT_STORE_PROV_COLLECTION,
  3281. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  3282. NULL,
  3283. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  3284. NULL
  3285. );
  3286. if (hNewerAdditionalStore) {
  3287. if (!CertAddStoreToCollection(hNewerAdditionalStore,
  3288. hNewerIssuerUrlStore, 0, 0) ||
  3289. !CertAddStoreToCollection(hNewerAdditionalStore,
  3290. hAdditionalStore, 0, 0)) {
  3291. CertCloseStore(hNewerAdditionalStore, 0);
  3292. hNewerAdditionalStore = NULL;
  3293. }
  3294. }
  3295. } else
  3296. hNewerAdditionalStore =
  3297. CertDuplicateStore(hNewerIssuerUrlStore);
  3298. if (hNewerAdditionalStore) {
  3299. PCCERT_CHAIN_CONTEXT pNewerChainContext = NULL;
  3300. LockEngine();
  3301. pCallContext->FlushObjectsInCreationCache( );
  3302. UnlockEngine();
  3303. if (CreateChainContextFromPathGraph(
  3304. pCallContext,
  3305. pCertContext,
  3306. hNewerAdditionalStore,
  3307. &pNewerChainContext
  3308. )) {
  3309. assert(pNewerChainContext);
  3310. CertFreeCertificateChain(pChainContext);
  3311. pChainContext = pNewerChainContext;
  3312. }
  3313. CertCloseStore(hNewerAdditionalStore, 0);
  3314. }
  3315. CertCloseStore(hNewerIssuerUrlStore, 0);
  3316. }
  3317. }
  3318. fResult = TRUE;
  3319. CommonReturn:
  3320. if (pCallContext) {
  3321. LockEngine();
  3322. CallContextFreeCallObject(pCallContext);
  3323. UnlockEngine();
  3324. }
  3325. if (0 != dwLastError)
  3326. SetLastError(dwLastError);
  3327. *ppChainContext = pChainContext;
  3328. return fResult;
  3329. ErrorReturn:
  3330. dwLastError = GetLastError();
  3331. assert(NULL == pChainContext);
  3332. fResult = FALSE;
  3333. goto CommonReturn;
  3334. TRACE_ERROR(CallContextCreateCallObjectError)
  3335. TRACE_ERROR(CreateChainContextFromPathGraphError)
  3336. }
  3337. //+---------------------------------------------------------------------------
  3338. //
  3339. // Member: CCertChainEngine::CreateChainContextFromPathGraph, public
  3340. //
  3341. // Synopsis: builds a chain path graph and returns quality ordered
  3342. // chain contexts
  3343. //
  3344. // NOTE: This method acquires the engine lock
  3345. //
  3346. //----------------------------------------------------------------------------
  3347. BOOL
  3348. CCertChainEngine::CreateChainContextFromPathGraph (
  3349. IN PCCHAINCALLCONTEXT pCallContext,
  3350. IN PCCERT_CONTEXT pCertContext,
  3351. IN OPTIONAL HCERTSTORE hAdditionalStore,
  3352. OUT PCCERT_CHAIN_CONTEXT* ppChainContext
  3353. )
  3354. {
  3355. BOOL fResult;
  3356. DWORD dwLastError = 0;
  3357. BOOL fLocked = FALSE;
  3358. BYTE rgbCertHash[CHAINHASHLEN];
  3359. DWORD cbCertHash;
  3360. PCCERTOBJECT pEndCertObject = NULL;
  3361. PCCHAINPATHOBJECT pEndPathObject = NULL;
  3362. PCCHAINPATHOBJECT pTopPathObject = NULL;
  3363. HCERTSTORE hAdditionalStoreToUse = NULL;
  3364. HCERTSTORE hAllStore = NULL;
  3365. PINTERNAL_CERT_CHAIN_CONTEXT pNewChainContext = NULL; // don't release
  3366. PINTERNAL_CERT_CHAIN_CONTEXT pChainContext = NULL;
  3367. DWORD cChainContext = 0;
  3368. DWORD dwFlags = pCallContext->CallFlags();
  3369. cbCertHash = CHAINHASHLEN;
  3370. if (!CertGetCertificateContextProperty(
  3371. pCertContext,
  3372. CERT_MD5_HASH_PROP_ID,
  3373. rgbCertHash,
  3374. &cbCertHash
  3375. ) || CHAINHASHLEN != cbCertHash)
  3376. goto GetCertHashError;
  3377. if (hAdditionalStore) {
  3378. if (!ChainCreateCollectionIncludingCtlCertificates(
  3379. hAdditionalStore,
  3380. &hAdditionalStoreToUse
  3381. ))
  3382. goto CreateAdditionalStoreCollectionError;
  3383. hAllStore = CertOpenStore(
  3384. CERT_STORE_PROV_COLLECTION,
  3385. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  3386. NULL,
  3387. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  3388. NULL
  3389. );
  3390. if (NULL == hAllStore)
  3391. goto OpenAllCollectionError;
  3392. if (!CertAddStoreToCollection(hAllStore, OtherStore(), 0, 0 ))
  3393. goto AddToAllCollectionError;
  3394. if (!CertAddStoreToCollection(hAllStore, hAdditionalStoreToUse, 0, 0 ))
  3395. goto AddToAllCollectionError;
  3396. } else
  3397. hAllStore = CertDuplicateStore(OtherStore());
  3398. LockEngine();
  3399. fLocked = TRUE;
  3400. // We're in this loop to handle the case where we leave the engine's
  3401. // critical section and another thread has entered the engine's
  3402. // critical section and done a resync or added a cached issuer cert object.
  3403. while (TRUE) {
  3404. if (!Resync(pCallContext, FALSE))
  3405. goto ResyncError;
  3406. pCallContext->ResetTouchEngine();
  3407. assert(NULL == pEndCertObject);
  3408. pEndCertObject = m_pCertObjectCache->FindIssuerObjectByHash(
  3409. rgbCertHash);
  3410. fResult = TRUE;
  3411. if (NULL == pEndCertObject) {
  3412. pEndCertObject = m_pCertObjectCache->FindEndObjectByHash(
  3413. rgbCertHash);
  3414. if (NULL == pEndCertObject) {
  3415. fResult = ChainCreateCertObject(
  3416. CERT_END_OBJECT_TYPE,
  3417. pCallContext,
  3418. pCertContext,
  3419. rgbCertHash,
  3420. &pEndCertObject
  3421. );
  3422. } else {
  3423. CertPerfIncrementChainEndCertInCacheCount();
  3424. }
  3425. }
  3426. if (pCallContext->IsTouchedEngine()) {
  3427. // The chain engine was touched at some point when we left
  3428. // the engine's lock to create the end cert object
  3429. if (pEndCertObject) {
  3430. pEndCertObject->Release();
  3431. pEndCertObject = NULL;
  3432. }
  3433. continue;
  3434. }
  3435. if (!fResult)
  3436. goto CreateCertObjectError;
  3437. assert(pEndCertObject);
  3438. // This will create the entire path graph
  3439. fResult = ChainCreatePathObject(
  3440. pCallContext,
  3441. pEndCertObject,
  3442. hAdditionalStoreToUse,
  3443. &pEndPathObject
  3444. );
  3445. if (pCallContext->IsTouchedEngine()) {
  3446. // The chain engine was touched at some point when we left
  3447. // the engine's lock to verify a signature or do URL fetching.
  3448. pEndCertObject->Release();
  3449. pEndCertObject = NULL;
  3450. pEndPathObject = NULL;
  3451. pCallContext->FlushObjectsInCreationCache( );
  3452. } else
  3453. break;
  3454. }
  3455. if (!fResult)
  3456. goto CreatePathObjectError;
  3457. if (pCallContext->CallOrEngineFlags() & CERT_CHAIN_CACHE_END_CERT)
  3458. m_pCertObjectCache->AddEndObject(pCallContext, pEndCertObject);
  3459. // Create the ChainContext without holding the engine lock
  3460. UnlockEngine();
  3461. fLocked = FALSE;
  3462. // Loop through all the certificate paths:
  3463. // - Calculate additional status
  3464. // - Create chain context and its quality value
  3465. // - Determine highest quality chain
  3466. // - Optionally, maintain a linked list of the lower quality chains
  3467. while (pTopPathObject = pEndPathObject->NextPath(
  3468. pCallContext,
  3469. pTopPathObject
  3470. )) {
  3471. PCCHAINPATHOBJECT pPathObject;
  3472. // Loop downward to calculate additional status
  3473. for (pPathObject = pTopPathObject;
  3474. pPathObject && !pPathObject->HasAdditionalStatus();
  3475. pPathObject = pPathObject->DownPathObject()) {
  3476. pPathObject->CalculateAdditionalStatus(
  3477. pCallContext,
  3478. hAllStore
  3479. );
  3480. }
  3481. // Also calculates the chain's quality value
  3482. pNewChainContext = pEndPathObject->CreateChainContextFromPath(
  3483. pCallContext,
  3484. pTopPathObject
  3485. );
  3486. if (NULL == pNewChainContext)
  3487. goto CreateChainContextFromPathError;
  3488. // Fixup end cert
  3489. ChainUpdateEndEntityCertContext(pNewChainContext, pCertContext);
  3490. // Add logic to call either the chain engine's or the caller's
  3491. // callback function here to provide additional chain context
  3492. // quality
  3493. if (NULL == pChainContext) {
  3494. pChainContext = pNewChainContext;
  3495. cChainContext = 1;
  3496. } else {
  3497. BOOL fNewHigherQuality = FALSE;
  3498. if (pNewChainContext->dwQuality > pChainContext->dwQuality)
  3499. fNewHigherQuality = TRUE;
  3500. else if (pNewChainContext->dwQuality == pChainContext->dwQuality) {
  3501. BOOL fDupPublicKey = FALSE;
  3502. PCERT_SIMPLE_CHAIN pChain =
  3503. pChainContext->ChainContext.rgpChain[0];
  3504. PCERT_SIMPLE_CHAIN pNewChain =
  3505. pNewChainContext->ChainContext.rgpChain[0];
  3506. DWORD cElement = pChain->cElement;
  3507. DWORD cNewElement = pNewChain->cElement;
  3508. if (cElement != cNewElement) {
  3509. // Check if the longer chain has any duplicate public
  3510. // keys. This could happen if we have 2 sets of cross
  3511. // certificates
  3512. PCERT_SIMPLE_CHAIN pLongChain;
  3513. DWORD cLongElement;
  3514. DWORD i;
  3515. if (cElement > cNewElement) {
  3516. pLongChain = pChain;
  3517. cLongElement = cElement;
  3518. } else {
  3519. pLongChain = pNewChain;
  3520. cLongElement = cNewElement;
  3521. }
  3522. // Start with the CA and compare all keys up to and
  3523. // including the root
  3524. for (i = 1; i + 1 < cLongElement; i++) {
  3525. DWORD j;
  3526. DWORD cbHash;
  3527. BYTE rgbHash0[ CHAINHASHLEN ];
  3528. cbHash = CHAINHASHLEN;
  3529. if (!CertGetCertificateContextProperty(
  3530. pLongChain->rgpElement[i]->pCertContext,
  3531. CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID,
  3532. rgbHash0,
  3533. &cbHash
  3534. ) || CHAINHASHLEN != cbHash)
  3535. break;
  3536. for (j = i + 1; j < cLongElement; j++) {
  3537. BYTE rgbHash1[ CHAINHASHLEN ];
  3538. cbHash = CHAINHASHLEN;
  3539. if (!CertGetCertificateContextProperty(
  3540. pLongChain->rgpElement[j]->pCertContext,
  3541. CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID,
  3542. rgbHash1,
  3543. &cbHash
  3544. ) || CHAINHASHLEN != cbHash)
  3545. break;
  3546. if (0 == memcmp(rgbHash0, rgbHash1, CHAINHASHLEN)) {
  3547. fDupPublicKey = TRUE;
  3548. break;
  3549. }
  3550. }
  3551. if (fDupPublicKey)
  3552. break;
  3553. }
  3554. }
  3555. if (fDupPublicKey) {
  3556. if (cElement > cNewElement)
  3557. fNewHigherQuality = TRUE;
  3558. } else {
  3559. DWORD i;
  3560. DWORD cMinElement;
  3561. // Chains having certs with later NotAfter/NotBefore dates
  3562. // starting with the first CA cert are considered higher
  3563. // quality when dwQuality is the same. Will only compare
  3564. // the first simple chain.
  3565. cMinElement = min(cElement, cNewElement);
  3566. for (i = 1; i < cMinElement; i++) {
  3567. LONG lCmp;
  3568. PCERT_INFO pCertInfo =
  3569. pChain->rgpElement[i]->pCertContext->pCertInfo;
  3570. PCERT_INFO pNewCertInfo =
  3571. pNewChain->rgpElement[i]->pCertContext->pCertInfo;
  3572. lCmp = CompareFileTime(&pNewCertInfo->NotAfter,
  3573. &pCertInfo->NotAfter);
  3574. if (0 < lCmp) {
  3575. fNewHigherQuality = TRUE;
  3576. break;
  3577. } else if (0 > lCmp) {
  3578. break;
  3579. } else {
  3580. // Same NotAfter. Check NotBefore.
  3581. lCmp = CompareFileTime(&pNewCertInfo->NotBefore,
  3582. &pCertInfo->NotBefore);
  3583. if (0 < lCmp) {
  3584. fNewHigherQuality = TRUE;
  3585. break;
  3586. } else if (0 > lCmp)
  3587. break;
  3588. // else
  3589. // Same
  3590. }
  3591. }
  3592. }
  3593. }
  3594. // else
  3595. // fNewHigherQuality = FALSE;
  3596. if (fNewHigherQuality) {
  3597. if (dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS) {
  3598. pNewChainContext->pNext = pChainContext;
  3599. pChainContext = pNewChainContext;
  3600. cChainContext++;
  3601. } else {
  3602. ChainReleaseInternalChainContext(pChainContext);
  3603. pChainContext = pNewChainContext;
  3604. }
  3605. } else {
  3606. if (dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS) {
  3607. PINTERNAL_CERT_CHAIN_CONTEXT p;
  3608. // Insert according to quality
  3609. for (p = pChainContext;
  3610. p->pNext && p->pNext->dwQuality >=
  3611. pNewChainContext->dwQuality;
  3612. p = p->pNext) {
  3613. ;
  3614. }
  3615. pNewChainContext->pNext = p->pNext;
  3616. p->pNext = pNewChainContext;
  3617. cChainContext++;
  3618. } else {
  3619. ChainReleaseInternalChainContext(pNewChainContext);
  3620. }
  3621. }
  3622. }
  3623. }
  3624. if (GetLastError() != CRYPT_E_NOT_FOUND)
  3625. goto NextPathError;
  3626. assert(pChainContext && cChainContext);
  3627. if (cChainContext > 1) {
  3628. PINTERNAL_CERT_CHAIN_CONTEXT p;
  3629. PCCERT_CHAIN_CONTEXT *ppLower;
  3630. // Create array of lower quality chain contexts
  3631. ppLower = new PCCERT_CHAIN_CONTEXT [ cChainContext - 1];
  3632. if (NULL == ppLower)
  3633. goto OutOfMemory;
  3634. pChainContext->ChainContext.cLowerQualityChainContext =
  3635. cChainContext - 1;
  3636. pChainContext->ChainContext.rgpLowerQualityChainContext = ppLower;
  3637. for (p = pChainContext->pNext; p; p = p->pNext, ppLower++) {
  3638. assert(cChainContext > 1);
  3639. cChainContext--;
  3640. *ppLower = (PCCERT_CHAIN_CONTEXT) p;
  3641. }
  3642. }
  3643. assert(1 == cChainContext);
  3644. fResult = TRUE;
  3645. CommonReturn:
  3646. if (!fLocked)
  3647. LockEngine();
  3648. if (pEndCertObject)
  3649. pEndCertObject->Release();
  3650. if (hAllStore)
  3651. CertCloseStore(hAllStore, 0);
  3652. if (hAdditionalStoreToUse)
  3653. CertCloseStore(hAdditionalStoreToUse, 0);
  3654. *ppChainContext = (PCCERT_CHAIN_CONTEXT) pChainContext;
  3655. UnlockEngine();
  3656. if (0 != dwLastError)
  3657. SetLastError(dwLastError);
  3658. return fResult;
  3659. ErrorReturn:
  3660. dwLastError = GetLastError();
  3661. if (pChainContext) {
  3662. PINTERNAL_CERT_CHAIN_CONTEXT p;
  3663. while (p = pChainContext->pNext) {
  3664. pChainContext->pNext = p->pNext;
  3665. ChainReleaseInternalChainContext(p);
  3666. }
  3667. ChainReleaseInternalChainContext(pChainContext);
  3668. pChainContext = NULL;
  3669. }
  3670. fResult = FALSE;
  3671. goto CommonReturn;
  3672. TRACE_ERROR(GetCertHashError)
  3673. TRACE_ERROR(CreateAdditionalStoreCollectionError)
  3674. TRACE_ERROR(OpenAllCollectionError)
  3675. TRACE_ERROR(AddToAllCollectionError)
  3676. TRACE_ERROR(ResyncError)
  3677. TRACE_ERROR(CreateCertObjectError)
  3678. TRACE_ERROR(CreatePathObjectError)
  3679. TRACE_ERROR(CreateChainContextFromPathError)
  3680. TRACE_ERROR(NextPathError)
  3681. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  3682. }
  3683. //+---------------------------------------------------------------------------
  3684. //
  3685. // Member: CCertChainEngine::GetIssuerUrlStore, public
  3686. //
  3687. // Synopsis: if the certificate has an Authority Info Access extension,
  3688. // return a store containing the issuing certificates
  3689. //
  3690. // Leaves the engine's critical section to do the URL
  3691. // fetching. If the engine was touched by another thread,
  3692. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  3693. //
  3694. // Assumption: Chain engine is locked once in the calling thread.
  3695. //
  3696. //----------------------------------------------------------------------------
  3697. BOOL
  3698. CCertChainEngine::GetIssuerUrlStore(
  3699. IN PCCHAINCALLCONTEXT pCallContext,
  3700. IN PCCERT_CONTEXT pSubjectCertContext,
  3701. IN DWORD dwRetrievalFlags,
  3702. OUT HCERTSTORE *phIssuerUrlStore
  3703. )
  3704. {
  3705. BOOL fTouchedResult = TRUE;
  3706. BOOL fResult;
  3707. DWORD cbUrlArray;
  3708. PCRYPT_URL_ARRAY pUrlArray = NULL;
  3709. DWORD cCount;
  3710. DWORD dwCacheResultFlag;
  3711. *phIssuerUrlStore = NULL;
  3712. dwRetrievalFlags |= CRYPT_RETRIEVE_MULTIPLE_OBJECTS |
  3713. CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL |
  3714. CRYPT_OFFLINE_CHECK_RETRIEVAL;
  3715. fResult = ChainGetObjectUrl(
  3716. URL_OID_CERTIFICATE_ISSUER,
  3717. (LPVOID) pSubjectCertContext,
  3718. CRYPT_GET_URL_FROM_EXTENSION,
  3719. NULL,
  3720. &cbUrlArray,
  3721. NULL,
  3722. NULL,
  3723. NULL
  3724. );
  3725. if ( fResult == TRUE )
  3726. {
  3727. pUrlArray = (PCRYPT_URL_ARRAY)new BYTE [ cbUrlArray ];
  3728. if ( pUrlArray == NULL )
  3729. {
  3730. SetLastError( (DWORD) E_OUTOFMEMORY );
  3731. return( FALSE );
  3732. }
  3733. fResult = ChainGetObjectUrl(
  3734. URL_OID_CERTIFICATE_ISSUER,
  3735. (LPVOID) pSubjectCertContext,
  3736. CRYPT_GET_URL_FROM_EXTENSION,
  3737. pUrlArray,
  3738. &cbUrlArray,
  3739. NULL,
  3740. NULL,
  3741. NULL
  3742. );
  3743. }
  3744. if ( fResult == TRUE )
  3745. {
  3746. BOOL fLocked = FALSE;
  3747. //
  3748. // We are about to go on the wire to retrieve the issuer certificate.
  3749. // At this time we will release the chain engine lock so others can
  3750. // go about there business while we wait for the protocols to do the
  3751. // fetching.
  3752. //
  3753. UnlockEngine();
  3754. for ( cCount = 0; cCount < pUrlArray->cUrl; cCount++ )
  3755. {
  3756. if ( !( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL ) &&
  3757. ( ChainIsFileOrLdapUrl( pUrlArray->rgwszUrl[ cCount ] ) == TRUE ) )
  3758. {
  3759. dwCacheResultFlag = CRYPT_DONT_CACHE_RESULT;
  3760. }
  3761. else
  3762. {
  3763. dwCacheResultFlag = 0;
  3764. }
  3765. fResult = ChainRetrieveObjectByUrlW(
  3766. pUrlArray->rgwszUrl[ cCount ],
  3767. CONTEXT_OID_CERTIFICATE,
  3768. dwRetrievalFlags | dwCacheResultFlag,
  3769. pCallContext->ChainPara()->dwUrlRetrievalTimeout,
  3770. (LPVOID *)phIssuerUrlStore,
  3771. NULL,
  3772. NULL,
  3773. NULL,
  3774. NULL
  3775. );
  3776. if ( fResult == TRUE )
  3777. {
  3778. CertPerfIncrementChainUrlIssuerCount();
  3779. if (dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL)
  3780. CertPerfIncrementChainCacheOnlyUrlIssuerCount();
  3781. //
  3782. // Retake the engine lock. Also check if the engine was
  3783. // touched during our absence.
  3784. //
  3785. LockEngine();
  3786. if (pCallContext->IsTouchedEngine()) {
  3787. fTouchedResult = FALSE;
  3788. SetLastError( (DWORD) ERROR_CAN_NOT_COMPLETE );
  3789. }
  3790. fLocked = TRUE;
  3791. ChainCopyToCAStore( this, *phIssuerUrlStore );
  3792. if (!fTouchedResult) {
  3793. CertCloseStore(*phIssuerUrlStore, 0);
  3794. *phIssuerUrlStore = NULL;
  3795. }
  3796. break;
  3797. }
  3798. }
  3799. //
  3800. // Retake the engine lock if necessary
  3801. //
  3802. if ( fLocked == FALSE )
  3803. {
  3804. LockEngine();
  3805. if (pCallContext->IsTouchedEngine()) {
  3806. fTouchedResult = FALSE;
  3807. SetLastError( (DWORD) ERROR_CAN_NOT_COMPLETE );
  3808. }
  3809. }
  3810. }
  3811. delete (LPBYTE)pUrlArray;
  3812. // NOTE: Need to somehow log that we tried to retrieve the issuer but
  3813. // it was inaccessible
  3814. return( fTouchedResult );
  3815. }
  3816. //+---------------------------------------------------------------------------
  3817. //
  3818. // Member: CCertChainEngine::GetNewerIssuerUrlStore, public
  3819. //
  3820. // Synopsis: if the subject certificate has an Authority Info Access
  3821. // extension, attempts an online URL retrieval of the
  3822. // issuer certificate(s). If any of the URL retrieved
  3823. // certs are different from the input Issuer cert,
  3824. // returns a store containing the issuing certificates.
  3825. // Otherwise, returns NULL store.
  3826. //
  3827. // Assumption: Chain engine isn't locked in the calling thread. Also,
  3828. // only called if online.
  3829. //
  3830. //----------------------------------------------------------------------------
  3831. HCERTSTORE
  3832. CCertChainEngine::GetNewerIssuerUrlStore(
  3833. IN PCCHAINCALLCONTEXT pCallContext,
  3834. IN PCCERT_CONTEXT pSubjectCertContext,
  3835. IN PCCERT_CONTEXT pIssuerCertContext
  3836. )
  3837. {
  3838. HCERTSTORE hNewIssuerUrlStore = NULL;
  3839. LockEngine();
  3840. while (TRUE) {
  3841. pCallContext->ResetTouchEngine();
  3842. GetIssuerUrlStore(
  3843. pCallContext,
  3844. pSubjectCertContext,
  3845. CRYPT_WIRE_ONLY_RETRIEVAL,
  3846. &hNewIssuerUrlStore
  3847. );
  3848. if (!pCallContext->IsTouchedEngine())
  3849. break;
  3850. assert(NULL == hNewIssuerUrlStore);
  3851. }
  3852. UnlockEngine();
  3853. if (hNewIssuerUrlStore) {
  3854. // Discard if it doesn't contain more than just the input
  3855. // pIssuerCertContext
  3856. PCCERT_CONTEXT pCert;
  3857. pCert = NULL;
  3858. while (pCert = CertEnumCertificatesInStore(hNewIssuerUrlStore, pCert)) {
  3859. if (!CertCompareCertificate(
  3860. pCert->dwCertEncodingType,
  3861. pCert->pCertInfo,
  3862. pIssuerCertContext->pCertInfo
  3863. )) {
  3864. CertFreeCertificateContext(pCert);
  3865. return hNewIssuerUrlStore;
  3866. }
  3867. }
  3868. CertCloseStore(hNewIssuerUrlStore, 0);
  3869. }
  3870. return NULL;
  3871. }
  3872. //+---------------------------------------------------------------------------
  3873. //
  3874. // Member: CCertChainEngine::Resync, public
  3875. //
  3876. // Synopsis: resync the store if necessary
  3877. //
  3878. // Leaves the engine's critical section to do the URL
  3879. // fetching. If the engine was touched by another thread,
  3880. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  3881. //
  3882. // A resync increments the engine's touch count.
  3883. //
  3884. // Assumption: Chain engine is locked once in the calling thread.
  3885. //
  3886. //----------------------------------------------------------------------------
  3887. BOOL
  3888. CCertChainEngine::Resync (IN PCCHAINCALLCONTEXT pCallContext, BOOL fForce)
  3889. {
  3890. BOOL fResync = FALSE;
  3891. BOOL fResult = TRUE;
  3892. if ( fForce == FALSE )
  3893. {
  3894. if ( WaitForSingleObject(
  3895. m_hEngineStoreChangeEvent,
  3896. 0
  3897. ) == WAIT_OBJECT_0 )
  3898. {
  3899. fResync = TRUE;
  3900. }
  3901. }
  3902. else
  3903. {
  3904. fResync = TRUE;
  3905. }
  3906. if ( fResync )
  3907. {
  3908. CertControlStore(
  3909. m_hEngineStore,
  3910. CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG,
  3911. CERT_STORE_CTRL_RESYNC,
  3912. &m_hEngineStoreChangeEvent
  3913. );
  3914. m_pCertObjectCache->FlushObjects( pCallContext );
  3915. fResult = m_pSSCtlObjectCache->Resync( this );
  3916. assert( fResult == TRUE );
  3917. assert( m_hCrossCertStore );
  3918. // Remove CrossCert collection from engine's list. Don't want to
  3919. // also search it for cross cert distribution points
  3920. CertRemoveStoreFromCollection(
  3921. m_hOtherStore,
  3922. m_hCrossCertStore
  3923. );
  3924. fResult = GetCrossCertDistPointsForStore(
  3925. m_hEngineStore,
  3926. &m_pCrossCertDPLink
  3927. );
  3928. CertAddStoreToCollection(
  3929. m_hOtherStore,
  3930. m_hCrossCertStore,
  3931. 0,
  3932. 0
  3933. );
  3934. pCallContext->TouchEngine();
  3935. CertPerfIncrementChainEngineResyncCount();
  3936. }
  3937. if ( fResult )
  3938. {
  3939. while (TRUE ) {
  3940. pCallContext->ResetTouchEngine();
  3941. // The following 2 updates leave the engine's critical
  3942. // section to do the URL fetching. If the engine was touched by
  3943. // another thread, it fails with LastError set to
  3944. // ERROR_CAN_NOT_COMPLETE and IsTouchedEngine() is TRUE.
  3945. UpdateCrossCerts(pCallContext);
  3946. if (pCallContext->IsTouchedEngine())
  3947. continue;
  3948. m_pSSCtlObjectCache->UpdateCache(this, pCallContext);
  3949. if (!pCallContext->IsTouchedEngine())
  3950. break;
  3951. }
  3952. }
  3953. return( TRUE );
  3954. }
  3955. //+===========================================================================
  3956. // CCertObject helper functions
  3957. //============================================================================
  3958. //+---------------------------------------------------------------------------
  3959. //
  3960. // Function: ChainCreateCertObject
  3961. //
  3962. // Synopsis: create a cert object, note since it is a ref-counted
  3963. // object, freeing occurs by doing a pCertObject->Release
  3964. //
  3965. //----------------------------------------------------------------------------
  3966. BOOL WINAPI
  3967. ChainCreateCertObject (
  3968. IN DWORD dwObjectType,
  3969. IN PCCHAINCALLCONTEXT pCallContext,
  3970. IN PCCERT_CONTEXT pCertContext,
  3971. IN OPTIONAL LPBYTE pbCertHash,
  3972. OUT PCCERTOBJECT *ppCertObject
  3973. )
  3974. {
  3975. BOOL fResult = TRUE;
  3976. PCCERTOBJECT pCertObject;
  3977. BYTE rgbHash[CHAINHASHLEN];
  3978. if (NULL == pbCertHash) {
  3979. DWORD cbHash = CHAINHASHLEN;
  3980. if (!CertGetCertificateContextProperty(
  3981. pCertContext,
  3982. CERT_MD5_HASH_PROP_ID,
  3983. rgbHash,
  3984. &cbHash
  3985. ) || CHAINHASHLEN != cbHash) {
  3986. *ppCertObject = NULL;
  3987. return FALSE;
  3988. }
  3989. pbCertHash = rgbHash;
  3990. }
  3991. if (CERT_CACHED_ISSUER_OBJECT_TYPE == dwObjectType) {
  3992. pCertObject =
  3993. pCallContext->ChainEngine()->CertObjectCache()->FindIssuerObjectByHash(
  3994. pbCertHash);
  3995. if (NULL != pCertObject) {
  3996. *ppCertObject = pCertObject;
  3997. return TRUE;
  3998. }
  3999. } else {
  4000. PCCHAINPATHOBJECT pPathObject;
  4001. pPathObject = pCallContext->FindPathObjectInCreationCache(
  4002. pbCertHash);
  4003. if (NULL != pPathObject) {
  4004. pCertObject = pPathObject->CertObject();
  4005. pCertObject->AddRef();
  4006. *ppCertObject = pCertObject;
  4007. return TRUE;
  4008. }
  4009. }
  4010. pCertObject = new CCertObject(
  4011. dwObjectType,
  4012. pCallContext,
  4013. pCertContext,
  4014. pbCertHash,
  4015. fResult
  4016. );
  4017. if (NULL != pCertObject) {
  4018. if (!fResult) {
  4019. pCertObject->Release();
  4020. pCertObject = NULL;
  4021. } else if (CERT_CACHED_ISSUER_OBJECT_TYPE == dwObjectType) {
  4022. // Following add increments the engine's touch count
  4023. pCallContext->ChainEngine()->CertObjectCache()->AddIssuerObject(
  4024. pCallContext,
  4025. pCertObject
  4026. );
  4027. }
  4028. } else {
  4029. fResult = FALSE;
  4030. }
  4031. *ppCertObject = pCertObject;
  4032. return fResult;
  4033. }
  4034. //+---------------------------------------------------------------------------
  4035. //
  4036. // Function: ChainFillCertObjectCtlCacheEnumFn
  4037. //
  4038. // Synopsis: CSSCtlObjectCache::EnumObjects callback used to create
  4039. // the linked list of CTL cache entries.
  4040. //
  4041. //----------------------------------------------------------------------------
  4042. BOOL WINAPI
  4043. ChainFillCertObjectCtlCacheEnumFn(
  4044. IN LPVOID pvParameter,
  4045. IN PCSSCTLOBJECT pSSCtlObject
  4046. )
  4047. {
  4048. PCERT_OBJECT_CTL_CACHE_ENUM_DATA pEnumData =
  4049. (PCERT_OBJECT_CTL_CACHE_ENUM_DATA) pvParameter;
  4050. PCERT_TRUST_LIST_INFO pTrustListInfo = NULL;
  4051. PCERT_OBJECT_CTL_CACHE_ENTRY pEntry = NULL;
  4052. if (!pEnumData->fResult)
  4053. return FALSE;
  4054. if (!pSSCtlObject->GetTrustListInfo(
  4055. pEnumData->pCertObject->CertContext(),
  4056. &pTrustListInfo
  4057. )) {
  4058. DWORD dwErr = GetLastError();
  4059. if (CRYPT_E_NOT_FOUND == dwErr)
  4060. return TRUE;
  4061. else {
  4062. pEnumData->fResult = FALSE;
  4063. pEnumData->dwLastError = dwErr;
  4064. return FALSE;
  4065. }
  4066. }
  4067. pEntry = new CERT_OBJECT_CTL_CACHE_ENTRY;
  4068. if (NULL == pEntry) {
  4069. SSCtlFreeTrustListInfo(pTrustListInfo);
  4070. pEnumData->fResult = FALSE;
  4071. pEnumData->dwLastError = (DWORD) E_OUTOFMEMORY;
  4072. return FALSE;
  4073. }
  4074. pSSCtlObject->AddRef();
  4075. pEntry->pSSCtlObject = pSSCtlObject;
  4076. pEntry->pTrustListInfo = pTrustListInfo;
  4077. pEnumData->pCertObject->InsertCtlCacheEntry(pEntry);
  4078. return TRUE;
  4079. }
  4080. //+---------------------------------------------------------------------------
  4081. //
  4082. // Function: ChainFreeCertObjectCtlCache
  4083. //
  4084. // Synopsis: free the linked list of CTL cache entries.
  4085. //
  4086. //----------------------------------------------------------------------------
  4087. VOID WINAPI
  4088. ChainFreeCertObjectCtlCache(
  4089. IN PCERT_OBJECT_CTL_CACHE_ENTRY pCtlCacheHead
  4090. )
  4091. {
  4092. PCERT_OBJECT_CTL_CACHE_ENTRY pCtlCache;
  4093. while (pCtlCache = pCtlCacheHead) {
  4094. pCtlCacheHead = pCtlCacheHead->pNext;
  4095. if (pCtlCache->pTrustListInfo)
  4096. SSCtlFreeTrustListInfo(pCtlCache->pTrustListInfo);
  4097. if (pCtlCache->pSSCtlObject)
  4098. pCtlCache->pSSCtlObject->Release();
  4099. delete pCtlCache;
  4100. }
  4101. }
  4102. //+---------------------------------------------------------------------------
  4103. //
  4104. // Function: ChainAllocAndDecodeObject
  4105. //
  4106. // Synopsis: allocate and decodes the ASN.1 encoded data structure.
  4107. //
  4108. // NULL is returned for a decoding or allocation error.
  4109. // PkiFree must be called to free the allocated data structure.
  4110. //
  4111. //----------------------------------------------------------------------------
  4112. LPVOID WINAPI
  4113. ChainAllocAndDecodeObject(
  4114. IN LPCSTR lpszStructType,
  4115. IN const BYTE *pbEncoded,
  4116. IN DWORD cbEncoded
  4117. )
  4118. {
  4119. DWORD cbStructInfo;
  4120. void *pvStructInfo;
  4121. if (!CryptDecodeObjectEx(
  4122. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4123. lpszStructType,
  4124. pbEncoded,
  4125. cbEncoded,
  4126. CRYPT_DECODE_SHARE_OID_STRING_FLAG |
  4127. CRYPT_DECODE_NOCOPY_FLAG |
  4128. CRYPT_DECODE_ALLOC_FLAG,
  4129. &PkiDecodePara,
  4130. (void *) &pvStructInfo,
  4131. &cbStructInfo
  4132. ))
  4133. goto DecodeError;
  4134. CommonReturn:
  4135. return pvStructInfo;
  4136. ErrorReturn:
  4137. pvStructInfo = NULL;
  4138. goto CommonReturn;
  4139. TRACE_ERROR(DecodeError)
  4140. }
  4141. //+---------------------------------------------------------------------------
  4142. //
  4143. // Function: ChainGetIssuerMatchInfo
  4144. //
  4145. // Synopsis: return match bits specifying the types of issuer matching
  4146. // that can be done for this certificate and if available return
  4147. // the decoded authority key identifier extension
  4148. //
  4149. //----------------------------------------------------------------------------
  4150. VOID WINAPI
  4151. ChainGetIssuerMatchInfo (
  4152. IN PCCERT_CONTEXT pCertContext,
  4153. OUT DWORD *pdwIssuerMatchFlags,
  4154. OUT PCERT_AUTHORITY_KEY_ID_INFO* ppAuthKeyIdentifier
  4155. )
  4156. {
  4157. PCERT_EXTENSION pExt;
  4158. LPVOID pv = NULL;
  4159. BOOL fV1AuthKeyIdInfo = TRUE;
  4160. PCERT_AUTHORITY_KEY_ID_INFO pAuthKeyIdentifier = NULL;
  4161. DWORD dwIssuerMatchFlags = 0;
  4162. pExt = CertFindExtension(
  4163. szOID_AUTHORITY_KEY_IDENTIFIER,
  4164. pCertContext->pCertInfo->cExtension,
  4165. pCertContext->pCertInfo->rgExtension
  4166. );
  4167. if ( pExt == NULL )
  4168. {
  4169. fV1AuthKeyIdInfo = FALSE;
  4170. pExt = CertFindExtension(
  4171. szOID_AUTHORITY_KEY_IDENTIFIER2,
  4172. pCertContext->pCertInfo->cExtension,
  4173. pCertContext->pCertInfo->rgExtension
  4174. );
  4175. }
  4176. if ( pExt != NULL )
  4177. {
  4178. pv = ChainAllocAndDecodeObject(
  4179. pExt->pszObjId,
  4180. pExt->Value.pbData,
  4181. pExt->Value.cbData
  4182. );
  4183. }
  4184. if ( pv )
  4185. {
  4186. if ( fV1AuthKeyIdInfo == FALSE )
  4187. {
  4188. // NOTENOTE: Yes, this is a bit backwards but, right now but the
  4189. // V1 structure is a bit easier to deal with and we
  4190. // only support the V1 version of the V2 structure
  4191. // anyway
  4192. ChainConvertAuthKeyIdentifierFromV2ToV1(
  4193. (PCERT_AUTHORITY_KEY_ID2_INFO)pv,
  4194. &pAuthKeyIdentifier
  4195. );
  4196. }
  4197. else
  4198. {
  4199. pAuthKeyIdentifier = (PCERT_AUTHORITY_KEY_ID_INFO)pv;
  4200. pv = NULL;
  4201. }
  4202. if ( pAuthKeyIdentifier != NULL )
  4203. {
  4204. if ( ( pAuthKeyIdentifier->CertIssuer.cbData != 0 ) &&
  4205. ( pAuthKeyIdentifier->CertSerialNumber.cbData != 0 ) )
  4206. {
  4207. dwIssuerMatchFlags |= CERT_EXACT_ISSUER_MATCH_FLAG;
  4208. }
  4209. if ( pAuthKeyIdentifier->KeyId.cbData != 0 )
  4210. {
  4211. dwIssuerMatchFlags |= CERT_KEYID_ISSUER_MATCH_FLAG;
  4212. }
  4213. if (0 == dwIssuerMatchFlags) {
  4214. delete (LPBYTE) pAuthKeyIdentifier;
  4215. pAuthKeyIdentifier = NULL;
  4216. }
  4217. }
  4218. }
  4219. dwIssuerMatchFlags |= CERT_NAME_ISSUER_MATCH_FLAG;
  4220. if (pv)
  4221. PkiFree(pv);
  4222. *pdwIssuerMatchFlags = dwIssuerMatchFlags;
  4223. *ppAuthKeyIdentifier = pAuthKeyIdentifier;
  4224. }
  4225. //+---------------------------------------------------------------------------
  4226. //
  4227. // Function: ChainConvertAuthKeyIdentifierFromV2ToV1
  4228. //
  4229. // Synopsis: convert authority key identifier from V2 to V1
  4230. //
  4231. //----------------------------------------------------------------------------
  4232. BOOL WINAPI
  4233. ChainConvertAuthKeyIdentifierFromV2ToV1 (
  4234. IN PCERT_AUTHORITY_KEY_ID2_INFO pAuthKeyIdentifier2,
  4235. OUT PCERT_AUTHORITY_KEY_ID_INFO* ppAuthKeyIdentifier
  4236. )
  4237. {
  4238. DWORD cb;
  4239. PCERT_AUTHORITY_KEY_ID_INFO pAuthKeyIdentifier;
  4240. BOOL fExactMatchAvailable = FALSE;
  4241. if ( ( pAuthKeyIdentifier2->AuthorityCertIssuer.cAltEntry == 1 ) &&
  4242. ( pAuthKeyIdentifier2->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice ==
  4243. CERT_ALT_NAME_DIRECTORY_NAME ) )
  4244. {
  4245. fExactMatchAvailable = TRUE;
  4246. }
  4247. cb = sizeof( CERT_AUTHORITY_KEY_ID_INFO );
  4248. cb += pAuthKeyIdentifier2->KeyId.cbData;
  4249. if ( fExactMatchAvailable == TRUE )
  4250. {
  4251. cb += pAuthKeyIdentifier2->AuthorityCertIssuer.rgAltEntry[0].DirectoryName.cbData;
  4252. cb += pAuthKeyIdentifier2->AuthorityCertSerialNumber.cbData;
  4253. }
  4254. pAuthKeyIdentifier = (PCERT_AUTHORITY_KEY_ID_INFO)PkiZeroAlloc(cb);
  4255. if ( pAuthKeyIdentifier == NULL )
  4256. {
  4257. return( FALSE );
  4258. }
  4259. pAuthKeyIdentifier->KeyId.cbData = pAuthKeyIdentifier2->KeyId.cbData;
  4260. pAuthKeyIdentifier->KeyId.pbData = (LPBYTE)pAuthKeyIdentifier + sizeof( CERT_AUTHORITY_KEY_ID_INFO );
  4261. memcpy(
  4262. pAuthKeyIdentifier->KeyId.pbData,
  4263. pAuthKeyIdentifier2->KeyId.pbData,
  4264. pAuthKeyIdentifier->KeyId.cbData
  4265. );
  4266. if ( fExactMatchAvailable == TRUE )
  4267. {
  4268. pAuthKeyIdentifier->CertIssuer.cbData = pAuthKeyIdentifier2->AuthorityCertIssuer.rgAltEntry[0].DirectoryName.cbData;
  4269. pAuthKeyIdentifier->CertIssuer.pbData = pAuthKeyIdentifier->KeyId.pbData + pAuthKeyIdentifier->KeyId.cbData;
  4270. memcpy(
  4271. pAuthKeyIdentifier->CertIssuer.pbData,
  4272. pAuthKeyIdentifier2->AuthorityCertIssuer.rgAltEntry[0].DirectoryName.pbData,
  4273. pAuthKeyIdentifier->CertIssuer.cbData
  4274. );
  4275. pAuthKeyIdentifier->CertSerialNumber.cbData = pAuthKeyIdentifier2->AuthorityCertSerialNumber.cbData;
  4276. pAuthKeyIdentifier->CertSerialNumber.pbData = pAuthKeyIdentifier->CertIssuer.pbData + pAuthKeyIdentifier->CertIssuer.cbData;
  4277. memcpy(
  4278. pAuthKeyIdentifier->CertSerialNumber.pbData,
  4279. pAuthKeyIdentifier2->AuthorityCertSerialNumber.pbData,
  4280. pAuthKeyIdentifier->CertSerialNumber.cbData
  4281. );
  4282. }
  4283. *ppAuthKeyIdentifier = pAuthKeyIdentifier;
  4284. return( TRUE );
  4285. }
  4286. //+---------------------------------------------------------------------------
  4287. //
  4288. // Function: ChainFreeAuthorityKeyIdentifier
  4289. //
  4290. // Synopsis: free the authority key identifier
  4291. //
  4292. //----------------------------------------------------------------------------
  4293. VOID WINAPI
  4294. ChainFreeAuthorityKeyIdentifier (
  4295. IN PCERT_AUTHORITY_KEY_ID_INFO pAuthKeyIdInfo
  4296. )
  4297. {
  4298. PkiFree(pAuthKeyIdInfo);
  4299. }
  4300. //+---------------------------------------------------------------------------
  4301. //
  4302. // Function: ChainProcessSpecialOrDuplicateOIDsInUsage
  4303. //
  4304. // Synopsis: process and removes special or duplicate OIDs from the usage
  4305. //
  4306. // For szOID_ANY_CERT_POLICY, frees the usage
  4307. //
  4308. //----------------------------------------------------------------------------
  4309. VOID WINAPI
  4310. ChainProcessSpecialOrDuplicateOIDsInUsage (
  4311. IN OUT PCERT_ENHKEY_USAGE *ppUsage,
  4312. IN OUT DWORD *pdwFlags
  4313. )
  4314. {
  4315. PCERT_ENHKEY_USAGE pUsage = *ppUsage;
  4316. DWORD dwFlags = *pdwFlags;
  4317. LPSTR *ppszOID;
  4318. DWORD cOID;
  4319. DWORD i;
  4320. cOID = pUsage->cUsageIdentifier;
  4321. ppszOID = pUsage->rgpszUsageIdentifier;
  4322. i = 0;
  4323. while (i < cOID) {
  4324. BOOL fSpecialOrDuplicate = TRUE;
  4325. LPSTR pszOID = ppszOID[i];
  4326. if (0 == strcmp(pszOID, szOID_ANY_CERT_POLICY))
  4327. dwFlags |= CHAIN_ANY_POLICY_FLAG;
  4328. else {
  4329. // Check for duplicate OID
  4330. DWORD j;
  4331. fSpecialOrDuplicate = FALSE;
  4332. for (j = 0; j < i; j++) {
  4333. if (0 == strcmp(ppszOID[j], ppszOID[i])) {
  4334. fSpecialOrDuplicate = TRUE;
  4335. break;
  4336. }
  4337. }
  4338. }
  4339. if (fSpecialOrDuplicate) {
  4340. // Remove the special or duplicate OID string and move the remaining
  4341. // strings up one.
  4342. DWORD j;
  4343. for (j = i; j + 1 < cOID; j++)
  4344. ppszOID[j] = ppszOID[j + 1];
  4345. cOID--;
  4346. pUsage->cUsageIdentifier = cOID;
  4347. } else
  4348. i++;
  4349. }
  4350. if (dwFlags & CHAIN_ANY_POLICY_FLAG) {
  4351. PkiFree(pUsage);
  4352. *ppUsage = NULL;
  4353. }
  4354. *pdwFlags = dwFlags;
  4355. }
  4356. //+---------------------------------------------------------------------------
  4357. //
  4358. // Function: ChainConvertPoliciesToUsage
  4359. //
  4360. // Synopsis: extract the usage OIDs from the cert policies
  4361. //
  4362. //----------------------------------------------------------------------------
  4363. VOID WINAPI
  4364. ChainConvertPoliciesToUsage (
  4365. IN PCERT_POLICIES_INFO pPolicy,
  4366. IN OUT DWORD *pdwFlags,
  4367. OUT PCERT_ENHKEY_USAGE *ppUsage
  4368. )
  4369. {
  4370. PCERT_ENHKEY_USAGE pUsage;
  4371. LPSTR *ppszOID;
  4372. DWORD cOID;
  4373. DWORD i;
  4374. cOID = pPolicy->cPolicyInfo;
  4375. pUsage = (PCERT_ENHKEY_USAGE) PkiNonzeroAlloc(
  4376. sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR) * cOID);
  4377. if (NULL == pUsage) {
  4378. *pdwFlags |= CHAIN_INVALID_POLICY_FLAG;
  4379. *ppUsage = NULL;
  4380. return;
  4381. }
  4382. ppszOID = (LPSTR *) &pUsage[1];
  4383. pUsage->cUsageIdentifier = cOID;
  4384. pUsage->rgpszUsageIdentifier = ppszOID;
  4385. for (i = 0; i < cOID; i++)
  4386. ppszOID[i] = pPolicy->rgPolicyInfo[i].pszPolicyIdentifier;
  4387. *ppUsage = pUsage;
  4388. ChainProcessSpecialOrDuplicateOIDsInUsage(ppUsage, pdwFlags);
  4389. }
  4390. //+---------------------------------------------------------------------------
  4391. //
  4392. // Function: ChainRemoveDuplicatePolicyMappings
  4393. //
  4394. // Synopsis: remove any duplicate mappings
  4395. //
  4396. //----------------------------------------------------------------------------
  4397. VOID WINAPI
  4398. ChainRemoveDuplicatePolicyMappings (
  4399. IN OUT PCERT_POLICY_MAPPINGS_INFO pInfo
  4400. )
  4401. {
  4402. DWORD cMap = pInfo->cPolicyMapping;
  4403. PCERT_POLICY_MAPPING pMap = pInfo->rgPolicyMapping;
  4404. DWORD i;
  4405. i = 0;
  4406. while (i < cMap) {
  4407. DWORD j;
  4408. for (j = 0; j < i; j++) {
  4409. if (0 == strcmp(pMap[i].pszSubjectDomainPolicy,
  4410. pMap[j].pszSubjectDomainPolicy))
  4411. break;
  4412. }
  4413. if (j < i) {
  4414. // Duplicate
  4415. //
  4416. // Remove the duplicate mapping and move the remaining
  4417. // mappings up one.
  4418. for (j = i; j + 1 < cMap; j++)
  4419. pMap[j] = pMap[j + 1];
  4420. cMap--;
  4421. pInfo->cPolicyMapping = cMap;
  4422. } else
  4423. i++;
  4424. }
  4425. }
  4426. //+---------------------------------------------------------------------------
  4427. //
  4428. // Function: ChainGetPoliciesInfo
  4429. //
  4430. // Synopsis: allocate and return the policies and usage info
  4431. //
  4432. //----------------------------------------------------------------------------
  4433. VOID WINAPI
  4434. ChainGetPoliciesInfo (
  4435. IN PCCERT_CONTEXT pCertContext,
  4436. IN OUT PCHAIN_POLICIES_INFO pPoliciesInfo
  4437. )
  4438. {
  4439. DWORD cExt = pCertContext->pCertInfo->cExtension;
  4440. PCERT_EXTENSION rgExt = pCertContext->pCertInfo->rgExtension;
  4441. DWORD i;
  4442. DWORD cbData;
  4443. for (i = 0; i < CHAIN_ISS_OR_APP_COUNT; i++ ) {
  4444. PCHAIN_ISS_OR_APP_INFO pInfo = &pPoliciesInfo->rgIssOrAppInfo[i];
  4445. PCERT_EXTENSION pExt;
  4446. pExt = CertFindExtension(
  4447. CHAIN_ISS_INDEX == i ?
  4448. szOID_CERT_POLICIES : szOID_APPLICATION_CERT_POLICIES,
  4449. cExt, rgExt);
  4450. if (pExt) {
  4451. pInfo->pPolicy =
  4452. (PCERT_POLICIES_INFO) ChainAllocAndDecodeObject(
  4453. X509_CERT_POLICIES,
  4454. pExt->Value.pbData,
  4455. pExt->Value.cbData
  4456. );
  4457. if (NULL == pInfo->pPolicy)
  4458. pInfo->dwFlags |= CHAIN_INVALID_POLICY_FLAG;
  4459. else
  4460. ChainConvertPoliciesToUsage(pInfo->pPolicy,
  4461. &pInfo->dwFlags, &pInfo->pUsage);
  4462. } else if (CHAIN_APP_INDEX == i) {
  4463. pExt = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
  4464. cExt, rgExt);
  4465. if (pExt) {
  4466. pInfo->pUsage =
  4467. (PCERT_ENHKEY_USAGE) ChainAllocAndDecodeObject(
  4468. X509_ENHANCED_KEY_USAGE,
  4469. pExt->Value.pbData,
  4470. pExt->Value.cbData
  4471. );
  4472. if (NULL == pInfo->pUsage)
  4473. pInfo->dwFlags |= CHAIN_INVALID_POLICY_FLAG;
  4474. else
  4475. ChainProcessSpecialOrDuplicateOIDsInUsage(
  4476. &pInfo->pUsage, &pInfo->dwFlags);
  4477. }
  4478. }
  4479. pExt = CertFindExtension(
  4480. CHAIN_ISS_INDEX == i ?
  4481. szOID_POLICY_MAPPINGS : szOID_APPLICATION_POLICY_MAPPINGS,
  4482. cExt, rgExt);
  4483. if (pExt) {
  4484. pInfo->pMappings =
  4485. (PCERT_POLICY_MAPPINGS_INFO) ChainAllocAndDecodeObject(
  4486. X509_POLICY_MAPPINGS,
  4487. pExt->Value.pbData,
  4488. pExt->Value.cbData
  4489. );
  4490. if (NULL == pInfo->pMappings)
  4491. pInfo->dwFlags |= CHAIN_INVALID_POLICY_FLAG;
  4492. else
  4493. ChainRemoveDuplicatePolicyMappings(pInfo->pMappings);
  4494. }
  4495. pExt = CertFindExtension(
  4496. CHAIN_ISS_INDEX == i ?
  4497. szOID_POLICY_CONSTRAINTS : szOID_APPLICATION_POLICY_CONSTRAINTS,
  4498. cExt, rgExt);
  4499. if (pExt) {
  4500. pInfo->pConstraints =
  4501. (PCERT_POLICY_CONSTRAINTS_INFO) ChainAllocAndDecodeObject(
  4502. X509_POLICY_CONSTRAINTS,
  4503. pExt->Value.pbData,
  4504. pExt->Value.cbData
  4505. );
  4506. if (NULL == pInfo->pConstraints)
  4507. pInfo->dwFlags |= CHAIN_INVALID_POLICY_FLAG;
  4508. }
  4509. }
  4510. cbData = 0;
  4511. if (CertGetCertificateContextProperty(
  4512. pCertContext,
  4513. CERT_ENHKEY_USAGE_PROP_ID,
  4514. NULL, // pbData
  4515. &cbData
  4516. ) && 0 != cbData) {
  4517. BYTE *pbData;
  4518. pbData = (BYTE *) PkiNonzeroAlloc(cbData);
  4519. if (pbData) {
  4520. if (CertGetCertificateContextProperty(
  4521. pCertContext,
  4522. CERT_ENHKEY_USAGE_PROP_ID,
  4523. pbData,
  4524. &cbData
  4525. ))
  4526. pPoliciesInfo->pPropertyUsage =
  4527. (PCERT_ENHKEY_USAGE) ChainAllocAndDecodeObject(
  4528. X509_ENHANCED_KEY_USAGE,
  4529. pbData,
  4530. cbData
  4531. );
  4532. PkiFree(pbData);
  4533. }
  4534. if (NULL == pPoliciesInfo->pPropertyUsage)
  4535. pPoliciesInfo->rgIssOrAppInfo[CHAIN_APP_INDEX].dwFlags |=
  4536. CHAIN_INVALID_POLICY_FLAG;
  4537. }
  4538. }
  4539. //+---------------------------------------------------------------------------
  4540. //
  4541. // Function: ChainFreePoliciesInfo
  4542. //
  4543. // Synopsis: free the policies and usage info
  4544. //
  4545. //----------------------------------------------------------------------------
  4546. VOID WINAPI
  4547. ChainFreePoliciesInfo (
  4548. IN OUT PCHAIN_POLICIES_INFO pPoliciesInfo
  4549. )
  4550. {
  4551. DWORD i;
  4552. for (i = 0; i < CHAIN_ISS_OR_APP_COUNT; i++ ) {
  4553. PCHAIN_ISS_OR_APP_INFO pInfo = &pPoliciesInfo->rgIssOrAppInfo[i];
  4554. PkiFree(pInfo->pPolicy);
  4555. PkiFree(pInfo->pUsage);
  4556. PkiFree(pInfo->pMappings);
  4557. PkiFree(pInfo->pConstraints);
  4558. }
  4559. PkiFree(pPoliciesInfo->pPropertyUsage);
  4560. }
  4561. //+---------------------------------------------------------------------------
  4562. //
  4563. // Function: ChainGetBasicConstraintsInfo
  4564. //
  4565. // Synopsis: alloc and return the basic constraints info.
  4566. //
  4567. //----------------------------------------------------------------------------
  4568. BOOL WINAPI
  4569. ChainGetBasicConstraintsInfo (
  4570. IN PCCERT_CONTEXT pCertContext,
  4571. IN OUT PCERT_BASIC_CONSTRAINTS2_INFO *ppInfo
  4572. )
  4573. {
  4574. BOOL fResult;
  4575. PCERT_EXTENSION pExt;
  4576. PCERT_BASIC_CONSTRAINTS2_INFO pInfo = NULL;
  4577. PCERT_BASIC_CONSTRAINTS_INFO pLegacyInfo = NULL;
  4578. pExt = CertFindExtension(
  4579. szOID_BASIC_CONSTRAINTS2,
  4580. pCertContext->pCertInfo->cExtension,
  4581. pCertContext->pCertInfo->rgExtension
  4582. );
  4583. if (pExt) {
  4584. pInfo = (PCERT_BASIC_CONSTRAINTS2_INFO) ChainAllocAndDecodeObject(
  4585. X509_BASIC_CONSTRAINTS2,
  4586. pExt->Value.pbData,
  4587. pExt->Value.cbData
  4588. );
  4589. if (NULL == pInfo)
  4590. goto DecodeError;
  4591. } else {
  4592. // Try to find the legacy extension
  4593. pExt = CertFindExtension(
  4594. szOID_BASIC_CONSTRAINTS,
  4595. pCertContext->pCertInfo->cExtension,
  4596. pCertContext->pCertInfo->rgExtension
  4597. );
  4598. if (pExt) {
  4599. pLegacyInfo =
  4600. (PCERT_BASIC_CONSTRAINTS_INFO) ChainAllocAndDecodeObject(
  4601. X509_BASIC_CONSTRAINTS,
  4602. pExt->Value.pbData,
  4603. pExt->Value.cbData
  4604. );
  4605. if (NULL == pLegacyInfo)
  4606. goto DecodeError;
  4607. // Convert to new format
  4608. pInfo = (PCERT_BASIC_CONSTRAINTS2_INFO) PkiZeroAlloc(
  4609. sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
  4610. if (NULL == pInfo)
  4611. goto OutOfMemory;
  4612. if (pLegacyInfo->SubjectType.cbData > 0 &&
  4613. (pLegacyInfo->SubjectType.pbData[0] &
  4614. CERT_CA_SUBJECT_FLAG)) {
  4615. pInfo->fCA = TRUE;
  4616. pInfo->fPathLenConstraint = pLegacyInfo->fPathLenConstraint;
  4617. pInfo->dwPathLenConstraint = pLegacyInfo->dwPathLenConstraint;
  4618. }
  4619. }
  4620. }
  4621. fResult = TRUE;
  4622. CommonReturn:
  4623. if (pLegacyInfo)
  4624. PkiFree(pLegacyInfo);
  4625. *ppInfo = pInfo;
  4626. return fResult;
  4627. ErrorReturn:
  4628. fResult = FALSE;
  4629. goto CommonReturn;
  4630. TRACE_ERROR(DecodeError)
  4631. TRACE_ERROR(OutOfMemory)
  4632. }
  4633. //+---------------------------------------------------------------------------
  4634. //
  4635. // Function: ChainFreeBasicConstraintsInfo
  4636. //
  4637. // Synopsis: free the basic constraints info
  4638. //
  4639. //----------------------------------------------------------------------------
  4640. VOID WINAPI
  4641. ChainFreeBasicConstraintsInfo (
  4642. IN OUT PCERT_BASIC_CONSTRAINTS2_INFO pInfo
  4643. )
  4644. {
  4645. PkiFree(pInfo);
  4646. }
  4647. //+---------------------------------------------------------------------------
  4648. //
  4649. // Function: ChainGetKeyUsage
  4650. //
  4651. // Synopsis: alloc and return the key usage.
  4652. //
  4653. //----------------------------------------------------------------------------
  4654. BOOL WINAPI
  4655. ChainGetKeyUsage (
  4656. IN PCCERT_CONTEXT pCertContext,
  4657. IN OUT PCRYPT_BIT_BLOB *ppKeyUsage
  4658. )
  4659. {
  4660. BOOL fResult;
  4661. PCERT_EXTENSION pExt;
  4662. PCRYPT_BIT_BLOB pKeyUsage = NULL;
  4663. pExt = CertFindExtension(
  4664. szOID_KEY_USAGE,
  4665. pCertContext->pCertInfo->cExtension,
  4666. pCertContext->pCertInfo->rgExtension
  4667. );
  4668. if (pExt) {
  4669. pKeyUsage = (PCRYPT_BIT_BLOB) ChainAllocAndDecodeObject(
  4670. X509_KEY_USAGE,
  4671. pExt->Value.pbData,
  4672. pExt->Value.cbData
  4673. );
  4674. if (NULL == pKeyUsage)
  4675. goto DecodeError;
  4676. }
  4677. fResult = TRUE;
  4678. CommonReturn:
  4679. *ppKeyUsage = pKeyUsage;
  4680. return fResult;
  4681. ErrorReturn:
  4682. fResult = FALSE;
  4683. goto CommonReturn;
  4684. TRACE_ERROR(DecodeError)
  4685. }
  4686. //+---------------------------------------------------------------------------
  4687. //
  4688. // Function: ChainFreeKeyUsage
  4689. //
  4690. // Synopsis: free the key usage
  4691. //
  4692. //----------------------------------------------------------------------------
  4693. VOID WINAPI
  4694. ChainFreeKeyUsage (
  4695. IN OUT PCRYPT_BIT_BLOB pKeyUsage
  4696. )
  4697. {
  4698. PkiFree(pKeyUsage);
  4699. }
  4700. //+---------------------------------------------------------------------------
  4701. //
  4702. // Function: ChainGetSelfSignedStatus
  4703. //
  4704. // Synopsis: return status bits specifying if the certificate is self signed
  4705. // and if so, if it is signature valid
  4706. //
  4707. //----------------------------------------------------------------------------
  4708. VOID WINAPI
  4709. ChainGetSelfSignedStatus (
  4710. IN PCCHAINCALLCONTEXT pCallContext,
  4711. IN PCCERTOBJECT pCertObject,
  4712. IN OUT DWORD *pdwIssuerStatusFlags
  4713. )
  4714. {
  4715. DWORD dwInfoStatus = 0;
  4716. // If the certificate has an AKI, then, ignore name matching
  4717. if (ChainGetMatchInfoStatus(pCertObject, pCertObject, &dwInfoStatus) &&
  4718. (CERT_TRUST_HAS_NAME_MATCH_ISSUER != dwInfoStatus)) {
  4719. *pdwIssuerStatusFlags |= CERT_ISSUER_SELF_SIGNED_FLAG;
  4720. if (CryptVerifyCertificateSignatureEx(
  4721. NULL, // hCryptProv
  4722. X509_ASN_ENCODING,
  4723. CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
  4724. (void *) pCertObject->CertContext(),
  4725. CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
  4726. (void *) pCertObject->CertContext(),
  4727. 0, // dwFlags
  4728. NULL // pvReserved
  4729. ))
  4730. *pdwIssuerStatusFlags |= CERT_ISSUER_VALID_SIGNATURE_FLAG;
  4731. CertPerfIncrementChainVerifyCertSignatureCount();
  4732. }
  4733. }
  4734. //+---------------------------------------------------------------------------
  4735. //
  4736. // Function: ChainGetRootStoreStatus
  4737. //
  4738. // Synopsis: determine if the certificate with the given hash is in the
  4739. // root store
  4740. //
  4741. // Assumption: Chain engine is locked once in the calling thread.
  4742. //----------------------------------------------------------------------------
  4743. VOID WINAPI
  4744. ChainGetRootStoreStatus (
  4745. IN HCERTSTORE hRoot,
  4746. IN HCERTSTORE hRealRoot,
  4747. IN BYTE rgbCertHash[ CHAINHASHLEN ],
  4748. IN OUT DWORD *pdwIssuerStatusFlags
  4749. )
  4750. {
  4751. CRYPT_HASH_BLOB HashBlob;
  4752. PCCERT_CONTEXT pCertContext;
  4753. HashBlob.cbData = CHAINHASHLEN;
  4754. HashBlob.pbData = rgbCertHash;
  4755. pCertContext = CertFindCertificateInStore(
  4756. hRoot,
  4757. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4758. 0,
  4759. CERT_FIND_MD5_HASH,
  4760. (LPVOID) &HashBlob,
  4761. NULL
  4762. );
  4763. if ( pCertContext )
  4764. {
  4765. CertFreeCertificateContext( pCertContext );
  4766. if ( hRoot == hRealRoot )
  4767. {
  4768. *pdwIssuerStatusFlags |= CERT_ISSUER_TRUSTED_ROOT_FLAG;
  4769. return;
  4770. }
  4771. pCertContext = CertFindCertificateInStore(
  4772. hRealRoot,
  4773. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  4774. 0,
  4775. CERT_FIND_MD5_HASH,
  4776. (LPVOID) &HashBlob,
  4777. NULL
  4778. );
  4779. if ( pCertContext )
  4780. {
  4781. CertFreeCertificateContext( pCertContext );
  4782. *pdwIssuerStatusFlags |= CERT_ISSUER_TRUSTED_ROOT_FLAG;
  4783. }
  4784. }
  4785. }
  4786. //+===========================================================================
  4787. // CCertObjectCache helper functions
  4788. //============================================================================
  4789. //+---------------------------------------------------------------------------
  4790. //
  4791. // Function: ChainCreateCertificateObjectCache
  4792. //
  4793. // Synopsis: create certificate object cache object
  4794. //
  4795. //----------------------------------------------------------------------------
  4796. BOOL WINAPI
  4797. ChainCreateCertificateObjectCache (
  4798. IN DWORD MaxIndexEntries,
  4799. OUT PCCERTOBJECTCACHE* ppCertObjectCache
  4800. )
  4801. {
  4802. BOOL fResult = FALSE;
  4803. PCCERTOBJECTCACHE pCertObjectCache = NULL;
  4804. pCertObjectCache = new CCertObjectCache( MaxIndexEntries, fResult );
  4805. if ( pCertObjectCache != NULL )
  4806. {
  4807. if ( fResult == TRUE )
  4808. {
  4809. *ppCertObjectCache = pCertObjectCache;
  4810. }
  4811. else
  4812. {
  4813. delete pCertObjectCache;
  4814. }
  4815. }
  4816. else
  4817. {
  4818. SetLastError( (DWORD) E_OUTOFMEMORY );
  4819. }
  4820. return( fResult );
  4821. }
  4822. //+---------------------------------------------------------------------------
  4823. //
  4824. // Function: ChainFreeCertificateObjectCache
  4825. //
  4826. // Synopsis: free the certificate object cache object
  4827. //
  4828. //----------------------------------------------------------------------------
  4829. VOID WINAPI
  4830. ChainFreeCertificateObjectCache (
  4831. IN PCCERTOBJECTCACHE pCertObjectCache
  4832. )
  4833. {
  4834. delete pCertObjectCache;
  4835. }
  4836. //+---------------------------------------------------------------------------
  4837. //
  4838. // Function: CertObjectCacheOnRemovalFromPrimaryIndex
  4839. //
  4840. // Synopsis: removes the cert object from all other indexes and also
  4841. // removes the reference on the cert object.
  4842. //
  4843. //----------------------------------------------------------------------------
  4844. VOID WINAPI
  4845. CertObjectCacheOnRemovalFromPrimaryIndex (
  4846. IN LPVOID pv,
  4847. IN OPTIONAL LPVOID pvRemovalContext
  4848. )
  4849. {
  4850. PCCERTOBJECT pCertObject = (PCCERTOBJECT) pv;
  4851. I_CryptRemoveLruEntry(
  4852. pCertObject->IdentifierIndexEntry(),
  4853. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  4854. NULL
  4855. );
  4856. I_CryptRemoveLruEntry(
  4857. pCertObject->SubjectNameIndexEntry(),
  4858. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  4859. NULL
  4860. );
  4861. I_CryptRemoveLruEntry(
  4862. pCertObject->KeyIdIndexEntry(),
  4863. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  4864. NULL
  4865. );
  4866. I_CryptRemoveLruEntry(
  4867. pCertObject->PublicKeyHashIndexEntry(),
  4868. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  4869. NULL
  4870. );
  4871. pCertObject->Release();
  4872. CertPerfDecrementChainCertCacheCount();
  4873. }
  4874. //+---------------------------------------------------------------------------
  4875. //
  4876. // Function: CertObjectCacheOnRemovalFromEndHashIndex
  4877. //
  4878. // Synopsis: removes the reference on the end cert object.
  4879. //
  4880. //----------------------------------------------------------------------------
  4881. VOID WINAPI
  4882. CertObjectCacheOnRemovalFromEndHashIndex (
  4883. IN LPVOID pv,
  4884. IN LPVOID pvRemovalContext
  4885. )
  4886. {
  4887. PCCERTOBJECT pCertObject = (PCCERTOBJECT) pv;
  4888. pCertObject->Release();
  4889. CertPerfDecrementChainCertCacheCount();
  4890. }
  4891. //+---------------------------------------------------------------------------
  4892. //
  4893. // Function: CertObjectCacheHashMd5Identifier
  4894. //
  4895. // Synopsis: DWORD hash an MD5 identifier. This is done by taking the
  4896. // first four bytes of the MD5 hash since there is enough
  4897. // randomness already
  4898. //
  4899. //----------------------------------------------------------------------------
  4900. DWORD WINAPI
  4901. CertObjectCacheHashMd5Identifier (
  4902. IN PCRYPT_DATA_BLOB pIdentifier
  4903. )
  4904. {
  4905. if ( sizeof(DWORD) > pIdentifier->cbData )
  4906. {
  4907. return 0;
  4908. }
  4909. else
  4910. {
  4911. return( *( (DWORD UNALIGNED *)pIdentifier->pbData ) );
  4912. }
  4913. }
  4914. //+---------------------------------------------------------------------------
  4915. //
  4916. // Function: CertObjectCacheHashNameIdentifier
  4917. //
  4918. // Synopsis: DWORD hash a subject or issuer name.
  4919. //
  4920. //----------------------------------------------------------------------------
  4921. DWORD WINAPI
  4922. CertObjectCacheHashNameIdentifier (
  4923. IN PCRYPT_DATA_BLOB pIdentifier
  4924. )
  4925. {
  4926. DWORD dwHash = 0;
  4927. DWORD cb = pIdentifier->cbData;
  4928. LPBYTE pb = pIdentifier->pbData;
  4929. while ( cb-- )
  4930. {
  4931. if ( dwHash & 0x80000000 )
  4932. {
  4933. dwHash = ( dwHash << 1 ) | 1;
  4934. }
  4935. else
  4936. {
  4937. dwHash = dwHash << 1;
  4938. }
  4939. dwHash += *pb++;
  4940. }
  4941. return( dwHash );
  4942. }
  4943. //+---------------------------------------------------------------------------
  4944. //
  4945. // Function: ChainCreateCertificateObjectIdentifier
  4946. //
  4947. // Synopsis: create an object identifier given the issuer name and serial
  4948. // number. This is done using an MD5 hash over the content
  4949. //
  4950. //----------------------------------------------------------------------------
  4951. VOID WINAPI
  4952. ChainCreateCertificateObjectIdentifier (
  4953. IN PCERT_NAME_BLOB pIssuer,
  4954. IN PCRYPT_INTEGER_BLOB pSerialNumber,
  4955. OUT CERT_OBJECT_IDENTIFIER ObjectIdentifier
  4956. )
  4957. {
  4958. MD5_CTX md5ctx;
  4959. MD5Init( &md5ctx );
  4960. MD5Update( &md5ctx, pIssuer->pbData, pIssuer->cbData );
  4961. MD5Update( &md5ctx, pSerialNumber->pbData, pSerialNumber->cbData );
  4962. MD5Final( &md5ctx );
  4963. assert(CHAINHASHLEN == MD5DIGESTLEN);
  4964. memcpy( ObjectIdentifier, md5ctx.digest, CHAINHASHLEN );
  4965. }
  4966. //+===========================================================================
  4967. // CChainPathObject helper functions
  4968. //============================================================================
  4969. //+---------------------------------------------------------------------------
  4970. //
  4971. // Function: ChainCreatePathObject
  4972. //
  4973. // Synopsis: create a path object, note since it is a ref-counted
  4974. // object, freeing occurs by doing a pCertObject->Release
  4975. //
  4976. //----------------------------------------------------------------------------
  4977. BOOL WINAPI
  4978. ChainCreatePathObject (
  4979. IN PCCHAINCALLCONTEXT pCallContext,
  4980. IN PCCERTOBJECT pCertObject,
  4981. IN OPTIONAL HCERTSTORE hAdditionalStore,
  4982. OUT PCCHAINPATHOBJECT *ppPathObject
  4983. )
  4984. {
  4985. BOOL fResult = TRUE;
  4986. BOOL fAddedToCreationCache = TRUE;
  4987. PCCHAINPATHOBJECT pPathObject = NULL;
  4988. pPathObject = pCallContext->FindPathObjectInCreationCache(
  4989. pCertObject->CertHash() );
  4990. if ( pPathObject != NULL )
  4991. {
  4992. *ppPathObject = pPathObject;
  4993. return( TRUE );
  4994. }
  4995. pPathObject = new CChainPathObject(
  4996. pCallContext,
  4997. FALSE, // fCyclic
  4998. (LPVOID) pCertObject,
  4999. hAdditionalStore,
  5000. fResult,
  5001. fAddedToCreationCache
  5002. );
  5003. if ( pPathObject != NULL )
  5004. {
  5005. if (!fResult) {
  5006. if (!fAddedToCreationCache)
  5007. {
  5008. delete pPathObject;
  5009. }
  5010. pPathObject = NULL;
  5011. }
  5012. }
  5013. else
  5014. {
  5015. fResult = FALSE;
  5016. }
  5017. *ppPathObject = pPathObject;
  5018. return( fResult );
  5019. }
  5020. //+---------------------------------------------------------------------------
  5021. //
  5022. // Function: ChainCreateCyclicPathObject
  5023. //
  5024. // Synopsis: create a path object, note since it is a ref-counted
  5025. // object, freeing occurs by doing a pCertObject->Release
  5026. //
  5027. //----------------------------------------------------------------------------
  5028. BOOL WINAPI
  5029. ChainCreateCyclicPathObject (
  5030. IN PCCHAINCALLCONTEXT pCallContext,
  5031. IN PCCHAINPATHOBJECT pPathObject,
  5032. OUT PCCHAINPATHOBJECT *ppCyclicPathObject
  5033. )
  5034. {
  5035. BOOL fResult = TRUE;
  5036. BOOL fAddedToCreationCache = TRUE;
  5037. PCCHAINPATHOBJECT pCyclicPathObject = NULL;
  5038. pCyclicPathObject = new CChainPathObject(
  5039. pCallContext,
  5040. TRUE, // fCyclic
  5041. (LPVOID) pPathObject,
  5042. NULL, // hAdditionalStore
  5043. fResult,
  5044. fAddedToCreationCache
  5045. );
  5046. if ( pCyclicPathObject != NULL )
  5047. {
  5048. if (!fResult) {
  5049. if (!fAddedToCreationCache) {
  5050. delete pCyclicPathObject;
  5051. }
  5052. pCyclicPathObject = NULL;
  5053. }
  5054. }
  5055. else
  5056. {
  5057. fResult = FALSE;
  5058. }
  5059. *ppCyclicPathObject = pCyclicPathObject;
  5060. return( fResult );
  5061. }
  5062. //+---------------------------------------------------------------------------
  5063. //
  5064. // Function: ChainAllocAndCopyOID
  5065. //
  5066. // Synopsis: allocate and copy OID
  5067. //
  5068. //----------------------------------------------------------------------------
  5069. LPSTR WINAPI
  5070. ChainAllocAndCopyOID (
  5071. IN LPSTR pszSrcOID
  5072. )
  5073. {
  5074. DWORD cchOID;
  5075. LPSTR pszDstOID;
  5076. cchOID = strlen(pszSrcOID) + 1;
  5077. pszDstOID = (LPSTR) PkiNonzeroAlloc(cchOID);
  5078. if (NULL == pszDstOID)
  5079. return NULL;
  5080. memcpy(pszDstOID, pszSrcOID, cchOID);
  5081. return pszDstOID;
  5082. }
  5083. //+---------------------------------------------------------------------------
  5084. //
  5085. // Function: ChainFreeOID
  5086. //
  5087. // Synopsis: free allocated OID
  5088. //
  5089. //----------------------------------------------------------------------------
  5090. VOID WINAPI
  5091. ChainFreeOID (
  5092. IN OUT LPSTR pszOID
  5093. )
  5094. {
  5095. PkiFree(pszOID);
  5096. }
  5097. //+---------------------------------------------------------------------------
  5098. //
  5099. // Function: ChainAllocAndCopyUsage
  5100. //
  5101. // Synopsis: allocates and copies usage OIDs.
  5102. //
  5103. //----------------------------------------------------------------------------
  5104. BOOL WINAPI
  5105. ChainAllocAndCopyUsage (
  5106. IN PCERT_ENHKEY_USAGE pSrcUsage,
  5107. OUT PCERT_ENHKEY_USAGE *ppDstUsage
  5108. )
  5109. {
  5110. BOOL fResult;
  5111. PCERT_ENHKEY_USAGE pDstUsage = NULL;
  5112. DWORD cOID;
  5113. LPSTR *ppszDstOID;
  5114. DWORD i;
  5115. if (NULL == pSrcUsage)
  5116. goto SuccessReturn;
  5117. cOID = pSrcUsage->cUsageIdentifier;
  5118. pDstUsage = (PCERT_ENHKEY_USAGE) PkiZeroAlloc(
  5119. sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR) * cOID);
  5120. if (NULL == pDstUsage)
  5121. goto OutOfMemory;
  5122. ppszDstOID = (LPSTR *) &pDstUsage[1];
  5123. pDstUsage->cUsageIdentifier = cOID;
  5124. pDstUsage->rgpszUsageIdentifier = ppszDstOID;
  5125. for (i = 0; i < cOID; i++) {
  5126. ppszDstOID[i] =
  5127. ChainAllocAndCopyOID(pSrcUsage->rgpszUsageIdentifier[i]);
  5128. if (NULL == ppszDstOID[i])
  5129. goto OutOfMemory;
  5130. }
  5131. SuccessReturn:
  5132. fResult = TRUE;
  5133. CommonReturn:
  5134. *ppDstUsage = pDstUsage;
  5135. return fResult;
  5136. ErrorReturn:
  5137. if (pDstUsage) {
  5138. ChainFreeUsage(pDstUsage);
  5139. pDstUsage = NULL;
  5140. }
  5141. fResult = FALSE;
  5142. goto CommonReturn;
  5143. SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
  5144. }
  5145. //+---------------------------------------------------------------------------
  5146. //
  5147. // Function: ChainFreeUsage
  5148. //
  5149. // Synopsis: frees usage OIDs allocated by ChainAllocAndCopyUsage
  5150. //
  5151. //----------------------------------------------------------------------------
  5152. VOID WINAPI
  5153. ChainFreeUsage (
  5154. IN OUT PCERT_ENHKEY_USAGE pUsage
  5155. )
  5156. {
  5157. if (pUsage) {
  5158. DWORD cOID = pUsage->cUsageIdentifier;
  5159. LPSTR *ppszOID = pUsage->rgpszUsageIdentifier;
  5160. DWORD i;
  5161. for (i = 0; i < cOID; i++)
  5162. ChainFreeOID(ppszOID[i]);
  5163. PkiFree(pUsage);
  5164. }
  5165. }
  5166. //+---------------------------------------------------------------------------
  5167. //
  5168. // Function: ChainIsOIDInUsage
  5169. //
  5170. // Synopsis: returns TRUE if the OID is in the usage
  5171. //
  5172. //----------------------------------------------------------------------------
  5173. BOOL WINAPI
  5174. ChainIsOIDInUsage (
  5175. IN LPSTR pszOID,
  5176. IN PCERT_ENHKEY_USAGE pUsage
  5177. )
  5178. {
  5179. DWORD cOID;
  5180. DWORD i;
  5181. assert(pUsage);
  5182. cOID = pUsage->cUsageIdentifier;
  5183. for (i = 0; i < cOID; i++){
  5184. if (0 == strcmp(pszOID, pUsage->rgpszUsageIdentifier[i]))
  5185. return TRUE;
  5186. }
  5187. return FALSE;
  5188. }
  5189. //+---------------------------------------------------------------------------
  5190. //
  5191. // Function: ChainIntersectUsages
  5192. //
  5193. // Synopsis: returns the intersection of the two usages
  5194. //
  5195. //----------------------------------------------------------------------------
  5196. VOID WINAPI
  5197. ChainIntersectUsages (
  5198. IN PCERT_ENHKEY_USAGE pCertUsage,
  5199. IN OUT PCERT_ENHKEY_USAGE pRestrictedUsage
  5200. )
  5201. {
  5202. LPSTR *ppszOID;
  5203. DWORD cOID;
  5204. DWORD i;
  5205. cOID = pRestrictedUsage->cUsageIdentifier;
  5206. ppszOID = pRestrictedUsage->rgpszUsageIdentifier;
  5207. i = 0;
  5208. while (i < cOID) {
  5209. if (ChainIsOIDInUsage(ppszOID[i], pCertUsage))
  5210. i++;
  5211. else {
  5212. // Remove the OID string and move the remaining
  5213. // strings up one.
  5214. DWORD j;
  5215. ChainFreeOID(ppszOID[i]);
  5216. for (j = i; j + 1 < cOID; j++)
  5217. ppszOID[j] = ppszOID[j + 1];
  5218. cOID--;
  5219. pRestrictedUsage->cUsageIdentifier = cOID;
  5220. }
  5221. }
  5222. }
  5223. //+---------------------------------------------------------------------------
  5224. //
  5225. // Function: ChainFreeAndClearRestrictedUsageInfo
  5226. //
  5227. // Synopsis: frees allocated restricted usage info
  5228. //
  5229. //----------------------------------------------------------------------------
  5230. VOID WINAPI
  5231. ChainFreeAndClearRestrictedUsageInfo(
  5232. IN OUT PCHAIN_RESTRICTED_USAGE_INFO pInfo
  5233. )
  5234. {
  5235. ChainFreeUsage(pInfo->pIssuanceRestrictedUsage);
  5236. ChainFreeUsage(pInfo->pIssuanceMappedUsage);
  5237. PkiFree(pInfo->rgdwIssuanceMappedIndex);
  5238. // fRequireIssuancePolicy
  5239. ChainFreeUsage(pInfo->pApplicationRestrictedUsage);
  5240. ChainFreeUsage(pInfo->pApplicationMappedUsage);
  5241. PkiFree(pInfo->rgdwApplicationMappedIndex);
  5242. ChainFreeUsage(pInfo->pPropertyRestrictedUsage);
  5243. memset(pInfo, 0, sizeof(*pInfo));
  5244. }
  5245. //+---------------------------------------------------------------------------
  5246. //
  5247. // Function: ChainCalculateRestrictedUsage
  5248. //
  5249. // Synopsis: update the restricted and mapped usage using the cert's
  5250. // usage and optional policy mappings
  5251. //
  5252. //----------------------------------------------------------------------------
  5253. BOOL WINAPI
  5254. ChainCalculateRestrictedUsage (
  5255. IN PCERT_ENHKEY_USAGE pCertUsage,
  5256. IN OPTIONAL PCERT_POLICY_MAPPINGS_INFO pMappings,
  5257. IN OUT PCERT_ENHKEY_USAGE *ppRestrictedUsage,
  5258. IN OUT PCERT_ENHKEY_USAGE *ppMappedUsage,
  5259. IN OUT LPDWORD *ppdwMappedIndex
  5260. )
  5261. {
  5262. BOOL fResult;
  5263. PCERT_ENHKEY_USAGE pNewMappedUsage = NULL;
  5264. LPDWORD pdwNewMappedIndex = NULL;
  5265. if (pCertUsage) {
  5266. if (NULL == *ppRestrictedUsage) {
  5267. // Top most, first certificate with a usage restriction
  5268. assert(NULL == *ppMappedUsage);
  5269. assert(NULL == *ppdwMappedIndex);
  5270. if (!ChainAllocAndCopyUsage(pCertUsage, ppRestrictedUsage))
  5271. goto AllocAndCopyUsageError;
  5272. } else {
  5273. PCERT_ENHKEY_USAGE pRestrictedUsage = *ppRestrictedUsage;
  5274. PCERT_ENHKEY_USAGE pMappedUsage = *ppMappedUsage;
  5275. if (NULL == pMappedUsage) {
  5276. // Take the intersection of the restricted and cert's
  5277. // usage
  5278. ChainIntersectUsages(pCertUsage, pRestrictedUsage);
  5279. } else {
  5280. // Take the intersection of the mapped and cert's
  5281. // usage. If removed from the mapped usage,
  5282. // we might also need to remove from the restricted usage.
  5283. LPDWORD pdwMappedIndex = *ppdwMappedIndex;
  5284. LPSTR *ppszOID;
  5285. DWORD cOID;
  5286. DWORD i;
  5287. assert(pdwMappedIndex);
  5288. cOID = pMappedUsage->cUsageIdentifier;
  5289. ppszOID = pMappedUsage->rgpszUsageIdentifier;
  5290. i = 0;
  5291. while (i < cOID) {
  5292. if (ChainIsOIDInUsage(ppszOID[i], pCertUsage))
  5293. i++;
  5294. else {
  5295. // If no other mappings to the restricted OID, then,
  5296. // remove the restricted OID.
  5297. DWORD j;
  5298. BOOL fRemoveRestricted;
  5299. if ((0 == i ||
  5300. pdwMappedIndex[i - 1] != pdwMappedIndex[i])
  5301. &&
  5302. (i + 1 == cOID ||
  5303. pdwMappedIndex[i] != pdwMappedIndex[i + 1])) {
  5304. // Remove the restricted OID we are mapped to.
  5305. LPSTR *ppszRestrictedOID =
  5306. pRestrictedUsage->rgpszUsageIdentifier;
  5307. DWORD cRestrictedOID =
  5308. pRestrictedUsage->cUsageIdentifier;
  5309. fRemoveRestricted = TRUE;
  5310. j = pdwMappedIndex[i];
  5311. assert(j < cRestrictedOID);
  5312. if (j < cRestrictedOID)
  5313. ChainFreeOID(ppszRestrictedOID[j]);
  5314. for ( ; j + 1 < cRestrictedOID; j++)
  5315. ppszRestrictedOID[j] = ppszRestrictedOID[j + 1];
  5316. cRestrictedOID--;
  5317. pRestrictedUsage->cUsageIdentifier =
  5318. cRestrictedOID;
  5319. } else
  5320. fRemoveRestricted = FALSE;
  5321. // Remove the OID string and mapped index. Move the
  5322. // remaining strings and indices up one.
  5323. ChainFreeOID(ppszOID[i]);
  5324. for (j = i; j + 1 < cOID; j++) {
  5325. ppszOID[j] = ppszOID[j + 1];
  5326. pdwMappedIndex[j] = pdwMappedIndex[j + 1];
  5327. if (fRemoveRestricted) {
  5328. assert(0 < pdwMappedIndex[j]);
  5329. pdwMappedIndex[j] -= 1;
  5330. }
  5331. }
  5332. cOID--;
  5333. pMappedUsage->cUsageIdentifier = cOID;
  5334. }
  5335. }
  5336. }
  5337. }
  5338. }
  5339. // else
  5340. // No restrictions added by certificate
  5341. if (pMappings) {
  5342. PCERT_ENHKEY_USAGE pRestrictedUsage = *ppRestrictedUsage;
  5343. PCERT_ENHKEY_USAGE pMappedUsage = *ppMappedUsage;
  5344. if (NULL == pRestrictedUsage ||
  5345. 0 == pRestrictedUsage->cUsageIdentifier) {
  5346. // Nothing to be mapped.
  5347. assert(NULL == pMappedUsage ||
  5348. 0 == pMappedUsage->cUsageIdentifier);
  5349. } else {
  5350. LPDWORD pdwMappedIndex;
  5351. PCERT_ENHKEY_USAGE pSrcUsage;
  5352. LPSTR *ppszSrcOID;
  5353. DWORD cSrcOID;
  5354. DWORD iSrc;
  5355. DWORD cMap;
  5356. PCERT_POLICY_MAPPING pMap;
  5357. DWORD cNewOID;
  5358. LPSTR *ppszNewOID;
  5359. if (pMappedUsage) {
  5360. // Subsequent mapping
  5361. assert(0 < pMappedUsage->cUsageIdentifier);
  5362. pSrcUsage = pMappedUsage;
  5363. pdwMappedIndex = *ppdwMappedIndex;
  5364. assert(pdwMappedIndex);
  5365. } else {
  5366. // First mapping
  5367. pSrcUsage = pRestrictedUsage;
  5368. pdwMappedIndex = NULL;
  5369. }
  5370. cSrcOID = pSrcUsage->cUsageIdentifier;
  5371. ppszSrcOID = pSrcUsage->rgpszUsageIdentifier;
  5372. cMap = pMappings->cPolicyMapping;
  5373. pMap = pMappings->rgPolicyMapping;
  5374. // Note, all duplicates have been remove from usage and
  5375. // mappings
  5376. cNewOID = cSrcOID + cMap;
  5377. pNewMappedUsage = (PCERT_ENHKEY_USAGE) PkiZeroAlloc(
  5378. sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR) * cNewOID);
  5379. if (NULL == pNewMappedUsage)
  5380. goto OutOfMemory;
  5381. ppszNewOID = (LPSTR *) &pNewMappedUsage[1];
  5382. pNewMappedUsage->cUsageIdentifier = cNewOID;
  5383. pNewMappedUsage->rgpszUsageIdentifier = ppszNewOID;
  5384. pdwNewMappedIndex = (LPDWORD) PkiZeroAlloc(
  5385. sizeof(DWORD) * cNewOID);
  5386. if (NULL == pdwNewMappedIndex)
  5387. goto OutOfMemory;
  5388. cNewOID = 0;
  5389. for (iSrc = 0; iSrc < cSrcOID; iSrc++) {
  5390. DWORD iMap;
  5391. BOOL fMapped = FALSE;
  5392. for (iMap = 0; iMap < cMap; iMap++) {
  5393. if (0 == strcmp(ppszSrcOID[iSrc],
  5394. pMap[iMap].pszIssuerDomainPolicy)) {
  5395. assert(cNewOID < pNewMappedUsage->cUsageIdentifier);
  5396. ppszNewOID[cNewOID] = ChainAllocAndCopyOID(
  5397. pMap[iMap].pszSubjectDomainPolicy);
  5398. if (NULL == ppszNewOID[cNewOID])
  5399. goto OutOfMemory;
  5400. if (pdwMappedIndex)
  5401. pdwNewMappedIndex[cNewOID] = pdwMappedIndex[iSrc];
  5402. else
  5403. pdwNewMappedIndex[cNewOID] = iSrc;
  5404. cNewOID++;
  5405. fMapped = TRUE;
  5406. }
  5407. }
  5408. if (!fMapped) {
  5409. assert(cNewOID < pNewMappedUsage->cUsageIdentifier);
  5410. ppszNewOID[cNewOID] =
  5411. ChainAllocAndCopyOID(ppszSrcOID[iSrc]);
  5412. if (NULL == ppszNewOID[cNewOID])
  5413. goto OutOfMemory;
  5414. if (pdwMappedIndex)
  5415. pdwNewMappedIndex[cNewOID] = pdwMappedIndex[iSrc];
  5416. else
  5417. pdwNewMappedIndex[cNewOID] = iSrc;
  5418. cNewOID++;
  5419. }
  5420. }
  5421. assert(cNewOID >= cSrcOID);
  5422. pNewMappedUsage->cUsageIdentifier = cNewOID;
  5423. if (pMappedUsage) {
  5424. ChainFreeUsage(pMappedUsage);
  5425. PkiFree(pdwMappedIndex);
  5426. }
  5427. *ppMappedUsage = pNewMappedUsage;
  5428. *ppdwMappedIndex = pdwNewMappedIndex;
  5429. }
  5430. }
  5431. fResult = TRUE;
  5432. CommonReturn:
  5433. return fResult;
  5434. ErrorReturn:
  5435. ChainFreeUsage(pNewMappedUsage);
  5436. PkiFree(pdwNewMappedIndex);
  5437. fResult = FALSE;
  5438. goto CommonReturn;
  5439. TRACE_ERROR(AllocAndCopyUsageError)
  5440. TRACE_ERROR(OutOfMemory)
  5441. }
  5442. //+---------------------------------------------------------------------------
  5443. //
  5444. // Function: ChainGetUsageStatus
  5445. //
  5446. // Synopsis: get the usage status
  5447. //
  5448. //----------------------------------------------------------------------------
  5449. VOID WINAPI
  5450. ChainGetUsageStatus (
  5451. IN PCERT_ENHKEY_USAGE pRequestedUsage,
  5452. IN PCERT_ENHKEY_USAGE pAvailableUsage,
  5453. IN DWORD dwMatchType,
  5454. IN OUT PCERT_TRUST_STATUS pStatus
  5455. )
  5456. {
  5457. DWORD cRequested;
  5458. DWORD cAvailable;
  5459. DWORD cFound;
  5460. BOOL fFound;
  5461. if ( pAvailableUsage == NULL )
  5462. {
  5463. return;
  5464. }
  5465. if ( ( pRequestedUsage->cUsageIdentifier >
  5466. pAvailableUsage->cUsageIdentifier ) &&
  5467. ( dwMatchType == USAGE_MATCH_TYPE_AND ) )
  5468. {
  5469. pStatus->dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
  5470. return;
  5471. }
  5472. for ( cRequested = 0, cFound = 0;
  5473. cRequested < pRequestedUsage->cUsageIdentifier;
  5474. cRequested++ )
  5475. {
  5476. for ( cAvailable = 0, fFound = FALSE;
  5477. ( cAvailable < pAvailableUsage->cUsageIdentifier ) &&
  5478. ( fFound == FALSE );
  5479. cAvailable++ )
  5480. {
  5481. // NOTE: Optimize compares of OIDs. Perhaps with a different
  5482. // encoding
  5483. if ( strcmp(
  5484. pRequestedUsage->rgpszUsageIdentifier[ cRequested ],
  5485. pAvailableUsage->rgpszUsageIdentifier[ cAvailable ]
  5486. ) == 0 )
  5487. {
  5488. fFound = TRUE;
  5489. }
  5490. }
  5491. if ( fFound == TRUE )
  5492. {
  5493. cFound += 1;
  5494. }
  5495. }
  5496. if ( ( dwMatchType == USAGE_MATCH_TYPE_AND ) &&
  5497. ( cFound != pRequestedUsage->cUsageIdentifier ) )
  5498. {
  5499. pStatus->dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
  5500. }
  5501. else if ( ( dwMatchType == USAGE_MATCH_TYPE_OR ) &&
  5502. ( cFound == 0 ) )
  5503. {
  5504. pStatus->dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
  5505. }
  5506. }
  5507. //+---------------------------------------------------------------------------
  5508. //
  5509. // Function: ChainOrInStatusBits
  5510. //
  5511. // Synopsis: bit or in the status bits from the source into the destination
  5512. //
  5513. //----------------------------------------------------------------------------
  5514. VOID WINAPI
  5515. ChainOrInStatusBits (
  5516. IN PCERT_TRUST_STATUS pDestStatus,
  5517. IN PCERT_TRUST_STATUS pSourceStatus
  5518. )
  5519. {
  5520. pDestStatus->dwErrorStatus |= pSourceStatus->dwErrorStatus;
  5521. pDestStatus->dwInfoStatus |= pSourceStatus->dwInfoStatus;
  5522. }
  5523. //+---------------------------------------------------------------------------
  5524. //
  5525. // Function: ChainGetMatchInfoStatus
  5526. //
  5527. // Synopsis: return the info status used to match the issuer
  5528. //
  5529. // For a match returns TRUE, where dwInfoStatus can be
  5530. // one of the following:
  5531. // - CERT_TRUST_HAS_EXACT_MATCH_ISSUER |
  5532. // CERT_TRUST_HAS_PREFERRED_ISSUER
  5533. // - CERT_TRUST_HAS_KEY_MATCH_ISSUER |
  5534. // CERT_TRUST_HAS_PREFERRED_ISSUER
  5535. // - CERT_TRUST_HAS_KEY_MATCH_ISSUER (nonmatching AKI exact match)
  5536. // - CERT_TRUST_HAS_NAME_MATCH_ISSUER |
  5537. // CERT_TRUST_HAS_PREFERRED_ISSUER
  5538. // - CERT_TRUST_HAS_NAME_MATCH_ISSUER (nonmatching AKI)
  5539. //
  5540. // For no match returns FALSE with dwInfoStatus set to the
  5541. // following:
  5542. // - CERT_TRUST_HAS_KEY_MATCH_ISSUER
  5543. //
  5544. //----------------------------------------------------------------------------
  5545. BOOL WINAPI
  5546. ChainGetMatchInfoStatus (
  5547. IN PCCERTOBJECT pIssuerObject,
  5548. IN PCCERTOBJECT pSubjectObject,
  5549. IN OUT DWORD *pdwInfoStatus
  5550. )
  5551. {
  5552. BOOL fResult = FALSE;
  5553. DWORD dwInfoStatus = 0;
  5554. DWORD dwPreferredStatus = CERT_TRUST_HAS_PREFERRED_ISSUER;
  5555. PCERT_INFO pSubjectInfo = pSubjectObject->CertContext()->pCertInfo;
  5556. PCERT_AUTHORITY_KEY_ID_INFO pAKI = pSubjectObject->AuthorityKeyIdentifier();
  5557. PCERT_INFO pIssuerInfo = pIssuerObject->CertContext()->pCertInfo;
  5558. if (pAKI) {
  5559. if ( ( pAKI->CertIssuer.cbData != 0 ) &&
  5560. ( pAKI->CertSerialNumber.cbData != 0 ) )
  5561. {
  5562. DWORD cbAuthIssuerName;
  5563. LPBYTE pbAuthIssuerName;
  5564. DWORD cbAuthSerialNumber;
  5565. LPBYTE pbAuthSerialNumber;
  5566. cbAuthIssuerName = pAKI->CertIssuer.cbData;
  5567. pbAuthIssuerName = pAKI->CertIssuer.pbData;
  5568. cbAuthSerialNumber = pAKI->CertSerialNumber.cbData;
  5569. pbAuthSerialNumber = pAKI->CertSerialNumber.pbData;
  5570. if ( ( cbAuthIssuerName == pIssuerInfo->Issuer.cbData ) &&
  5571. ( memcmp(
  5572. pbAuthIssuerName,
  5573. pIssuerInfo->Issuer.pbData,
  5574. cbAuthIssuerName
  5575. ) == 0 ) &&
  5576. ( cbAuthSerialNumber == pIssuerInfo->SerialNumber.cbData ) &&
  5577. ( memcmp(
  5578. pbAuthSerialNumber,
  5579. pIssuerInfo->SerialNumber.pbData,
  5580. cbAuthSerialNumber
  5581. ) == 0 ) )
  5582. {
  5583. dwInfoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER |
  5584. CERT_TRUST_HAS_PREFERRED_ISSUER;
  5585. goto SuccessReturn;
  5586. } else {
  5587. // Doesn't have preferred match
  5588. dwPreferredStatus = 0;
  5589. }
  5590. }
  5591. if ( pAKI->KeyId.cbData != 0 )
  5592. {
  5593. DWORD cbAuthKeyIdentifier;
  5594. LPBYTE pbAuthKeyIdentifier;
  5595. DWORD cbIssuerKeyIdentifier;
  5596. LPBYTE pbIssuerKeyIdentifier;
  5597. cbAuthKeyIdentifier = pAKI->KeyId.cbData;
  5598. pbAuthKeyIdentifier = pAKI->KeyId.pbData;
  5599. cbIssuerKeyIdentifier = pIssuerObject->KeyIdentifierSize();
  5600. pbIssuerKeyIdentifier = pIssuerObject->KeyIdentifier();
  5601. if ( ( cbAuthKeyIdentifier == cbIssuerKeyIdentifier ) &&
  5602. ( memcmp(
  5603. pbAuthKeyIdentifier,
  5604. pbIssuerKeyIdentifier,
  5605. cbAuthKeyIdentifier
  5606. ) == 0 ) )
  5607. {
  5608. dwInfoStatus = dwPreferredStatus |
  5609. CERT_TRUST_HAS_KEY_MATCH_ISSUER;
  5610. goto SuccessReturn;
  5611. } else {
  5612. // Doesn't have preferred match
  5613. dwPreferredStatus = 0;
  5614. }
  5615. }
  5616. }
  5617. if ( ( pSubjectInfo->Issuer.cbData == pIssuerInfo->Subject.cbData ) &&
  5618. ( pSubjectInfo->Issuer.cbData != 0) &&
  5619. ( memcmp(
  5620. pSubjectInfo->Issuer.pbData,
  5621. pIssuerInfo->Subject.pbData,
  5622. pIssuerInfo->Subject.cbData
  5623. ) == 0 ) )
  5624. {
  5625. dwInfoStatus = dwPreferredStatus | CERT_TRUST_HAS_NAME_MATCH_ISSUER;
  5626. goto SuccessReturn;
  5627. }
  5628. // Default to nonPreferred public key match
  5629. dwInfoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
  5630. goto ErrorReturn;
  5631. SuccessReturn:
  5632. fResult = TRUE;
  5633. CommonReturn:
  5634. *pdwInfoStatus |= dwInfoStatus;
  5635. return fResult;
  5636. ErrorReturn:
  5637. fResult = FALSE;
  5638. goto CommonReturn;
  5639. }
  5640. //+---------------------------------------------------------------------------
  5641. //
  5642. // Function: ChainGetMatchInfoStatusForNoIssuer
  5643. //
  5644. // Synopsis: return the info status when unable to find our issuer
  5645. //
  5646. //----------------------------------------------------------------------------
  5647. DWORD WINAPI
  5648. ChainGetMatchInfoStatusForNoIssuer (
  5649. IN DWORD dwIssuerMatchFlags
  5650. )
  5651. {
  5652. if (dwIssuerMatchFlags & CERT_EXACT_ISSUER_MATCH_FLAG)
  5653. return CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
  5654. else if (dwIssuerMatchFlags & CERT_KEYID_ISSUER_MATCH_TYPE)
  5655. return CERT_TRUST_HAS_KEY_MATCH_ISSUER;
  5656. else
  5657. return CERT_TRUST_HAS_NAME_MATCH_ISSUER;
  5658. }
  5659. //+---------------------------------------------------------------------------
  5660. //
  5661. // Function: ChainIsValidPubKeyMatchForIssuer
  5662. //
  5663. // Synopsis: returns TRUE if the issuer matches more than just the
  5664. // public key match criteria
  5665. //
  5666. // This logic is mainly here to handle tstore2.exe and regress.bat
  5667. // which has end, CA and root certificates using the same
  5668. // public key.
  5669. //
  5670. //----------------------------------------------------------------------------
  5671. BOOL WINAPI
  5672. ChainIsValidPubKeyMatchForIssuer (
  5673. IN PCCERTOBJECT pIssuer,
  5674. IN PCCERTOBJECT pSubject
  5675. )
  5676. {
  5677. BOOL fResult = TRUE;
  5678. BOOL fCheckMatchInfo;
  5679. PCERT_BASIC_CONSTRAINTS2_INFO pIssuerBasicConstraints;
  5680. fCheckMatchInfo = FALSE;
  5681. // Check if the issuer has a basic constraints extension. If it does
  5682. // and it isn't a CA, then, we will need to do an additional issuer match.
  5683. pIssuerBasicConstraints = pIssuer->BasicConstraintsInfo();
  5684. if (pIssuerBasicConstraints && !pIssuerBasicConstraints->fCA)
  5685. fCheckMatchInfo = TRUE;
  5686. else {
  5687. // Check if the issuer has the same public key as the subject. If it
  5688. // does, then, will need to do an additional issuer match.
  5689. BYTE *pbIssuerPublicKeyHash;
  5690. BYTE *pbSubjectPublicKeyHash;
  5691. pbIssuerPublicKeyHash = pIssuer->PublicKeyHash();
  5692. pbSubjectPublicKeyHash = pSubject->PublicKeyHash();
  5693. if (0 == memcmp(pbIssuerPublicKeyHash, pbSubjectPublicKeyHash,
  5694. CHAINHASHLEN))
  5695. fCheckMatchInfo = TRUE;
  5696. }
  5697. if (fCheckMatchInfo) {
  5698. // Check that the issuer matches the subject's AKI or subject's
  5699. // issuer name.
  5700. DWORD dwInfoStatus = 0;
  5701. // Following returns FALSE if only has the public key match
  5702. fResult = ChainGetMatchInfoStatus(pIssuer, pSubject, &dwInfoStatus);
  5703. }
  5704. return fResult;
  5705. }
  5706. //+---------------------------------------------------------------------------
  5707. //
  5708. // Function: ChainGetSubjectStatus
  5709. //
  5710. // Synopsis: get the subject status bits by checking the time nesting and
  5711. // signature validity
  5712. //
  5713. // For CERT_END_OBJECT_TYPE or CERT_EXTERNAL_ISSUER_OBJECT_TYPE
  5714. // CCertObject types, leaves the engine's critical section to
  5715. // verify the signature. If the engine was touched by another
  5716. // thread, it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  5717. //
  5718. // Assumption: Chain engine is locked once in the calling thread.
  5719. //
  5720. //----------------------------------------------------------------------------
  5721. BOOL WINAPI
  5722. ChainGetSubjectStatus (
  5723. IN PCCHAINCALLCONTEXT pCallContext,
  5724. IN PCCHAINPATHOBJECT pIssuerPathObject,
  5725. IN PCCHAINPATHOBJECT pSubjectPathObject,
  5726. IN OUT PCERT_TRUST_STATUS pStatus
  5727. )
  5728. {
  5729. BOOL fResult;
  5730. PCCERTOBJECT pIssuerObject = pIssuerPathObject->CertObject();
  5731. PCCERTOBJECT pSubjectObject = pSubjectPathObject->CertObject();
  5732. PCCERT_CONTEXT pIssuerContext = pIssuerObject->CertContext();
  5733. PCCERT_CONTEXT pSubjectContext = pSubjectObject->CertContext();
  5734. DWORD dwIssuerStatusFlags;
  5735. ChainGetMatchInfoStatus(
  5736. pIssuerObject,
  5737. pSubjectObject,
  5738. &pStatus->dwInfoStatus
  5739. );
  5740. dwIssuerStatusFlags = pSubjectObject->IssuerStatusFlags();
  5741. if (!(dwIssuerStatusFlags & CERT_ISSUER_VALID_SIGNATURE_FLAG)) {
  5742. DWORD dwObjectType;
  5743. dwObjectType = pSubjectObject->ObjectType();
  5744. if (CERT_END_OBJECT_TYPE == dwObjectType ||
  5745. CERT_EXTERNAL_ISSUER_OBJECT_TYPE == dwObjectType)
  5746. pCallContext->ChainEngine()->UnlockEngine();
  5747. fResult = CryptVerifyCertificateSignatureEx(
  5748. NULL, // hCryptProv
  5749. X509_ASN_ENCODING,
  5750. CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
  5751. (void *) pSubjectContext,
  5752. CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
  5753. (void *) pIssuerContext,
  5754. 0, // dwFlags
  5755. NULL // pvReserved
  5756. );
  5757. if (CERT_END_OBJECT_TYPE == dwObjectType ||
  5758. CERT_EXTERNAL_ISSUER_OBJECT_TYPE == dwObjectType) {
  5759. pCallContext->ChainEngine()->LockEngine();
  5760. if (pCallContext->IsTouchedEngine())
  5761. goto TouchedDuringSignatureVerification;
  5762. }
  5763. if (!fResult) {
  5764. pStatus->dwErrorStatus |= CERT_TRUST_IS_NOT_SIGNATURE_VALID;
  5765. pStatus->dwInfoStatus &= ~CERT_TRUST_HAS_PREFERRED_ISSUER;
  5766. } else {
  5767. if (dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG) {
  5768. // Verify the issuer's public key hash
  5769. if (0 != memcmp(pSubjectObject->IssuerPublicKeyHash(),
  5770. pIssuerObject->PublicKeyHash(), CHAINHASHLEN))
  5771. dwIssuerStatusFlags &= ~CERT_ISSUER_PUBKEY_FLAG;
  5772. }
  5773. if (!(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG)) {
  5774. CRYPT_DATA_BLOB DataBlob;
  5775. memcpy(pSubjectObject->IssuerPublicKeyHash(),
  5776. pIssuerObject->PublicKeyHash(), CHAINHASHLEN);
  5777. DataBlob.pbData = pSubjectObject->IssuerPublicKeyHash(),
  5778. DataBlob.cbData = CHAINHASHLEN;
  5779. CertSetCertificateContextProperty(
  5780. pSubjectContext,
  5781. CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID,
  5782. CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG,
  5783. &DataBlob
  5784. );
  5785. }
  5786. pSubjectObject->OrIssuerStatusFlags(
  5787. CERT_ISSUER_PUBKEY_FLAG |
  5788. CERT_ISSUER_VALID_SIGNATURE_FLAG
  5789. );
  5790. }
  5791. CertPerfIncrementChainVerifyCertSignatureCount();
  5792. } else {
  5793. // also need to check public key parameters
  5794. assert(dwIssuerStatusFlags & CERT_ISSUER_PUBKEY_FLAG);
  5795. if (0 != memcmp(pSubjectObject->IssuerPublicKeyHash(),
  5796. pIssuerObject->PublicKeyHash(), CHAINHASHLEN)) {
  5797. pStatus->dwErrorStatus |= CERT_TRUST_IS_NOT_SIGNATURE_VALID;
  5798. pStatus->dwInfoStatus &= ~CERT_TRUST_HAS_PREFERRED_ISSUER;
  5799. }
  5800. CertPerfIncrementChainCompareIssuerPublicKeyCount();
  5801. }
  5802. fResult = TRUE;
  5803. CommonReturn:
  5804. return fResult;
  5805. ErrorReturn:
  5806. fResult = FALSE;
  5807. goto CommonReturn;
  5808. SET_ERROR(TouchedDuringSignatureVerification, ERROR_CAN_NOT_COMPLETE)
  5809. }
  5810. //+---------------------------------------------------------------------------
  5811. //
  5812. // Function: ChainUpdateSummaryStatusByTrustStatus
  5813. //
  5814. // Synopsis: update the summary status bits given new trust status bits
  5815. //
  5816. //----------------------------------------------------------------------------
  5817. VOID WINAPI
  5818. ChainUpdateSummaryStatusByTrustStatus(
  5819. IN OUT PCERT_TRUST_STATUS pSummaryStatus,
  5820. IN PCERT_TRUST_STATUS pTrustStatus
  5821. )
  5822. {
  5823. pSummaryStatus->dwErrorStatus |= pTrustStatus->dwErrorStatus;
  5824. pSummaryStatus->dwInfoStatus |=
  5825. pTrustStatus->dwInfoStatus &
  5826. ~(CERT_TRUST_CERTIFICATE_ONLY_INFO_STATUS |
  5827. CERT_TRUST_HAS_PREFERRED_ISSUER);
  5828. if (!(pTrustStatus->dwInfoStatus & CERT_TRUST_HAS_PREFERRED_ISSUER))
  5829. pSummaryStatus->dwInfoStatus &= ~CERT_TRUST_HAS_PREFERRED_ISSUER;
  5830. if (pSummaryStatus->dwErrorStatus &
  5831. CERT_TRUST_ANY_NAME_CONSTRAINT_ERROR_STATUS)
  5832. pSummaryStatus->dwInfoStatus &= ~CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS;
  5833. }
  5834. //+===========================================================================
  5835. // Format and append extended error information helper functions
  5836. //============================================================================
  5837. //+---------------------------------------------------------------------------
  5838. //
  5839. // Function: ChainAllocAndEncodeObject
  5840. //
  5841. // Synopsis: allocate and ASN.1 encodes the data structure.
  5842. //
  5843. // PkiFree must be called to free the encoded bytes
  5844. //
  5845. //----------------------------------------------------------------------------
  5846. BOOL WINAPI
  5847. ChainAllocAndEncodeObject(
  5848. IN LPCSTR lpszStructType,
  5849. IN const void *pvStructInfo,
  5850. OUT BYTE **ppbEncoded,
  5851. OUT DWORD *pcbEncoded
  5852. )
  5853. {
  5854. return CryptEncodeObjectEx(
  5855. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  5856. lpszStructType,
  5857. pvStructInfo,
  5858. CRYPT_ENCODE_ALLOC_FLAG,
  5859. &PkiEncodePara,
  5860. (void *) ppbEncoded,
  5861. pcbEncoded
  5862. );
  5863. }
  5864. //+---------------------------------------------------------------------------
  5865. //
  5866. // Function: ChainAppendExtendedErrorInfo
  5867. //
  5868. // Synopsis: PkiReallocate and append an already localization formatted
  5869. // line of extended error information
  5870. //
  5871. //----------------------------------------------------------------------------
  5872. VOID WINAPI
  5873. ChainAppendExtendedErrorInfo(
  5874. IN OUT LPWSTR *ppwszExtErrorInfo,
  5875. IN LPWSTR pwszAppend,
  5876. IN DWORD cchAppend // Includes NULL terminator
  5877. )
  5878. {
  5879. LPWSTR pwszExtErrorInfo = *ppwszExtErrorInfo;
  5880. DWORD cchExtErrorInfo;
  5881. if (pwszExtErrorInfo)
  5882. cchExtErrorInfo = wcslen(pwszExtErrorInfo);
  5883. else
  5884. cchExtErrorInfo = 0;
  5885. assert(0 < cchAppend);
  5886. if (pwszExtErrorInfo = (LPWSTR) PkiRealloc(pwszExtErrorInfo,
  5887. (cchExtErrorInfo + cchAppend) * sizeof(WCHAR))) {
  5888. memcpy(&pwszExtErrorInfo[cchExtErrorInfo], pwszAppend,
  5889. cchAppend * sizeof(WCHAR));
  5890. *ppwszExtErrorInfo = pwszExtErrorInfo;
  5891. }
  5892. }
  5893. //+---------------------------------------------------------------------------
  5894. //
  5895. // Function: ChainFormatAndAppendExtendedErrorInfo
  5896. //
  5897. // Synopsis: localization format a line of extended error information
  5898. // and append via the above ChainAppendExtendedErrorInfo
  5899. //
  5900. //----------------------------------------------------------------------------
  5901. VOID WINAPI
  5902. ChainFormatAndAppendExtendedErrorInfo(
  5903. IN OUT LPWSTR *ppwszExtErrorInfo,
  5904. IN UINT nFormatID,
  5905. ...
  5906. )
  5907. {
  5908. DWORD cchMsg = 0;
  5909. LPWSTR pwszMsg = NULL;
  5910. WCHAR wszFormat[256];
  5911. wszFormat[0] = '\0';
  5912. va_list argList;
  5913. // get format string from resources
  5914. if(0 == LoadStringU(g_hChainInst, nFormatID, wszFormat,
  5915. sizeof(wszFormat)/sizeof(wszFormat[0])))
  5916. return;
  5917. __try {
  5918. // format message into requested buffer
  5919. va_start(argList, nFormatID);
  5920. cchMsg = FormatMessageU(
  5921. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  5922. wszFormat,
  5923. 0, // dwMessageId
  5924. 0, // dwLanguageId
  5925. (LPWSTR) &pwszMsg,
  5926. 0, // minimum size to allocate
  5927. &argList);
  5928. va_end(argList);
  5929. // Must at least have the L'\n' terminator
  5930. if (1 < cchMsg && pwszMsg)
  5931. ChainAppendExtendedErrorInfo(
  5932. ppwszExtErrorInfo,
  5933. pwszMsg,
  5934. cchMsg + 1
  5935. );
  5936. } __except(EXCEPTION_EXECUTE_HANDLER) {
  5937. }
  5938. if (pwszMsg)
  5939. LocalFree(pwszMsg);
  5940. }
  5941. //+===========================================================================
  5942. // Name Constraint helper functions
  5943. //============================================================================
  5944. //+---------------------------------------------------------------------------
  5945. //
  5946. // Function: ChainIsWhiteSpace
  5947. //
  5948. // Synopsis: returns TRUE for a white space character
  5949. //
  5950. //----------------------------------------------------------------------------
  5951. static inline BOOL ChainIsWhiteSpace(WCHAR wc)
  5952. {
  5953. return wc == L' ' || (wc >= 0x09 && wc <= 0x0d);
  5954. }
  5955. //+---------------------------------------------------------------------------
  5956. //
  5957. // Function: ChainRemoveLeadingAndTrailingWhiteSpace
  5958. //
  5959. // Synopsis: advances the pointer past any leading white space. Removes
  5960. // any trailing white space by inserting the L'\0' and updating
  5961. // the character count.
  5962. //
  5963. //----------------------------------------------------------------------------
  5964. VOID WINAPI
  5965. ChainRemoveLeadingAndTrailingWhiteSpace(
  5966. IN LPWSTR pwszIn,
  5967. OUT LPWSTR *ppwszOut,
  5968. OUT DWORD *pcchOut
  5969. )
  5970. {
  5971. LPWSTR pwszOut;
  5972. DWORD cchOut;
  5973. WCHAR wc;
  5974. // Remove leading white space
  5975. for (pwszOut = pwszIn ; L'\0' != (wc = *pwszOut); pwszOut++) {
  5976. if (!ChainIsWhiteSpace(wc))
  5977. break;
  5978. }
  5979. for (cchOut = wcslen(pwszOut); 0 < cchOut; cchOut--) {
  5980. if (!ChainIsWhiteSpace(pwszOut[cchOut - 1]))
  5981. break;
  5982. }
  5983. pwszOut[cchOut] = L'\0';
  5984. *ppwszOut = pwszOut;
  5985. *pcchOut = cchOut;
  5986. }
  5987. #define NO_LOCALE MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
  5988. //+---------------------------------------------------------------------------
  5989. //
  5990. // Function: ChainIsRightStringInString
  5991. //
  5992. // Synopsis: returns TRUE for a case insensitive match of the
  5993. // "Right" string with the right most characters of the
  5994. // string.
  5995. //
  5996. //----------------------------------------------------------------------------
  5997. BOOL WINAPI
  5998. ChainIsRightStringInString(
  5999. IN LPCWSTR pwszRight,
  6000. IN DWORD cchRight,
  6001. IN LPCWSTR pwszString,
  6002. IN DWORD cchString
  6003. )
  6004. {
  6005. if (0 == cchRight)
  6006. return TRUE;
  6007. if (cchRight > cchString)
  6008. return FALSE;
  6009. if (CSTR_EQUAL == CompareStringU(
  6010. NO_LOCALE,
  6011. NORM_IGNORECASE,
  6012. pwszRight,
  6013. cchRight,
  6014. pwszString + (cchString - cchRight),
  6015. cchRight
  6016. ))
  6017. return TRUE;
  6018. else
  6019. return FALSE;
  6020. }
  6021. //+---------------------------------------------------------------------------
  6022. //
  6023. // Function: ChainFixupNameConstraintsUPN
  6024. //
  6025. // Synopsis: fixup the CERT_ALT_NAME_OTHER_NAME AltName entry choice
  6026. // for szOID_NT_PRINCIPAL_NAME by allocating and converting
  6027. // to a PCERT_NAME_VALUE containing the unicode string
  6028. // with leading and trailing white space removed.
  6029. //
  6030. // The pOtherName->Value.pbData is updated to point to the
  6031. // PCERT_NAME_VALUE instead of the original ASN.1 encoded
  6032. // bytes.
  6033. //
  6034. //----------------------------------------------------------------------------
  6035. BOOL WINAPI
  6036. ChainFixupNameConstraintsUPN(
  6037. IN OUT PCRYPT_OBJID_BLOB pUPN
  6038. )
  6039. {
  6040. BOOL fResult;
  6041. PCERT_NAME_VALUE pNameValue;
  6042. LPWSTR pwsz;
  6043. DWORD cch;
  6044. pNameValue = (PCERT_NAME_VALUE) ChainAllocAndDecodeObject(
  6045. X509_UNICODE_ANY_STRING,
  6046. pUPN->pbData,
  6047. pUPN->cbData
  6048. );
  6049. if (NULL == pNameValue)
  6050. goto DecodeError;
  6051. if (!IS_CERT_RDN_CHAR_STRING(pNameValue->dwValueType)) {
  6052. PkiFree(pNameValue);
  6053. goto InvalidUPNStringType;
  6054. }
  6055. ChainRemoveLeadingAndTrailingWhiteSpace(
  6056. (LPWSTR) pNameValue->Value.pbData,
  6057. &pwsz,
  6058. &cch
  6059. );
  6060. pNameValue->Value.pbData = (BYTE *) pwsz;
  6061. pNameValue->Value.cbData = cch * sizeof(WCHAR);
  6062. pUPN->pbData = (BYTE *) pNameValue;
  6063. fResult = TRUE;
  6064. CommonReturn:
  6065. return fResult;
  6066. ErrorReturn:
  6067. pUPN->pbData = NULL;
  6068. fResult = FALSE;
  6069. goto CommonReturn;
  6070. TRACE_ERROR(DecodeError)
  6071. SET_ERROR(InvalidUPNStringType, CRYPT_E_BAD_ENCODE)
  6072. }
  6073. //+---------------------------------------------------------------------------
  6074. //
  6075. // Function: ChainAllocDecodeAndFixupNameConstraintsDirectoryName
  6076. //
  6077. // Synopsis: fixup the CERT_ALT_NAME_DIRECTORY_NAME AltName entry choice
  6078. // or the encoded certificate Subject name by allocating and
  6079. // converting to a unicode PCERT_NAME_INFO where
  6080. // leading and trailing white space has been removed from
  6081. // all the attributes.
  6082. //
  6083. // The DirectoryName.pbData is updated to point to the
  6084. // PCERT_NAME_INFO instead of the original ASN.1 encoded
  6085. // bytes.
  6086. //
  6087. //----------------------------------------------------------------------------
  6088. BOOL WINAPI
  6089. ChainAllocDecodeAndFixupNameConstraintsDirectoryName(
  6090. IN PCERT_NAME_BLOB pDirName,
  6091. OUT PCERT_NAME_INFO *ppNameInfo
  6092. )
  6093. {
  6094. BOOL fResult;
  6095. PCERT_NAME_INFO pNameInfo = NULL;
  6096. DWORD cRDN;
  6097. PCERT_RDN pRDN;
  6098. if (0 == pDirName->cbData)
  6099. goto SuccessReturn;
  6100. pNameInfo = (PCERT_NAME_INFO) ChainAllocAndDecodeObject(
  6101. X509_UNICODE_NAME,
  6102. pDirName->pbData,
  6103. pDirName->cbData
  6104. );
  6105. if (NULL == pNameInfo)
  6106. goto DecodeError;
  6107. if (0 == pNameInfo->cRDN) {
  6108. PkiFree(pNameInfo);
  6109. pNameInfo = NULL;
  6110. goto SuccessReturn;
  6111. }
  6112. // Iterate through all the attributes and remove leading and trailing
  6113. // white space.
  6114. cRDN = pNameInfo->cRDN;
  6115. pRDN = pNameInfo->rgRDN;
  6116. for ( ; cRDN > 0; cRDN--, pRDN++) {
  6117. DWORD cAttr = pRDN->cRDNAttr;
  6118. PCERT_RDN_ATTR pAttr = pRDN->rgRDNAttr;
  6119. for ( ; cAttr > 0; cAttr--, pAttr++) {
  6120. LPWSTR pwsz;
  6121. DWORD cch;
  6122. if (!IS_CERT_RDN_CHAR_STRING(pAttr->dwValueType))
  6123. continue;
  6124. ChainRemoveLeadingAndTrailingWhiteSpace(
  6125. (LPWSTR) pAttr->Value.pbData,
  6126. &pwsz,
  6127. &cch
  6128. );
  6129. pAttr->Value.pbData = (BYTE *) pwsz;
  6130. pAttr->Value.cbData = cch * sizeof(WCHAR);
  6131. }
  6132. }
  6133. SuccessReturn:
  6134. fResult = TRUE;
  6135. CommonReturn:
  6136. *ppNameInfo = pNameInfo;
  6137. return fResult;
  6138. ErrorReturn:
  6139. fResult = FALSE;
  6140. goto CommonReturn;
  6141. TRACE_ERROR(DecodeError)
  6142. }
  6143. //+---------------------------------------------------------------------------
  6144. //
  6145. // Function: ChainFixupNameConstraintsAltNameEntry
  6146. //
  6147. // Synopsis: fixup the AltName entry choices as follows:
  6148. // CERT_ALT_NAME_OTHER_NAME
  6149. // For szOID_NT_PRINCIPAL_NAME, pOtherName->Value.pbData
  6150. // is updated to point to the allocated
  6151. // PCERT_NAME_VALUE containing the decoded unicode string.
  6152. //
  6153. // CERT_ALT_NAME_RFC822_NAME
  6154. // CERT_ALT_NAME_DNS_NAME
  6155. // CERT_ALT_NAME_URL
  6156. // Uses DirectoryName.pbData and DirectoryName.cbData
  6157. // to contain the pointer to and length of the unicode
  6158. // string.
  6159. //
  6160. // For the subject URL, the DirectoryName.pbData's
  6161. // unicode string is the allocated host name.
  6162. //
  6163. // CERT_ALT_NAME_DIRECTORY_NAME:
  6164. // DirectoryName.pbData is updated to point to the
  6165. // allocated and decoded unicode PCERT_NAME_INFO.
  6166. //
  6167. // For the above choices, leading and trailing white space
  6168. // has been removed. cbData is number of bytes and not number
  6169. // of characters, ie, cbData = cch * sizeof(WCHAR)
  6170. //
  6171. //----------------------------------------------------------------------------
  6172. BOOL WINAPI
  6173. ChainFixupNameConstraintsAltNameEntry(
  6174. IN BOOL fSubjectConstraint,
  6175. IN OUT PCERT_ALT_NAME_ENTRY pEntry
  6176. )
  6177. {
  6178. BOOL fResult = TRUE;
  6179. LPWSTR pwsz = NULL;
  6180. DWORD cch = 0;
  6181. switch (pEntry->dwAltNameChoice) {
  6182. case CERT_ALT_NAME_OTHER_NAME:
  6183. if (0 == strcmp(pEntry->pOtherName->pszObjId,
  6184. szOID_NT_PRINCIPAL_NAME))
  6185. fResult = ChainFixupNameConstraintsUPN(
  6186. &pEntry->pOtherName->Value);
  6187. break;
  6188. case CERT_ALT_NAME_RFC822_NAME:
  6189. case CERT_ALT_NAME_DNS_NAME:
  6190. ChainRemoveLeadingAndTrailingWhiteSpace(
  6191. pEntry->pwszRfc822Name,
  6192. &pwsz,
  6193. &cch
  6194. );
  6195. // Use the directory name's BLOB choice to contain both
  6196. // the pointer to and length of the string
  6197. pEntry->DirectoryName.pbData = (BYTE *) pwsz;
  6198. pEntry->DirectoryName.cbData = cch * sizeof(WCHAR);
  6199. break;
  6200. case CERT_ALT_NAME_URL:
  6201. if (fSubjectConstraint) {
  6202. WCHAR rgwszHostName[MAX_PATH + 1];
  6203. LPWSTR pwszHostName;
  6204. rgwszHostName[0] = L'\0';
  6205. fResult = ChainGetHostNameFromUrl(
  6206. pEntry->pwszURL, MAX_PATH, rgwszHostName);
  6207. if (fResult) {
  6208. ChainRemoveLeadingAndTrailingWhiteSpace(
  6209. rgwszHostName,
  6210. &pwszHostName,
  6211. &cch
  6212. );
  6213. pwsz = (LPWSTR) PkiNonzeroAlloc((cch + 1) * sizeof(WCHAR));
  6214. if (NULL == pwsz)
  6215. fResult = FALSE;
  6216. else
  6217. memcpy(pwsz, pwszHostName, (cch + 1) * sizeof(WCHAR));
  6218. }
  6219. if (!fResult) {
  6220. pwsz = NULL;
  6221. cch = 0;
  6222. }
  6223. } else {
  6224. ChainRemoveLeadingAndTrailingWhiteSpace(
  6225. pEntry->pwszURL,
  6226. &pwsz,
  6227. &cch
  6228. );
  6229. }
  6230. // Use the directory name's BLOB choice to contain both
  6231. // the pointer to and length of the string
  6232. pEntry->DirectoryName.pbData = (BYTE *) pwsz;
  6233. pEntry->DirectoryName.cbData = cch * sizeof(WCHAR);
  6234. break;
  6235. case CERT_ALT_NAME_DIRECTORY_NAME:
  6236. {
  6237. PCERT_NAME_INFO pNameInfo = NULL;
  6238. fResult = ChainAllocDecodeAndFixupNameConstraintsDirectoryName(
  6239. &pEntry->DirectoryName, &pNameInfo);
  6240. // Update the directory name's BLOB to contain the pointer
  6241. // to the decoded name info
  6242. pEntry->DirectoryName.pbData = (BYTE *) pNameInfo;
  6243. }
  6244. break;
  6245. case CERT_ALT_NAME_X400_ADDRESS:
  6246. case CERT_ALT_NAME_EDI_PARTY_NAME:
  6247. case CERT_ALT_NAME_IP_ADDRESS:
  6248. case CERT_ALT_NAME_REGISTERED_ID:
  6249. default:
  6250. break;
  6251. }
  6252. return fResult;
  6253. }
  6254. //+---------------------------------------------------------------------------
  6255. //
  6256. // Function: ChainFreeNameConstraintsAltNameEntryFixup
  6257. //
  6258. // Synopsis: free memory allocated by the above
  6259. // ChainFixupNameConstraintsAltNameEntry
  6260. //
  6261. //----------------------------------------------------------------------------
  6262. VOID WINAPI
  6263. ChainFreeNameConstraintsAltNameEntryFixup(
  6264. IN BOOL fSubjectConstraint,
  6265. IN OUT PCERT_ALT_NAME_ENTRY pEntry
  6266. )
  6267. {
  6268. switch (pEntry->dwAltNameChoice) {
  6269. case CERT_ALT_NAME_OTHER_NAME:
  6270. if (0 == strcmp(pEntry->pOtherName->pszObjId,
  6271. szOID_NT_PRINCIPAL_NAME))
  6272. // pbData :: PCERT_NAME_VALUE
  6273. PkiFree(pEntry->pOtherName->Value.pbData);
  6274. break;
  6275. case CERT_ALT_NAME_RFC822_NAME:
  6276. case CERT_ALT_NAME_DNS_NAME:
  6277. break;
  6278. case CERT_ALT_NAME_URL:
  6279. if (fSubjectConstraint)
  6280. // pbData :: LPWSTR
  6281. PkiFree(pEntry->DirectoryName.pbData);
  6282. break;
  6283. case CERT_ALT_NAME_DIRECTORY_NAME:
  6284. // pbData :: PCERT_NAME_INFO
  6285. PkiFree(pEntry->DirectoryName.pbData);
  6286. break;
  6287. case CERT_ALT_NAME_X400_ADDRESS:
  6288. case CERT_ALT_NAME_EDI_PARTY_NAME:
  6289. case CERT_ALT_NAME_IP_ADDRESS:
  6290. case CERT_ALT_NAME_REGISTERED_ID:
  6291. default:
  6292. break;
  6293. }
  6294. }
  6295. //+---------------------------------------------------------------------------
  6296. //
  6297. // Function: ChainFormatNameConstraintsAltNameEntryFixup
  6298. //
  6299. // Synopsis: localization format and allocate a previously fixed up
  6300. // AltName entry.
  6301. //
  6302. // The returned string must be freed via PkiFree().
  6303. //
  6304. //----------------------------------------------------------------------------
  6305. LPWSTR WINAPI
  6306. ChainFormatNameConstraintsAltNameEntryFixup(
  6307. IN PCERT_ALT_NAME_ENTRY pEntry
  6308. )
  6309. {
  6310. DWORD dwExceptionCode;
  6311. LPWSTR pwszFormat = NULL;
  6312. DWORD cbFormat = 0;
  6313. CERT_ALT_NAME_ENTRY AltEntry;
  6314. const CERT_ALT_NAME_INFO AltNameInfo = { 1, &AltEntry };
  6315. CERT_OTHER_NAME OtherName;
  6316. BYTE *pbEncoded = NULL;
  6317. DWORD cbEncoded;
  6318. BYTE *pbEncoded2 = NULL;
  6319. DWORD cbEncoded2;
  6320. __try {
  6321. AltEntry = *pEntry;
  6322. // Restore fixed up entries so we can re-encode
  6323. switch (AltEntry.dwAltNameChoice) {
  6324. case CERT_ALT_NAME_OTHER_NAME:
  6325. if (0 == strcmp(pEntry->pOtherName->pszObjId,
  6326. szOID_NT_PRINCIPAL_NAME)) {
  6327. // Restore from the following fixup:
  6328. // pEntry->pOtherName->Value.pbData :: PCERT_NAME_VALUE
  6329. if (NULL == pEntry->pOtherName->Value.pbData)
  6330. goto InvalidUPN;
  6331. if (!ChainAllocAndEncodeObject(
  6332. X509_UNICODE_ANY_STRING,
  6333. (PCERT_NAME_VALUE) pEntry->pOtherName->Value.pbData,
  6334. &pbEncoded2,
  6335. &cbEncoded2
  6336. ))
  6337. goto EncodedUPNError;
  6338. OtherName.pszObjId = pEntry->pOtherName->pszObjId;
  6339. OtherName.Value.pbData = pbEncoded2;
  6340. OtherName.Value.cbData = cbEncoded2;
  6341. AltEntry.pOtherName = &OtherName;
  6342. }
  6343. break;
  6344. case CERT_ALT_NAME_RFC822_NAME:
  6345. case CERT_ALT_NAME_DNS_NAME:
  6346. case CERT_ALT_NAME_URL:
  6347. // Restore from the following fixup:
  6348. // pEntry->DirectoryName.pbData = (BYTE *) pwsz;
  6349. // pEntry->DirectoryName.cbData = cch * sizeof(WCHAR);
  6350. if (NULL == pEntry->DirectoryName.pbData ||
  6351. 0 == pEntry->DirectoryName.cbData)
  6352. AltEntry.pwszRfc822Name = L"???";
  6353. else
  6354. AltEntry.pwszRfc822Name =
  6355. (LPWSTR) pEntry->DirectoryName.pbData;
  6356. break;
  6357. case CERT_ALT_NAME_DIRECTORY_NAME:
  6358. // Restore from the following fixup:
  6359. // pEntry->DirectoryName.pbData :: PCERT_NAME_INFO
  6360. if (NULL == pEntry->DirectoryName.pbData)
  6361. goto InvalidDirName;
  6362. if (!ChainAllocAndEncodeObject(
  6363. X509_UNICODE_NAME,
  6364. (PCERT_NAME_INFO) pEntry->DirectoryName.pbData,
  6365. &pbEncoded2,
  6366. &cbEncoded2
  6367. ))
  6368. goto EncodeDirNameError;
  6369. AltEntry.DirectoryName.pbData = pbEncoded2;
  6370. AltEntry.DirectoryName.cbData = cbEncoded2;
  6371. break;
  6372. case CERT_ALT_NAME_X400_ADDRESS:
  6373. case CERT_ALT_NAME_EDI_PARTY_NAME:
  6374. case CERT_ALT_NAME_IP_ADDRESS:
  6375. case CERT_ALT_NAME_REGISTERED_ID:
  6376. default:
  6377. break;
  6378. }
  6379. if (!ChainAllocAndEncodeObject(
  6380. X509_ALTERNATE_NAME,
  6381. &AltNameInfo,
  6382. &pbEncoded,
  6383. &cbEncoded
  6384. ))
  6385. goto EncodeAltNameError;
  6386. if (!CryptFormatObject(
  6387. X509_ASN_ENCODING,
  6388. 0, // dwFormatType
  6389. 0, // dwFormatStrType
  6390. NULL, // pFormatStruct
  6391. X509_ALTERNATE_NAME,
  6392. pbEncoded,
  6393. cbEncoded,
  6394. NULL, // pwszFormat
  6395. &cbFormat
  6396. ))
  6397. goto FormatAltNameError;
  6398. if (NULL == (pwszFormat = (LPWSTR) PkiZeroAlloc(
  6399. cbFormat + sizeof(WCHAR))))
  6400. goto OutOfMemory;
  6401. if (!CryptFormatObject(
  6402. X509_ASN_ENCODING,
  6403. 0, // dwFormatType
  6404. 0, // dwFormatStrType
  6405. NULL, // pFormatStruct
  6406. X509_ALTERNATE_NAME,
  6407. pbEncoded,
  6408. cbEncoded,
  6409. pwszFormat,
  6410. &cbFormat
  6411. ))
  6412. goto FormatAltNameError;
  6413. } __except(EXCEPTION_EXECUTE_HANDLER) {
  6414. dwExceptionCode = GetExceptionCode();
  6415. goto ExceptionError;
  6416. }
  6417. CommonReturn:
  6418. PkiFree(pbEncoded);
  6419. PkiFree(pbEncoded2);
  6420. return pwszFormat;
  6421. ErrorReturn:
  6422. if (pwszFormat) {
  6423. PkiFree(pwszFormat);
  6424. pwszFormat = NULL;
  6425. }
  6426. goto CommonReturn;
  6427. SET_ERROR(InvalidUPN, ERROR_INVALID_DATA)
  6428. TRACE_ERROR(EncodedUPNError)
  6429. TRACE_ERROR(InvalidDirName)
  6430. TRACE_ERROR(EncodeDirNameError)
  6431. TRACE_ERROR(EncodeAltNameError)
  6432. TRACE_ERROR(FormatAltNameError)
  6433. TRACE_ERROR(OutOfMemory)
  6434. SET_ERROR_VAR(ExceptionError, dwExceptionCode)
  6435. }
  6436. //+---------------------------------------------------------------------------
  6437. //
  6438. // Function: ChainFormatAndAppendNameConstraintsAltNameEntryFixup
  6439. //
  6440. // Synopsis: localization format a previously fixed up
  6441. // AltName entry and append to the extended error information.
  6442. //
  6443. //----------------------------------------------------------------------------
  6444. VOID WINAPI
  6445. ChainFormatAndAppendNameConstraintsAltNameEntryFixup(
  6446. IN OUT LPWSTR *ppwszExtErrorInfo,
  6447. IN PCERT_ALT_NAME_ENTRY pEntry,
  6448. IN UINT nFormatID,
  6449. IN OPTIONAL DWORD dwSubtreeIndex // 0 => no subtree parameter
  6450. )
  6451. {
  6452. LPWSTR pwszAllocFormatEntry = NULL;
  6453. LPWSTR pwszFormatEntry;
  6454. pwszAllocFormatEntry = ChainFormatNameConstraintsAltNameEntryFixup(pEntry);
  6455. if (pwszAllocFormatEntry)
  6456. pwszFormatEntry = pwszAllocFormatEntry;
  6457. else
  6458. pwszFormatEntry = L"???";
  6459. if (0 == dwSubtreeIndex)
  6460. ChainFormatAndAppendExtendedErrorInfo(
  6461. ppwszExtErrorInfo,
  6462. nFormatID,
  6463. pwszFormatEntry
  6464. );
  6465. else
  6466. ChainFormatAndAppendExtendedErrorInfo(
  6467. ppwszExtErrorInfo,
  6468. nFormatID,
  6469. dwSubtreeIndex,
  6470. pwszFormatEntry
  6471. );
  6472. PkiFree(pwszAllocFormatEntry);
  6473. }
  6474. //+---------------------------------------------------------------------------
  6475. //
  6476. // Function: ChainGetIssuerNameConstraintsInfo
  6477. //
  6478. // Synopsis: alloc and return the issuer name constraints info.
  6479. //
  6480. //----------------------------------------------------------------------------
  6481. BOOL WINAPI
  6482. ChainGetIssuerNameConstraintsInfo (
  6483. IN PCCERT_CONTEXT pCertContext,
  6484. IN OUT PCERT_NAME_CONSTRAINTS_INFO *ppInfo
  6485. )
  6486. {
  6487. BOOL fResult;
  6488. PCERT_EXTENSION pExt;
  6489. PCERT_NAME_CONSTRAINTS_INFO pInfo = NULL;
  6490. PCERT_GENERAL_SUBTREE pSubtree;
  6491. DWORD cSubtree;
  6492. pExt = CertFindExtension(
  6493. szOID_NAME_CONSTRAINTS,
  6494. pCertContext->pCertInfo->cExtension,
  6495. pCertContext->pCertInfo->rgExtension
  6496. );
  6497. if (NULL == pExt)
  6498. goto SuccessReturn;
  6499. pInfo = (PCERT_NAME_CONSTRAINTS_INFO) ChainAllocAndDecodeObject(
  6500. X509_NAME_CONSTRAINTS,
  6501. pExt->Value.pbData,
  6502. pExt->Value.cbData
  6503. );
  6504. if (NULL == pInfo)
  6505. goto DecodeError;
  6506. // Fixup all the AltName entries
  6507. // Note, even for an error we need to fixup all the entries.
  6508. // ChainFreeIssuerNameConstraintsInfo iterates through all the entries.
  6509. fResult = TRUE;
  6510. cSubtree = pInfo->cPermittedSubtree;
  6511. pSubtree = pInfo->rgPermittedSubtree;
  6512. for ( ; 0 < cSubtree; cSubtree--, pSubtree++) {
  6513. if (!ChainFixupNameConstraintsAltNameEntry(FALSE, &pSubtree->Base))
  6514. fResult = FALSE;
  6515. }
  6516. cSubtree = pInfo->cExcludedSubtree;
  6517. pSubtree = pInfo->rgExcludedSubtree;
  6518. for ( ; 0 < cSubtree; cSubtree--, pSubtree++) {
  6519. if (!ChainFixupNameConstraintsAltNameEntry(FALSE, &pSubtree->Base))
  6520. fResult = FALSE;
  6521. }
  6522. if (!fResult)
  6523. goto FixupAltNameEntryError;
  6524. SuccessReturn:
  6525. fResult = TRUE;
  6526. CommonReturn:
  6527. *ppInfo = pInfo;
  6528. return fResult;
  6529. ErrorReturn:
  6530. fResult = FALSE;
  6531. goto CommonReturn;
  6532. TRACE_ERROR(DecodeError)
  6533. TRACE_ERROR(FixupAltNameEntryError)
  6534. }
  6535. //+---------------------------------------------------------------------------
  6536. //
  6537. // Function: ChainFreeIssuerNameConstraintsInfo
  6538. //
  6539. // Synopsis: free the issuer name constraints info
  6540. //
  6541. //----------------------------------------------------------------------------
  6542. VOID WINAPI
  6543. ChainFreeIssuerNameConstraintsInfo (
  6544. IN OUT PCERT_NAME_CONSTRAINTS_INFO pInfo
  6545. )
  6546. {
  6547. PCERT_GENERAL_SUBTREE pSubtree;
  6548. DWORD cSubtree;
  6549. if (NULL == pInfo)
  6550. return;
  6551. cSubtree = pInfo->cPermittedSubtree;
  6552. pSubtree = pInfo->rgPermittedSubtree;
  6553. for ( ; 0 < cSubtree; cSubtree--, pSubtree++)
  6554. ChainFreeNameConstraintsAltNameEntryFixup(FALSE, &pSubtree->Base);
  6555. cSubtree = pInfo->cExcludedSubtree;
  6556. pSubtree = pInfo->rgExcludedSubtree;
  6557. for ( ; 0 < cSubtree; cSubtree--, pSubtree++)
  6558. ChainFreeNameConstraintsAltNameEntryFixup(FALSE, &pSubtree->Base);
  6559. PkiFree(pInfo);
  6560. }
  6561. //+---------------------------------------------------------------------------
  6562. //
  6563. // Function: ChainGetSubjectNameConstraintsInfo
  6564. //
  6565. // Synopsis: alloc and return the subject name constraints info.
  6566. //
  6567. //----------------------------------------------------------------------------
  6568. VOID WINAPI
  6569. ChainGetSubjectNameConstraintsInfo (
  6570. IN PCCERT_CONTEXT pCertContext,
  6571. IN OUT PCHAIN_SUBJECT_NAME_CONSTRAINTS_INFO pSubjectInfo
  6572. )
  6573. {
  6574. PCERT_EXTENSION pExt;
  6575. BOOL fHasEmailAltNameEntry = FALSE;
  6576. pExt = CertFindExtension(
  6577. szOID_SUBJECT_ALT_NAME2,
  6578. pCertContext->pCertInfo->cExtension,
  6579. pCertContext->pCertInfo->rgExtension
  6580. );
  6581. if (NULL == pExt) {
  6582. pExt = CertFindExtension(
  6583. szOID_SUBJECT_ALT_NAME,
  6584. pCertContext->pCertInfo->cExtension,
  6585. pCertContext->pCertInfo->rgExtension
  6586. );
  6587. }
  6588. if (pExt) {
  6589. PCERT_ALT_NAME_INFO pAltNameInfo;
  6590. pAltNameInfo = (PCERT_ALT_NAME_INFO) ChainAllocAndDecodeObject(
  6591. X509_ALTERNATE_NAME,
  6592. pExt->Value.pbData,
  6593. pExt->Value.cbData
  6594. );
  6595. if (NULL == pAltNameInfo)
  6596. pSubjectInfo->fInvalid = TRUE;
  6597. else {
  6598. DWORD cEntry;
  6599. PCERT_ALT_NAME_ENTRY pEntry;
  6600. pSubjectInfo->pAltNameInfo = pAltNameInfo;
  6601. // Fixup all the AltName entries
  6602. // Note, even for an error we need to fixup all the entries.
  6603. // ChainFreeSubjectNameConstraintsInfo iterates through all
  6604. // the entries.
  6605. cEntry = pAltNameInfo->cAltEntry;
  6606. pEntry = pAltNameInfo->rgAltEntry;
  6607. for ( ; 0 < cEntry; cEntry--, pEntry++) {
  6608. if (CERT_ALT_NAME_RFC822_NAME == pEntry->dwAltNameChoice)
  6609. fHasEmailAltNameEntry = TRUE;
  6610. else if (CERT_ALT_NAME_DNS_NAME == pEntry->dwAltNameChoice)
  6611. pSubjectInfo->fHasDnsAltNameEntry = TRUE;
  6612. if (!ChainFixupNameConstraintsAltNameEntry(TRUE, pEntry))
  6613. pSubjectInfo->fInvalid = TRUE;
  6614. }
  6615. }
  6616. }
  6617. if (!ChainAllocDecodeAndFixupNameConstraintsDirectoryName(
  6618. &pCertContext->pCertInfo->Subject,
  6619. &pSubjectInfo->pUnicodeNameInfo
  6620. ))
  6621. pSubjectInfo->fInvalid = TRUE;
  6622. if (!fHasEmailAltNameEntry && pSubjectInfo->pUnicodeNameInfo) {
  6623. DWORD cRDN;
  6624. PCERT_RDN pRDN;
  6625. cRDN = pSubjectInfo->pUnicodeNameInfo->cRDN;
  6626. pRDN = pSubjectInfo->pUnicodeNameInfo->rgRDN;
  6627. for ( ; cRDN > 0; cRDN--, pRDN++) {
  6628. DWORD cAttr = pRDN->cRDNAttr;
  6629. PCERT_RDN_ATTR pAttr = pRDN->rgRDNAttr;
  6630. for ( ; cAttr > 0; cAttr--, pAttr++) {
  6631. if (!IS_CERT_RDN_CHAR_STRING(pAttr->dwValueType))
  6632. continue;
  6633. if (0 == strcmp(pAttr->pszObjId, szOID_RSA_emailAddr)) {
  6634. pSubjectInfo->pEmailAttr = pAttr;
  6635. break;
  6636. }
  6637. }
  6638. if (cAttr > 0)
  6639. break;
  6640. }
  6641. }
  6642. }
  6643. //+---------------------------------------------------------------------------
  6644. //
  6645. // Function: ChainFreeSubjectNameConstraintsInfo
  6646. //
  6647. // Synopsis: free the subject name constraints info
  6648. //
  6649. //----------------------------------------------------------------------------
  6650. VOID WINAPI
  6651. ChainFreeSubjectNameConstraintsInfo (
  6652. IN OUT PCHAIN_SUBJECT_NAME_CONSTRAINTS_INFO pSubjectInfo
  6653. )
  6654. {
  6655. PCERT_ALT_NAME_INFO pAltNameInfo;
  6656. pAltNameInfo = pSubjectInfo->pAltNameInfo;
  6657. if (pAltNameInfo) {
  6658. DWORD cEntry;
  6659. PCERT_ALT_NAME_ENTRY pEntry;
  6660. cEntry = pAltNameInfo->cAltEntry;
  6661. pEntry = pAltNameInfo->rgAltEntry;
  6662. for ( ; 0 < cEntry; cEntry--, pEntry++)
  6663. ChainFreeNameConstraintsAltNameEntryFixup(TRUE, pEntry);
  6664. PkiFree(pAltNameInfo);
  6665. }
  6666. PkiFree(pSubjectInfo->pUnicodeNameInfo);
  6667. }
  6668. //+---------------------------------------------------------------------------
  6669. //
  6670. // Function: ChainCompareNameConstraintsDirectoryName
  6671. //
  6672. // Synopsis: returns TRUE if all the subtree RDN attributes match
  6673. // the RDN attributes at the beginning of the subject
  6674. // directory name. A case insensitive match
  6675. // is performed on each RDN attribute that is a string type.
  6676. // A binary compare is performed on nonstring attribute types.
  6677. //
  6678. // The OIDs of the RDN attributes must match.
  6679. //
  6680. // Note, a NULL subtree or a subtree with no RDNs matches
  6681. // any subject directory name. Also, an empty subtree
  6682. // RDN attribute matches any subject attribute.
  6683. //
  6684. //----------------------------------------------------------------------------
  6685. BOOL WINAPI
  6686. ChainCompareNameConstraintsDirectoryName(
  6687. IN PCERT_NAME_INFO pSubjectInfo,
  6688. IN PCERT_NAME_INFO pSubtreeInfo
  6689. )
  6690. {
  6691. DWORD cSubjectRDN;
  6692. PCERT_RDN pSubjectRDN;
  6693. DWORD cSubtreeRDN;
  6694. PCERT_RDN pSubtreeRDN;
  6695. if (NULL == pSubtreeInfo || 0 == pSubtreeInfo->cRDN)
  6696. // Match any subject
  6697. return TRUE;
  6698. if (NULL == pSubjectInfo)
  6699. return FALSE;
  6700. cSubjectRDN = pSubjectInfo->cRDN;
  6701. cSubtreeRDN = pSubtreeInfo->cRDN;
  6702. if (cSubtreeRDN > cSubjectRDN)
  6703. return FALSE;
  6704. pSubjectRDN = pSubjectInfo->rgRDN;
  6705. pSubtreeRDN = pSubtreeInfo->rgRDN;
  6706. for ( ; cSubtreeRDN > 0; cSubtreeRDN--, pSubtreeRDN++, pSubjectRDN++) {
  6707. DWORD cSubjectAttr = pSubjectRDN->cRDNAttr;
  6708. PCERT_RDN_ATTR pSubjectAttr = pSubjectRDN->rgRDNAttr;
  6709. DWORD cSubtreeAttr = pSubtreeRDN->cRDNAttr;
  6710. PCERT_RDN_ATTR pSubtreeAttr = pSubtreeRDN->rgRDNAttr;
  6711. if (1 < cSubtreeRDN) {
  6712. if (cSubtreeAttr != cSubjectAttr)
  6713. return FALSE;
  6714. } else {
  6715. if (cSubtreeAttr > cSubjectAttr)
  6716. return FALSE;
  6717. }
  6718. for ( ; cSubtreeAttr > 0; cSubtreeAttr--, pSubtreeAttr++, pSubjectAttr++) {
  6719. if (0 != strcmp(pSubtreeAttr->pszObjId, pSubjectAttr->pszObjId))
  6720. return FALSE;
  6721. if (IS_CERT_RDN_CHAR_STRING(pSubtreeAttr->dwValueType) !=
  6722. IS_CERT_RDN_CHAR_STRING(pSubjectAttr->dwValueType))
  6723. return FALSE;
  6724. if (IS_CERT_RDN_CHAR_STRING(pSubtreeAttr->dwValueType)) {
  6725. DWORD cchSubtree = pSubtreeAttr->Value.cbData / sizeof(WCHAR);
  6726. if (0 == cchSubtree) {
  6727. // Match any attribute
  6728. ;
  6729. } else if (cchSubtree !=
  6730. pSubjectAttr->Value.cbData / sizeof(WCHAR)) {
  6731. // For X.509, must match entire attribute
  6732. return FALSE;
  6733. } else if (!ChainIsRightStringInString(
  6734. (LPCWSTR) pSubtreeAttr->Value.pbData,
  6735. cchSubtree,
  6736. (LPCWSTR) pSubjectAttr->Value.pbData,
  6737. cchSubtree
  6738. )) {
  6739. return FALSE;
  6740. }
  6741. } else {
  6742. if (pSubtreeAttr->Value.cbData != pSubjectAttr->Value.cbData)
  6743. return FALSE;
  6744. if (0 != memcmp(pSubtreeAttr->Value.pbData,
  6745. pSubjectAttr->Value.pbData,
  6746. pSubtreeAttr->Value.cbData
  6747. ))
  6748. return FALSE;
  6749. }
  6750. }
  6751. }
  6752. return TRUE;
  6753. }
  6754. //+---------------------------------------------------------------------------
  6755. //
  6756. // Function: ChainCompareNameConstraintsIPAddress
  6757. //
  6758. // Synopsis: returns TRUE if the subject IP address is within the IP
  6759. // range specified by subtree IP address and mask.
  6760. //
  6761. // The subtree IP contains the octet bytes for both the
  6762. // IP address and its mask.
  6763. //
  6764. // For IPv4, there are 4 address bytes followed by 4 mask bytes.
  6765. // See RFC 2459 for more details.
  6766. //
  6767. // Here's my interpretation:
  6768. //
  6769. // For a match: SubtreeIPAddr == (SubjectIPAddr & SubtreeIPMask)
  6770. //
  6771. //----------------------------------------------------------------------------
  6772. BOOL WINAPI
  6773. ChainCompareNameConstraintsIPAddress(
  6774. IN PCRYPT_DATA_BLOB pSubjectIPAddress,
  6775. IN PCRYPT_DATA_BLOB pSubtreeIPAddress
  6776. )
  6777. {
  6778. BYTE *pbSubject = pSubjectIPAddress->pbData;
  6779. DWORD cbSubject = pSubjectIPAddress->cbData;
  6780. BYTE *pbSubtree = pSubtreeIPAddress->pbData;
  6781. DWORD cbSubtree = pSubtreeIPAddress->cbData;
  6782. BYTE *pbSubtreeMask = pbSubtree + cbSubject;
  6783. DWORD i;
  6784. if (0 == cbSubtree)
  6785. // Match any IP address
  6786. return TRUE;
  6787. // Only compare if the number of subtree bytes is twice the length of
  6788. // the subject. Second half contains the mask.
  6789. if (cbSubtree != 2 * cbSubject)
  6790. return FALSE;
  6791. for (i = 0; i < cbSubject; i++) {
  6792. if (pbSubtree[i] != (pbSubject[i] & pbSubtreeMask[i]))
  6793. return FALSE;
  6794. }
  6795. return TRUE;
  6796. }
  6797. //+---------------------------------------------------------------------------
  6798. //
  6799. // Function: ChainCompareNameConstraintsUPN
  6800. //
  6801. // Synopsis: returns TRUE if the subtree UPN string matches the right most
  6802. // characters of the subject's UPN doing a case insensitive
  6803. // match.
  6804. //
  6805. // Note, the Value.pbData points to the decoded PCERT_NAME_VALUE.
  6806. //
  6807. //----------------------------------------------------------------------------
  6808. BOOL WINAPI
  6809. ChainCompareNameConstraintsUPN(
  6810. IN PCRYPT_OBJID_BLOB pSubjectValue,
  6811. IN PCRYPT_OBJID_BLOB pSubtreeValue
  6812. )
  6813. {
  6814. // The UPN's Value.pbData is used to point to the decoded
  6815. // PCERT_NAME_VALUE
  6816. BOOL fCompare;
  6817. PCERT_NAME_VALUE pSubjectNameValue;
  6818. PCERT_NAME_VALUE pSubtreeNameValue;
  6819. pSubjectNameValue =
  6820. (PCERT_NAME_VALUE) pSubjectValue->pbData;
  6821. pSubtreeNameValue =
  6822. (PCERT_NAME_VALUE) pSubtreeValue->pbData;
  6823. if (pSubjectNameValue && pSubtreeNameValue)
  6824. fCompare = ChainIsRightStringInString(
  6825. (LPCWSTR) pSubtreeNameValue->Value.pbData,
  6826. pSubtreeNameValue->Value.cbData / sizeof(WCHAR),
  6827. (LPCWSTR) pSubjectNameValue->Value.pbData,
  6828. pSubjectNameValue->Value.cbData / sizeof(WCHAR)
  6829. );
  6830. else
  6831. fCompare = FALSE;
  6832. return fCompare;
  6833. }
  6834. //+---------------------------------------------------------------------------
  6835. //
  6836. // Function: ChainCalculateNameConstraintsSubtreeErrorStatusForAltNameEntry
  6837. //
  6838. // Synopsis: calculates the name constraints error status by seeing if
  6839. // the subject AltName entry matches any subtree AltName entry.
  6840. //
  6841. //----------------------------------------------------------------------------
  6842. DWORD WINAPI
  6843. ChainCalculateNameConstraintsSubtreeErrorStatusForAltNameEntry(
  6844. IN PCERT_ALT_NAME_ENTRY pSubjectEntry,
  6845. IN BOOL fExcludedSubtree,
  6846. IN DWORD cSubtree,
  6847. IN PCERT_GENERAL_SUBTREE pSubtree,
  6848. IN OUT LPWSTR *ppwszExtErrorInfo
  6849. )
  6850. {
  6851. DWORD dwErrorStatus = 0;
  6852. BOOL fHasSubtreeEntry = FALSE;
  6853. DWORD dwAltNameChoice = pSubjectEntry->dwAltNameChoice;
  6854. DWORD i;
  6855. for (i = 0; i < cSubtree; i++, pSubtree++) {
  6856. PCERT_ALT_NAME_ENTRY pSubtreeEntry;
  6857. BOOL fCompare;
  6858. if (0 != pSubtree->dwMinimum || pSubtree->fMaximum) {
  6859. dwErrorStatus |= CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
  6860. ChainFormatAndAppendExtendedErrorInfo(
  6861. ppwszExtErrorInfo,
  6862. fExcludedSubtree ?
  6863. IDS_NOT_SUPPORTED_EXCLUDED_NAME_CONSTRAINT :
  6864. IDS_NOT_SUPPORTED_PERMITTED_NAME_CONSTRAINT,
  6865. i + 1
  6866. );
  6867. continue;
  6868. }
  6869. pSubtreeEntry = &pSubtree->Base;
  6870. if (dwAltNameChoice != pSubtreeEntry->dwAltNameChoice)
  6871. continue;
  6872. fCompare = FALSE;
  6873. switch (dwAltNameChoice) {
  6874. case CERT_ALT_NAME_OTHER_NAME:
  6875. // Only support the UPN OID
  6876. if (0 != strcmp(pSubtreeEntry->pOtherName->pszObjId,
  6877. szOID_NT_PRINCIPAL_NAME)) {
  6878. dwErrorStatus |=
  6879. CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
  6880. ChainFormatAndAppendExtendedErrorInfo(
  6881. ppwszExtErrorInfo,
  6882. fExcludedSubtree ?
  6883. IDS_NOT_SUPPORTED_EXCLUDED_NAME_CONSTRAINT :
  6884. IDS_NOT_SUPPORTED_PERMITTED_NAME_CONSTRAINT,
  6885. i + 1
  6886. );
  6887. } else {
  6888. assert(0 == strcmp(pSubjectEntry->pOtherName->pszObjId,
  6889. szOID_NT_PRINCIPAL_NAME));
  6890. fHasSubtreeEntry = TRUE;
  6891. fCompare = ChainCompareNameConstraintsUPN(
  6892. &pSubjectEntry->pOtherName->Value,
  6893. &pSubtreeEntry->pOtherName->Value
  6894. );
  6895. }
  6896. break;
  6897. case CERT_ALT_NAME_RFC822_NAME:
  6898. case CERT_ALT_NAME_DNS_NAME:
  6899. case CERT_ALT_NAME_URL:
  6900. fHasSubtreeEntry = TRUE;
  6901. // The directory name's BLOB choice is used to contain both
  6902. // the pointer to and length of the string
  6903. fCompare = ChainIsRightStringInString(
  6904. (LPCWSTR) pSubtreeEntry->DirectoryName.pbData,
  6905. pSubtreeEntry->DirectoryName.cbData / sizeof(WCHAR),
  6906. (LPCWSTR) pSubjectEntry->DirectoryName.pbData,
  6907. pSubjectEntry->DirectoryName.cbData / sizeof(WCHAR)
  6908. );
  6909. break;
  6910. case CERT_ALT_NAME_DIRECTORY_NAME:
  6911. fHasSubtreeEntry = TRUE;
  6912. fCompare = ChainCompareNameConstraintsDirectoryName(
  6913. (PCERT_NAME_INFO) pSubjectEntry->DirectoryName.pbData,
  6914. (PCERT_NAME_INFO) pSubtreeEntry->DirectoryName.pbData
  6915. );
  6916. break;
  6917. case CERT_ALT_NAME_IP_ADDRESS:
  6918. fHasSubtreeEntry = TRUE;
  6919. fCompare = ChainCompareNameConstraintsIPAddress(
  6920. &pSubjectEntry->IPAddress, &pSubtreeEntry->IPAddress);
  6921. break;
  6922. case CERT_ALT_NAME_X400_ADDRESS:
  6923. case CERT_ALT_NAME_EDI_PARTY_NAME:
  6924. case CERT_ALT_NAME_REGISTERED_ID:
  6925. default:
  6926. assert(0);
  6927. break;
  6928. }
  6929. if (fCompare) {
  6930. if (fExcludedSubtree) {
  6931. dwErrorStatus |= CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
  6932. ChainFormatAndAppendNameConstraintsAltNameEntryFixup(
  6933. ppwszExtErrorInfo,
  6934. pSubjectEntry,
  6935. IDS_EXCLUDED_ENTRY_NAME_CONSTRAINT,
  6936. i + 1
  6937. );
  6938. }
  6939. return dwErrorStatus;
  6940. }
  6941. }
  6942. if (!fExcludedSubtree) {
  6943. if (fHasSubtreeEntry) {
  6944. dwErrorStatus |= CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
  6945. ChainFormatAndAppendNameConstraintsAltNameEntryFixup(
  6946. ppwszExtErrorInfo,
  6947. pSubjectEntry,
  6948. IDS_NOT_PERMITTED_ENTRY_NAME_CONSTRAINT
  6949. );
  6950. } else {
  6951. dwErrorStatus |= CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT;
  6952. ChainFormatAndAppendNameConstraintsAltNameEntryFixup(
  6953. ppwszExtErrorInfo,
  6954. pSubjectEntry,
  6955. IDS_NOT_DEFINED_ENTRY_NAME_CONSTRAINT
  6956. );
  6957. }
  6958. }
  6959. return dwErrorStatus;
  6960. }
  6961. //+---------------------------------------------------------------------------
  6962. //
  6963. // Function: ChainCalculateNameConstraintsErrorStatusForAltNameEntry
  6964. //
  6965. // Synopsis: calculates the name constraints error status by seeing if
  6966. // the subject AltName entry matches either an excluded
  6967. // or permitted subtree AltName entry.
  6968. //
  6969. //----------------------------------------------------------------------------
  6970. DWORD WINAPI
  6971. ChainCalculateNameConstraintsErrorStatusForAltNameEntry(
  6972. IN PCERT_ALT_NAME_ENTRY pSubjectEntry,
  6973. IN PCERT_NAME_CONSTRAINTS_INFO pNameConstraintsInfo,
  6974. IN OUT LPWSTR *ppwszExtErrorInfo
  6975. )
  6976. {
  6977. DWORD dwErrorStatus;
  6978. dwErrorStatus =
  6979. ChainCalculateNameConstraintsSubtreeErrorStatusForAltNameEntry(
  6980. pSubjectEntry,
  6981. TRUE, // fExcludedSubtree
  6982. pNameConstraintsInfo->cExcludedSubtree,
  6983. pNameConstraintsInfo->rgExcludedSubtree,
  6984. ppwszExtErrorInfo
  6985. );
  6986. if (!(dwErrorStatus & CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT))
  6987. dwErrorStatus =
  6988. ChainCalculateNameConstraintsSubtreeErrorStatusForAltNameEntry(
  6989. pSubjectEntry,
  6990. FALSE, // fExcludedSubtree
  6991. pNameConstraintsInfo->cPermittedSubtree,
  6992. pNameConstraintsInfo->rgPermittedSubtree,
  6993. ppwszExtErrorInfo
  6994. );
  6995. return dwErrorStatus;
  6996. }
  6997. //+===========================================================================
  6998. // CCertIssuerList helper functions
  6999. //============================================================================
  7000. //+---------------------------------------------------------------------------
  7001. //
  7002. // Function: ChainCreateIssuerList
  7003. //
  7004. // Synopsis: create the issuer list object for the given subject
  7005. //
  7006. //----------------------------------------------------------------------------
  7007. BOOL WINAPI
  7008. ChainCreateIssuerList (
  7009. IN PCCHAINPATHOBJECT pSubject,
  7010. OUT PCCERTISSUERLIST* ppIssuerList
  7011. )
  7012. {
  7013. PCCERTISSUERLIST pIssuerList;
  7014. pIssuerList = new CCertIssuerList( pSubject );
  7015. if ( pIssuerList == NULL )
  7016. {
  7017. SetLastError( (DWORD) E_OUTOFMEMORY );
  7018. return( FALSE );
  7019. }
  7020. *ppIssuerList = pIssuerList;
  7021. return( TRUE );
  7022. }
  7023. //+---------------------------------------------------------------------------
  7024. //
  7025. // Function: ChainFreeIssuerList
  7026. //
  7027. // Synopsis: free the issuer list object
  7028. //
  7029. //----------------------------------------------------------------------------
  7030. VOID WINAPI
  7031. ChainFreeIssuerList (
  7032. IN PCCERTISSUERLIST pIssuerList
  7033. )
  7034. {
  7035. delete pIssuerList;
  7036. }
  7037. //+---------------------------------------------------------------------------
  7038. //
  7039. // Function: ChainFreeCtlIssuerData
  7040. //
  7041. // Synopsis: free CTL issuer data
  7042. //
  7043. //----------------------------------------------------------------------------
  7044. VOID WINAPI
  7045. ChainFreeCtlIssuerData (
  7046. IN PCTL_ISSUER_DATA pCtlIssuerData
  7047. )
  7048. {
  7049. if ( pCtlIssuerData->pTrustListInfo != NULL )
  7050. {
  7051. SSCtlFreeTrustListInfo( pCtlIssuerData->pTrustListInfo );
  7052. }
  7053. if ( pCtlIssuerData->pSSCtlObject != NULL )
  7054. {
  7055. pCtlIssuerData->pSSCtlObject->Release();
  7056. }
  7057. delete pCtlIssuerData;
  7058. }
  7059. //+===========================================================================
  7060. // INTERNAL_CERT_CHAIN_CONTEXT helper functions
  7061. //============================================================================
  7062. //+---------------------------------------------------------------------------
  7063. //
  7064. // Function: ChainAddRefInternalChainContext
  7065. //
  7066. // Synopsis: addref the internal chain context
  7067. //
  7068. //----------------------------------------------------------------------------
  7069. VOID WINAPI
  7070. ChainAddRefInternalChainContext (
  7071. IN PINTERNAL_CERT_CHAIN_CONTEXT pChainContext
  7072. )
  7073. {
  7074. InterlockedIncrement( &pChainContext->cRefs );
  7075. }
  7076. //+---------------------------------------------------------------------------
  7077. //
  7078. // Function: ChainReleaseInternalChainContext
  7079. //
  7080. // Synopsis: release the internal chain context
  7081. //
  7082. //----------------------------------------------------------------------------
  7083. VOID WINAPI
  7084. ChainReleaseInternalChainContext (
  7085. IN PINTERNAL_CERT_CHAIN_CONTEXT pChainContext
  7086. )
  7087. {
  7088. if ( InterlockedDecrement( &pChainContext->cRefs ) == 0 )
  7089. {
  7090. ChainFreeInternalChainContext( pChainContext );
  7091. }
  7092. }
  7093. //+---------------------------------------------------------------------------
  7094. //
  7095. // Function: ChainFreeInternalChainContext
  7096. //
  7097. // Synopsis: free the internal chain context
  7098. //
  7099. //----------------------------------------------------------------------------
  7100. VOID WINAPI
  7101. ChainFreeInternalChainContext (
  7102. IN PINTERNAL_CERT_CHAIN_CONTEXT pContext
  7103. )
  7104. {
  7105. PCERT_SIMPLE_CHAIN *ppChain;
  7106. DWORD cChain;
  7107. PINTERNAL_CERT_CHAIN_CONTEXT *ppLowerContext;
  7108. if (NULL == pContext)
  7109. return;
  7110. cChain = pContext->ChainContext.cChain;
  7111. ppChain = pContext->ChainContext.rgpChain;
  7112. for ( ; 0 < cChain; cChain--, ppChain++) {
  7113. PCERT_SIMPLE_CHAIN pChain;
  7114. DWORD cElement;
  7115. PCERT_CHAIN_ELEMENT *ppElement;
  7116. pChain = *ppChain;
  7117. if (NULL == pChain)
  7118. continue;
  7119. if (pChain->pTrustListInfo)
  7120. SSCtlFreeTrustListInfo(pChain->pTrustListInfo);
  7121. cElement = pChain->cElement;
  7122. ppElement = pChain->rgpElement;
  7123. for ( ; 0 < cElement; cElement--, ppElement++) {
  7124. PCERT_CHAIN_ELEMENT pElement;
  7125. pElement = *ppElement;
  7126. if (NULL == pElement)
  7127. continue;
  7128. if (pElement->pRevocationInfo) {
  7129. PCERT_REVOCATION_CRL_INFO pCrlInfo =
  7130. pElement->pRevocationInfo->pCrlInfo;
  7131. if (pCrlInfo) {
  7132. if (pCrlInfo->pBaseCrlContext)
  7133. CertFreeCRLContext(pCrlInfo->pBaseCrlContext);
  7134. if (pCrlInfo->pDeltaCrlContext)
  7135. CertFreeCRLContext(pCrlInfo->pDeltaCrlContext);
  7136. delete pCrlInfo;
  7137. }
  7138. delete pElement->pRevocationInfo;
  7139. }
  7140. if (pElement->pCertContext)
  7141. CertFreeCertificateContext(pElement->pCertContext);
  7142. ChainFreeUsage(pElement->pIssuanceUsage);
  7143. ChainFreeUsage(pElement->pApplicationUsage);
  7144. if (pElement->pwszExtendedErrorInfo)
  7145. PkiFree((LPWSTR) pElement->pwszExtendedErrorInfo);
  7146. }
  7147. }
  7148. ppLowerContext = (PINTERNAL_CERT_CHAIN_CONTEXT*)
  7149. pContext->ChainContext.rgpLowerQualityChainContext;
  7150. if (ppLowerContext) {
  7151. DWORD cLowerContext;
  7152. DWORD i;
  7153. cLowerContext = pContext->ChainContext.cLowerQualityChainContext;
  7154. for (i = 0; i < cLowerContext; i++)
  7155. ChainReleaseInternalChainContext(ppLowerContext[i]);
  7156. delete ppLowerContext;
  7157. }
  7158. PkiFree(pContext);
  7159. }
  7160. //+---------------------------------------------------------------------------
  7161. //
  7162. // Function: ChainUpdateEndEntityCertContext
  7163. //
  7164. // Synopsis: update the end entity cert context in the chain context
  7165. //
  7166. //----------------------------------------------------------------------------
  7167. VOID
  7168. ChainUpdateEndEntityCertContext(
  7169. IN OUT PINTERNAL_CERT_CHAIN_CONTEXT pChainContext,
  7170. IN OUT PCCERT_CONTEXT pEndCertContext
  7171. )
  7172. {
  7173. PCCERT_CONTEXT pCertContext =
  7174. pChainContext->ChainContext.rgpChain[0]->rgpElement[0]->pCertContext;
  7175. if (pCertContext == pEndCertContext)
  7176. return;
  7177. pChainContext->ChainContext.rgpChain[0]->rgpElement[0]->pCertContext =
  7178. pEndCertContext;
  7179. {
  7180. DWORD cbData;
  7181. DWORD cbEndData;
  7182. // If the chain context's end context has the public key parameter
  7183. // property and the end context passed in to CertGetCertificateChain
  7184. // doesn't, then copy the public key parameter property.
  7185. if (CertGetCertificateContextProperty(
  7186. pCertContext,
  7187. CERT_PUBKEY_ALG_PARA_PROP_ID,
  7188. NULL, // pvData
  7189. &cbData) && 0 < cbData &&
  7190. !CertGetCertificateContextProperty(
  7191. pEndCertContext,
  7192. CERT_PUBKEY_ALG_PARA_PROP_ID,
  7193. NULL, // pvData
  7194. &cbEndData))
  7195. {
  7196. BYTE *pbData;
  7197. __try {
  7198. pbData = (BYTE *) _alloca(cbData);
  7199. } __except(EXCEPTION_EXECUTE_HANDLER) {
  7200. pbData = NULL;
  7201. }
  7202. if (pbData)
  7203. {
  7204. if (CertGetCertificateContextProperty(
  7205. pCertContext,
  7206. CERT_PUBKEY_ALG_PARA_PROP_ID,
  7207. pbData,
  7208. &cbData))
  7209. {
  7210. CRYPT_DATA_BLOB Para;
  7211. Para.pbData = pbData;
  7212. Para.cbData = cbData;
  7213. CertSetCertificateContextProperty(
  7214. pEndCertContext,
  7215. CERT_PUBKEY_ALG_PARA_PROP_ID,
  7216. CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG,
  7217. &Para
  7218. );
  7219. }
  7220. }
  7221. }
  7222. }
  7223. CertDuplicateCertificateContext(pEndCertContext);
  7224. CertFreeCertificateContext(pCertContext);
  7225. }
  7226. //+===========================================================================
  7227. // CERT_REVOCATION_INFO helper functions
  7228. //============================================================================
  7229. //+---------------------------------------------------------------------------
  7230. //
  7231. // Function: ChainUpdateRevocationInfo
  7232. //
  7233. // Synopsis: update the revocation information on the element
  7234. //
  7235. //----------------------------------------------------------------------------
  7236. VOID WINAPI
  7237. ChainUpdateRevocationInfo (
  7238. IN PCERT_REVOCATION_STATUS pRevStatus,
  7239. IN OUT PCERT_REVOCATION_INFO pRevocationInfo,
  7240. IN OUT PCERT_TRUST_STATUS pTrustStatus
  7241. )
  7242. {
  7243. CertPerfIncrementChainRevocationCount();
  7244. if (ERROR_SUCCESS == pRevStatus->dwError) {
  7245. ;
  7246. } else if (CRYPT_E_REVOKED == pRevStatus->dwError) {
  7247. pTrustStatus->dwErrorStatus |= CERT_TRUST_IS_REVOKED;
  7248. CertPerfIncrementChainRevokedCount();
  7249. } else {
  7250. pTrustStatus->dwErrorStatus |= CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
  7251. if (CRYPT_E_NO_REVOCATION_CHECK == pRevStatus->dwError) {
  7252. CertPerfIncrementChainNoRevocationCheckCount();
  7253. } else {
  7254. pTrustStatus->dwErrorStatus |= CERT_TRUST_IS_OFFLINE_REVOCATION;
  7255. CertPerfIncrementChainRevocationOfflineCount();
  7256. }
  7257. }
  7258. pRevocationInfo->cbSize = sizeof(CERT_REVOCATION_INFO);
  7259. pRevocationInfo->dwRevocationResult = pRevStatus->dwError;
  7260. pRevocationInfo->fHasFreshnessTime = pRevStatus->fHasFreshnessTime;
  7261. pRevocationInfo->dwFreshnessTime = pRevStatus->dwFreshnessTime;
  7262. }
  7263. //+===========================================================================
  7264. // CCertChainEngine helper functions
  7265. //============================================================================
  7266. //+---------------------------------------------------------------------------
  7267. //
  7268. // Function: ChainCreateWorldStore
  7269. //
  7270. // Synopsis: create the world store
  7271. //
  7272. //----------------------------------------------------------------------------
  7273. BOOL WINAPI
  7274. ChainCreateWorldStore (
  7275. IN HCERTSTORE hRoot,
  7276. IN HCERTSTORE hCA,
  7277. IN DWORD cAdditionalStore,
  7278. IN HCERTSTORE* rghAdditionalStore,
  7279. IN DWORD dwStoreFlags,
  7280. OUT HCERTSTORE* phWorld
  7281. )
  7282. {
  7283. BOOL fResult;
  7284. HCERTSTORE hWorld;
  7285. HCERTSTORE hStore;
  7286. DWORD cCount;
  7287. hWorld = CertOpenStore(
  7288. CERT_STORE_PROV_COLLECTION,
  7289. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7290. NULL,
  7291. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  7292. NULL
  7293. );
  7294. if ( hWorld == NULL )
  7295. {
  7296. return( FALSE );
  7297. }
  7298. fResult = CertAddStoreToCollection( hWorld, hRoot, 0, 0 );
  7299. for ( cCount = 0;
  7300. ( cCount < cAdditionalStore ) && ( fResult == TRUE );
  7301. cCount++ )
  7302. {
  7303. fResult = CertAddStoreToCollection(
  7304. hWorld,
  7305. rghAdditionalStore[ cCount ],
  7306. 0,
  7307. 0
  7308. );
  7309. }
  7310. dwStoreFlags |=
  7311. CERT_STORE_MAXIMUM_ALLOWED_FLAG | CERT_STORE_SHARE_CONTEXT_FLAG;
  7312. if ( fResult == TRUE )
  7313. {
  7314. hStore = CertOpenStore(
  7315. CERT_STORE_PROV_SYSTEM_W,
  7316. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7317. NULL,
  7318. dwStoreFlags,
  7319. L"trust"
  7320. );
  7321. if ( hStore != NULL )
  7322. {
  7323. fResult = CertAddStoreToCollection( hWorld, hStore, 0, 0 );
  7324. CertCloseStore( hStore, 0 );
  7325. }
  7326. else
  7327. {
  7328. fResult = FALSE;
  7329. }
  7330. }
  7331. if ( fResult == TRUE )
  7332. {
  7333. if ( hCA != NULL )
  7334. {
  7335. fResult = CertAddStoreToCollection( hWorld, hCA, 0, 0 );
  7336. }
  7337. else
  7338. {
  7339. fResult = FALSE;
  7340. }
  7341. }
  7342. if ( fResult == TRUE )
  7343. {
  7344. hStore = CertOpenStore(
  7345. CERT_STORE_PROV_SYSTEM_W,
  7346. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7347. NULL,
  7348. dwStoreFlags,
  7349. L"my"
  7350. );
  7351. if ( hStore != NULL )
  7352. {
  7353. fResult = CertAddStoreToCollection( hWorld, hStore, 0, 0 );
  7354. CertCloseStore( hStore, 0 );
  7355. }
  7356. else
  7357. {
  7358. fResult = FALSE;
  7359. }
  7360. }
  7361. if ( fResult == TRUE )
  7362. {
  7363. *phWorld = hWorld;
  7364. }
  7365. else
  7366. {
  7367. CertCloseStore( hWorld, 0 );
  7368. }
  7369. return( fResult );
  7370. }
  7371. //+---------------------------------------------------------------------------
  7372. //
  7373. // Function: ChainCreateEngineStore
  7374. //
  7375. // Synopsis: create the engine store and the change event handle
  7376. //
  7377. //----------------------------------------------------------------------------
  7378. BOOL WINAPI
  7379. ChainCreateEngineStore (
  7380. IN HCERTSTORE hRootStore,
  7381. IN HCERTSTORE hTrustStore,
  7382. IN HCERTSTORE hOtherStore,
  7383. IN BOOL fDefaultEngine,
  7384. IN DWORD dwFlags,
  7385. OUT HCERTSTORE* phEngineStore,
  7386. OUT HANDLE* phEngineStoreChangeEvent
  7387. )
  7388. {
  7389. BOOL fResult = TRUE;
  7390. HCERTSTORE hEngineStore;
  7391. HANDLE hEvent;
  7392. hEngineStore = CertOpenStore(
  7393. CERT_STORE_PROV_COLLECTION,
  7394. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7395. NULL,
  7396. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  7397. NULL
  7398. );
  7399. hEvent = CreateEventA( NULL, FALSE, FALSE, NULL );
  7400. if ( ( hEngineStore == NULL ) || ( hEvent == NULL ) )
  7401. {
  7402. fResult = FALSE;
  7403. }
  7404. if ( fResult == TRUE )
  7405. {
  7406. fResult = CertAddStoreToCollection( hEngineStore, hRootStore, 0, 0 );
  7407. }
  7408. if ( fResult == TRUE )
  7409. {
  7410. fResult = CertAddStoreToCollection( hEngineStore, hTrustStore, 0, 0 );
  7411. }
  7412. if ( fResult == TRUE )
  7413. {
  7414. fResult = CertAddStoreToCollection( hEngineStore, hOtherStore, 0, 0 );
  7415. }
  7416. if ( ( fResult == TRUE ) &&
  7417. ( dwFlags & CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE ) )
  7418. {
  7419. // Someday support a let me know about errors flag
  7420. CertControlStore(
  7421. hEngineStore,
  7422. CERT_STORE_CTRL_INHIBIT_DUPLICATE_HANDLE_FLAG,
  7423. CERT_STORE_CTRL_NOTIFY_CHANGE,
  7424. &hEvent
  7425. );
  7426. }
  7427. if ( fResult == TRUE )
  7428. {
  7429. *phEngineStore = hEngineStore;
  7430. *phEngineStoreChangeEvent = hEvent;
  7431. }
  7432. else
  7433. {
  7434. if ( hEngineStore != NULL )
  7435. {
  7436. CertCloseStore( hEngineStore, 0 );
  7437. }
  7438. if ( hEvent != NULL )
  7439. {
  7440. CloseHandle( hEvent );
  7441. }
  7442. }
  7443. return( fResult );
  7444. }
  7445. //+---------------------------------------------------------------------------
  7446. //
  7447. // Function: ChainIsProperRestrictedRoot
  7448. //
  7449. // Synopsis: check to see if this restricted root store is a proper subset
  7450. // of the real root store
  7451. //
  7452. //----------------------------------------------------------------------------
  7453. BOOL WINAPI
  7454. ChainIsProperRestrictedRoot (
  7455. IN HCERTSTORE hRealRoot,
  7456. IN HCERTSTORE hRestrictedRoot
  7457. )
  7458. {
  7459. PCCERT_CONTEXT pCertContext = NULL;
  7460. PCCERT_CONTEXT pFound = NULL;
  7461. DWORD cbData = CHAINHASHLEN;
  7462. BYTE CertificateHash[ CHAINHASHLEN ];
  7463. CRYPT_HASH_BLOB HashBlob;
  7464. HashBlob.cbData = cbData;
  7465. HashBlob.pbData = CertificateHash;
  7466. while ( ( pCertContext = CertEnumCertificatesInStore(
  7467. hRestrictedRoot,
  7468. pCertContext
  7469. ) ) != NULL )
  7470. {
  7471. if ( CertGetCertificateContextProperty(
  7472. pCertContext,
  7473. CERT_MD5_HASH_PROP_ID,
  7474. CertificateHash,
  7475. &cbData
  7476. ) == TRUE )
  7477. {
  7478. pFound = CertFindCertificateInStore(
  7479. hRealRoot,
  7480. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7481. 0,
  7482. CERT_FIND_MD5_HASH,
  7483. &HashBlob,
  7484. NULL
  7485. );
  7486. if ( pFound == NULL )
  7487. {
  7488. CertFreeCertificateContext( pCertContext );
  7489. return( FALSE );
  7490. }
  7491. else
  7492. {
  7493. CertFreeCertificateContext( pFound );
  7494. }
  7495. }
  7496. }
  7497. return( TRUE );
  7498. }
  7499. //+---------------------------------------------------------------------------
  7500. //
  7501. // Function: ChainCreateCollectionIncludingCtlCertificates
  7502. //
  7503. // Synopsis: create a collection which includes the source store hStore and
  7504. // any CTL certificates from it
  7505. //
  7506. //----------------------------------------------------------------------------
  7507. BOOL WINAPI
  7508. ChainCreateCollectionIncludingCtlCertificates (
  7509. IN HCERTSTORE hStore,
  7510. OUT HCERTSTORE* phCollection
  7511. )
  7512. {
  7513. BOOL fResult = FALSE;
  7514. HCERTSTORE hCollection;
  7515. PCCTL_CONTEXT pCtlContext = NULL;
  7516. HCERTSTORE hCtlStore;
  7517. hCollection = CertOpenStore(
  7518. CERT_STORE_PROV_COLLECTION,
  7519. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7520. NULL,
  7521. CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
  7522. NULL
  7523. );
  7524. if ( hCollection == NULL )
  7525. {
  7526. return( FALSE );
  7527. }
  7528. fResult = CertAddStoreToCollection( hCollection, hStore, 0, 0 );
  7529. while ( ( fResult == TRUE ) &&
  7530. ( ( pCtlContext = CertEnumCTLsInStore(
  7531. hStore,
  7532. pCtlContext
  7533. ) ) != NULL ) )
  7534. {
  7535. hCtlStore = CertOpenStore(
  7536. CERT_STORE_PROV_MSG,
  7537. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7538. NULL,
  7539. 0,
  7540. pCtlContext->hCryptMsg
  7541. );
  7542. if ( hCtlStore != NULL )
  7543. {
  7544. fResult = CertAddStoreToCollection(
  7545. hCollection,
  7546. hCtlStore,
  7547. 0,
  7548. 0
  7549. );
  7550. CertCloseStore( hCtlStore, 0 );
  7551. }
  7552. }
  7553. if ( fResult == TRUE )
  7554. {
  7555. *phCollection = hCollection;
  7556. }
  7557. else
  7558. {
  7559. CertCloseStore( hCollection, 0 );
  7560. }
  7561. return( fResult );
  7562. }
  7563. //+---------------------------------------------------------------------------
  7564. //
  7565. // Function: ChainCopyToCAStore
  7566. //
  7567. // Synopsis: copies the hStore to the m_hCAStore of the engine
  7568. //
  7569. //----------------------------------------------------------------------------
  7570. BOOL WINAPI
  7571. ChainCopyToCAStore (
  7572. PCCERTCHAINENGINE pChainEngine,
  7573. HCERTSTORE hStore
  7574. )
  7575. {
  7576. PCCERT_CONTEXT pCertContext = NULL;
  7577. if ( pChainEngine->CAStore() == NULL )
  7578. {
  7579. SetLastError( ERROR_INVALID_PARAMETER );
  7580. return( FALSE );
  7581. }
  7582. while ( ( pCertContext = CertEnumCertificatesInStore(
  7583. hStore,
  7584. pCertContext
  7585. ) ) != NULL )
  7586. {
  7587. // Don't add self signed certificates to the CA store
  7588. if (!CertCompareCertificateName(
  7589. pCertContext->dwCertEncodingType,
  7590. &pCertContext->pCertInfo->Subject,
  7591. &pCertContext->pCertInfo->Issuer
  7592. ))
  7593. {
  7594. CertAddCertificateContextToStore(
  7595. pChainEngine->CAStore(),
  7596. pCertContext,
  7597. CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES,
  7598. NULL
  7599. );
  7600. }
  7601. }
  7602. return( TRUE );
  7603. }
  7604. //+===========================================================================
  7605. // URL helper functions
  7606. //============================================================================
  7607. //+---------------------------------------------------------------------------
  7608. //
  7609. // Function: ChainGetObjectUrl
  7610. //
  7611. // Synopsis: thunk to CryptGetObjectUrl in cryptnet.dll
  7612. //
  7613. //----------------------------------------------------------------------------
  7614. BOOL WINAPI
  7615. ChainGetObjectUrl (
  7616. IN LPCSTR pszUrlOid,
  7617. IN LPVOID pvPara,
  7618. IN DWORD dwFlags,
  7619. OUT OPTIONAL PCRYPT_URL_ARRAY pUrlArray,
  7620. IN OUT DWORD* pcbUrlArray,
  7621. OUT OPTIONAL PCRYPT_URL_INFO pUrlInfo,
  7622. IN OUT OPTIONAL DWORD* pcbUrlInfo,
  7623. IN OPTIONAL LPVOID pvReserved
  7624. )
  7625. {
  7626. BOOL fResult = FALSE;
  7627. HMODULE hModule;
  7628. PFN_GETOBJECTURL pfn = NULL;
  7629. hModule = ChainGetCryptnetModule();
  7630. if ( hModule != NULL )
  7631. {
  7632. pfn = (PFN_GETOBJECTURL)GetProcAddress( hModule, "CryptGetObjectUrl" );
  7633. }
  7634. if ( pfn != NULL )
  7635. {
  7636. fResult = ( *pfn )(
  7637. pszUrlOid,
  7638. pvPara,
  7639. dwFlags,
  7640. pUrlArray,
  7641. pcbUrlArray,
  7642. pUrlInfo,
  7643. pcbUrlInfo,
  7644. pvReserved
  7645. );
  7646. }
  7647. return( fResult );
  7648. }
  7649. //+---------------------------------------------------------------------------
  7650. //
  7651. // Function: ChainRetrieveObjectByUrlW
  7652. //
  7653. // Synopsis: thunk to CryptRetrieveObjectByUrlW in cryptnet.dll
  7654. //
  7655. //----------------------------------------------------------------------------
  7656. BOOL WINAPI
  7657. ChainRetrieveObjectByUrlW (
  7658. IN LPCWSTR pszUrl,
  7659. IN LPCSTR pszObjectOid,
  7660. IN DWORD dwRetrievalFlags,
  7661. IN DWORD dwTimeout,
  7662. OUT LPVOID* ppvObject,
  7663. IN HCRYPTASYNC hAsyncRetrieve,
  7664. IN PCRYPT_CREDENTIALS pCredentials,
  7665. IN LPVOID pvVerify,
  7666. IN OPTIONAL PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  7667. )
  7668. {
  7669. BOOL fResult = FALSE;
  7670. HMODULE hModule;
  7671. PFN_RETRIEVEOBJECTBYURLW pfn = NULL;
  7672. hModule = ChainGetCryptnetModule();
  7673. if ( hModule != NULL )
  7674. {
  7675. pfn = (PFN_RETRIEVEOBJECTBYURLW)GetProcAddress(
  7676. hModule,
  7677. "CryptRetrieveObjectByUrlW"
  7678. );
  7679. }
  7680. if ( pfn != NULL )
  7681. {
  7682. fResult = ( *pfn )(
  7683. pszUrl,
  7684. pszObjectOid,
  7685. dwRetrievalFlags,
  7686. dwTimeout,
  7687. ppvObject,
  7688. hAsyncRetrieve,
  7689. pCredentials,
  7690. pvVerify,
  7691. pAuxInfo
  7692. );
  7693. }
  7694. return( fResult );
  7695. }
  7696. //+---------------------------------------------------------------------------
  7697. //
  7698. // Function: ChainIsConnected
  7699. //
  7700. // Synopsis: thunk to I_CryptNetIsConnected in cryptnet.dll
  7701. //
  7702. //----------------------------------------------------------------------------
  7703. BOOL WINAPI
  7704. ChainIsConnected()
  7705. {
  7706. BOOL fResult = FALSE;
  7707. HMODULE hModule;
  7708. PFN_I_CRYPTNET_IS_CONNECTED pfn = NULL;
  7709. hModule = ChainGetCryptnetModule();
  7710. if ( hModule != NULL )
  7711. {
  7712. pfn = (PFN_I_CRYPTNET_IS_CONNECTED)GetProcAddress(
  7713. hModule,
  7714. "I_CryptNetIsConnected"
  7715. );
  7716. }
  7717. if ( pfn != NULL )
  7718. {
  7719. fResult = ( *pfn )();
  7720. }
  7721. return( fResult );
  7722. }
  7723. //+---------------------------------------------------------------------------
  7724. //
  7725. // Function: ChainGetHostNameFromUrl
  7726. //
  7727. // Synopsis: thunk to I_CryptNetGetHostNameFromUrl in cryptnet.dll
  7728. //
  7729. //----------------------------------------------------------------------------
  7730. BOOL
  7731. WINAPI
  7732. ChainGetHostNameFromUrl (
  7733. IN LPWSTR pwszUrl,
  7734. IN DWORD cchHostName,
  7735. OUT LPWSTR pwszHostName
  7736. )
  7737. {
  7738. BOOL fResult = FALSE;
  7739. HMODULE hModule;
  7740. PFN_I_CRYPTNET_GET_HOST_NAME_FROM_URL pfn = NULL;
  7741. hModule = ChainGetCryptnetModule();
  7742. if ( hModule != NULL )
  7743. {
  7744. pfn = (PFN_I_CRYPTNET_GET_HOST_NAME_FROM_URL)GetProcAddress(
  7745. hModule,
  7746. "I_CryptNetGetHostNameFromUrl"
  7747. );
  7748. }
  7749. if ( pfn != NULL )
  7750. {
  7751. fResult = ( *pfn )(
  7752. pwszUrl,
  7753. cchHostName,
  7754. pwszHostName
  7755. );
  7756. }
  7757. return( fResult );
  7758. }
  7759. //+---------------------------------------------------------------------------
  7760. //
  7761. // Function: ChainIsFileOrLdapUrl
  7762. //
  7763. // Synopsis: check if the URL given is a file or ldap one
  7764. //
  7765. //----------------------------------------------------------------------------
  7766. BOOL WINAPI
  7767. ChainIsFileOrLdapUrl (
  7768. IN LPCWSTR pwszUrl
  7769. )
  7770. {
  7771. LPWSTR pwsz;
  7772. pwsz = wcschr( pwszUrl, L':' );
  7773. if ( pwsz != NULL )
  7774. {
  7775. if ( ( _wcsnicmp( pwszUrl, L"file", 4 ) == 0 ) ||
  7776. ( _wcsnicmp( pwszUrl, L"ldap", 4 ) == 0 ) )
  7777. {
  7778. return( TRUE );
  7779. }
  7780. else
  7781. {
  7782. return( FALSE );
  7783. }
  7784. }
  7785. return( TRUE );
  7786. }
  7787. //+---------------------------------------------------------------------------
  7788. //
  7789. // Function: ChainGetOfflineUrlDeltaSeconds
  7790. //
  7791. // Synopsis: given the number of unsuccessful attempts to retrieve the
  7792. // Url, returns the number of seconds to wait before the
  7793. // next attempt.
  7794. //
  7795. //----------------------------------------------------------------------------
  7796. const DWORD rgdwChainOfflineUrlDeltaSeconds[] = {
  7797. 15, // 15 seconds
  7798. 15, // 15 seconds
  7799. 60, // 1 minute
  7800. 60 * 5, // 5 minutes
  7801. 60 * 10, // 10 minutes
  7802. 60 * 30, // 30 minutes
  7803. };
  7804. #define CHAIN_OFFLINE_URL_DELTA_SECONDS_CNT \
  7805. (sizeof(rgdwChainOfflineUrlDeltaSeconds) / \
  7806. sizeof(rgdwChainOfflineUrlDeltaSeconds[0]))
  7807. DWORD
  7808. WINAPI
  7809. ChainGetOfflineUrlDeltaSeconds (
  7810. IN DWORD dwOfflineCnt
  7811. )
  7812. {
  7813. if (0 == dwOfflineCnt)
  7814. return 0;
  7815. if (CHAIN_OFFLINE_URL_DELTA_SECONDS_CNT < dwOfflineCnt)
  7816. dwOfflineCnt = CHAIN_OFFLINE_URL_DELTA_SECONDS_CNT;
  7817. return rgdwChainOfflineUrlDeltaSeconds[dwOfflineCnt - 1];
  7818. }
  7819. //+===========================================================================
  7820. // AuthRoot Auto Update methods and helper functions
  7821. //============================================================================
  7822. //+---------------------------------------------------------------------------
  7823. //
  7824. // Member: CChainPathObject::GetAuthRootAutoUpdateUrlStore, public
  7825. //
  7826. // Synopsis: attempts to get a time valid AuthRoot Auto Update CTL.
  7827. // Checks if there is CTL entry matching the subject
  7828. // certificate's AKI exact match, key identifier or name
  7829. // match. For a match URL retrieves the certificate and
  7830. // returns a store containing the retrieved certificates
  7831. //
  7832. // Leaves the engine's critical section to do the URL
  7833. // fetching. If the engine was touched by another thread,
  7834. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  7835. //
  7836. // Assumption: Chain engine is locked once in the calling thread.
  7837. //
  7838. // Only returns FALSE, if the engine was touched when
  7839. // leaving the critical section.
  7840. //
  7841. // The caller has already checked that we are online.
  7842. //
  7843. //----------------------------------------------------------------------------
  7844. // CN=Root Agency
  7845. const BYTE rgbRootAgencyIssuerName[] = {
  7846. 0x30, 0x16, // SEQUENCE
  7847. 0x31, 0x14, // SET
  7848. 0x30, 0x12, // SEQUENCE
  7849. 0x06, 0x03, 0x55, 0x04, 0x03, // OID
  7850. // PRINTABLE STRING
  7851. 0x13, 0x0b, 0x52, 0x6f, 0x6f, 0x74, 0x20,
  7852. 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79
  7853. };
  7854. // CN=Root SGC Authority
  7855. const BYTE rgbRootSGCAuthorityIssuerName[] = {
  7856. 0x30, 0x1d, // SEQUENCE
  7857. 0x31, 0x1b, // SET
  7858. 0x30, 0x19, // SEQUENCE
  7859. 0x06, 0x03, 0x55, 0x04, 0x03, // OID
  7860. // PRINTABLE STRING
  7861. 0x13, 0x12, 0x52, 0x6f, 0x6f, 0x74, 0x20,
  7862. 0x53, 0x47, 0x43, 0x20, 0x41,
  7863. 0x75, 0x74, 0x68, 0x6f, 0x72,
  7864. 0x69, 0x74, 0x79
  7865. };
  7866. const CRYPT_DATA_BLOB rgSkipPartialIssuer[] = {
  7867. sizeof(rgbRootAgencyIssuerName), (BYTE *) rgbRootAgencyIssuerName,
  7868. sizeof(rgbRootSGCAuthorityIssuerName), (BYTE *) rgbRootSGCAuthorityIssuerName
  7869. };
  7870. #define SKIP_PARTIAL_ISSUER_CNT (sizeof(rgSkipPartialIssuer)/ \
  7871. sizeof(rgSkipPartialIssuer[0]))
  7872. BOOL
  7873. CChainPathObject::GetAuthRootAutoUpdateUrlStore(
  7874. IN PCCHAINCALLCONTEXT pCallContext,
  7875. OUT HCERTSTORE *phIssuerUrlStore
  7876. )
  7877. {
  7878. BOOL fTouchedResult = TRUE;
  7879. PCCERTCHAINENGINE pChainEngine = pCallContext->ChainEngine();
  7880. PCERT_INFO pCertInfo = m_pCertObject->CertContext()->pCertInfo;
  7881. PCCTL_CONTEXT pCtl = NULL;
  7882. HCERTSTORE hIssuerUrlStore = NULL;
  7883. CRYPT_DATA_BLOB rgAuthRootMatchHash[AUTH_ROOT_MATCH_CNT];
  7884. DWORD cEntry = 0;
  7885. PCTL_ENTRY *rgpEntry = NULL;
  7886. PCCERT_CONTEXT pCert;
  7887. DWORD cCert;
  7888. DWORD i;
  7889. *phIssuerUrlStore = NULL;
  7890. // Loop and skip known issuers such as, "Root Agency". Don't want all
  7891. // clients in the world hiting the wire when building these chains
  7892. for (i = 0; i < SKIP_PARTIAL_ISSUER_CNT; i++) {
  7893. if (pCertInfo->Issuer.cbData == rgSkipPartialIssuer[i].cbData &&
  7894. 0 == memcmp(pCertInfo->Issuer.pbData,
  7895. rgSkipPartialIssuer[i].pbData,
  7896. rgSkipPartialIssuer[i].cbData))
  7897. return TRUE;
  7898. }
  7899. fTouchedResult = pChainEngine->GetAuthRootAutoUpdateCtl(
  7900. pCallContext,
  7901. &pCtl
  7902. );
  7903. if (!fTouchedResult || NULL == pCtl) {
  7904. #if 0
  7905. // This logs too many test failures
  7906. if (fTouchedResult) {
  7907. PAUTH_ROOT_AUTO_UPDATE_INFO pInfo =
  7908. pChainEngine->AuthRootAutoUpdateInfo();
  7909. if (NULL == pInfo || !(pInfo->dwFlags &
  7910. CERT_AUTH_ROOT_AUTO_UPDATE_DISABLE_PARTIAL_CHAIN_LOGGING_FLAG))
  7911. IPR_LogCertInformation(
  7912. MSG_PARTIAL_CHAIN_INFORMATIONAL,
  7913. m_pCertObject->CertContext(),
  7914. TRUE // fFormatIssuerName
  7915. );
  7916. }
  7917. #endif
  7918. return fTouchedResult;
  7919. }
  7920. // We have a valid AuthRoot Auto Update CTL.
  7921. // See if we can find any matching AuthRoots
  7922. memset(rgAuthRootMatchHash, 0, sizeof(rgAuthRootMatchHash));
  7923. m_pCertObject->GetIssuerKeyMatchHash(
  7924. &rgAuthRootMatchHash[AUTH_ROOT_KEY_MATCH_IDX]);
  7925. m_pCertObject->GetIssuerNameMatchHash(
  7926. &rgAuthRootMatchHash[AUTH_ROOT_NAME_MATCH_IDX]);
  7927. pChainEngine->FindAuthRootAutoUpdateMatchingCtlEntries(
  7928. rgAuthRootMatchHash,
  7929. &pCtl,
  7930. &cEntry,
  7931. &rgpEntry
  7932. );
  7933. if (0 == cEntry) {
  7934. #if 0
  7935. // This logs too many test failures
  7936. PAUTH_ROOT_AUTO_UPDATE_INFO pInfo =
  7937. pChainEngine->AuthRootAutoUpdateInfo();
  7938. if (NULL == pInfo || !(pInfo->dwFlags &
  7939. CERT_AUTH_ROOT_AUTO_UPDATE_DISABLE_PARTIAL_CHAIN_LOGGING_FLAG))
  7940. IPR_LogCertInformation(
  7941. MSG_PARTIAL_CHAIN_INFORMATIONAL,
  7942. m_pCertObject->CertContext(),
  7943. TRUE // fFormatIssuerName
  7944. );
  7945. #endif
  7946. goto NoAutoUpdateCtlEntry;
  7947. }
  7948. hIssuerUrlStore = CertOpenStore(
  7949. CERT_STORE_PROV_MEMORY,
  7950. 0, // dwEncodingType
  7951. NULL, // hCryptProv
  7952. 0, // dwFlags
  7953. NULL // pvPara
  7954. );
  7955. if (NULL == hIssuerUrlStore)
  7956. goto OpenMemoryStoreError;
  7957. for (i = 0; i < cEntry; i++) {
  7958. PCTL_ENTRY pEntry = rgpEntry[i];
  7959. // If already in our store, no need to hit the wire and retrieve.
  7960. if (pCert = CertFindCertificateInStore(
  7961. pChainEngine->OtherStore(),
  7962. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  7963. 0,
  7964. CERT_FIND_SHA1_HASH,
  7965. (LPVOID) &pEntry->SubjectIdentifier,
  7966. NULL
  7967. )) {
  7968. CertFreeCertificateContext(pCert);
  7969. continue;
  7970. }
  7971. fTouchedResult = pChainEngine->GetAuthRootAutoUpdateCert(
  7972. pCallContext,
  7973. pEntry,
  7974. hIssuerUrlStore
  7975. );
  7976. if (!fTouchedResult)
  7977. goto TouchedDuringUrlRetrievalOfAuthRoots;
  7978. }
  7979. pCert = NULL;
  7980. cCert = 0;
  7981. while (pCert = CertEnumCertificatesInStore(hIssuerUrlStore, pCert))
  7982. cCert++;
  7983. if (0 == cCert)
  7984. goto NoAuthRootAutoUpdateCerts;
  7985. if (1 < cCert) {
  7986. // If more than one root in the list, explicitly add them all here.
  7987. // While building the chain using the returned AuthRoots we might
  7988. // leave the critical section and restart. After restarting may
  7989. // have a trusted root and won't redo this URL retrieval.
  7990. pChainEngine->UnlockEngine();
  7991. pCert = NULL;
  7992. while (pCert = CertEnumCertificatesInStore(hIssuerUrlStore, pCert))
  7993. IPR_AddCertInAuthRootAutoUpdateCtl(pCert, pCtl);
  7994. pChainEngine->LockEngine();
  7995. if (pCallContext->IsTouchedEngine()) {
  7996. fTouchedResult = FALSE;
  7997. goto TouchedDuringAddOfAuthRoots;
  7998. }
  7999. }
  8000. *phIssuerUrlStore = hIssuerUrlStore;
  8001. CommonReturn:
  8002. if (rgpEntry)
  8003. PkiFree(rgpEntry);
  8004. if (pCtl)
  8005. CertFreeCTLContext(pCtl);
  8006. return fTouchedResult;
  8007. ErrorReturn:
  8008. if (hIssuerUrlStore)
  8009. CertCloseStore(hIssuerUrlStore, 0);
  8010. goto CommonReturn;
  8011. TRACE_ERROR(NoAutoUpdateCtlEntry)
  8012. TRACE_ERROR(OpenMemoryStoreError)
  8013. TRACE_ERROR(TouchedDuringUrlRetrievalOfAuthRoots)
  8014. TRACE_ERROR(NoAuthRootAutoUpdateCerts)
  8015. TRACE_ERROR(TouchedDuringAddOfAuthRoots)
  8016. }
  8017. //+---------------------------------------------------------------------------
  8018. //
  8019. // Member: CCertChainEngine::RetrieveAuthRootAutoUpdateObjectByUrlW, public
  8020. //
  8021. // Synopsis: URL retrieves an AuthRoot Auto Update object. For wire
  8022. // retrieval, logs the event.
  8023. //
  8024. // Leaves the engine's critical section to do the URL
  8025. // fetching. If the engine was touched by another thread,
  8026. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  8027. //
  8028. // Assumption: Chain engine is locked once in the calling thread.
  8029. //
  8030. // If the object was successfully retrieved,
  8031. // *ppvObject != NULL. Otherwise, *ppvObject = NULL.
  8032. //
  8033. // Only returns FALSE, if the engine was touched when
  8034. // leaving the critical section. *ppvObject may be != NULL
  8035. // when touched.
  8036. //
  8037. //----------------------------------------------------------------------------
  8038. BOOL
  8039. CCertChainEngine::RetrieveAuthRootAutoUpdateObjectByUrlW(
  8040. IN PCCHAINCALLCONTEXT pCallContext,
  8041. IN DWORD dwSuccessEventID,
  8042. IN DWORD dwFailEventID,
  8043. IN LPCWSTR pwszUrl,
  8044. IN LPCSTR pszObjectOid,
  8045. IN DWORD dwRetrievalFlags,
  8046. IN DWORD dwTimeout, // 0 => use default
  8047. OUT LPVOID* ppvObject,
  8048. IN OPTIONAL PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
  8049. )
  8050. {
  8051. BOOL fTouchedResult = TRUE;
  8052. BOOL fResult;
  8053. *ppvObject = NULL;
  8054. if (0 == dwTimeout)
  8055. dwTimeout = pCallContext->ChainPara()->dwUrlRetrievalTimeout;
  8056. //
  8057. // We are about to go on the wire to retrieve the object.
  8058. // At this time we will release the chain engine lock so others can
  8059. // go about there business while we wait for the protocols to do the
  8060. // fetching.
  8061. //
  8062. UnlockEngine();
  8063. // Note, the windows update server doesn't require authentication.
  8064. // wininet sometimes calls us within a critical section. NO_AUTH
  8065. // normally will fix this deadlock.
  8066. //
  8067. // On 09-May-01 the above was fixed by wininet.
  8068. // Removed setting CRYPT_NO_AUTH_RETRIEVAL.
  8069. //
  8070. // Authentication may be required by a proxy.
  8071. fResult = ChainRetrieveObjectByUrlW(
  8072. pwszUrl,
  8073. pszObjectOid,
  8074. dwRetrievalFlags,
  8075. dwTimeout,
  8076. ppvObject,
  8077. NULL, // hAsyncRetrieve
  8078. NULL, // pCredentials
  8079. NULL, // pvVerify
  8080. pAuxInfo
  8081. );
  8082. if (dwRetrievalFlags & CRYPT_WIRE_ONLY_RETRIEVAL) {
  8083. // Only log wire retrievals
  8084. if (fResult) {
  8085. LPCWSTR rgpwszStrings[1] = { pwszUrl };
  8086. IPR_LogCrypt32Event(
  8087. EVENTLOG_INFORMATION_TYPE,
  8088. dwSuccessEventID,
  8089. 1, // wNumStrings
  8090. rgpwszStrings
  8091. );
  8092. } else
  8093. IPR_LogCrypt32Error(
  8094. dwFailEventID,
  8095. pwszUrl,
  8096. GetLastError()
  8097. );
  8098. }
  8099. LockEngine();
  8100. if (pCallContext->IsTouchedEngine()) {
  8101. fTouchedResult = FALSE;
  8102. goto TouchedDuringAuthRootObjectUrlRetrieval;
  8103. }
  8104. if (fResult)
  8105. assert(*ppvObject);
  8106. else
  8107. assert(NULL == *ppvObject);
  8108. CommonReturn:
  8109. return fTouchedResult;
  8110. ErrorReturn:
  8111. goto CommonReturn;
  8112. SET_ERROR(TouchedDuringAuthRootObjectUrlRetrieval, ERROR_CAN_NOT_COMPLETE)
  8113. }
  8114. //+---------------------------------------------------------------------------
  8115. //
  8116. // Member: CCertChainEngine::GetAuthRootAutoUpdateCtl, public
  8117. //
  8118. // Synopsis: if auto update hasn't been disabled,
  8119. // returns the AuthRoot Auto Update CTL. Hits the wire
  8120. // if necessary to get a "fresh" CTL.
  8121. //
  8122. // Note, 2 URL fetches. One for the SequenceNumber file. The
  8123. // other for the CTL cab file. The SequenceNumber file
  8124. // is small and bounded in size. If it matches the SequenceNumber
  8125. // in an already retrieved CTL, then, no need to hit the
  8126. // wire to retrive the larger CTL file. This optimization will
  8127. // reduce the number of bytes needing to be fetched across the
  8128. // wire. The CTL won't be updated that often.
  8129. //
  8130. // Leaves the engine's critical section to do the URL
  8131. // fetching. If the engine was touched by another thread,
  8132. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  8133. //
  8134. // Assumption: Chain engine is locked once in the calling thread.
  8135. //
  8136. // If auto update has been disabled, returns TRUE and
  8137. // *ppCtl = NULL.
  8138. //
  8139. // Only returns FALSE, if the engine was touched when
  8140. // leaving the critical section.
  8141. //
  8142. // The returned pCtl is AddRef'ed.
  8143. //
  8144. //----------------------------------------------------------------------------
  8145. BOOL
  8146. CCertChainEngine::GetAuthRootAutoUpdateCtl(
  8147. IN PCCHAINCALLCONTEXT pCallContext,
  8148. OUT PCCTL_CONTEXT *ppCtl
  8149. )
  8150. {
  8151. BOOL fTouchedResult = TRUE;
  8152. FILETIME CurrentTime;
  8153. PAUTH_ROOT_AUTO_UPDATE_INFO pInfo;
  8154. PCRYPT_BLOB_ARRAY pcbaSeq = NULL;
  8155. PCRYPT_BLOB_ARRAY pcbaCab = NULL;
  8156. PCCTL_CONTEXT pNewCtl = NULL;
  8157. CRYPT_RETRIEVE_AUX_INFO RetrieveAuxInfo;
  8158. DWORD i;
  8159. *ppCtl = NULL;
  8160. if ((pCallContext->CallOrEngineFlags() &
  8161. CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE) ||
  8162. IPR_IsAuthRootAutoUpdateDisabled())
  8163. return TRUE;
  8164. if (NULL == (pInfo = m_pAuthRootAutoUpdateInfo)) {
  8165. if (NULL == (pInfo = CreateAuthRootAutoUpdateInfo()))
  8166. return TRUE;
  8167. m_pAuthRootAutoUpdateInfo = pInfo;
  8168. }
  8169. pCallContext->CurrentTime(&CurrentTime);
  8170. memset(&RetrieveAuxInfo, 0, sizeof(RetrieveAuxInfo));
  8171. RetrieveAuxInfo.cbSize = sizeof(RetrieveAuxInfo);
  8172. // First try the cache. If unable to retrieve the seq file or
  8173. // find a time valid CTL cab in the cache, hit the wire.
  8174. for (i = 0; i <= 1; i++) {
  8175. BOOL fResult;
  8176. DWORD dwRetrievalFlags;
  8177. DWORD dwCtlTimeout = 0;
  8178. PCRYPT_INTEGER_BLOB pSequenceNumber;
  8179. FILETIME NewLastSyncTime;
  8180. FILETIME CtlLastSyncTime;
  8181. PCTL_INFO pNewCtlInfo;
  8182. if (pInfo->pCtl &&
  8183. 0 < CompareFileTime(&pInfo->NextSyncTime, &CurrentTime))
  8184. // We already have a time valid CTL
  8185. break;
  8186. if (0 == i)
  8187. dwRetrievalFlags = CRYPT_CACHE_ONLY_RETRIEVAL;
  8188. else {
  8189. if (!pCallContext->IsOnline())
  8190. break;
  8191. dwRetrievalFlags = CRYPT_WIRE_ONLY_RETRIEVAL;
  8192. }
  8193. // First try to fetch the CTL's sequence number file
  8194. RetrieveAuxInfo.pLastSyncTime = &NewLastSyncTime;
  8195. fTouchedResult = RetrieveAuthRootAutoUpdateObjectByUrlW(
  8196. pCallContext,
  8197. MSG_ROOT_SEQUENCE_NUMBER_AUTO_UPDATE_URL_RETRIEVAL_INFORMATIONAL,
  8198. MSG_ROOT_SEQUENCE_NUMBER_AUTO_UPDATE_URL_RETRIEVAL_ERROR,
  8199. pInfo->pwszSeqUrl,
  8200. NULL, // pszObjectOid,
  8201. dwRetrievalFlags |
  8202. CRYPT_OFFLINE_CHECK_RETRIEVAL |
  8203. CRYPT_STICKY_CACHE_RETRIEVAL,
  8204. 0, // dwTimeout (use default)
  8205. (LPVOID*) &pcbaSeq,
  8206. &RetrieveAuxInfo
  8207. );
  8208. if (!fTouchedResult)
  8209. goto TouchedDuringAuthRootSeqUrlRetrieval;
  8210. pSequenceNumber = NULL;
  8211. if (NULL == pcbaSeq) {
  8212. // SequenceNumber retrieval failed
  8213. if (0 != i)
  8214. // For wire retrieval failure, don't try to fetch the CTL
  8215. continue;
  8216. } else if (0 > CompareFileTime(&NewLastSyncTime,
  8217. &pInfo->LastSyncTime)) {
  8218. // An older sync time
  8219. CryptMemFree(pcbaSeq);
  8220. pcbaSeq = NULL;
  8221. } else {
  8222. // Extract the Sequence Number from the retrieved blob.
  8223. // Convert the ascii hex characters to binary. Overwrite
  8224. // the ascii hex with the converted bytes.
  8225. // Convert binary to little endian.
  8226. DWORD cchSeq;
  8227. BOOL fUpperNibble = TRUE;
  8228. DWORD cb = 0;
  8229. DWORD j;
  8230. pSequenceNumber = pcbaSeq->rgBlob;
  8231. if (0 == pcbaSeq->cBlob)
  8232. cchSeq = 0;
  8233. else
  8234. cchSeq = pSequenceNumber->cbData;
  8235. for (j = 0; j < cchSeq; j++) {
  8236. char ch = (char) pSequenceNumber->pbData[j];
  8237. BYTE b;
  8238. // only convert ascii hex characters 0..9, a..f, A..F
  8239. // silently ignore all others
  8240. if (ch >= '0' && ch <= '9')
  8241. b = (BYTE) (ch - '0');
  8242. else if (ch >= 'a' && ch <= 'f')
  8243. b = (BYTE) (10 + ch - 'a');
  8244. else if (ch >= 'A' && ch <= 'F')
  8245. b = (BYTE) (10 + ch - 'A');
  8246. else
  8247. continue;
  8248. if (fUpperNibble) {
  8249. pSequenceNumber->pbData[cb] = b << 4;
  8250. fUpperNibble = FALSE;
  8251. } else {
  8252. pSequenceNumber->pbData[cb] |= b;
  8253. cb++;
  8254. fUpperNibble = TRUE;
  8255. }
  8256. }
  8257. if (0 == cb) {
  8258. // Empty sequence number.
  8259. CryptMemFree(pcbaSeq);
  8260. pcbaSeq = NULL;
  8261. } else {
  8262. pSequenceNumber->cbData = cb;
  8263. PkiAsn1ReverseBytes(pSequenceNumber->pbData,
  8264. pSequenceNumber->cbData);
  8265. // Check if we already have a CTL corresponding to this
  8266. // fetched SequenceNumber
  8267. if (pInfo->pCtl) {
  8268. PCTL_INFO pCtlInfo = pInfo->pCtl->pCtlInfo;
  8269. if (pCtlInfo->SequenceNumber.cbData ==
  8270. pSequenceNumber->cbData &&
  8271. 0 == memcmp(pCtlInfo->SequenceNumber.pbData,
  8272. pSequenceNumber->pbData,
  8273. pSequenceNumber->cbData)) {
  8274. // Same CTL
  8275. pInfo->LastSyncTime = NewLastSyncTime;
  8276. I_CryptIncrementFileTimeBySeconds(
  8277. &pInfo->LastSyncTime,
  8278. pInfo->dwSyncDeltaTime,
  8279. &pInfo->NextSyncTime
  8280. );
  8281. CryptMemFree(pcbaSeq);
  8282. pcbaSeq = NULL;
  8283. continue;
  8284. }
  8285. }
  8286. // The SequenceNumber consists of the FILETIME followed by
  8287. // an optional byte containing a hint for the CTL URL
  8288. // retrieval timeout (in seconds). If we are using the
  8289. // default retrieval timeout, use the hint if it exceeds
  8290. // the default timeout.
  8291. if (sizeof(FILETIME) < cb &&
  8292. pCallContext->HasDefaultUrlRetrievalTimeout()) {
  8293. dwCtlTimeout =
  8294. ((DWORD) pSequenceNumber->pbData[sizeof(FILETIME)]) *
  8295. 1000;
  8296. if (dwCtlTimeout <
  8297. pCallContext->ChainPara()->dwUrlRetrievalTimeout)
  8298. dwCtlTimeout =
  8299. pCallContext->ChainPara()->dwUrlRetrievalTimeout;
  8300. }
  8301. }
  8302. }
  8303. // After retrieving the sequence number file, now
  8304. // try to fetch the cab containing the CTL
  8305. RetrieveAuxInfo.pLastSyncTime = &CtlLastSyncTime;
  8306. fTouchedResult = RetrieveAuthRootAutoUpdateObjectByUrlW(
  8307. pCallContext,
  8308. MSG_ROOT_LIST_AUTO_UPDATE_URL_RETRIEVAL_INFORMATIONAL,
  8309. MSG_ROOT_LIST_AUTO_UPDATE_URL_RETRIEVAL_ERROR,
  8310. pInfo->pwszCabUrl,
  8311. NULL, // pszObjectOid,
  8312. dwRetrievalFlags |
  8313. CRYPT_OFFLINE_CHECK_RETRIEVAL |
  8314. CRYPT_STICKY_CACHE_RETRIEVAL,
  8315. dwCtlTimeout,
  8316. (LPVOID*) &pcbaCab,
  8317. &RetrieveAuxInfo
  8318. );
  8319. if (!fTouchedResult)
  8320. goto TouchedDuringAuthRootCabUrlRetrieval;
  8321. if (NULL == pcbaCab) {
  8322. // Cab Retrieval failed
  8323. if (pcbaSeq) {
  8324. CryptMemFree(pcbaSeq);
  8325. pcbaSeq = NULL;
  8326. }
  8327. continue;
  8328. }
  8329. // Leave the engine to extract the CTL from the cab
  8330. UnlockEngine();
  8331. pNewCtl = ExtractAuthRootAutoUpdateCtlFromCab(pcbaCab);
  8332. if (NULL == pNewCtl)
  8333. IPR_LogCrypt32Error(
  8334. MSG_ROOT_LIST_AUTO_UPDATE_EXTRACT_ERROR,
  8335. pInfo->pwszCabUrl,
  8336. GetLastError()
  8337. );
  8338. CryptMemFree(pcbaCab);
  8339. pcbaCab = NULL;
  8340. LockEngine();
  8341. if (pCallContext->IsTouchedEngine()) {
  8342. fTouchedResult = FALSE;
  8343. goto TouchedDuringExtractAuthRootCtl;
  8344. }
  8345. if (NULL == pNewCtl) {
  8346. // Ctl Extraction failed
  8347. if (pcbaSeq) {
  8348. CryptMemFree(pcbaSeq);
  8349. pcbaSeq = NULL;
  8350. }
  8351. continue;
  8352. }
  8353. // If the SequenceNumber is the same as the one in the retrieved
  8354. // Ctl, then, use the lastest sync of the 2 URL fetches. Otherwise,
  8355. // use the Ctl sync time
  8356. pNewCtlInfo = pNewCtl->pCtlInfo;
  8357. if (NULL == pcbaSeq ||
  8358. pNewCtlInfo->SequenceNumber.cbData != pSequenceNumber->cbData ||
  8359. 0 != memcmp(pNewCtlInfo->SequenceNumber.pbData,
  8360. pSequenceNumber->pbData, pSequenceNumber->cbData)
  8361. ||
  8362. 0 < CompareFileTime(&CtlLastSyncTime, &NewLastSyncTime))
  8363. NewLastSyncTime = CtlLastSyncTime;
  8364. // We are done with the SequenceNumber info
  8365. if (pcbaSeq) {
  8366. CryptMemFree(pcbaSeq);
  8367. pcbaSeq = NULL;
  8368. }
  8369. if (0 >= CompareFileTime(&NewLastSyncTime, &pInfo->LastSyncTime)) {
  8370. // Not a newer sync
  8371. CertFreeCTLContext(pNewCtl);
  8372. pNewCtl = NULL;
  8373. continue;
  8374. }
  8375. if (pInfo->pCtl &&
  8376. pInfo->pCtl->cbCtlEncoded == pNewCtl->cbCtlEncoded &&
  8377. 0 == memcmp(pInfo->pCtl->pbCtlEncoded,
  8378. pNewCtl->pbCtlEncoded, pNewCtl->cbCtlEncoded)) {
  8379. // Same CTL
  8380. pInfo->LastSyncTime = NewLastSyncTime;
  8381. I_CryptIncrementFileTimeBySeconds(
  8382. &pInfo->LastSyncTime,
  8383. pInfo->dwSyncDeltaTime,
  8384. &pInfo->NextSyncTime
  8385. );
  8386. CertFreeCTLContext(pNewCtl);
  8387. pNewCtl = NULL;
  8388. continue;
  8389. }
  8390. // Leave the engine to verify the CTL
  8391. UnlockEngine();
  8392. fResult = IRL_VerifyAuthRootAutoUpdateCtl(pNewCtl);
  8393. if (!fResult)
  8394. IPR_LogCrypt32Error(
  8395. MSG_ROOT_LIST_AUTO_UPDATE_EXTRACT_ERROR,
  8396. pInfo->pwszCabUrl,
  8397. GetLastError()
  8398. );
  8399. LockEngine();
  8400. if (fResult &&
  8401. 0 < CompareFileTime(&NewLastSyncTime, &pInfo->LastSyncTime)) {
  8402. // Valid CTL that is newer
  8403. pInfo->LastSyncTime = NewLastSyncTime;
  8404. I_CryptIncrementFileTimeBySeconds(
  8405. &pInfo->LastSyncTime,
  8406. pInfo->dwSyncDeltaTime,
  8407. &pInfo->NextSyncTime
  8408. );
  8409. FreeAuthRootAutoUpdateMatchCaches(pInfo->rghMatchCache);
  8410. if (pInfo->pCtl)
  8411. CertFreeCTLContext(pInfo->pCtl);
  8412. pInfo->pCtl = pNewCtl;
  8413. pNewCtl = NULL;
  8414. }
  8415. if (pCallContext->IsTouchedEngine()) {
  8416. fTouchedResult = FALSE;
  8417. goto TouchedDuringVerifyAuthRootCtl;
  8418. }
  8419. }
  8420. if (pInfo->pCtl)
  8421. *ppCtl = CertDuplicateCTLContext(pInfo->pCtl);
  8422. CommonReturn:
  8423. if (pcbaSeq)
  8424. CryptMemFree(pcbaSeq);
  8425. if (pcbaCab)
  8426. CryptMemFree(pcbaCab);
  8427. if (pNewCtl)
  8428. CertFreeCTLContext(pNewCtl);
  8429. return fTouchedResult;
  8430. ErrorReturn:
  8431. goto CommonReturn;
  8432. TRACE_ERROR(TouchedDuringAuthRootSeqUrlRetrieval)
  8433. TRACE_ERROR(TouchedDuringAuthRootCabUrlRetrieval)
  8434. SET_ERROR(TouchedDuringExtractAuthRootCtl, ERROR_CAN_NOT_COMPLETE)
  8435. SET_ERROR(TouchedDuringVerifyAuthRootCtl, ERROR_CAN_NOT_COMPLETE)
  8436. }
  8437. //+---------------------------------------------------------------------------
  8438. //
  8439. // Member: CCertChainEngine::FindAuthRootAutoUpdateMatchingCtlEntries, public
  8440. //
  8441. // Synopsis: If the CTL hash match cache doesn't exist its created.
  8442. // Iterates through the key and name hash cache entries.
  8443. // Returns matching entries. Removes duplicates.
  8444. //
  8445. // Assumption: Chain engine is locked once in the calling thread.
  8446. //
  8447. // The returned prgpCtlEntry must be PkiFree()'ed.
  8448. //
  8449. // Note, if the engine's pCtl is different then the passed in
  8450. // pCtl, the passed in pCtl is free'ed and updated with the
  8451. // engine's.
  8452. //
  8453. //----------------------------------------------------------------------------
  8454. VOID
  8455. CCertChainEngine::FindAuthRootAutoUpdateMatchingCtlEntries(
  8456. IN CRYPT_DATA_BLOB rgMatchHash[AUTH_ROOT_MATCH_CNT],
  8457. IN OUT PCCTL_CONTEXT *ppCtl,
  8458. OUT DWORD *pcCtlEntry,
  8459. OUT PCTL_ENTRY **prgpCtlEntry
  8460. )
  8461. {
  8462. PAUTH_ROOT_AUTO_UPDATE_INFO pInfo;
  8463. PCCTL_CONTEXT pCtl;
  8464. DWORD cCtlEntry = 0;
  8465. PCTL_ENTRY *rgpCtlEntry = NULL;
  8466. DWORD i;
  8467. pInfo = m_pAuthRootAutoUpdateInfo;
  8468. if (NULL == pInfo || NULL == pInfo->pCtl)
  8469. goto InvalidCtl;
  8470. pCtl = *ppCtl;
  8471. if (pCtl != pInfo->pCtl) {
  8472. assert(pCtl);
  8473. CertFreeCTLContext(pCtl);
  8474. *ppCtl = pCtl = pInfo->pCtl;
  8475. CertDuplicateCTLContext(pCtl);
  8476. }
  8477. if (!CreateAuthRootAutoUpdateMatchCaches(
  8478. pCtl,
  8479. pInfo->rghMatchCache
  8480. ))
  8481. goto CreateMatchCachesError;
  8482. assert(pInfo->rghMatchCache[0]);
  8483. assert(pInfo->rghMatchCache[AUTH_ROOT_MATCH_CNT - 1]);
  8484. // Loop through the exact, key and name match hashes and try to find an
  8485. // entry in the corresponding CTL match cache
  8486. for (i = 0; i < AUTH_ROOT_MATCH_CNT; i++) {
  8487. HLRUENTRY hEntry;
  8488. if (0 == rgMatchHash[i].cbData)
  8489. continue;
  8490. hEntry = I_CryptFindLruEntry(pInfo->rghMatchCache[i], &rgMatchHash[i]);
  8491. while (NULL != hEntry) {
  8492. PCTL_ENTRY pCtlEntry;
  8493. PCTL_ENTRY *rgpNewCtlEntry;
  8494. DWORD j;
  8495. pCtlEntry = (PCTL_ENTRY) I_CryptGetLruEntryData(hEntry);
  8496. hEntry = I_CryptEnumMatchingLruEntries(hEntry);
  8497. assert(pCtlEntry);
  8498. if (NULL == pCtlEntry)
  8499. continue;
  8500. // Check if we already have this Ctl Entry
  8501. for (j = 0; j < cCtlEntry; j++) {
  8502. if (pCtlEntry == rgpCtlEntry[j])
  8503. break;
  8504. }
  8505. if (j < cCtlEntry)
  8506. continue;
  8507. if (NULL == (rgpNewCtlEntry = (PCTL_ENTRY *) PkiRealloc(
  8508. rgpCtlEntry, (cCtlEntry + 1) * sizeof(PCTL_ENTRY))))
  8509. continue;
  8510. rgpCtlEntry = rgpNewCtlEntry;
  8511. rgpCtlEntry[cCtlEntry++] = pCtlEntry;
  8512. }
  8513. }
  8514. CommonReturn:
  8515. *pcCtlEntry = cCtlEntry;
  8516. *prgpCtlEntry = rgpCtlEntry;
  8517. return;
  8518. ErrorReturn:
  8519. goto CommonReturn;
  8520. TRACE_ERROR(InvalidCtl)
  8521. TRACE_ERROR(CreateMatchCachesError)
  8522. }
  8523. //+---------------------------------------------------------------------------
  8524. //
  8525. // Member: CCertChainEngine::GetAuthRootAutoUpdateCert, public
  8526. //
  8527. // Synopsis: URL retrieval of the AuthRoot from the Microsoft web
  8528. // server.
  8529. //
  8530. // Leaves the engine's critical section to do the URL
  8531. // fetching. If the engine was touched by another thread,
  8532. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  8533. //
  8534. // Assumption: Chain engine is locked once in the calling thread.
  8535. //
  8536. // Only returns FALSE, if the engine was touched when
  8537. // leaving the critical section.
  8538. //
  8539. //----------------------------------------------------------------------------
  8540. BOOL
  8541. CCertChainEngine::GetAuthRootAutoUpdateCert(
  8542. IN PCCHAINCALLCONTEXT pCallContext,
  8543. IN PCTL_ENTRY pCtlEntry,
  8544. IN OUT HCERTSTORE hStore
  8545. )
  8546. {
  8547. BOOL fTouchedResult = TRUE;
  8548. LPWSTR pwszCertUrl = NULL;
  8549. HCERTSTORE hUrlStore = NULL;
  8550. assert(m_pAuthRootAutoUpdateInfo);
  8551. if (SHA1_HASH_LEN != pCtlEntry->SubjectIdentifier.cbData)
  8552. goto InvalidCtlEntryError;
  8553. if (NULL == (pwszCertUrl = FormatAuthRootAutoUpdateCertUrl(
  8554. pCtlEntry->SubjectIdentifier.pbData,
  8555. m_pAuthRootAutoUpdateInfo
  8556. )))
  8557. goto FormatCertUrlError;
  8558. fTouchedResult = RetrieveAuthRootAutoUpdateObjectByUrlW(
  8559. pCallContext,
  8560. MSG_ROOT_CERT_AUTO_UPDATE_URL_RETRIEVAL_INFORMATIONAL,
  8561. MSG_ROOT_CERT_AUTO_UPDATE_URL_RETRIEVAL_ERROR,
  8562. pwszCertUrl,
  8563. CONTEXT_OID_CERTIFICATE,
  8564. CRYPT_RETRIEVE_MULTIPLE_OBJECTS |
  8565. CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL |
  8566. CRYPT_OFFLINE_CHECK_RETRIEVAL |
  8567. CRYPT_WIRE_ONLY_RETRIEVAL |
  8568. CRYPT_DONT_CACHE_RESULT,
  8569. 0, // dwTimeout (use default)
  8570. (LPVOID *) &hUrlStore,
  8571. NULL // pAuxInfo
  8572. );
  8573. if (!fTouchedResult)
  8574. goto TouchedDuringAuthRootCertUrlRetrieval;
  8575. if (hUrlStore)
  8576. I_CertUpdateStore(hStore, hUrlStore, 0, NULL);
  8577. CommonReturn:
  8578. PkiFree(pwszCertUrl);
  8579. if (hUrlStore)
  8580. CertCloseStore(hUrlStore, 0);
  8581. return fTouchedResult;
  8582. ErrorReturn:
  8583. goto CommonReturn;
  8584. SET_ERROR(InvalidCtlEntryError, ERROR_INVALID_DATA)
  8585. TRACE_ERROR(FormatCertUrlError)
  8586. TRACE_ERROR(TouchedDuringAuthRootCertUrlRetrieval)
  8587. }
  8588. //+---------------------------------------------------------------------------
  8589. //
  8590. // Function: CreateAuthRootAutoUpdateInfo
  8591. //
  8592. // Synopsis: creates and initializes the AuthRoot Auto Update info
  8593. //
  8594. //----------------------------------------------------------------------------
  8595. PAUTH_ROOT_AUTO_UPDATE_INFO WINAPI
  8596. CreateAuthRootAutoUpdateInfo()
  8597. {
  8598. HKEY hKey = NULL;
  8599. PAUTH_ROOT_AUTO_UPDATE_INFO pInfo = NULL;
  8600. DWORD cchDir;
  8601. DWORD cchUrl;
  8602. if (NULL == (pInfo = (PAUTH_ROOT_AUTO_UPDATE_INFO) PkiZeroAlloc(
  8603. sizeof(AUTH_ROOT_AUTO_UPDATE_INFO))))
  8604. goto OutOfMemory;
  8605. if (ERROR_SUCCESS != RegOpenKeyExU(
  8606. HKEY_LOCAL_MACHINE,
  8607. CERT_AUTH_ROOT_AUTO_UPDATE_LOCAL_MACHINE_REGPATH,
  8608. 0, // dwReserved
  8609. KEY_READ,
  8610. &hKey
  8611. ))
  8612. hKey = NULL;
  8613. if (hKey) {
  8614. // Attempt to get values from registry
  8615. ILS_ReadDWORDValueFromRegistry(
  8616. hKey,
  8617. CERT_AUTH_ROOT_AUTO_UPDATE_SYNC_DELTA_TIME_VALUE_NAME,
  8618. &pInfo->dwSyncDeltaTime
  8619. );
  8620. ILS_ReadDWORDValueFromRegistry(
  8621. hKey,
  8622. CERT_AUTH_ROOT_AUTO_UPDATE_FLAGS_VALUE_NAME,
  8623. &pInfo->dwFlags
  8624. );
  8625. pInfo->pwszRootDirUrl = ILS_ReadSZValueFromRegistry(
  8626. hKey,
  8627. CERT_AUTH_ROOT_AUTO_UPDATE_ROOT_DIR_URL_VALUE_NAME
  8628. );
  8629. if (pInfo->pwszRootDirUrl && L'\0' == *pInfo->pwszRootDirUrl) {
  8630. PkiFree(pInfo->pwszRootDirUrl);
  8631. pInfo->pwszRootDirUrl = NULL;
  8632. }
  8633. }
  8634. // If not defined in registry, use our defaults
  8635. if (0 == pInfo->dwSyncDeltaTime)
  8636. pInfo->dwSyncDeltaTime = AUTH_ROOT_AUTO_UPDATE_SYNC_DELTA_TIME;
  8637. if (NULL == pInfo->pwszRootDirUrl) {
  8638. if (NULL == (pInfo->pwszRootDirUrl = ILS_AllocAndCopyString(
  8639. AUTH_ROOT_AUTO_UPDATE_ROOT_DIR_URL)))
  8640. goto OutOfMemory;
  8641. }
  8642. // Construct the CTL and Seq Urls
  8643. cchDir = wcslen(pInfo->pwszRootDirUrl);
  8644. cchUrl = cchDir + 1 + wcslen(CERT_AUTH_ROOT_CAB_FILENAME) + 1;
  8645. if (NULL == (pInfo->pwszCabUrl = (LPWSTR) PkiNonzeroAlloc(
  8646. sizeof(WCHAR) * cchUrl)))
  8647. goto OutOfMemory;
  8648. wcscpy(pInfo->pwszCabUrl, pInfo->pwszRootDirUrl);
  8649. pInfo->pwszCabUrl[cchDir] = L'/';
  8650. wcscpy(pInfo->pwszCabUrl + cchDir + 1, CERT_AUTH_ROOT_CAB_FILENAME);
  8651. cchUrl = cchDir + 1 + wcslen(CERT_AUTH_ROOT_SEQ_FILENAME) + 1;
  8652. if (NULL == (pInfo->pwszSeqUrl = (LPWSTR) PkiNonzeroAlloc(
  8653. sizeof(WCHAR) * cchUrl)))
  8654. goto OutOfMemory;
  8655. wcscpy(pInfo->pwszSeqUrl, pInfo->pwszRootDirUrl);
  8656. pInfo->pwszSeqUrl[cchDir] = L'/';
  8657. wcscpy(pInfo->pwszSeqUrl + cchDir + 1, CERT_AUTH_ROOT_SEQ_FILENAME);
  8658. CommonReturn:
  8659. ILS_CloseRegistryKey(hKey);
  8660. return pInfo;
  8661. ErrorReturn:
  8662. FreeAuthRootAutoUpdateInfo(pInfo);
  8663. pInfo = NULL;
  8664. goto CommonReturn;
  8665. TRACE_ERROR(OutOfMemory)
  8666. }
  8667. //+---------------------------------------------------------------------------
  8668. //
  8669. // Function: FreeAuthRootAutoUpdateInfo
  8670. //
  8671. // Synopsis: frees the AuthRoot Auto Update info
  8672. //
  8673. //----------------------------------------------------------------------------
  8674. VOID WINAPI
  8675. FreeAuthRootAutoUpdateInfo(
  8676. IN OUT PAUTH_ROOT_AUTO_UPDATE_INFO pInfo
  8677. )
  8678. {
  8679. if (NULL == pInfo)
  8680. return;
  8681. PkiFree(pInfo->pwszRootDirUrl);
  8682. PkiFree(pInfo->pwszCabUrl);
  8683. PkiFree(pInfo->pwszSeqUrl);
  8684. FreeAuthRootAutoUpdateMatchCaches(pInfo->rghMatchCache);
  8685. if (pInfo->pCtl)
  8686. CertFreeCTLContext(pInfo->pCtl);
  8687. PkiFree(pInfo);
  8688. }
  8689. const LPCSTR rgpszAuthRootMatchOID[AUTH_ROOT_MATCH_CNT] = {
  8690. szOID_CERT_KEY_IDENTIFIER_PROP_ID,
  8691. szOID_CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
  8692. };
  8693. //+---------------------------------------------------------------------------
  8694. //
  8695. // Function: CreateAuthRootAutoUpdateMatchCaches
  8696. //
  8697. // Synopsis: if not already created, iterates through the CTL entries
  8698. // and creates key and name match caches entries from
  8699. // the associated entry hash attribute values.
  8700. //
  8701. //----------------------------------------------------------------------------
  8702. BOOL WINAPI
  8703. CreateAuthRootAutoUpdateMatchCaches(
  8704. IN PCCTL_CONTEXT pCtl,
  8705. IN OUT HLRUCACHE rghMatchCache[AUTH_ROOT_MATCH_CNT]
  8706. )
  8707. {
  8708. BOOL fResult;
  8709. LRU_CACHE_CONFIG Config;
  8710. DWORD i;
  8711. DWORD cEntry;
  8712. PCTL_ENTRY pEntry;
  8713. if (NULL != rghMatchCache[0])
  8714. // Already created.
  8715. return TRUE;
  8716. memset( &Config, 0, sizeof( Config ) );
  8717. Config.dwFlags = LRU_CACHE_NO_SERIALIZE | LRU_CACHE_NO_COPY_IDENTIFIER;
  8718. Config.pfnHash = CertObjectCacheHashMd5Identifier;
  8719. Config.cBuckets = AUTH_ROOT_MATCH_CACHE_BUCKETS;
  8720. for (i = 0; i < AUTH_ROOT_MATCH_CNT; i++) {
  8721. if (!I_CryptCreateLruCache(&Config, &rghMatchCache[i]))
  8722. goto CreateLruCacheError;
  8723. }
  8724. // Loop through the CTL entries and add the exact, key and name match
  8725. // hash cache entries
  8726. cEntry = pCtl->pCtlInfo->cCTLEntry;
  8727. pEntry = pCtl->pCtlInfo->rgCTLEntry;
  8728. for ( ; cEntry > 0; cEntry--, pEntry++) {
  8729. DWORD cAttr;
  8730. PCRYPT_ATTRIBUTE pAttr;
  8731. cAttr = pEntry->cAttribute;
  8732. pAttr = pEntry->rgAttribute;
  8733. // Skip a remove entry
  8734. if (CertFindAttribute(
  8735. szOID_REMOVE_CERTIFICATE,
  8736. cAttr,
  8737. pAttr
  8738. ))
  8739. continue;
  8740. for ( ; cAttr > 0; cAttr--, pAttr++) {
  8741. for (i = 0; i < AUTH_ROOT_MATCH_CNT; i++) {
  8742. if (0 == strcmp(rgpszAuthRootMatchOID[i], pAttr->pszObjId))
  8743. break;
  8744. }
  8745. if (i < AUTH_ROOT_MATCH_CNT) {
  8746. PCRYPT_ATTR_BLOB pValue;
  8747. DWORD cbHash;
  8748. const BYTE *pbHash;
  8749. CRYPT_DATA_BLOB DataBlob;
  8750. HLRUENTRY hEntry = NULL;
  8751. // Check that we have a single valued attribute encoded as an
  8752. // OCTET STRING
  8753. if (1 != pAttr->cValue)
  8754. continue;
  8755. pValue = pAttr->rgValue;
  8756. if (2 > pValue->cbData ||
  8757. ASN1UTIL_TAG_OCTETSTRING != pValue->pbData[0])
  8758. continue;
  8759. // Extract the hash bytes from the encoded OCTET STRING
  8760. if (0 >= Asn1UtilExtractContent(
  8761. pValue->pbData,
  8762. pValue->cbData,
  8763. &cbHash,
  8764. &pbHash
  8765. ) || CMSG_INDEFINITE_LENGTH == cbHash || 0 == cbHash)
  8766. continue;
  8767. DataBlob.cbData = cbHash;
  8768. DataBlob.pbData = (BYTE *) pbHash;
  8769. if (!I_CryptCreateLruEntry(
  8770. rghMatchCache[i],
  8771. &DataBlob,
  8772. pEntry,
  8773. &hEntry
  8774. ))
  8775. goto CreateLruEntryError;
  8776. I_CryptInsertLruEntry(hEntry, NULL);
  8777. I_CryptReleaseLruEntry(hEntry);
  8778. }
  8779. }
  8780. }
  8781. fResult = TRUE;
  8782. CommonReturn:
  8783. return fResult;
  8784. ErrorReturn:
  8785. FreeAuthRootAutoUpdateMatchCaches(rghMatchCache);
  8786. fResult = FALSE;
  8787. goto CommonReturn;
  8788. TRACE_ERROR(CreateLruCacheError)
  8789. TRACE_ERROR(CreateLruEntryError)
  8790. }
  8791. //+---------------------------------------------------------------------------
  8792. //
  8793. // Function: FreeAuthRootAutoUpdateMatchCaches
  8794. //
  8795. // Synopsis: frees the AuthRoot Auto Match Caches
  8796. //
  8797. //----------------------------------------------------------------------------
  8798. VOID WINAPI
  8799. FreeAuthRootAutoUpdateMatchCaches(
  8800. IN OUT HLRUCACHE rghMatchCache[AUTH_ROOT_MATCH_CNT]
  8801. )
  8802. {
  8803. DWORD i;
  8804. for (i = 0; i < AUTH_ROOT_MATCH_CNT; i++) {
  8805. if (NULL != rghMatchCache[i]) {
  8806. I_CryptFreeLruCache(
  8807. rghMatchCache[i],
  8808. LRU_SUPPRESS_REMOVAL_NOTIFICATION,
  8809. NULL
  8810. );
  8811. rghMatchCache[i] = NULL;
  8812. }
  8813. }
  8814. }
  8815. //+---------------------------------------------------------------------------
  8816. //
  8817. // Function: FormatAuthRootAutoUpdateCertUrl
  8818. //
  8819. // Synopsis: allocates and formats the URL to retrieve the auth root cert
  8820. //
  8821. // returns "RootDir" "/" "AsciiHexHash" ".cer"
  8822. // for example,
  8823. // "http://www.xyz.com/roots/216B2A29E62A00CE820146D8244141B92511B279.cer"
  8824. //
  8825. //----------------------------------------------------------------------------
  8826. LPWSTR WINAPI
  8827. FormatAuthRootAutoUpdateCertUrl(
  8828. IN BYTE rgbSha1Hash[SHA1_HASH_LEN],
  8829. IN PAUTH_ROOT_AUTO_UPDATE_INFO pInfo
  8830. )
  8831. {
  8832. LPWSTR pwszUrl;
  8833. DWORD cchDir;
  8834. DWORD cchUrl;
  8835. assert(pInfo->pwszRootDirUrl);
  8836. cchDir = wcslen(pInfo->pwszRootDirUrl);
  8837. cchUrl = cchDir + 1 + SHA1_HASH_NAME_LEN +
  8838. wcslen(CERT_AUTH_ROOT_CERT_EXT) + 1;
  8839. if (NULL == (pwszUrl = (LPWSTR) PkiNonzeroAlloc(sizeof(WCHAR) * cchUrl)))
  8840. return NULL;
  8841. wcscpy(pwszUrl, pInfo->pwszRootDirUrl);
  8842. pwszUrl[cchDir] = L'/';
  8843. ILS_BytesToWStr(SHA1_HASH_LEN, rgbSha1Hash, pwszUrl + cchDir + 1);
  8844. wcscpy(pwszUrl + cchDir + 1 + SHA1_HASH_NAME_LEN, CERT_AUTH_ROOT_CERT_EXT);
  8845. return pwszUrl;
  8846. }
  8847. // Known invalid roots
  8848. BYTE AuthRootInvalidList[][SHA1_HASH_LEN] = {
  8849. // verisign "timestamp" - '97
  8850. { 0xD4, 0x73, 0x5D, 0x8A, 0x9A, 0xE5, 0xBC, 0x4B, 0x0A, 0x0D,
  8851. 0xC2, 0x70, 0xD6, 0xA6, 0x25, 0x38, 0xA5, 0x87, 0xD3, 0x2F },
  8852. // Root Agency (test root)
  8853. { 0xFE, 0xE4, 0x49, 0xEE, 0x0E, 0x39, 0x65, 0xA5, 0x24, 0x6F,
  8854. 0x00, 0x0E, 0x87, 0xFD, 0xE2, 0xA0, 0x65, 0xFD, 0x89, 0xD4 },
  8855. };
  8856. #define AUTH_ROOT_INVALID_LIST_CNT (sizeof(AuthRootInvalidList) / \
  8857. sizeof(AuthRootInvalidList[0]))
  8858. //+---------------------------------------------------------------------------
  8859. //
  8860. // Function: ChainGetAuthRootAutoUpdateStatus
  8861. //
  8862. // Synopsis: return status bits specifying if the root is
  8863. // trusted via the AuthRoot Auto Update CTL.
  8864. //
  8865. // Leaves the engine's critical section to URL retrieve and
  8866. // validate the CTL. Also leaves critical section to
  8867. // add the cert to the AuthRoot store via crypt32 service.
  8868. // If the engine was touched by another thread,
  8869. // it fails with LastError set to ERROR_CAN_NOT_COMPLETE.
  8870. //
  8871. // Assumption: Chain engine is locked once in the calling thread.
  8872. //
  8873. // Only returns FALSE, if the engine was touched when
  8874. // leaving the critical section.
  8875. //
  8876. //----------------------------------------------------------------------------
  8877. BOOL WINAPI
  8878. ChainGetAuthRootAutoUpdateStatus (
  8879. IN PCCHAINCALLCONTEXT pCallContext,
  8880. IN PCCERTOBJECT pCertObject,
  8881. IN OUT DWORD *pdwIssuerStatusFlags
  8882. )
  8883. {
  8884. BOOL fTouchedResult = TRUE;
  8885. BOOL fResult;
  8886. PCCERTCHAINENGINE pChainEngine = pCallContext->ChainEngine();
  8887. PCCERT_CONTEXT pCert = pCertObject->CertContext();
  8888. PCCTL_CONTEXT pCtl = NULL;
  8889. PCTL_ENTRY pCtlEntry;
  8890. PCERT_BASIC_CONSTRAINTS2_INFO pBasicConstraintsInfo;
  8891. DWORD i;
  8892. DWORD cbData;
  8893. BYTE rgbSha1Hash[SHA1_HASH_LEN];
  8894. // Check if the root has an end entity basic constraint. These can't
  8895. // be used for roots.
  8896. pBasicConstraintsInfo = pCertObject->BasicConstraintsInfo();
  8897. if (pBasicConstraintsInfo && !pBasicConstraintsInfo->fCA)
  8898. return TRUE;
  8899. // Check if a known invalid root, such as, expired timestamp
  8900. // root or the "Root Agency" test root. Don't want all clients in the
  8901. // world hiting the wire for these guys.
  8902. cbData = SHA1_HASH_LEN;
  8903. if (!CertGetCertificateContextProperty(
  8904. pCert,
  8905. CERT_SHA1_HASH_PROP_ID,
  8906. rgbSha1Hash,
  8907. &cbData
  8908. ) || SHA1_HASH_LEN != cbData)
  8909. goto GetSha1HashPropertyError;
  8910. for (i = 0; i < AUTH_ROOT_INVALID_LIST_CNT; i++) {
  8911. if (0 == memcmp(AuthRootInvalidList[i], rgbSha1Hash, SHA1_HASH_LEN))
  8912. return TRUE;
  8913. }
  8914. // Check if this certificate has an associated private key. Such
  8915. // certificates are generated by EFS.
  8916. cbData = 0;
  8917. if (CertGetCertificateContextProperty(
  8918. pCert,
  8919. CERT_KEY_PROV_INFO_PROP_ID,
  8920. NULL, // pbData
  8921. &cbData) && 0 < cbData)
  8922. return TRUE;
  8923. fTouchedResult = pChainEngine->GetAuthRootAutoUpdateCtl(
  8924. pCallContext,
  8925. &pCtl
  8926. );
  8927. if (!fTouchedResult || NULL == pCtl) {
  8928. #if 0
  8929. // This logs too many test failures
  8930. if (fTouchedResult) {
  8931. PAUTH_ROOT_AUTO_UPDATE_INFO pInfo =
  8932. pChainEngine->AuthRootAutoUpdateInfo();
  8933. if (NULL == pInfo || !(pInfo->dwFlags &
  8934. CERT_AUTH_ROOT_AUTO_UPDATE_DISABLE_UNTRUSTED_ROOT_LOGGING_FLAG))
  8935. IPR_LogCertInformation(
  8936. MSG_UNTRUSTED_ROOT_INFORMATIONAL,
  8937. pCert,
  8938. FALSE // fFormatIssuerName
  8939. );
  8940. }
  8941. #endif
  8942. return fTouchedResult;
  8943. }
  8944. if (NULL == (pCtlEntry = CertFindSubjectInCTL(
  8945. pCert->dwCertEncodingType,
  8946. CTL_CERT_SUBJECT_TYPE,
  8947. (void *) pCert,
  8948. pCtl,
  8949. 0 // dwFlags
  8950. ))) {
  8951. #if 0
  8952. // This logs too many test failures
  8953. PAUTH_ROOT_AUTO_UPDATE_INFO pInfo =
  8954. pChainEngine->AuthRootAutoUpdateInfo();
  8955. if (NULL == pInfo || !(pInfo->dwFlags &
  8956. CERT_AUTH_ROOT_AUTO_UPDATE_DISABLE_UNTRUSTED_ROOT_LOGGING_FLAG))
  8957. IPR_LogCertInformation(
  8958. MSG_UNTRUSTED_ROOT_INFORMATIONAL,
  8959. pCert,
  8960. FALSE // fFormatIssuerName
  8961. );
  8962. #endif
  8963. goto CommonReturn;
  8964. }
  8965. // Check if a remove entry
  8966. if (CertFindAttribute(
  8967. szOID_REMOVE_CERTIFICATE,
  8968. pCtlEntry->cAttribute,
  8969. pCtlEntry->rgAttribute
  8970. ))
  8971. goto CommonReturn;
  8972. pChainEngine->UnlockEngine();
  8973. fResult = IPR_AddCertInAuthRootAutoUpdateCtl(pCert, pCtl);
  8974. pChainEngine->LockEngine();
  8975. if (pCallContext->IsTouchedEngine()) {
  8976. fTouchedResult = FALSE;
  8977. goto TouchedDuringAddAuthRootInCtl;
  8978. }
  8979. if (fResult && CertSetCertificateContextPropertiesFromCTLEntry(
  8980. pCert,
  8981. pCtlEntry,
  8982. CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG
  8983. ))
  8984. *pdwIssuerStatusFlags |= CERT_ISSUER_TRUSTED_ROOT_FLAG;
  8985. CommonReturn:
  8986. if (pCtl)
  8987. CertFreeCTLContext(pCtl);
  8988. return fTouchedResult;
  8989. ErrorReturn:
  8990. goto CommonReturn;
  8991. TRACE_ERROR(GetSha1HashPropertyError)
  8992. SET_ERROR(TouchedDuringAddAuthRootInCtl, ERROR_CAN_NOT_COMPLETE)
  8993. }