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

1430 lines
31 KiB

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