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

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