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.

1493 lines
34 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: certpick.cpp
  7. //
  8. // Contents: Cert Server wrapper routines
  9. //
  10. //---------------------------------------------------------------------------
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. #include "cainfop.h"
  14. #include "csdisp.h"
  15. #include "csldap.h"
  16. #include "tfc.h"
  17. #include "clibres.h"
  18. #define __dwFILE__ __dwFILE_CERTLIB_CERTPICK_CPP__
  19. #define CUCS_SOURCEMASK (CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_DSSTORE)
  20. #define CUCS_TYPEMASK (CUCS_MYSTORE | \
  21. CUCS_CASTORE | \
  22. CUCS_KRASTORE | \
  23. CUCS_ROOTSTORE)
  24. #define CUCS_VALIDMASK (CUCS_SOURCEMASK | \
  25. CUCS_TYPEMASK | \
  26. CUCS_V1ONLY | \
  27. CUCS_V3ONLY | \
  28. CUCS_ARCHIVED | \
  29. CUCS_USAGEREQUIRED | \
  30. CUCS_SILENT | \
  31. CUCS_PRIVATEKEYREQUIRED | \
  32. CUCS_USAGEKEYENCIPHER)
  33. // My, CA, KRA and Root stores -- in HKLM, HKCU and the DS
  34. #define CDISPLAYSTOREMAX (4 * 3)
  35. typedef struct _STOREMAP {
  36. DWORD dwFlags;
  37. WCHAR const *pwszStoreName;
  38. WCHAR const *pwszDSTemplate;
  39. } STOREMAP;
  40. STOREMAP s_aStoreMap[] = {
  41. { CUCS_MYSTORE, wszMY_CERTSTORE, NULL },
  42. { CUCS_CASTORE, wszCA_CERTSTORE, wszDSAIAQUERYTEMPLATE },
  43. { CUCS_KRASTORE, wszKRA_CERTSTORE, wszDSKRAQUERYTEMPLATE },
  44. { CUCS_ROOTSTORE, wszROOT_CERTSTORE, NULL },
  45. { 0x0, NULL, NULL },
  46. };
  47. HRESULT
  48. FormatDSStoreName(
  49. IN OUT BSTR *pstrDomainDN,
  50. IN OUT BSTR *pstrConfigDN,
  51. IN WCHAR const *pwszTemplate,
  52. OUT WCHAR **ppwszOut)
  53. {
  54. HRESULT hr;
  55. LDAP *pld = NULL;
  56. if (NULL == *pstrConfigDN) // first call
  57. {
  58. // Renewal domain and config containers (%5, %6)
  59. hr = myLdapOpen(
  60. NULL, // pwszDomainName
  61. RLBF_REQUIRE_SECURE_LDAP, // dwFlags
  62. &pld,
  63. pstrDomainDN,
  64. pstrConfigDN);
  65. _JumpIfError(hr, error, "myLdapOpen");
  66. }
  67. hr = myFormatCertsrvStringArray(
  68. FALSE, // fURL
  69. L"", // pwszServerName_p1_2
  70. L"", // pwszSanitizedName_p3_7
  71. 0, // iCert_p4
  72. MAXDWORD, // iCertTarget_p4
  73. *pstrDomainDN, // pwszDomainDN_p5
  74. *pstrConfigDN, // pwszConfigDN_p6
  75. 0, // iCRL_p8
  76. FALSE, // fDeltaCRL_p9
  77. FALSE, // fDSAttrib_p10_11
  78. 1, // cStrings
  79. (LPCWSTR *) &pwszTemplate, // apwszStringsIn
  80. ppwszOut); // apwszStringsOut
  81. _JumpIfError(hr, error, "myFormatCertsrvStringArray");
  82. error:
  83. myLdapClose(pld, NULL, NULL);
  84. return(hr);
  85. }
  86. HRESULT
  87. myOpenCertStores(
  88. IN DWORD dwFlags, // CUCS_*
  89. OUT DWORD *pcStore,
  90. OUT HCERTSTORE **prghStore)
  91. {
  92. HRESULT hr;
  93. HRESULT hr2;
  94. HCERTSTORE *rghStore = NULL;
  95. DWORD cStore = 0;
  96. STOREMAP *psm;
  97. DWORD OpenFlags;
  98. BSTR strDomainDN = NULL;
  99. BSTR strConfigDN = NULL;
  100. WCHAR *pwszDSStore = NULL;
  101. *pcStore = 0;
  102. *prghStore = NULL;
  103. rghStore = (HCERTSTORE *) LocalAlloc(
  104. LMEM_FIXED,
  105. CDISPLAYSTOREMAX * sizeof(HCERTSTORE));
  106. if (NULL == rghStore)
  107. {
  108. hr = E_OUTOFMEMORY;
  109. _JumpError(hr, error, "LocalAlloc(rghStore)");
  110. }
  111. OpenFlags = CERT_STORE_READONLY_FLAG | CERT_STORE_SET_LOCALIZED_NAME_FLAG;
  112. if (CUCS_ARCHIVED & dwFlags)
  113. {
  114. OpenFlags |= CERT_STORE_ENUM_ARCHIVED_FLAG;
  115. }
  116. hr2 = S_OK;
  117. if ((CUCS_SOURCEMASK | CUCS_TYPEMASK) & dwFlags)
  118. {
  119. if (~CUCS_VALIDMASK & dwFlags)
  120. {
  121. hr = E_INVALIDARG;
  122. _JumpError(hr, error, "dwFlags");
  123. }
  124. if (0 == (CUCS_SOURCEMASK & dwFlags))
  125. {
  126. dwFlags |= CUCS_SOURCEMASK; // source default: all cert store sources
  127. }
  128. if (0 == (CUCS_TYPEMASK & dwFlags))
  129. {
  130. dwFlags |= CUCS_MYSTORE; // type default: use my store
  131. }
  132. for (psm = s_aStoreMap; NULL != psm->pwszStoreName; psm++)
  133. {
  134. if (dwFlags & psm->dwFlags)
  135. {
  136. HCERTSTORE hStore;
  137. if (CUCS_MACHINESTORE & dwFlags)
  138. {
  139. hStore = CertOpenStore(
  140. CERT_STORE_PROV_SYSTEM_W,
  141. X509_ASN_ENCODING,
  142. NULL,
  143. CERT_SYSTEM_STORE_LOCAL_MACHINE | OpenFlags,
  144. psm->pwszStoreName);
  145. if (NULL == hStore)
  146. {
  147. hr = myHLastError();
  148. _PrintErrorStr(hr, "CertOpenStore LocalMachine", psm->pwszStoreName);
  149. if (S_OK == hr2)
  150. {
  151. hr2 = hr;
  152. }
  153. }
  154. else
  155. {
  156. DBGPRINT((
  157. DBG_SS_CERTLIBI,
  158. "CertOpenStore LocalMachine(%ws, HKLM)[%u]\n",
  159. psm->pwszStoreName,
  160. cStore));
  161. rghStore[cStore++] = hStore;
  162. }
  163. }
  164. if (CUCS_USERSTORE & dwFlags)
  165. {
  166. hStore = CertOpenStore(
  167. CERT_STORE_PROV_SYSTEM_W,
  168. X509_ASN_ENCODING,
  169. NULL,
  170. CERT_SYSTEM_STORE_CURRENT_USER | OpenFlags,
  171. psm->pwszStoreName);
  172. if (NULL == hStore)
  173. {
  174. hr = myHLastError();
  175. _PrintErrorStr(hr, "CertOpenStore User", psm->pwszStoreName);
  176. if (S_OK == hr2)
  177. {
  178. hr2 = hr;
  179. }
  180. }
  181. else
  182. {
  183. DBGPRINT((
  184. DBG_SS_CERTLIBI,
  185. "CertOpenStore User(%ws, HKCU)[%u]\n",
  186. psm->pwszStoreName,
  187. cStore));
  188. rghStore[cStore++] = hStore;
  189. }
  190. }
  191. if ((CUCS_DSSTORE & dwFlags) && NULL != psm->pwszDSTemplate)
  192. {
  193. CString strStoreFriendlyName;
  194. int idResource;
  195. switch(psm->dwFlags)
  196. {
  197. case CUCS_CASTORE:
  198. idResource = IDS_STORENAME_DS_AIA;
  199. break;
  200. case CUCS_KRASTORE:
  201. idResource = IDS_STORENAME_DS_KRA;
  202. break;
  203. default:
  204. CSASSERT(CSExpr(!"Invalid cert store name"));
  205. idResource = 0;
  206. }
  207. strStoreFriendlyName.LoadString(idResource);
  208. if (NULL != pwszDSStore)
  209. {
  210. LocalFree(pwszDSStore);
  211. pwszDSStore = NULL;
  212. }
  213. hr = FormatDSStoreName(
  214. &strDomainDN,
  215. &strConfigDN,
  216. psm->pwszDSTemplate,
  217. &pwszDSStore);
  218. if (S_OK != hr)
  219. {
  220. _PrintError(hr, "FormatDSStoreName");
  221. }
  222. else
  223. {
  224. hStore = myUrlCertOpenStore(
  225. CRYPT_WIRE_ONLY_RETRIEVAL |
  226. CRYPT_RETRIEVE_MULTIPLE_OBJECTS,
  227. pwszDSStore);
  228. if (NULL == hStore)
  229. {
  230. hr = myHLastError();
  231. _PrintErrorStr(hr, "myUrlCertOpenStore", pwszDSStore);
  232. if (S_OK == hr2)
  233. {
  234. hr2 = hr;
  235. }
  236. }
  237. else
  238. {
  239. CRYPT_DATA_BLOB cdb;
  240. cdb.pbData = (BYTE *) strStoreFriendlyName.GetBuffer();
  241. cdb.cbData = sizeof(WCHAR) *
  242. (wcslen(strStoreFriendlyName.GetBuffer()) + 1);
  243. if (!CertSetStoreProperty(
  244. hStore,
  245. CERT_STORE_LOCALIZED_NAME_PROP_ID,
  246. 0,
  247. (const void *) &cdb))
  248. {
  249. hr = myHLastError();
  250. _PrintErrorStr(hr, "CertSetStoreProp LDAP", pwszDSStore);
  251. hr = S_OK;
  252. }
  253. DBGPRINT((
  254. DBG_SS_CERTLIBI,
  255. "myUrlCertOpenStore(%ws)[%u]\n",
  256. pwszDSStore,
  257. cStore));
  258. rghStore[cStore++] = hStore;
  259. }
  260. }
  261. }
  262. }
  263. }
  264. }
  265. hr = hr2;
  266. if (0 == cStore)
  267. {
  268. if (hr == S_OK)
  269. {
  270. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  271. }
  272. _JumpError(hr, error, "no Cert Store");
  273. }
  274. CSASSERT(CDISPLAYSTOREMAX >= cStore);
  275. *pcStore = cStore;
  276. *prghStore = rghStore;
  277. rghStore = NULL;
  278. // successfully opened some stores
  279. hr = S_OK;
  280. error:
  281. if (NULL != strDomainDN)
  282. {
  283. SysFreeString(strDomainDN);
  284. }
  285. if (NULL != strConfigDN)
  286. {
  287. SysFreeString(strConfigDN);
  288. }
  289. if (NULL != pwszDSStore)
  290. {
  291. LocalFree(pwszDSStore);
  292. }
  293. if (NULL != rghStore)
  294. {
  295. myCloseCertStores(cStore, rghStore);
  296. }
  297. return(hr);
  298. }
  299. VOID
  300. myCloseCertStores(
  301. IN DWORD cStore,
  302. IN HCERTSTORE *rghStore)
  303. {
  304. DWORD i;
  305. if (NULL != rghStore)
  306. {
  307. for (i = cStore; i < cStore; i++)
  308. {
  309. if (NULL != rghStore[i])
  310. {
  311. CertCloseStore(rghStore[i], CERT_CLOSE_STORE_CHECK_FLAG);
  312. }
  313. }
  314. LocalFree(rghStore);
  315. }
  316. }
  317. // Search for and load the cryptographic provider and private key.
  318. HRESULT
  319. myLoadPrivateKey(
  320. IN CERT_PUBLIC_KEY_INFO const *pPubKeyInfo,
  321. IN DWORD dwFlags, // CUCS_*
  322. OUT HCRYPTPROV *phProv,
  323. OUT DWORD *pdwKeySpec,
  324. OUT BOOL *pfCallerFreeProv)
  325. {
  326. HRESULT hr;
  327. HCERTSTORE *rghStore = NULL;
  328. DWORD cStore;
  329. hr = myOpenCertStores(dwFlags, &cStore, &rghStore);
  330. _JumpIfError(hr, error, "myOpenCertStores");
  331. hr = myLoadPrivateKeyFromCertStores(
  332. pPubKeyInfo,
  333. cStore,
  334. rghStore,
  335. phProv,
  336. pdwKeySpec,
  337. pfCallerFreeProv);
  338. _JumpIfError(hr, error, "myLoadPrivateKeyFromCertStores");
  339. error:
  340. if (NULL != rghStore)
  341. {
  342. myCloseCertStores(cStore, rghStore);
  343. }
  344. return(hr);
  345. }
  346. HRESULT
  347. myLoadPrivateKeyFromCertStores(
  348. IN CERT_PUBLIC_KEY_INFO const *pPubKeyInfo,
  349. IN DWORD cStore,
  350. IN HCERTSTORE *rghStore,
  351. OUT HCRYPTPROV *phProv,
  352. OUT DWORD *pdwKeySpec,
  353. OUT BOOL *pfCallerFreeProv)
  354. {
  355. HRESULT hr;
  356. DWORD i;
  357. CERT_CONTEXT const *pcc = NULL;
  358. // for each cert store
  359. // for each cert in store with matching public key (lookup by public key)
  360. // call CryptAcquireCertificatePrivateKey
  361. // if succeeds, exit w/S_OK
  362. hr = S_OK;
  363. for (i = 0; i < cStore; i++)
  364. {
  365. HCERTSTORE hStore = rghStore[i];
  366. for (;;)
  367. {
  368. pcc = CertFindCertificateInStore(
  369. hStore,
  370. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  371. 0,
  372. CERT_FIND_PUBLIC_KEY,
  373. pPubKeyInfo,
  374. pcc);
  375. if (NULL == pcc)
  376. {
  377. hr = myHLastError();
  378. _PrintError(hr, "CertFindCertificateInStore");
  379. break;
  380. }
  381. if (!CryptAcquireCertificatePrivateKey(
  382. pcc,
  383. CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
  384. NULL, // pvReserved
  385. phProv,
  386. pdwKeySpec,
  387. pfCallerFreeProv))
  388. {
  389. hr = myHLastError();
  390. _PrintError(hr, "CryptAcquireCertificatePrivateKey");
  391. continue;
  392. }
  393. hr = S_OK;
  394. goto error;
  395. }
  396. }
  397. if (S_OK == hr)
  398. {
  399. hr = CRYPT_E_NOT_FOUND;
  400. }
  401. _JumpError(hr, error, "CertFindCertificateInStore");
  402. error:
  403. if (NULL != pcc)
  404. {
  405. CertFreeCertificateContext(pcc);
  406. pcc = NULL;
  407. }
  408. return(hr);
  409. }
  410. HRESULT
  411. myMakeSerialBstr(
  412. IN WCHAR const *pwszSerialNumber,
  413. OUT BSTR *pstrSerialNumber)
  414. {
  415. HRESULT hr = E_OUTOFMEMORY;
  416. WCHAR *pwszDup = NULL;
  417. WCHAR const *pwszSrc;
  418. WCHAR *pwszDst;
  419. pwszDup = (WCHAR *) LocalAlloc(
  420. LMEM_FIXED,
  421. (wcslen(pwszSerialNumber) + 2) * sizeof(*pwszDup));
  422. if (NULL == pwszDup)
  423. {
  424. _JumpError(hr, error, "LocalAlloc");
  425. }
  426. pwszSrc = pwszSerialNumber;
  427. *pwszDup = L'0'; // allow possible leading zero
  428. pwszDst = &pwszDup[1];
  429. while (L'\0' != *pwszSrc)
  430. {
  431. WCHAR wc = *pwszSrc++;
  432. if (iswspace(wc))
  433. {
  434. continue;
  435. }
  436. if (L'A' <= wc && L'F' >= wc)
  437. {
  438. wc += L'a' - L'A';
  439. }
  440. if ((L'a' > wc || L'f' < wc) &&
  441. (L'0' > wc || L'9' < wc))
  442. {
  443. hr = E_INVALIDARG;
  444. _JumpErrorStr2(hr, error, "myMakeSerialBstr", pwszSerialNumber, hr);
  445. }
  446. *pwszDst++ = wc;
  447. }
  448. *pwszDst = L'\0';
  449. pwszSrc = pwszDup; // point at possible extra leading zero
  450. if (1 & (pwszDst - pwszSrc))
  451. {
  452. pwszSrc++; // keep the length even
  453. }
  454. while (L'0' == pwszSrc[0] && L'0' == pwszSrc[1] && L'\0' != pwszSrc[2])
  455. {
  456. pwszSrc += 2; // skip pairs of leading zeros
  457. }
  458. if (!myConvertWszToBstr(pstrSerialNumber, pwszSrc, MAXDWORD))
  459. {
  460. _JumpError(hr, error, "myConvertWszToBstr");
  461. }
  462. hr = S_OK;
  463. error:
  464. if (NULL != pwszDup)
  465. {
  466. LocalFree(pwszDup);
  467. }
  468. return(hr);
  469. }
  470. HRESULT
  471. myNameBlobMatch(
  472. IN CERT_NAME_BLOB const *pSubject,
  473. IN WCHAR const *pwszCertName,
  474. IN BOOL fAllowMissingCN,
  475. OUT BOOL *pfMatch)
  476. {
  477. HRESULT hr;
  478. BOOL fFoundCN = FALSE;
  479. BOOL fMatchCN = FALSE;
  480. CERT_NAME_INFO *pNameInfo = NULL;
  481. DWORD cbNameInfo;
  482. DWORD i;
  483. if (!myDecodeName(
  484. X509_ASN_ENCODING,
  485. X509_UNICODE_NAME,
  486. pSubject->pbData,
  487. pSubject->cbData,
  488. CERTLIB_USE_LOCALALLOC,
  489. &pNameInfo,
  490. &cbNameInfo))
  491. {
  492. hr = myHLastError();
  493. _JumpError(hr, error, "myDecodeName");
  494. }
  495. for (i = 0; i < pNameInfo->cRDN; i++)
  496. {
  497. CERT_RDN const *prdn;
  498. DWORD j;
  499. prdn = &pNameInfo->rgRDN[i];
  500. for (j = 0; j < prdn->cRDNAttr; j++)
  501. {
  502. CERT_RDN_ATTR const *prdna;
  503. prdna = &prdn->rgRDNAttr[j];
  504. if (0 == strcmp(szOID_COMMON_NAME, prdna->pszObjId) &&
  505. NULL != prdna->Value.pbData)
  506. {
  507. fFoundCN = TRUE;
  508. if (0 == mylstrcmpiL(
  509. pwszCertName,
  510. (WCHAR const *) prdna->Value.pbData))
  511. {
  512. fMatchCN = TRUE;
  513. break;
  514. }
  515. }
  516. }
  517. }
  518. hr = S_OK;
  519. error:
  520. if (NULL != pNameInfo)
  521. {
  522. LocalFree(pNameInfo);
  523. }
  524. *pfMatch = fMatchCN || (fAllowMissingCN && !fFoundCN);
  525. return(hr);
  526. }
  527. HRESULT
  528. mySerialNumberMatch(
  529. IN CRYPT_INTEGER_BLOB const *pSerialNumber,
  530. IN WCHAR const *pwszSerialNumber,
  531. OUT BOOL *pfMatch)
  532. {
  533. HRESULT hr;
  534. BSTR strSerialNumber = NULL;
  535. BOOL fMatch = FALSE;
  536. hr = MultiByteIntegerToBstr(
  537. FALSE,
  538. pSerialNumber->cbData,
  539. pSerialNumber->pbData,
  540. &strSerialNumber);
  541. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  542. if (0 == mylstrcmpiL(pwszSerialNumber, strSerialNumber))
  543. {
  544. fMatch = TRUE;
  545. }
  546. CSASSERT(S_OK == hr);
  547. error:
  548. if (NULL != strSerialNumber)
  549. {
  550. SysFreeString(strSerialNumber);
  551. }
  552. *pfMatch = fMatch;
  553. return(hr);
  554. }
  555. HRESULT
  556. myCertHashMatch(
  557. IN CERT_CONTEXT const *pCert,
  558. IN DWORD cb,
  559. IN BYTE const *pb,
  560. OUT BOOL *pfMatch)
  561. {
  562. HRESULT hr;
  563. BOOL fMatch = FALSE;
  564. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  565. DWORD cbHash;
  566. //wprintf(L"IN: ");
  567. //DumpHex(DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 1, pb, cb);
  568. cbHash = sizeof(abHash);
  569. if (!CertGetCertificateContextProperty(
  570. pCert,
  571. CERT_SHA1_HASH_PROP_ID,
  572. abHash,
  573. &cbHash))
  574. {
  575. hr = myHLastError();
  576. _JumpError(hr, error, "CertGetCertificateContextProperty");
  577. }
  578. //wprintf(L"CH: ");
  579. //DumpHex(DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 1, abHash, cbHash);
  580. if (cbHash == cb && 0 == memcmp(abHash, pb, cb))
  581. {
  582. fMatch = TRUE;
  583. hr = S_OK;
  584. goto error;
  585. }
  586. cbHash = sizeof(abHash);
  587. if (!CertGetCertificateContextProperty(
  588. pCert,
  589. CERT_KEY_IDENTIFIER_PROP_ID,
  590. abHash,
  591. &cbHash))
  592. {
  593. hr = myHLastError();
  594. _PrintError(hr, "CertGetCertificateContextProperty(KeyId)");
  595. }
  596. else
  597. {
  598. //wprintf(L"KH: ");
  599. //DumpHex(DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 1, abHash, cbHash);
  600. if (cbHash == cb && 0 == memcmp(abHash, pb, cb))
  601. {
  602. fMatch = TRUE;
  603. hr = S_OK;
  604. goto error;
  605. }
  606. }
  607. hr = S_OK;
  608. error:
  609. *pfMatch = fMatch;
  610. return(hr);
  611. }
  612. HRESULT
  613. myCertMatch(
  614. IN CERT_CONTEXT const *pCert,
  615. IN WCHAR const *pwszCertName,
  616. IN BOOL fAllowMissingCN,
  617. OPTIONAL IN BYTE const *pbHash,
  618. IN DWORD cbHash,
  619. OPTIONAL IN WCHAR const *pwszSerialNumber,
  620. OUT BOOL *pfMatch)
  621. {
  622. HRESULT hr;
  623. BOOL fMatch = FALSE;
  624. if (NULL != pbHash)
  625. {
  626. hr = myCertHashMatch(pCert, cbHash, pbHash, &fMatch);
  627. _JumpIfError(hr, error, "myCertHashMatch");
  628. }
  629. if (!fMatch && NULL != pwszSerialNumber)
  630. {
  631. hr = mySerialNumberMatch(
  632. &pCert->pCertInfo->SerialNumber,
  633. pwszSerialNumber,
  634. &fMatch);
  635. _JumpIfError(hr, error, "mySerialNumberMatch");
  636. }
  637. if (!fMatch)
  638. {
  639. hr = myNameBlobMatch(
  640. &pCert->pCertInfo->Subject,
  641. pwszCertName,
  642. fAllowMissingCN,
  643. &fMatch);
  644. _JumpIfError(hr, error, "myNameBlobMatch");
  645. }
  646. hr = S_OK;
  647. error:
  648. *pfMatch = fMatch;
  649. return(hr);
  650. }
  651. HRESULT
  652. myCertMatchEKUOrApplicationPolicies(
  653. IN CERT_CONTEXT const *pCert,
  654. IN DWORD cpszObjId,
  655. IN CHAR const * const *apszObjId,
  656. IN BOOL fUsageRequired,
  657. OUT BOOL *pfMatch)
  658. {
  659. HRESULT hr;
  660. CERT_ENHKEY_USAGE *pKeyUsage = NULL;
  661. DWORD cbKeyUsage = 0;
  662. BOOL fMatch = FALSE;
  663. DWORD i;
  664. DWORD j;
  665. for (;;)
  666. {
  667. // get enhanced key usage OIDs
  668. if (!CertGetEnhancedKeyUsage(
  669. pCert,
  670. CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
  671. pKeyUsage,
  672. &cbKeyUsage))
  673. {
  674. // accept match if EKU extension not found
  675. hr = myHLastError();
  676. if (!fUsageRequired && CRYPT_E_NOT_FOUND == hr)
  677. {
  678. fMatch = TRUE;
  679. }
  680. _PrintError2(hr, "CertGetEnhancedKeyUsage", CRYPT_E_NOT_FOUND);
  681. hr = S_OK;
  682. goto error;
  683. }
  684. if (NULL != pKeyUsage)
  685. {
  686. break; // EKU extension fetched; break out of while loop
  687. }
  688. pKeyUsage = (CERT_ENHKEY_USAGE *) LocalAlloc(LMEM_FIXED, cbKeyUsage);
  689. if (NULL == pKeyUsage)
  690. {
  691. hr = E_OUTOFMEMORY;
  692. _JumpError(hr, error, "out of memory");
  693. }
  694. }
  695. if (NULL != pKeyUsage)
  696. {
  697. if (0 == pKeyUsage->cUsageIdentifier)
  698. {
  699. hr = myHLastError(); // set by CertGetEnhancedKeyUsage
  700. if (S_OK != hr)
  701. {
  702. fMatch = TRUE;
  703. }
  704. }
  705. else
  706. {
  707. for (i = 0; i < pKeyUsage->cUsageIdentifier; i++)
  708. {
  709. if (fMatch)
  710. {
  711. break;
  712. }
  713. for (j = 0; j < cpszObjId; j++)
  714. {
  715. if (0 == strcmp(
  716. pKeyUsage->rgpszUsageIdentifier[i],
  717. apszObjId[j]))
  718. {
  719. fMatch = TRUE; // found matching EKU OID
  720. break;
  721. }
  722. }
  723. }
  724. }
  725. }
  726. hr = S_OK;
  727. error:
  728. *pfMatch = fMatch;
  729. if (NULL != pKeyUsage)
  730. {
  731. LocalFree(pKeyUsage);
  732. }
  733. return(hr);
  734. }
  735. HRESULT
  736. myCRLHashMatch(
  737. IN CRL_CONTEXT const *pCRL,
  738. IN DWORD cb,
  739. IN BYTE const *pb,
  740. OUT BOOL *pfMatch)
  741. {
  742. HRESULT hr;
  743. BOOL fMatch = FALSE;
  744. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  745. DWORD cbHash;
  746. cbHash = sizeof(abHash);
  747. if (!CertGetCRLContextProperty(
  748. pCRL,
  749. CERT_SHA1_HASH_PROP_ID,
  750. abHash,
  751. &cbHash))
  752. {
  753. hr = myHLastError();
  754. _JumpError(hr, error, "CertGetCRLContextProperty");
  755. }
  756. if (cbHash == cb && 0 == memcmp(abHash, pb, cb))
  757. {
  758. fMatch = TRUE;
  759. }
  760. hr = S_OK;
  761. error:
  762. *pfMatch = fMatch;
  763. return(hr);
  764. }
  765. HRESULT
  766. myCRLMatch(
  767. IN CRL_CONTEXT const *pCRL,
  768. IN WCHAR const *pwszCRLName,
  769. IN BOOL fAllowMissingCN,
  770. OPTIONAL IN BYTE const *pbHash,
  771. IN DWORD cbHash,
  772. OUT BOOL *pfMatch)
  773. {
  774. HRESULT hr;
  775. BOOL fMatch = FALSE;
  776. if (NULL != pbHash)
  777. {
  778. hr = myCRLHashMatch(pCRL, cbHash, pbHash, &fMatch);
  779. _JumpIfError(hr, error, "myCRLHashMatch");
  780. }
  781. if (!fMatch)
  782. {
  783. hr = myNameBlobMatch(
  784. &pCRL->pCrlInfo->Issuer,
  785. pwszCRLName,
  786. fAllowMissingCN,
  787. &fMatch);
  788. _JumpIfError(hr, error, "myNameBlobMatch");
  789. }
  790. hr = S_OK;
  791. error:
  792. *pfMatch = fMatch;
  793. return(hr);
  794. }
  795. HRESULT
  796. myCTLHashMatch(
  797. IN CTL_CONTEXT const *pCTL,
  798. IN DWORD cb,
  799. IN BYTE const *pb,
  800. OUT BOOL *pfMatch)
  801. {
  802. HRESULT hr;
  803. BOOL fMatch = FALSE;
  804. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  805. DWORD cbHash;
  806. cbHash = sizeof(abHash);
  807. if (!CertGetCTLContextProperty(
  808. pCTL,
  809. CERT_SHA1_HASH_PROP_ID,
  810. abHash,
  811. &cbHash))
  812. {
  813. hr = myHLastError();
  814. _JumpError(hr, error, "CertGetCTLContextProperty");
  815. }
  816. if (cbHash == cb && 0 == memcmp(abHash, pb, cb))
  817. {
  818. fMatch = TRUE;
  819. }
  820. hr = S_OK;
  821. error:
  822. *pfMatch = fMatch;
  823. return(hr);
  824. }
  825. HRESULT
  826. myCTLMatch(
  827. IN CTL_CONTEXT const *pCTL,
  828. OPTIONAL IN BYTE const *pbHash,
  829. IN DWORD cbHash,
  830. OUT BOOL *pfMatch)
  831. {
  832. HRESULT hr;
  833. BOOL fMatch = FALSE;
  834. if (NULL != pbHash)
  835. {
  836. hr = myCTLHashMatch(pCTL, cbHash, pbHash, &fMatch);
  837. _JumpIfError(hr, error, "myCTLHashMatch");
  838. }
  839. hr = S_OK;
  840. error:
  841. *pfMatch = fMatch;
  842. return(hr);
  843. }
  844. typedef struct _CERTFILTERCALLBACKDATA
  845. {
  846. DWORD dwFlags; // CUCS_*
  847. DWORD cpszObjId;
  848. CHAR const * const *apszObjId;
  849. WCHAR const *pwszCommonName;
  850. BYTE *pbHash;
  851. DWORD cbHash;
  852. BSTR strSerialNumber;
  853. HRESULT hr;
  854. HCERTSTORE hMemStore;
  855. } CERTFILTERCALLBACKDATA;
  856. BOOL WINAPI
  857. CertificateFilterProc(
  858. PCCERT_CONTEXT pCertContext,
  859. BOOL *pfInitialSelectedCert,
  860. void *pvCallbackData)
  861. {
  862. HRESULT hr;
  863. BOOL fMatch;
  864. CERTFILTERCALLBACKDATA *pCallbackData =
  865. (CERTFILTERCALLBACKDATA *) pvCallbackData;
  866. CERT_NAME_INFO *pNameInfo = NULL;
  867. WCHAR *pwszSubject = NULL;
  868. CSASSERT(NULL != pCertContext);
  869. *pfInitialSelectedCert = FALSE;
  870. hr = myCertNameToStr(
  871. X509_ASN_ENCODING,
  872. &pCertContext->pCertInfo->Subject,
  873. CERT_X500_NAME_STR |
  874. CERT_NAME_STR_REVERSE_FLAG |
  875. CERT_NAME_STR_NO_QUOTING_FLAG,
  876. &pwszSubject);
  877. _PrintIfError(hr, "myCertNameToStr");
  878. if (NULL != pCallbackData->apszObjId)
  879. {
  880. hr = myCertMatchEKUOrApplicationPolicies(
  881. pCertContext,
  882. pCallbackData->cpszObjId,
  883. pCallbackData->apszObjId,
  884. CUCS_USAGEREQUIRED & pCallbackData->dwFlags,
  885. &fMatch);
  886. _JumpIfError(hr, error, "myCertMatchEKUOrApplicationPolicies");
  887. if (!fMatch)
  888. {
  889. _PrintErrorStr2(
  890. CRYPT_E_NOT_FOUND,
  891. "no matching EKU",
  892. pwszSubject,
  893. CRYPT_E_NOT_FOUND);
  894. hr = S_OK;
  895. goto error;
  896. }
  897. }
  898. // The CommonName filter serves three purposes: 1: a common name, 2: the
  899. // sha-1 hash of the cert, 3: the sha-1 hash of the public key (or the
  900. // Subject Key Id extension), 4: the serial number of the cert. If any one
  901. // of these match, the cert is accepted.
  902. if (NULL != pCallbackData->pwszCommonName)
  903. {
  904. hr = myCertMatch(
  905. pCertContext,
  906. pCallbackData->pwszCommonName,
  907. FALSE, // fAllowMissingCN
  908. pCallbackData->pbHash,
  909. pCallbackData->cbHash,
  910. pCallbackData->strSerialNumber,
  911. &fMatch);
  912. _JumpIfError(hr, error, "myCertMatch");
  913. if (!fMatch)
  914. {
  915. _PrintErrorStr2(
  916. CRYPT_E_NOT_FOUND,
  917. "no matching CN/Hash/Serial",
  918. pwszSubject,
  919. CRYPT_E_NOT_FOUND);
  920. hr = S_OK;
  921. goto error;
  922. }
  923. }
  924. fMatch = FALSE;
  925. if ((CUCS_V1ONLY & pCallbackData->dwFlags) &&
  926. CERT_V1 != pCertContext->pCertInfo->dwVersion)
  927. {
  928. _PrintErrorStr2(
  929. CRYPT_E_NOT_FOUND,
  930. "not V1",
  931. pwszSubject,
  932. CRYPT_E_NOT_FOUND);
  933. hr = S_OK;
  934. goto error;
  935. }
  936. if ((CUCS_V3ONLY & pCallbackData->dwFlags) &&
  937. CERT_V3 != pCertContext->pCertInfo->dwVersion)
  938. {
  939. _PrintErrorStr2(
  940. CRYPT_E_NOT_FOUND,
  941. "not V3",
  942. pwszSubject,
  943. CRYPT_E_NOT_FOUND);
  944. hr = S_OK;
  945. goto error;
  946. }
  947. if (CUCS_PRIVATEKEYREQUIRED & pCallbackData->dwFlags)
  948. {
  949. DWORD cb;
  950. if (!CertGetCertificateContextProperty(
  951. pCertContext,
  952. CERT_KEY_PROV_INFO_PROP_ID,
  953. NULL,
  954. &cb))
  955. {
  956. _PrintErrorStr(CRYPT_E_NOT_FOUND, "no KeyProvInfo", pwszSubject);
  957. hr = S_OK;
  958. goto error;
  959. }
  960. }
  961. if (CUCS_USAGEKEYENCIPHER & pCallbackData->dwFlags)
  962. {
  963. DWORD dwKeyUsage;
  964. DWORD cb = sizeof(dwKeyUsage);
  965. if (!CertGetIntendedKeyUsage(
  966. X509_ASN_ENCODING,
  967. pCertContext->pCertInfo,
  968. (BYTE*)&dwKeyUsage,
  969. cb))
  970. {
  971. _PrintErrorStr(CRYPT_E_NOT_FOUND, "CertGetIntendedKeyUsage", pwszSubject);
  972. hr = S_OK;
  973. goto error;
  974. }
  975. if (!(dwKeyUsage & CERT_KEY_ENCIPHERMENT_KEY_USAGE))
  976. {
  977. _PrintErrorStr2(
  978. CRYPT_E_NOT_FOUND,
  979. "key encipherment key usage not found",
  980. pwszSubject,
  981. CRYPT_E_NOT_FOUND);
  982. hr = S_OK;
  983. goto error;
  984. }
  985. }
  986. // Attempt to add to the temporary store; if it fails then it already
  987. // exists so we don't want it displayed.
  988. if (!CertAddCertificateLinkToStore(
  989. pCallbackData->hMemStore,
  990. pCertContext,
  991. CERT_STORE_ADD_NEW,
  992. NULL))
  993. {
  994. hr = myHLastError();
  995. _PrintErrorStr2(hr, "CertAddCertificateLinkToStore Dup", pwszSubject, hr);
  996. hr = S_OK;
  997. goto error;
  998. }
  999. fMatch = TRUE;
  1000. hr = S_OK;
  1001. error:
  1002. if (S_OK == pCallbackData->hr || (fMatch && S_FALSE == pCallbackData->hr))
  1003. {
  1004. pCallbackData->hr = hr; // keep the first HRESULT
  1005. }
  1006. if (NULL != pwszSubject)
  1007. {
  1008. LocalFree(pwszSubject);
  1009. }
  1010. if (NULL != pNameInfo)
  1011. {
  1012. LocalFree(pNameInfo);
  1013. }
  1014. return(fMatch);
  1015. }
  1016. HRESULT
  1017. myGetKRACertificateFromPicker(
  1018. OPTIONAL IN HINSTANCE hInstance,
  1019. OPTIONAL IN HWND hwndParent,
  1020. OPTIONAL IN int idTitle,
  1021. OPTIONAL IN int idSubTitle,
  1022. OPTIONAL IN WCHAR const *pwszCommonName,
  1023. IN BOOL fUseDS,
  1024. IN BOOL fSilent,
  1025. OUT CERT_CONTEXT const **ppCert)
  1026. {
  1027. HRESULT hr;
  1028. CHAR const *pszObjId = szOID_KP_KEY_RECOVERY_AGENT;
  1029. hr = myGetCertificateFromPicker(
  1030. hInstance,
  1031. hwndParent,
  1032. idTitle,
  1033. idSubTitle,
  1034. CUCS_MYSTORE | CUCS_KRASTORE | CUCS_CASTORE |
  1035. CUCS_MACHINESTORE | CUCS_USERSTORE |
  1036. CUCS_USAGEREQUIRED | CUCS_USAGEKEYENCIPHER |
  1037. (fUseDS? CUCS_DSSTORE : 0) |
  1038. (fSilent? CUCS_SILENT : 0),
  1039. pwszCommonName,
  1040. 0, // cStore
  1041. NULL, // rghStore
  1042. 1, // cpszObjId
  1043. &pszObjId,
  1044. ppCert);
  1045. _JumpIfError(hr, error, "myGetCertificateFromPicker");
  1046. error:
  1047. return(hr);
  1048. }
  1049. HRESULT
  1050. myGetERACertificateFromPicker(
  1051. OPTIONAL IN HINSTANCE hInstance,
  1052. OPTIONAL IN HWND hwndParent,
  1053. OPTIONAL IN int idTitle,
  1054. OPTIONAL IN int idSubTitle,
  1055. OPTIONAL IN WCHAR const *pwszCommonName,
  1056. IN BOOL fSilent,
  1057. OUT CERT_CONTEXT const **ppCert)
  1058. {
  1059. HRESULT hr;
  1060. CHAR const * const apszObjId[2] = {
  1061. szOID_ENROLLMENT_AGENT,
  1062. szOID_KP_QUALIFIED_SUBORDINATION,
  1063. };
  1064. hr = myGetCertificateFromPicker(
  1065. hInstance,
  1066. hwndParent,
  1067. idTitle,
  1068. idSubTitle,
  1069. CUCS_MYSTORE |
  1070. CUCS_PRIVATEKEYREQUIRED |
  1071. //CUCS_USAGEREQUIRED |
  1072. (fSilent? CUCS_SILENT : 0),
  1073. pwszCommonName,
  1074. 0, // cStore
  1075. NULL, // rghStore
  1076. ARRAYSIZE(apszObjId), // cpszObjId
  1077. apszObjId,
  1078. ppCert);
  1079. _JumpIfError(hr, error, "myGetCertificateFromPicker");
  1080. error:
  1081. return(hr);
  1082. }
  1083. HRESULT
  1084. mySelectCertificateFromStore(
  1085. IN OUT CRYPTUI_SELECTCERTIFICATE_STRUCT *pCertSelect,
  1086. IN HCERTSTORE hStore,
  1087. IN OUT CERT_CONTEXT const **ppCertRet)
  1088. {
  1089. HRESULT hr;
  1090. CERT_CONTEXT const *pCertRet = *ppCertRet;
  1091. CERT_CONTEXT const *pCert = NULL;
  1092. BOOL fInitialSelectedCert = FALSE;
  1093. for (;;)
  1094. {
  1095. pCert = CertEnumCertificatesInStore(hStore, pCert);
  1096. if (NULL == pCert)
  1097. {
  1098. hr = myHLastError();
  1099. _PrintError(hr, "CertEnumCertificatesInStore");
  1100. break;
  1101. }
  1102. if ((*pCertSelect->pFilterCallback)(
  1103. pCert,
  1104. &fInitialSelectedCert,
  1105. pCertSelect->pvCallbackData))
  1106. {
  1107. if (NULL != pCertRet)
  1108. {
  1109. hr = CRYPT_E_EXISTS;
  1110. _JumpError(hr, error, "more than one cert matches");
  1111. }
  1112. pCertRet = CertDuplicateCertificateContext(pCert);
  1113. if (NULL == pCertRet)
  1114. {
  1115. hr = CRYPT_E_NOT_FOUND;
  1116. _JumpError(hr, error, "CertDuplicateCertificateContext");
  1117. }
  1118. }
  1119. }
  1120. hr = S_OK;
  1121. error:
  1122. if (NULL != pCert)
  1123. {
  1124. CertFreeCertificateContext(pCert);
  1125. }
  1126. *ppCertRet = pCertRet;
  1127. return(hr);
  1128. }
  1129. CERT_CONTEXT const *
  1130. mySelectCertificate(
  1131. IN OUT CRYPTUI_SELECTCERTIFICATE_STRUCT *pCertSelect)
  1132. {
  1133. HRESULT hr;
  1134. CERT_CONTEXT const *pCert = NULL;
  1135. DWORD i;
  1136. if (NULL == pCertSelect->rghDisplayStores ||
  1137. 0 == pCertSelect->cDisplayStores)
  1138. {
  1139. hr = CRYPT_E_NOT_FOUND;
  1140. _JumpError(hr, error, "no Cert Stores");
  1141. }
  1142. for (i = 0; i < pCertSelect->cDisplayStores; i++)
  1143. {
  1144. hr = mySelectCertificateFromStore(
  1145. pCertSelect,
  1146. pCertSelect->rghDisplayStores[i],
  1147. &pCert);
  1148. _JumpIfError(hr, error, "mySelectCertificateFromStore");
  1149. }
  1150. hr = S_OK;
  1151. error:
  1152. if (S_OK != hr)
  1153. {
  1154. if (NULL != pCert)
  1155. {
  1156. CertFreeCertificateContext(pCert);
  1157. pCert = NULL;
  1158. }
  1159. SetLastError(hr);
  1160. }
  1161. return(pCert);
  1162. }
  1163. HRESULT
  1164. myGetCertificateFromPicker(
  1165. OPTIONAL IN HINSTANCE hInstance,
  1166. OPTIONAL IN HWND hwndParent,
  1167. OPTIONAL IN int idTitle,
  1168. OPTIONAL IN int idSubTitle,
  1169. IN DWORD dwFlags, // CUCS_*
  1170. OPTIONAL IN WCHAR const *pwszCommonName,
  1171. OPTIONAL IN DWORD cStore,
  1172. OPTIONAL IN HCERTSTORE *rghStore,
  1173. IN DWORD cpszObjId,
  1174. OPTIONAL IN CHAR const * const *apszObjId,
  1175. OUT CERT_CONTEXT const **ppCert)
  1176. {
  1177. HRESULT hr;
  1178. HCERTSTORE *rghStoreOpened = NULL;
  1179. DWORD cStoreOpened;
  1180. CERTFILTERCALLBACKDATA callbackData;
  1181. CRYPTUI_SELECTCERTIFICATE_STRUCT CertSelect;
  1182. ZeroMemory(&callbackData, sizeof(callbackData));
  1183. ZeroMemory(&CertSelect, sizeof(CertSelect));
  1184. // custom titles
  1185. if (NULL != hInstance)
  1186. {
  1187. // try to load title from resource
  1188. hr = myLoadRCString(
  1189. hInstance,
  1190. idTitle,
  1191. const_cast<WCHAR **>(&CertSelect.szTitle));
  1192. if (S_OK != hr)
  1193. {
  1194. CSASSERT(NULL == CertSelect.szTitle);
  1195. _PrintError(hr, "myLoadRCString(Title)");
  1196. }
  1197. hr = myLoadRCString(
  1198. hInstance,
  1199. idSubTitle,
  1200. const_cast<WCHAR **>(&CertSelect.szDisplayString));
  1201. if (S_OK != hr)
  1202. {
  1203. CSASSERT(NULL == CertSelect.szDisplayString);
  1204. _PrintError(hr, "myLoadRCString(Title)");
  1205. }
  1206. }
  1207. if (NULL == rghStore)
  1208. {
  1209. cStore = 0;
  1210. }
  1211. cStoreOpened = 0;
  1212. if ((CUCS_SOURCEMASK | CUCS_TYPEMASK) & dwFlags)
  1213. {
  1214. CWaitCursor cwait;
  1215. hr = myOpenCertStores(dwFlags, &cStoreOpened, &rghStoreOpened);
  1216. _PrintIfError(hr, "myOpenCertStores");
  1217. }
  1218. CertSelect.cDisplayStores = cStore + cStoreOpened;
  1219. if (0 == CertSelect.cDisplayStores)
  1220. {
  1221. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1222. _JumpError(hr, error, "no Cert Store");
  1223. }
  1224. CertSelect.rghDisplayStores = (HCERTSTORE *) LocalAlloc(
  1225. LMEM_FIXED,
  1226. CertSelect.cDisplayStores * sizeof(HCERTSTORE));
  1227. if (NULL == CertSelect.rghDisplayStores)
  1228. {
  1229. hr = E_OUTOFMEMORY;
  1230. _JumpError(hr, error, "LocalAlloc(CertSelect.rghDisplayStores)");
  1231. }
  1232. if (0 != cStore)
  1233. {
  1234. CopyMemory(
  1235. &CertSelect.rghDisplayStores[0],
  1236. rghStore,
  1237. cStore * sizeof(rghStore[0]));
  1238. }
  1239. if (0 != cStoreOpened)
  1240. {
  1241. CopyMemory(
  1242. &CertSelect.rghDisplayStores[cStore],
  1243. rghStoreOpened,
  1244. cStoreOpened * sizeof(rghStore[0]));
  1245. }
  1246. // temporary store where the callback will store links to found certs
  1247. // so it can check for duplicates
  1248. callbackData.hMemStore = CertOpenStore(
  1249. CERT_STORE_PROV_MEMORY,
  1250. X509_ASN_ENCODING,
  1251. NULL,
  1252. CERT_STORE_CREATE_NEW_FLAG,
  1253. NULL);
  1254. if (NULL == callbackData.hMemStore)
  1255. {
  1256. hr = myHLastError();
  1257. _JumpError(hr, error, "can't create memory store");
  1258. }
  1259. CertSelect.dwSize = sizeof(CertSelect);
  1260. CertSelect.hwndParent = hwndParent;
  1261. //CertSelect.dwFlags = 0; // single selection
  1262. //CertSelect.dwDontUseColumn = 0; // display all column
  1263. CertSelect.pFilterCallback = CertificateFilterProc; // assign callback
  1264. //CertSelect.pDisplayCallback = NULL; // use default cert view dlg
  1265. callbackData.dwFlags = dwFlags;
  1266. callbackData.cpszObjId = cpszObjId;
  1267. callbackData.apszObjId = apszObjId;
  1268. callbackData.pwszCommonName = pwszCommonName;
  1269. if (NULL != pwszCommonName)
  1270. {
  1271. hr = WszToMultiByteInteger(
  1272. TRUE,
  1273. pwszCommonName,
  1274. &callbackData.cbHash,
  1275. &callbackData.pbHash);
  1276. _PrintIfError2(hr, "WszToMultiByteInteger", hr);
  1277. hr = myMakeSerialBstr(pwszCommonName, &callbackData.strSerialNumber);
  1278. _PrintIfError2(hr, "myMakeSerialBstr", hr);
  1279. }
  1280. callbackData.hr = S_FALSE;
  1281. CertSelect.pvCallbackData = &callbackData; // pass filter info as data
  1282. //CertSelect.cStores = 0; // no additional stores for chain verify
  1283. //CertSelect.rghStores = NULL; // no additional stores for chain verify
  1284. //CertSelect.cPropSheetPages = 0; // no custom cert view pages
  1285. //CertSelect.rgPropSheetPages = NULL; // no custom cert view pages
  1286. //CertSelect.hSelectedCertStore = NULL; // single selection
  1287. if (CUCS_SILENT & dwFlags)
  1288. {
  1289. *ppCert = mySelectCertificate(&CertSelect);
  1290. if (NULL == *ppCert)
  1291. {
  1292. hr = myHLastError();
  1293. _JumpError(hr, error, "mySelectCertificate");
  1294. }
  1295. }
  1296. else
  1297. {
  1298. *ppCert = CryptUIDlgSelectCertificate(&CertSelect);
  1299. }
  1300. // check for error in selection dialog
  1301. hr = callbackData.hr;
  1302. if (S_FALSE == hr)
  1303. {
  1304. hr = S_OK;
  1305. //hr = CRYPT_E_NOT_FOUND;
  1306. }
  1307. _JumpIfError(hr, error, "CryptUIDlgSelectCertificate");
  1308. error:
  1309. if (NULL != rghStoreOpened)
  1310. {
  1311. myCloseCertStores(cStoreOpened, rghStoreOpened);
  1312. }
  1313. if (NULL != callbackData.hMemStore)
  1314. {
  1315. CertCloseStore(callbackData.hMemStore, 0);
  1316. }
  1317. if (NULL != callbackData.strSerialNumber)
  1318. {
  1319. SysFreeString(callbackData.strSerialNumber);
  1320. }
  1321. if (NULL != callbackData.pbHash)
  1322. {
  1323. LocalFree(callbackData.pbHash);
  1324. }
  1325. if (NULL != CertSelect.szTitle)
  1326. {
  1327. LocalFree(const_cast<WCHAR *>(CertSelect.szTitle));
  1328. }
  1329. if (NULL != CertSelect.szDisplayString)
  1330. {
  1331. LocalFree(const_cast<WCHAR *>(CertSelect.szDisplayString));
  1332. }
  1333. if (NULL != CertSelect.rghDisplayStores)
  1334. {
  1335. LocalFree(CertSelect.rghDisplayStores);
  1336. }
  1337. return(hr);
  1338. }