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.

506 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: fndchain.cpp
  8. //
  9. // Contents: Find Certificate Chain in Store API
  10. //
  11. // Functions: CertFindChainInStore
  12. // IFC_IsEndCertValidForUsage
  13. //
  14. // History: 28-Feb-98 philh created
  15. //--------------------------------------------------------------------------
  16. #include "global.hxx"
  17. #include <dbgdef.h>
  18. BOOL IFC_IsEndCertValidForUsages(
  19. IN PCCERT_CONTEXT pCert,
  20. IN PCERT_ENHKEY_USAGE pUsage,
  21. IN BOOL fOrUsage
  22. )
  23. {
  24. BOOL fResult;
  25. int cNumOIDs;
  26. LPSTR *ppOIDs = NULL;
  27. DWORD cbOIDs;
  28. if (0 == pUsage->cUsageIdentifier)
  29. goto SuccessReturn;
  30. cbOIDs = 0;
  31. if (!CertGetValidUsages(
  32. 1, // cCerts
  33. &pCert,
  34. &cNumOIDs,
  35. NULL, // rghOIDs
  36. &cbOIDs
  37. )) goto CertGetValidUsagesError;
  38. if (-1 == cNumOIDs)
  39. // Cert doesn't have any EKU
  40. goto SuccessReturn;
  41. else if (0 == cNumOIDs)
  42. // Intersection of usages in properties and extensions is NONE
  43. goto NoMatch;
  44. assert(cbOIDs);
  45. if (NULL == (ppOIDs = (LPSTR *) PkiNonzeroAlloc(cbOIDs)))
  46. goto OutOfMemory;
  47. if (!CertGetValidUsages(
  48. 1, // cCerts
  49. &pCert,
  50. &cNumOIDs,
  51. ppOIDs,
  52. &cbOIDs
  53. )) goto CertGetValidUsagesError;
  54. if (0 >= cNumOIDs)
  55. // We had a change from the first call
  56. goto NoMatch;
  57. {
  58. DWORD cId1 = pUsage->cUsageIdentifier;
  59. LPSTR *ppszId1 = pUsage->rgpszUsageIdentifier;
  60. for ( ; cId1 > 0; cId1--, ppszId1++) {
  61. DWORD cId2 = cNumOIDs;
  62. LPSTR *ppszId2 = ppOIDs;
  63. for ( ; cId2 > 0; cId2--, ppszId2++) {
  64. if (0 == strcmp(*ppszId1, *ppszId2)) {
  65. if (fOrUsage)
  66. goto SuccessReturn;
  67. else
  68. break;
  69. }
  70. }
  71. if (!fOrUsage && 0 == cId2)
  72. goto NoMatch;
  73. }
  74. if (fOrUsage)
  75. // For the "OR" option we're here without any match
  76. goto NoMatch;
  77. // else
  78. // For the "AND" option we have matched all the specified
  79. // identifiers
  80. }
  81. SuccessReturn:
  82. fResult = TRUE;
  83. CommonReturn:
  84. PkiFree(ppOIDs);
  85. return fResult;
  86. NoMatch:
  87. ErrorReturn:
  88. fResult = FALSE;
  89. goto CommonReturn;
  90. TRACE_ERROR(CertGetValidUsagesError)
  91. TRACE_ERROR(OutOfMemory)
  92. }
  93. BOOL IFC_IsEndCertValidForUsage(
  94. IN PCCERT_CONTEXT pCert,
  95. IN LPCSTR pszUsageIdentifier
  96. )
  97. {
  98. CERT_ENHKEY_USAGE Usage = { 1, (LPSTR *) &pszUsageIdentifier};
  99. return IFC_IsEndCertValidForUsages(
  100. pCert,
  101. &Usage,
  102. TRUE // fOrUsage
  103. );
  104. }
  105. BOOL CompareChainIssuerNameBlobs(
  106. IN DWORD dwCertEncodingType,
  107. IN DWORD dwFindFlags,
  108. IN PCERT_CHAIN_FIND_BY_ISSUER_PARA pPara,
  109. IN OUT PCCERT_CHAIN_CONTEXT *ppChainContext
  110. )
  111. {
  112. DWORD i;
  113. DWORD cIssuer = pPara->cIssuer;
  114. PCERT_NAME_BLOB pIssuer = pPara->rgIssuer;
  115. PCCERT_CHAIN_CONTEXT pChainContext = *ppChainContext;
  116. if (0 == cIssuer)
  117. return TRUE;
  118. for (i = 0; i < pChainContext->cChain; i++) {
  119. DWORD j;
  120. PCERT_SIMPLE_CHAIN pChain;
  121. if (0 < i && 0 == (dwFindFlags &
  122. CERT_CHAIN_FIND_BY_ISSUER_COMPLEX_CHAIN_FLAG))
  123. break;
  124. pChain = pChainContext->rgpChain[i];
  125. for (j = 0; j < pChain->cElement; j++) {
  126. DWORD k;
  127. PCCERT_CONTEXT pCert = pChain->rgpElement[j]->pCertContext;
  128. PCERT_NAME_BLOB pChainIssuer = &pCert->pCertInfo->Issuer;
  129. for (k = 0; k < cIssuer; k++) {
  130. if (CertCompareCertificateName(
  131. dwCertEncodingType,
  132. pChainIssuer,
  133. &pIssuer[k]
  134. )) {
  135. if (STRUCT_CBSIZE(CERT_CHAIN_FIND_BY_ISSUER_PARA,
  136. pdwIssuerElementIndex) <= pPara->cbSize) {
  137. if (pPara->pdwIssuerChainIndex)
  138. *pPara->pdwIssuerChainIndex = i;
  139. if (pPara->pdwIssuerElementIndex)
  140. *pPara->pdwIssuerElementIndex = j + 1;
  141. }
  142. return TRUE;
  143. }
  144. }
  145. }
  146. }
  147. // See if we have a match in any of the lower quality chains
  148. for (i = 0; i < pChainContext->cLowerQualityChainContext; i++) {
  149. PCCERT_CHAIN_CONTEXT pLowerQualityChainContext =
  150. pChainContext->rgpLowerQualityChainContext[i];
  151. if (pLowerQualityChainContext->TrustStatus.dwErrorStatus &
  152. CERT_TRUST_IS_NOT_SIGNATURE_VALID)
  153. // Lower quality chains must at least have valid signatures
  154. continue;
  155. CertDuplicateCertificateChain(pLowerQualityChainContext);
  156. if (CompareChainIssuerNameBlobs(
  157. dwCertEncodingType,
  158. dwFindFlags,
  159. pPara,
  160. &pLowerQualityChainContext
  161. )) {
  162. // Replace the input chain context with the lower quality
  163. // chain context
  164. CertFreeCertificateChain(pChainContext);
  165. *ppChainContext = pLowerQualityChainContext;
  166. return TRUE;
  167. } else {
  168. assert(pLowerQualityChainContext ==
  169. pChainContext->rgpLowerQualityChainContext[i]);
  170. CertFreeCertificateChain(pLowerQualityChainContext);
  171. }
  172. }
  173. return FALSE;
  174. }
  175. static DWORD GetChainKeyIdentifierPropId(
  176. IN PCCERT_CONTEXT pCert,
  177. IN DWORD dwKeySpec
  178. )
  179. {
  180. DWORD dwPropId;
  181. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  182. DWORD cbKeyProvInfo;
  183. BYTE rgbKeyId[MAX_HASH_LEN];
  184. DWORD cbKeyId;
  185. CRYPT_HASH_BLOB KeyIdentifier;
  186. cbKeyId = sizeof(rgbKeyId);
  187. if (!CertGetCertificateContextProperty(
  188. pCert,
  189. CERT_KEY_IDENTIFIER_PROP_ID,
  190. rgbKeyId,
  191. &cbKeyId
  192. ))
  193. return 0;
  194. KeyIdentifier.pbData = rgbKeyId;
  195. KeyIdentifier.cbData = cbKeyId;
  196. if (!CryptGetKeyIdentifierProperty(
  197. &KeyIdentifier,
  198. CERT_KEY_PROV_INFO_PROP_ID,
  199. CRYPT_KEYID_ALLOC_FLAG,
  200. NULL, // pwszComputerName
  201. NULL, // pvReserved
  202. (void *) &pKeyProvInfo,
  203. &cbKeyProvInfo
  204. )) {
  205. // Try again, searching LocalMachine
  206. if (!CryptGetKeyIdentifierProperty(
  207. &KeyIdentifier,
  208. CERT_KEY_PROV_INFO_PROP_ID,
  209. CRYPT_KEYID_ALLOC_FLAG | CRYPT_KEYID_MACHINE_FLAG,
  210. NULL, // pwszComputerName
  211. NULL, // pvReserved
  212. (void *) &pKeyProvInfo,
  213. &cbKeyProvInfo
  214. ))
  215. return 0;
  216. }
  217. if (dwKeySpec && dwKeySpec != pKeyProvInfo->dwKeySpec)
  218. dwPropId = 0;
  219. else
  220. dwPropId = CERT_KEY_PROV_INFO_PROP_ID;
  221. PkiDefaultCryptFree(pKeyProvInfo);
  222. return dwPropId;
  223. }
  224. DWORD GetChainPrivateKeyPropId(
  225. IN PCCERT_CONTEXT pCert,
  226. IN DWORD dwKeySpec
  227. )
  228. {
  229. DWORD dwPropId;
  230. CERT_KEY_CONTEXT KeyContext;
  231. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  232. DWORD cbProp;
  233. cbProp = sizeof(KeyContext);
  234. if (CertGetCertificateContextProperty(
  235. pCert,
  236. CERT_KEY_CONTEXT_PROP_ID,
  237. &KeyContext,
  238. &cbProp
  239. )) {
  240. assert(sizeof(KeyContext) <= cbProp);
  241. if (dwKeySpec && dwKeySpec != KeyContext.dwKeySpec)
  242. return 0;
  243. else
  244. return CERT_KEY_CONTEXT_PROP_ID;
  245. }
  246. if (!CertGetCertificateContextProperty(
  247. pCert,
  248. CERT_KEY_PROV_INFO_PROP_ID,
  249. NULL, // pvData
  250. &cbProp
  251. ))
  252. return 0;
  253. if (NULL == (pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) PkiNonzeroAlloc(
  254. cbProp)))
  255. goto OutOfMemory;
  256. if (!CertGetCertificateContextProperty(
  257. pCert,
  258. CERT_KEY_PROV_INFO_PROP_ID,
  259. pKeyProvInfo,
  260. &cbProp
  261. )) goto CertGetCertificateContextPropertyError;
  262. if (dwKeySpec && dwKeySpec != pKeyProvInfo->dwKeySpec)
  263. goto NoMatch;
  264. dwPropId = CERT_KEY_PROV_INFO_PROP_ID;
  265. CommonReturn:
  266. PkiFree(pKeyProvInfo);
  267. return dwPropId;
  268. NoMatch:
  269. ErrorReturn:
  270. dwPropId = 0;
  271. goto CommonReturn;
  272. TRACE_ERROR(OutOfMemory)
  273. TRACE_ERROR(CertGetCertificateContextPropertyError)
  274. }
  275. BOOL FindChainByIssuer(
  276. IN DWORD dwCertEncodingType,
  277. IN DWORD dwFindFlags,
  278. IN PCERT_CHAIN_FIND_BY_ISSUER_PARA pPara,
  279. IN PCCERT_CONTEXT pCert,
  280. OUT PCCERT_CHAIN_CONTEXT *ppChainContext
  281. )
  282. {
  283. BOOL fResult = TRUE;
  284. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  285. DWORD dwPrivateKeyPropId;
  286. CERT_CHAIN_PARA ChainPara;
  287. DWORD dwCreateChainFlags;
  288. if (NULL == pPara ||
  289. offsetof(CERT_CHAIN_FIND_BY_ISSUER_PARA, pvFindArg) >
  290. pPara->cbSize) {
  291. fResult = FALSE;
  292. goto InvalidArg;
  293. }
  294. if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG)
  295. dwPrivateKeyPropId = CERT_KEY_CONTEXT_PROP_ID;
  296. else if (0 == (dwPrivateKeyPropId = GetChainPrivateKeyPropId(
  297. pCert,
  298. pPara->dwKeySpec
  299. ))) {
  300. if (0 == (dwPrivateKeyPropId = GetChainKeyIdentifierPropId(
  301. pCert,
  302. pPara->dwKeySpec
  303. )))
  304. goto NoMatch;
  305. }
  306. if (pPara->pszUsageIdentifier) {
  307. if (!IFC_IsEndCertValidForUsage(
  308. pCert,
  309. pPara->pszUsageIdentifier
  310. )) goto NoMatch;
  311. }
  312. if (pPara->pfnFindCallback) {
  313. if (!pPara->pfnFindCallback(
  314. pCert,
  315. pPara->pvFindArg
  316. )) goto NoMatch;
  317. }
  318. memset(&ChainPara, 0, sizeof(ChainPara));
  319. ChainPara.cbSize = sizeof(ChainPara);
  320. if (pPara->pszUsageIdentifier) {
  321. ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  322. ChainPara.RequestedUsage.Usage.cUsageIdentifier = 1;
  323. ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier =
  324. (LPSTR *) &pPara->pszUsageIdentifier;
  325. }
  326. dwCreateChainFlags = 0;
  327. if (0 != pPara->cIssuer) {
  328. // For cross certs, might need to look at the lower quality chains
  329. dwCreateChainFlags |= CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS;
  330. }
  331. if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG)
  332. dwCreateChainFlags |= CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL;
  333. if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_LOCAL_MACHINE_FLAG)
  334. dwCreateChainFlags |= CERT_CHAIN_USE_LOCAL_MACHINE_STORE;
  335. if (!CertGetCertificateChain(
  336. NULL, // hChainEngine
  337. pCert,
  338. NULL, // pTime
  339. dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG ?
  340. 0 : pCert->hCertStore,
  341. &ChainPara,
  342. dwCreateChainFlags,
  343. NULL, // pvReserved
  344. &pChainContext
  345. )) goto CertGetCertificateChainError;
  346. if (!CompareChainIssuerNameBlobs(
  347. dwCertEncodingType,
  348. dwFindFlags,
  349. pPara,
  350. &pChainContext
  351. )) goto NoMatch;
  352. if (dwFindFlags & CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG) {
  353. if (CERT_KEY_CONTEXT_PROP_ID != dwPrivateKeyPropId) {
  354. DWORD dwAcquireFlags = pPara->dwAcquirePrivateKeyFlags |
  355. CRYPT_ACQUIRE_COMPARE_KEY_FLAG;
  356. HCRYPTPROV hProv;
  357. BOOL fCallerFreeProv;
  358. if (!CryptAcquireCertificatePrivateKey(
  359. pCert,
  360. dwAcquireFlags,
  361. NULL, // pvReserved
  362. &hProv,
  363. NULL, // pdwKeySpec
  364. &fCallerFreeProv
  365. )) goto CryptAcquireCertificatePrivateKeyError;
  366. if (fCallerFreeProv)
  367. CryptReleaseContext(hProv, 0);
  368. }
  369. }
  370. CommonReturn:
  371. *ppChainContext = pChainContext;
  372. return fResult;
  373. NoMatch:
  374. ErrorReturn:
  375. if (pChainContext) {
  376. CertFreeCertificateChain(pChainContext);
  377. pChainContext = NULL;
  378. }
  379. goto CommonReturn;
  380. SET_ERROR(InvalidArg, E_INVALIDARG)
  381. TRACE_ERROR(CertGetCertificateChainError)
  382. TRACE_ERROR(CryptAcquireCertificatePrivateKeyError)
  383. }
  384. PCCERT_CHAIN_CONTEXT
  385. WINAPI
  386. CertFindChainInStore(
  387. IN HCERTSTORE hCertStore,
  388. IN DWORD dwCertEncodingType,
  389. IN DWORD dwFindFlags,
  390. IN DWORD dwFindType,
  391. IN const void *pvFindPara,
  392. IN PCCERT_CHAIN_CONTEXT pPrevChainContext
  393. )
  394. {
  395. PCCERT_CONTEXT pCert = NULL;
  396. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  397. if (0 == dwCertEncodingType)
  398. dwCertEncodingType = X509_ASN_ENCODING;
  399. if (pPrevChainContext) {
  400. if (pPrevChainContext->cChain) {
  401. PCERT_SIMPLE_CHAIN pChain = pPrevChainContext->rgpChain[0];
  402. if (pChain->cElement)
  403. pCert = CertDuplicateCertificateContext(
  404. pChain->rgpElement[0]->pCertContext);
  405. }
  406. CertFreeCertificateChain(pPrevChainContext);
  407. }
  408. while (pCert = CertEnumCertificatesInStore(hCertStore, pCert)) {
  409. switch (dwFindType) {
  410. case CERT_CHAIN_FIND_BY_ISSUER:
  411. if (!FindChainByIssuer(
  412. dwCertEncodingType,
  413. dwFindFlags,
  414. (PCERT_CHAIN_FIND_BY_ISSUER_PARA) pvFindPara,
  415. pCert,
  416. &pChainContext
  417. )) goto FindChainByIssuerError;
  418. if (pChainContext)
  419. goto CommonReturn;
  420. break;
  421. default:
  422. goto InvalidArg;
  423. }
  424. }
  425. SetLastError((DWORD) CRYPT_E_NOT_FOUND);
  426. CommonReturn:
  427. if (pCert)
  428. CertFreeCertificateContext(pCert);
  429. return pChainContext;
  430. ErrorReturn:
  431. goto CommonReturn;
  432. SET_ERROR(InvalidArg, E_INVALIDARG)
  433. TRACE_ERROR(FindChainByIssuerError)
  434. }