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.

807 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: expapis.cpp
  8. //
  9. // Contents: Microsoft Internet Security Trust Provider
  10. //
  11. // Functions: FindCertsByIssuer
  12. //
  13. // History: 01-Jun-1997 pberkman created
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "global.hxx"
  17. /////////////////////////////////////////////////////////////////////////////
  18. //
  19. // The root of the certificate store that we manage.
  20. //
  21. #define HEAPALLOC(size) HeapAlloc ( GetProcessHeap(), 0, size )
  22. #define HEAPFREE(data) HeapFree ( GetProcessHeap(), 0, data )
  23. #define SZIE30CERTCLIENTAUTH "Software\\Microsoft\\Cryptography\\PersonalCertificates\\ClientAuth"
  24. #define SZIE30TAGS "CertificateTags"
  25. #define SZIE30AUXINFO "CertificateAuxiliaryInfo"
  26. #define SZIE30CERTBUCKET "Certificates"
  27. #define ALIGN_LEN(Len) ((Len + 7) & ~7)
  28. #define IE30CONVERTEDSTORE "My"
  29. static LPCSTR rgpszMyStore[] = {
  30. "My"
  31. };
  32. #define NMYSTORES (sizeof(rgpszMyStore)/sizeof(rgpszMyStore[0]))
  33. static const struct {
  34. LPCSTR pszStore;
  35. DWORD dwFlags;
  36. } rgCaStoreInfo[] = {
  37. "ROOT", CERT_SYSTEM_STORE_CURRENT_USER,
  38. "CA", CERT_SYSTEM_STORE_CURRENT_USER,
  39. "SPC", CERT_SYSTEM_STORE_LOCAL_MACHINE
  40. };
  41. #define NCASTORES (sizeof(rgCaStoreInfo)/sizeof(rgCaStoreInfo[0]))
  42. #define MAX_CHAIN_LEN 16
  43. typedef struct _CHAIN_INFO CHAIN_INFO, *PCHAIN_INFO;
  44. struct _CHAIN_INFO {
  45. DWORD cCert;
  46. PCCERT_CONTEXT rgpCert[MAX_CHAIN_LEN];
  47. DWORD cbKeyProvInfo; // aligned
  48. DWORD cbCert; // aligned
  49. PCHAIN_INFO pNext;
  50. };
  51. //+-------------------------------------------------------------------------
  52. // AuthCert allocation and free functions
  53. //--------------------------------------------------------------------------
  54. static void *ACAlloc(
  55. IN size_t cbBytes
  56. )
  57. {
  58. void *pv;
  59. pv = (void *)new BYTE[cbBytes];
  60. if (pv == NULL)
  61. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  62. return pv;
  63. }
  64. static void ACFree(
  65. IN void *pv
  66. )
  67. {
  68. if (pv)
  69. {
  70. delete pv;
  71. }
  72. }
  73. static HRESULT GetAndIe30ClientAuthCertificates(HCERTSTORE hStore)
  74. // Check for and copy any existing certificates stored in Bob's
  75. // certificate store.
  76. {
  77. HRESULT hr = S_OK;
  78. LONG Status;
  79. HKEY hKeyRoot = NULL;
  80. HKEY hKeyBucket = NULL;
  81. HKEY hKeyTags = NULL;
  82. HKEY hKeyAux = NULL;
  83. if (ERROR_SUCCESS != RegOpenKeyExA(
  84. HKEY_CURRENT_USER,
  85. SZIE30CERTCLIENTAUTH,
  86. 0, // dwReserved
  87. KEY_READ,
  88. &hKeyRoot
  89. ))
  90. return S_OK;
  91. // Copy any existing certificates
  92. if (ERROR_SUCCESS == RegOpenKeyExA(
  93. hKeyRoot,
  94. SZIE30CERTBUCKET,
  95. 0, // dwReserved
  96. KEY_READ,
  97. &hKeyBucket
  98. ) &&
  99. ERROR_SUCCESS == RegOpenKeyExA(
  100. hKeyRoot,
  101. SZIE30AUXINFO,
  102. 0, // dwReserved
  103. KEY_READ,
  104. &hKeyAux
  105. ) &&
  106. ERROR_SUCCESS == RegOpenKeyExA(
  107. hKeyRoot,
  108. SZIE30TAGS,
  109. 0, // dwReserved
  110. KEY_READ,
  111. &hKeyTags
  112. )) {
  113. DWORD cValuesCert, cchMaxNameCert, cbMaxDataCert;
  114. DWORD cValuesTag, cchMaxNameTag, cbMaxDataTag;
  115. DWORD cValuesAux, cchMaxNameAux, cbMaxDataAux;
  116. LPSTR szName = NULL;
  117. BYTE *pbDataCert = NULL;
  118. BYTE *pbDataAux = NULL;
  119. BYTE *pbDataTag = NULL;
  120. // see how many and how big the registry is
  121. if (ERROR_SUCCESS != RegQueryInfoKey(
  122. hKeyBucket,
  123. NULL,
  124. NULL,
  125. NULL,
  126. NULL,
  127. NULL,
  128. NULL,
  129. &cValuesCert,
  130. &cchMaxNameCert,
  131. &cbMaxDataCert,
  132. NULL,
  133. NULL
  134. ) ||
  135. ERROR_SUCCESS != RegQueryInfoKey(
  136. hKeyTags,
  137. NULL,
  138. NULL,
  139. NULL,
  140. NULL,
  141. NULL,
  142. NULL,
  143. &cValuesTag,
  144. &cchMaxNameTag,
  145. &cbMaxDataTag,
  146. NULL,
  147. NULL
  148. ) ||
  149. ERROR_SUCCESS != RegQueryInfoKey(
  150. hKeyAux,
  151. NULL,
  152. NULL,
  153. NULL,
  154. NULL,
  155. NULL,
  156. NULL,
  157. &cValuesAux,
  158. &cchMaxNameAux,
  159. &cbMaxDataAux,
  160. NULL,
  161. NULL
  162. ))
  163. {
  164. hr = SignError();
  165. goto Return;
  166. }
  167. else {
  168. // allocate the memory needed to read the reg
  169. szName = (LPSTR) HEAPALLOC(cchMaxNameCert + 1);
  170. pbDataCert = (BYTE *) HEAPALLOC(cbMaxDataCert);
  171. pbDataTag = (BYTE *) HEAPALLOC(cbMaxDataTag);
  172. pbDataAux = (BYTE *) HEAPALLOC(cbMaxDataAux);
  173. if (NULL == szName ||
  174. NULL == pbDataCert ||
  175. NULL == pbDataAux ||
  176. NULL == pbDataTag )
  177. hr = E_OUTOFMEMORY;
  178. }
  179. // enum the registry getting certs
  180. for (DWORD i = 0; SUCCEEDED(hr) && i < cValuesCert; i++ ) {
  181. DWORD dwType;
  182. BYTE * pb;
  183. CRYPT_KEY_PROV_INFO keyInfo;
  184. DWORD cchName = cchMaxNameCert + 1;
  185. DWORD cbDataCert = cbMaxDataCert;
  186. DWORD cbDataTag = cbMaxDataTag;
  187. DWORD cbDataAux = cbMaxDataAux;
  188. PCCERT_CONTEXT pCertContxt = NULL;
  189. // don't have to worry about errors, just skip
  190. // sliently just be cause there is an internal
  191. // error in the registry doesn't mean we should
  192. // get all upset about it.
  193. // get the cert
  194. if (RegEnumValueA(
  195. hKeyBucket,
  196. i,
  197. szName,
  198. &cchName,
  199. NULL,
  200. &dwType,
  201. pbDataCert,
  202. &cbDataCert
  203. ) == ERROR_SUCCESS &&
  204. dwType == REG_BINARY &&
  205. // get the cert context
  206. (pCertContxt = CertCreateCertificateContext(
  207. X509_ASN_ENCODING,
  208. pbDataCert,
  209. cbDataCert)) != NULL &&
  210. // get the tag
  211. RegQueryValueExA(
  212. hKeyTags,
  213. szName,
  214. NULL,
  215. &dwType,
  216. pbDataTag,
  217. &cbDataTag) == ERROR_SUCCESS &&
  218. // get the aux info
  219. RegQueryValueExA(
  220. hKeyAux,
  221. (LPTSTR) pbDataTag,
  222. NULL,
  223. &dwType,
  224. pbDataAux,
  225. &cbDataAux) == ERROR_SUCCESS ) {
  226. // aux info is
  227. // wszPurpose
  228. // wszProvider
  229. // wszKeySet
  230. // wszFilename
  231. // wszCredentials
  232. // dwProviderType
  233. // dwKeySpec
  234. pb = pbDataAux;
  235. memset(&keyInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
  236. // skip purpose, should be client auth
  237. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  238. // get the provider
  239. keyInfo.pwszProvName = (LPWSTR) pb;
  240. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  241. // get the container name
  242. keyInfo.pwszContainerName = (LPWSTR) pb;
  243. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  244. // skip filename, should be '\0'
  245. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  246. // skip credential, don't really know what it is?
  247. pb += (lstrlenW((LPWSTR) pb) + 1) * sizeof(WCHAR);
  248. // get the provider type
  249. keyInfo.dwProvType = *((DWORD *) pb);
  250. pb += sizeof(DWORD);
  251. // get the key spec
  252. keyInfo.dwKeySpec = *((DWORD *) pb);
  253. // add the property to the certificate
  254. if( !CertSetCertificateContextProperty(
  255. pCertContxt,
  256. CERT_KEY_PROV_INFO_PROP_ID,
  257. 0,
  258. &keyInfo) ||
  259. !CertAddCertificateContextToStore(
  260. hStore,
  261. pCertContxt,
  262. CERT_STORE_ADD_USE_EXISTING,
  263. NULL // ppStoreContext
  264. )) {
  265. MessageBox(
  266. NULL,
  267. "Copy Certificate Failed",
  268. NULL,
  269. MB_OK);
  270. hr = SignError();
  271. }
  272. }
  273. if(pCertContxt != NULL)
  274. CertFreeCertificateContext(pCertContxt);
  275. }
  276. if (szName)
  277. HEAPFREE(szName);
  278. if (pbDataCert)
  279. HEAPFREE(pbDataCert);
  280. if(pbDataAux)
  281. HEAPFREE(pbDataAux);
  282. if(pbDataTag)
  283. HEAPFREE(pbDataTag);
  284. }
  285. Return:
  286. if(hKeyRoot != NULL)
  287. RegCloseKey(hKeyRoot);
  288. if(hKeyBucket != NULL)
  289. RegCloseKey(hKeyBucket);
  290. if(hKeyTags != NULL)
  291. RegCloseKey(hKeyTags);
  292. if(hKeyAux != NULL)
  293. RegCloseKey(hKeyAux);
  294. if (FAILED(hr))
  295. return hr;
  296. return hr;
  297. }
  298. // Return List is Null terminated
  299. static HCERTSTORE * GetMyStoreList()
  300. {
  301. int i;
  302. HCERTSTORE *phStoreList;
  303. if (NULL == (phStoreList = (HCERTSTORE *) ACAlloc(
  304. sizeof(HCERTSTORE) * (NMYSTORES + 1))))
  305. return NULL;
  306. memset(phStoreList, 0, sizeof(HCERTSTORE) * (NMYSTORES + 1));
  307. for (i = 0; i < NMYSTORES; i++) {
  308. if (NULL == (phStoreList[i] = CertOpenSystemStore(
  309. NULL,
  310. rgpszMyStore[i])))
  311. goto ErrorReturn;
  312. }
  313. goto CommonReturn;
  314. ErrorReturn:
  315. for (i = 0; i < NMYSTORES; i++) {
  316. if (phStoreList[i])
  317. CertCloseStore(phStoreList[i], 0);
  318. }
  319. ACFree(phStoreList);
  320. phStoreList = NULL;
  321. CommonReturn:
  322. return phStoreList;
  323. }
  324. static HCERTSTORE * GetCaStoreList()
  325. {
  326. int i;
  327. int cStore;
  328. HCERTSTORE *phStoreList;
  329. if (NULL == (phStoreList = (HCERTSTORE *) ACAlloc(
  330. sizeof(HCERTSTORE) * (NCASTORES + 1))))
  331. return NULL;
  332. memset(phStoreList, 0, sizeof(HCERTSTORE) * (NCASTORES + 1));
  333. cStore = 0;
  334. for (i = 0; i < NCASTORES; i++) {
  335. DWORD dwFlags;
  336. dwFlags = rgCaStoreInfo[i].dwFlags | CERT_STORE_READONLY_FLAG;
  337. if (phStoreList[cStore] = CertOpenStore(
  338. CERT_STORE_PROV_SYSTEM_A,
  339. 0, // dwEncodingType
  340. 0, // hCryptProv
  341. dwFlags,
  342. (const void *) rgCaStoreInfo[i].pszStore
  343. ))
  344. cStore++;
  345. }
  346. return phStoreList;
  347. }
  348. // Find first Issuer match. Don't verify anything. Returns TRUE if an
  349. // issuer was found. For a self-signed issuer returns TRUE with *ppIssuer
  350. // set to NULL.
  351. static BOOL GetIssuer(
  352. IN PCCERT_CONTEXT pSubject,
  353. IN HCERTSTORE *phCaStoreList,
  354. OUT PCCERT_CONTEXT *ppIssuer
  355. )
  356. {
  357. BOOL fResult = FALSE;
  358. PCCERT_CONTEXT pIssuer = NULL;
  359. HCERTSTORE hStore;
  360. while (hStore = *phCaStoreList++) {
  361. DWORD dwFlags = 0;
  362. pIssuer = CertGetIssuerCertificateFromStore(
  363. hStore,
  364. pSubject,
  365. NULL, // pPrevIssuer,
  366. &dwFlags
  367. );
  368. if (pIssuer || GetLastError() == CRYPT_E_SELF_SIGNED) {
  369. fResult = TRUE;
  370. break;
  371. }
  372. }
  373. *ppIssuer = pIssuer;
  374. return fResult;
  375. }
  376. //+-------------------------------------------------------------------------
  377. // If issuer name matches any cert in the chain, return allocated
  378. // chain info. Otherwise, return NULL.
  379. //
  380. // If pbEncodedIssuerName == NULL || cbEncodedIssuerName = 0, match any
  381. // issuer.
  382. //--------------------------------------------------------------------------
  383. static PCHAIN_INFO CreateChainInfo(
  384. IN PCCERT_CONTEXT pCert,
  385. IN BYTE *pbEncodedIssuerName,
  386. IN DWORD cbEncodedIssuerName,
  387. IN HCERTSTORE *phCaStoreList,
  388. IN HCERTSTORE *phMyStoreList
  389. )
  390. {
  391. BOOL fIssuerMatch = FALSE;
  392. DWORD cCert = 1;
  393. DWORD cbCert = 0;
  394. PCHAIN_INFO pChainInfo;
  395. if (NULL == (pChainInfo = (PCHAIN_INFO) ACAlloc(sizeof(CHAIN_INFO))))
  396. return NULL;
  397. memset(pChainInfo, 0, sizeof(CHAIN_INFO));
  398. pChainInfo->rgpCert[0] = CertDuplicateCertificateContext(pCert);
  399. if (pbEncodedIssuerName == NULL)
  400. cbEncodedIssuerName = 0;
  401. while (pCert) {
  402. PCCERT_CONTEXT pIssuer;
  403. cbCert += ALIGN_LEN(pCert->cbCertEncoded);
  404. if (!fIssuerMatch) {
  405. if (cbEncodedIssuerName == 0 ||
  406. (cbEncodedIssuerName == pCert->pCertInfo->Issuer.cbData &&
  407. memcmp(pbEncodedIssuerName,
  408. pCert->pCertInfo->Issuer.pbData,
  409. cbEncodedIssuerName) == 0))
  410. fIssuerMatch = TRUE;
  411. }
  412. if (GetIssuer(pCert, phCaStoreList, &pIssuer) ||
  413. GetIssuer(pCert, phMyStoreList, &pIssuer)) {
  414. pCert = pIssuer;
  415. if (pCert) {
  416. assert (cCert < MAX_CHAIN_LEN);
  417. if (cCert < MAX_CHAIN_LEN)
  418. pChainInfo->rgpCert[cCert++] = pCert;
  419. else {
  420. CertFreeCertificateContext(pCert);
  421. pCert = NULL;
  422. }
  423. }
  424. // else
  425. // Self-signed
  426. }
  427. else
  428. pCert = NULL;
  429. }
  430. if (fIssuerMatch) {
  431. pChainInfo->cCert = cCert;
  432. pChainInfo->cbCert = cbCert;
  433. return pChainInfo;
  434. } else {
  435. while (cCert--)
  436. CertFreeCertificateContext(pChainInfo->rgpCert[cCert]);
  437. ACFree(pChainInfo);
  438. return NULL;
  439. }
  440. }
  441. //+-------------------------------------------------------------------------
  442. // Check if the certificate has key provider information.
  443. // If dwKeySpec != 0, also check that the provider's public key matches the
  444. // public key in the certificate.
  445. //--------------------------------------------------------------------------
  446. static BOOL CheckKeyProvInfo(
  447. IN PCCERT_CONTEXT pCert,
  448. IN DWORD dwKeySpec,
  449. OUT DWORD *pcbKeyProvInfo
  450. )
  451. {
  452. BOOL fResult = FALSE;
  453. HCRYPTPROV hCryptProv = 0;
  454. PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
  455. DWORD cbKeyProvInfo;
  456. DWORD cbData;
  457. PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
  458. DWORD cbPubKeyInfo;
  459. cbKeyProvInfo = 0;
  460. CertGetCertificateContextProperty(
  461. pCert,
  462. CERT_KEY_PROV_INFO_PROP_ID,
  463. NULL, // pvData
  464. &cbKeyProvInfo
  465. );
  466. if (cbKeyProvInfo) {
  467. if (dwKeySpec == 0)
  468. fResult = TRUE;
  469. else {
  470. DWORD dwIdx;
  471. if (NULL == (pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) ACAlloc(cbKeyProvInfo)))
  472. goto CommonReturn;
  473. if (!CertGetCertificateContextProperty(
  474. pCert,
  475. CERT_KEY_PROV_INFO_PROP_ID,
  476. pKeyProvInfo,
  477. &cbKeyProvInfo
  478. )) goto CommonReturn;
  479. if (!CryptAcquireContextU(
  480. &hCryptProv,
  481. pKeyProvInfo->pwszContainerName,
  482. pKeyProvInfo->pwszProvName,
  483. pKeyProvInfo->dwProvType,
  484. pKeyProvInfo->dwFlags & ~CERT_SET_KEY_PROV_HANDLE_PROP_ID
  485. )) {
  486. hCryptProv = NULL;
  487. goto CommonReturn;
  488. }
  489. for (dwIdx = 0; dwIdx < pKeyProvInfo->cProvParam; dwIdx++) {
  490. PCRYPT_KEY_PROV_PARAM pKeyProvParam =
  491. &pKeyProvInfo->rgProvParam[dwIdx];
  492. if (!CryptSetProvParam(
  493. hCryptProv,
  494. pKeyProvParam->dwParam,
  495. pKeyProvParam->pbData,
  496. pKeyProvParam->dwFlags
  497. )) goto CommonReturn;
  498. }
  499. // Get public key to compare certificate with
  500. cbPubKeyInfo = 0;
  501. CryptExportPublicKeyInfo(
  502. hCryptProv,
  503. dwKeySpec,
  504. pCert->dwCertEncodingType,
  505. NULL, // pPubKeyInfo
  506. &cbPubKeyInfo
  507. );
  508. if (cbPubKeyInfo == 0) goto CommonReturn;
  509. if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) ACAlloc(
  510. cbPubKeyInfo)))
  511. goto CommonReturn;
  512. if (!CryptExportPublicKeyInfo(
  513. hCryptProv,
  514. dwKeySpec,
  515. pCert->dwCertEncodingType,
  516. pPubKeyInfo,
  517. &cbPubKeyInfo
  518. )) goto CommonReturn;
  519. fResult = CertComparePublicKeyInfo(
  520. pCert->dwCertEncodingType,
  521. &pCert->pCertInfo->SubjectPublicKeyInfo,
  522. pPubKeyInfo);
  523. }
  524. }
  525. CommonReturn:
  526. if (hCryptProv) {
  527. DWORD dwErr = GetLastError();
  528. CryptReleaseContext(hCryptProv, 0);
  529. SetLastError(dwErr);
  530. }
  531. if (pKeyProvInfo)
  532. ACFree(pKeyProvInfo);
  533. if (pPubKeyInfo)
  534. ACFree(pPubKeyInfo);
  535. *pcbKeyProvInfo = cbKeyProvInfo;
  536. return fResult;
  537. }
  538. //+-------------------------------------------------------------------------
  539. // Find all certificate chains tying the given issuer name to any certificate
  540. // that the current user has a private key for.
  541. //
  542. // If pbEncodedIssuerName == NULL || cbEncodedIssuerName = 0, match any
  543. // issuer.
  544. //--------------------------------------------------------------------------
  545. HRESULT
  546. WINAPI
  547. FindCertsByIssuer(
  548. OUT PCERT_CHAIN pCertChains,
  549. IN OUT DWORD *pcbCertChains,
  550. OUT DWORD *pcCertChains, // count of certificates chains returned
  551. IN BYTE* pbEncodedIssuerName, // DER encoded issuer name
  552. IN DWORD cbEncodedIssuerName, // count in bytes of encoded issuer name
  553. IN LPCWSTR pwszPurpose, // "ClientAuth" or "CodeSigning"
  554. IN DWORD dwKeySpec // only return signers supporting this
  555. // keyspec
  556. )
  557. {
  558. HRESULT hr;
  559. HCERTSTORE *phMyStoreList = NULL;
  560. HCERTSTORE *phCaStoreList = NULL;
  561. HCERTSTORE *phStore;
  562. HCERTSTORE hStore;
  563. DWORD cChain = 0;
  564. DWORD cbChain;
  565. DWORD cTotalCert = 0;
  566. PCHAIN_INFO pChainInfoHead = NULL;
  567. LONG cbExtra = 0;
  568. // get the certs out of the IE30 tree and put it in ours
  569. // open the IE30 store
  570. if (NULL != (hStore = CertOpenSystemStore(
  571. NULL,
  572. IE30CONVERTEDSTORE))) {
  573. // don't care about errors, and we don't
  574. // want to delete the old store just yet.
  575. GetAndIe30ClientAuthCertificates(hStore);
  576. CertCloseStore(hStore, 0);
  577. }
  578. // copy the IE30 certs
  579. if (NULL == (phMyStoreList = GetMyStoreList()))
  580. goto ErrorReturn;
  581. if (NULL == (phCaStoreList = GetCaStoreList()))
  582. goto ErrorReturn;
  583. // Iterate through all "My" cert stores to find certificates having a
  584. // CRYPT_KEY_PROV_INFO property
  585. phStore = phMyStoreList;
  586. while (hStore = *phStore++) {
  587. PCCERT_CONTEXT pCert = NULL;
  588. while (pCert = CertEnumCertificatesInStore(hStore, pCert)) {
  589. DWORD cbKeyProvInfo;
  590. if (CheckKeyProvInfo(pCert, dwKeySpec, &cbKeyProvInfo)) {
  591. // Create a cert chain and check for an issuer name match
  592. // of any cert in the chain.
  593. PCHAIN_INFO pChainInfo;
  594. if (pChainInfo = CreateChainInfo(
  595. pCert,
  596. pbEncodedIssuerName,
  597. cbEncodedIssuerName,
  598. phCaStoreList,
  599. phMyStoreList
  600. )) {
  601. // Add to list of chains
  602. pChainInfo->pNext = pChainInfoHead;
  603. pChainInfoHead = pChainInfo;
  604. // Update bytes needed for KeyProvInfo
  605. pChainInfo->cbKeyProvInfo = ALIGN_LEN(cbKeyProvInfo);
  606. // Update totals
  607. cbExtra += pChainInfo->cbKeyProvInfo + pChainInfo->cbCert;
  608. cChain++;
  609. cTotalCert += pChainInfo->cCert;
  610. }
  611. }
  612. }
  613. }
  614. cbChain = sizeof(CERT_CHAIN) * cChain +
  615. sizeof(CERT_BLOB) * cTotalCert + cbExtra;
  616. {
  617. // Check and update output lengths and counts
  618. DWORD cbIn;
  619. if (cChain == 0) {
  620. hr = CRYPT_E_NOT_FOUND;
  621. goto HrError;
  622. }
  623. if (pCertChains == NULL)
  624. *pcbCertChains = 0;
  625. cbIn = *pcbCertChains;
  626. *pcCertChains = cChain;
  627. *pcbCertChains = cbChain;
  628. if (cbIn == 0) {
  629. hr = S_OK;
  630. goto CommonReturn;
  631. } else if (cbIn < cbChain) {
  632. hr = HRESULT_FROM_WIN32(ERROR_BAD_LENGTH);
  633. goto CommonReturn;
  634. }
  635. }
  636. {
  637. // Copy cert chains to output
  638. PCERT_CHAIN pOutChain;
  639. PCERT_BLOB pCertBlob;
  640. BYTE *pbExtra;
  641. PCHAIN_INFO pChainInfo;
  642. pOutChain = pCertChains;
  643. pCertBlob = (PCERT_BLOB) (((BYTE *) pOutChain) +
  644. sizeof(CERT_CHAIN) * cChain);
  645. pbExtra = ((BYTE *) pCertBlob) + sizeof(CERT_BLOB) * cTotalCert;
  646. pChainInfo = pChainInfoHead;
  647. for ( ; pChainInfo != NULL;
  648. pChainInfo = pChainInfo->pNext, pOutChain++) {
  649. DWORD cb;
  650. DWORD cCert = pChainInfo->cCert;
  651. PCCERT_CONTEXT *ppCert = pChainInfo->rgpCert;
  652. pOutChain->cCerts = cCert;
  653. pOutChain->certs = pCertBlob;
  654. cb = pChainInfo->cbKeyProvInfo;
  655. cbExtra -= cb;
  656. assert(cbExtra >= 0);
  657. if (cbExtra < 0) goto UnexpectedError;
  658. if (!CertGetCertificateContextProperty(
  659. *ppCert,
  660. CERT_KEY_PROV_INFO_PROP_ID,
  661. pbExtra,
  662. &cb
  663. ))
  664. goto UnexpectedError;
  665. pOutChain->keyLocatorInfo = * ((PCRYPT_KEY_PROV_INFO) pbExtra);
  666. pbExtra += pChainInfo->cbKeyProvInfo;
  667. for ( ; cCert > 0; cCert--, ppCert++, pCertBlob++) {
  668. cb = (*ppCert)->cbCertEncoded;
  669. cbExtra -= ALIGN_LEN(cb);
  670. assert(cbExtra >= 0);
  671. if (cbExtra < 0) goto UnexpectedError;
  672. pCertBlob->cbData = cb;
  673. pCertBlob->pbData = pbExtra;
  674. memcpy(pbExtra, (*ppCert)->pbCertEncoded, cb);
  675. pbExtra += ALIGN_LEN(cb);
  676. }
  677. }
  678. assert(cbExtra == 0);
  679. assert(pCertBlob == (PCERT_BLOB) ((BYTE *) pCertChains +
  680. sizeof(CERT_CHAIN) * cChain +
  681. sizeof(CERT_BLOB) * cTotalCert));
  682. }
  683. hr = S_OK;
  684. goto CommonReturn;
  685. UnexpectedError:
  686. hr = E_UNEXPECTED;
  687. goto HrError;
  688. ErrorReturn:
  689. hr = SignError();
  690. HrError:
  691. *pcbCertChains = 0;
  692. *pcCertChains = 0;
  693. CommonReturn:
  694. while (pChainInfoHead) {
  695. PCHAIN_INFO pChainInfo = pChainInfoHead;
  696. DWORD cCert = pChainInfo->cCert;
  697. while (cCert--)
  698. CertFreeCertificateContext(pChainInfo->rgpCert[cCert]);
  699. pChainInfoHead = pChainInfo->pNext;
  700. ACFree(pChainInfo);
  701. }
  702. if (phMyStoreList) {
  703. phStore = phMyStoreList;
  704. while (hStore = *phStore++)
  705. CertCloseStore(hStore, 0);
  706. ACFree(phMyStoreList);
  707. }
  708. if (phCaStoreList) {
  709. phStore = phCaStoreList;
  710. while (hStore = *phStore++)
  711. CertCloseStore(hStore, 0);
  712. ACFree(phCaStoreList);
  713. }
  714. return hr;
  715. }