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.

7290 lines
159 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: store.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <pch.cpp>
  11. #pragma hdrstop
  12. #include <winldap.h>
  13. #include <setupapi.h>
  14. #include "ocmanage.h"
  15. #include "initcert.h"
  16. #include "cscsp.h"
  17. #include "csber.h"
  18. #include "csldap.h"
  19. #define __dwFILE__ __dwFILE_CERTUTIL_STORE_CPP__
  20. #define RSAPRIV_MAGIC 0x32415352 // "RSA2"
  21. DWORD
  22. cuGetSystemStoreFlags()
  23. {
  24. return(g_fEnterpriseRegistry?
  25. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE :
  26. (g_fUserRegistry?
  27. CERT_SYSTEM_STORE_CURRENT_USER :
  28. CERT_SYSTEM_STORE_LOCAL_MACHINE));
  29. }
  30. // Parse a CertIndex -- any one of the following:
  31. //
  32. // Return the following in *piCert, *piCRL and *piCTL. MAXDWORD if not
  33. // specified
  34. // Each value must be less than 64k.
  35. // iCert decimal number
  36. // iCert.iCRL decimal number, period, decimal number
  37. // iCert.iCRL.iCTL decimal number, period, decimal number, period, number
  38. // .iCRL period, decimal number
  39. // ..iCTL period, period, decimal number
  40. //
  41. // Return the string in *ppwszCertName, if no Cert, CRL and CTL indexes.
  42. HRESULT
  43. ParseCertCRLIndex(
  44. IN WCHAR const *pwszCertIndex,
  45. OUT WCHAR **ppwszCertName,
  46. OUT DWORD *piCert,
  47. OUT DWORD *piCRL,
  48. OUT DWORD *piCTL)
  49. {
  50. HRESULT hr;
  51. WCHAR *pwszCopy = NULL;
  52. *ppwszCertName = NULL;
  53. *piCert = MAXDWORD;
  54. *piCRL = MAXDWORD;
  55. *piCTL = MAXDWORD;
  56. if (NULL != pwszCertIndex && 0 != lstrcmp(L"*", pwszCertIndex))
  57. {
  58. BOOL fNumericIndex = TRUE;
  59. WCHAR *pwszCert;
  60. WCHAR *pwszCRL;
  61. WCHAR *pwszCTL;
  62. if (L' ' == *pwszCertIndex)
  63. {
  64. fNumericIndex = FALSE;
  65. pwszCertIndex++;
  66. }
  67. hr = myDupString(pwszCertIndex, &pwszCopy);
  68. _JumpIfError(hr, error, "myDupString");
  69. pwszCert = pwszCopy;
  70. if (!iswdigit(*pwszCert) && L'.' != *pwszCert)
  71. {
  72. fNumericIndex = FALSE;
  73. }
  74. pwszCRL = NULL;
  75. pwszCTL = NULL;
  76. if (fNumericIndex)
  77. {
  78. pwszCRL = wcschr(pwszCert, L'.');
  79. if (NULL != pwszCRL)
  80. {
  81. *pwszCRL++ = L'\0';
  82. pwszCTL = wcschr(pwszCRL, L'.');
  83. if (NULL != pwszCTL)
  84. {
  85. *pwszCTL++ = L'\0';
  86. if (L'\0' != *pwszCTL)
  87. {
  88. hr = myGetLong(pwszCTL, (LONG *) piCTL);
  89. if (S_OK != hr || 64*1024 <= *piCTL)
  90. {
  91. fNumericIndex = FALSE;
  92. }
  93. }
  94. }
  95. if (fNumericIndex && L'\0' != *pwszCRL)
  96. {
  97. hr = myGetLong(pwszCRL, (LONG *) piCRL);
  98. if (S_OK != hr || 64*1024 <= *piCRL)
  99. {
  100. fNumericIndex = FALSE;
  101. }
  102. }
  103. }
  104. }
  105. if (fNumericIndex && L'\0' != *pwszCert)
  106. {
  107. hr = myGetLong(pwszCert, (LONG *) piCert);
  108. if (S_OK != hr || 64*1024 <= *piCert)
  109. {
  110. fNumericIndex = FALSE;
  111. }
  112. }
  113. if (!fNumericIndex)
  114. {
  115. hr = myRevertSanitizeName(pwszCertIndex, ppwszCertName);
  116. _JumpIfError(hr, error, "myRevertSanitizeName");
  117. *piCert = MAXDWORD;
  118. *piCRL = MAXDWORD;
  119. *piCTL = MAXDWORD;
  120. }
  121. }
  122. if (1 < g_fVerbose)
  123. {
  124. wprintf(
  125. L"pwszCertIndex=%ws, %ws, %d.%d.%d\n",
  126. pwszCertIndex,
  127. *ppwszCertName,
  128. *piCert,
  129. *piCRL,
  130. *piCTL);
  131. }
  132. hr = S_OK;
  133. error:
  134. if (NULL != pwszCopy)
  135. {
  136. LocalFree(pwszCopy);
  137. }
  138. return(hr);
  139. }
  140. HRESULT
  141. DeleteKeys(
  142. IN CERT_CONTEXT const *pcc,
  143. IN BOOL fUser)
  144. {
  145. HRESULT hr;
  146. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  147. hr = myCertGetKeyProviderInfo(pcc, &pkpi);
  148. _PrintIfError(hr, "myCertGetKeyProviderInfo");
  149. if (S_OK == hr)
  150. {
  151. HCRYPTPROV hProv;
  152. if (!myCertSrvCryptAcquireContext(
  153. &hProv,
  154. pkpi->pwszContainerName,
  155. pkpi->pwszProvName,
  156. pkpi->dwProvType,
  157. pkpi->dwFlags | CRYPT_DELETEKEYSET,
  158. !fUser))
  159. {
  160. hr = myHLastError();
  161. _PrintIfError(hr, "myCertSrvCryptAcquireContext");
  162. }
  163. else
  164. {
  165. DBGPRINT((
  166. DBG_SS_CERTLIBI,
  167. "DeleteKeys(%ws, %ws)\n",
  168. !fUser? L"Machine" : L"User",
  169. pkpi->pwszContainerName));
  170. }
  171. }
  172. hr = S_OK;
  173. //error:
  174. if (NULL != pkpi)
  175. {
  176. LocalFree(pkpi);
  177. }
  178. return(hr);
  179. }
  180. // Delete keys copied into new CSP, and close store
  181. HRESULT
  182. cuDeleteStoreAndKeys(
  183. OPTIONAL IN HCERTSTORE hStore,
  184. IN BOOL fUser)
  185. {
  186. HRESULT hr;
  187. CERT_CONTEXT const *pcc;
  188. // Enumerate certs and delete keys
  189. pcc = NULL;
  190. while (TRUE)
  191. {
  192. pcc = CertEnumCertificatesInStore(hStore, pcc);
  193. if (NULL == pcc)
  194. {
  195. break;
  196. }
  197. hr = DeleteKeys(pcc, fUser);
  198. _PrintIfError(hr, "DeleteKeys");
  199. }
  200. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  201. hr = S_OK;
  202. //error:
  203. return(hr);
  204. }
  205. HRESULT
  206. CopyOneCertAndKeys(
  207. IN CERT_CONTEXT const *pcc,
  208. IN BOOL fUser,
  209. IN WCHAR const *pwszNewCSP,
  210. IN OUT HCERTSTORE hStore)
  211. {
  212. HRESULT hr;
  213. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  214. WCHAR *pwszKeyContainerName = NULL;
  215. CERT_CONTEXT const *pccNew = NULL;
  216. pccNew = CertCreateCertificateContext(
  217. X509_ASN_ENCODING,
  218. pcc->pbCertEncoded,
  219. pcc->cbCertEncoded);
  220. if (NULL == pccNew)
  221. {
  222. hr = myHLastError();
  223. _JumpError(hr, error, "CertCreateCertificateContext");
  224. }
  225. hr = myCertGetKeyProviderInfo(pcc, &pkpi);
  226. _PrintIfError(hr, "myCertGetKeyProviderInfo");
  227. if (S_OK == hr)
  228. {
  229. hr = cuGenerateKeyContainerName(pcc, &pwszKeyContainerName);
  230. _JumpIfError(hr, error, "cuGenerateKeyContainerName");
  231. hr = myCopyKeys(
  232. pkpi,
  233. pkpi->pwszContainerName, // pwszOldContainer
  234. pwszKeyContainerName, // pwszNewContainer
  235. pwszNewCSP, // pwszNewCSP
  236. fUser, // fOldUserKey
  237. fUser, // fNewUserKey
  238. FALSE, // fNewProtect
  239. g_fForce);
  240. _JumpIfError(hr, error, "myCopyKeys");
  241. pkpi->pwszContainerName = pwszKeyContainerName;
  242. pkpi->pwszProvName = const_cast<WCHAR *>(pwszNewCSP);
  243. if (!CertSetCertificateContextProperty(
  244. pccNew,
  245. CERT_KEY_PROV_INFO_PROP_ID,
  246. 0,
  247. pkpi))
  248. {
  249. hr = myHLastError();
  250. _JumpError(hr, error, "CertSetCertificateContextProperty");
  251. }
  252. }
  253. if (!CertAddCertificateContextToStore(
  254. hStore,
  255. pccNew,
  256. CERT_STORE_ADD_ALWAYS,
  257. NULL))
  258. {
  259. hr = myHLastError();
  260. _JumpError(hr, error, "CertAddCertificateContextToStore");
  261. }
  262. hr = S_OK;
  263. error:
  264. if (NULL != pccNew)
  265. {
  266. CertFreeCertificateContext(pccNew);
  267. }
  268. if (NULL != pkpi)
  269. {
  270. LocalFree(pkpi);
  271. }
  272. if (NULL != pwszKeyContainerName)
  273. {
  274. LocalFree(pwszKeyContainerName);
  275. }
  276. return(hr);
  277. }
  278. HRESULT
  279. cuCopyStoreToNewCSP(
  280. IN HCERTSTORE hStoreIn,
  281. IN BOOL fUser,
  282. IN WCHAR const *pwszNewCSP,
  283. OUT HCERTSTORE *phStoreOut)
  284. {
  285. HRESULT hr;
  286. HCERTSTORE hStoreOut = NULL;
  287. CERT_CONTEXT const *pcc;
  288. *phStoreOut = NULL;
  289. hStoreOut = CertOpenStore(
  290. CERT_STORE_PROV_MEMORY,
  291. X509_ASN_ENCODING,
  292. NULL,
  293. CERT_STORE_NO_CRYPT_RELEASE_FLAG |
  294. CERT_STORE_ENUM_ARCHIVED_FLAG,
  295. NULL);
  296. if (NULL == hStoreOut)
  297. {
  298. hr = myHLastError();
  299. _JumpError(hr, error, "CertOpenStore");
  300. }
  301. // Enumerate certs:
  302. // copy certs to new store and keys to new CSP
  303. pcc = NULL;
  304. while (TRUE)
  305. {
  306. pcc = CertEnumCertificatesInStore(hStoreIn, pcc);
  307. if (NULL == pcc)
  308. {
  309. break;
  310. }
  311. hr = CopyOneCertAndKeys(pcc, fUser, pwszNewCSP, hStoreOut);
  312. _JumpIfError(hr, error, "CopyOneCertAndKeys");
  313. }
  314. *phStoreOut = hStoreOut;
  315. hStoreOut = NULL;
  316. hr = S_OK;
  317. error:
  318. if (NULL != hStoreOut)
  319. {
  320. cuDeleteStoreAndKeys(hStoreOut, fUser);
  321. }
  322. return(hr);
  323. }
  324. HRESULT
  325. SavePFXStoreToFile(
  326. IN HCERTSTORE hStoreSave,
  327. IN WCHAR const *pwszfnOut,
  328. OPTIONAL IN WCHAR const *pwszNewCSP,
  329. OPTIONAL IN WCHAR const *pwszSalt,
  330. OPTIONAL IN WCHAR const *pwszV3CACertId,
  331. IN BOOL fSaveAsPFX,
  332. IN DWORD dwEPFAlg,
  333. IN WCHAR const *pwszPassword,
  334. IN OUT WCHAR **ppwszPassword)
  335. {
  336. HRESULT hr;
  337. CRYPT_DATA_BLOB pfx;
  338. WCHAR wszPassword[MAX_PATH];
  339. HCERTSTORE hStoreT = NULL;
  340. BOOL fUser = !g_fEnterpriseRegistry && g_fUserRegistry;
  341. pfx.pbData = NULL;
  342. if (NULL == *ppwszPassword)
  343. {
  344. hr = cuGetPassword(
  345. IDS_FORMAT_ENTER_PASSWORD_OUTPUT_FILE,
  346. pwszfnOut,
  347. pwszPassword,
  348. TRUE, // fVerify
  349. wszPassword,
  350. ARRAYSIZE(wszPassword),
  351. &pwszPassword);
  352. _JumpIfError(hr, error, "cuGetPassword");
  353. hr = myDupString(pwszPassword, ppwszPassword);
  354. _JumpIfError(hr, error, "myDupString");
  355. }
  356. pwszPassword = *ppwszPassword;
  357. if (fSaveAsPFX)
  358. {
  359. if (NULL != pwszNewCSP)
  360. {
  361. // Copy keys to new CSP, create new store with updated KeyProvInfo
  362. //wprintf(L"New CSP: %ws\n", pwszNewCSP);
  363. hr = cuCopyStoreToNewCSP(hStoreSave, fUser, pwszNewCSP, &hStoreT);
  364. _JumpIfError(hr, error, "cuCopyStoreToNewCSP");
  365. hStoreSave = hStoreT;
  366. }
  367. // GemPlus returns NTE_BAD_TYPE instead of NTE_BAD_KEY, blowing up
  368. // REPORT_NOT_ABLE* filtering. If they ever get this right, we can
  369. // pass "[...] : EXPORT_PRIVATE_KEYS"
  370. hr = myPFXExportCertStore(
  371. hStoreSave,
  372. &pfx,
  373. pwszPassword,
  374. !g_fWeakPFX,
  375. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY);
  376. _JumpIfError(hr, error, "myPFXExportCertStore");
  377. hr = EncodeToFileW(
  378. pwszfnOut,
  379. pfx.pbData,
  380. pfx.cbData,
  381. CRYPT_STRING_BINARY | g_EncodeFlags);
  382. _JumpIfError(hr, error, "EncodeToFileW");
  383. }
  384. else
  385. {
  386. hr = EPFSaveCertStoreToFile(
  387. hStoreSave,
  388. pwszPassword,
  389. pwszfnOut,
  390. pwszV3CACertId,
  391. dwEPFAlg,
  392. pwszSalt);
  393. _JumpIfError(hr, error, "EPFSaveCertStoreToFile");
  394. }
  395. error:
  396. SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
  397. if (NULL != hStoreT)
  398. {
  399. cuDeleteStoreAndKeys(hStoreT, fUser);
  400. }
  401. if (NULL != pfx.pbData)
  402. {
  403. LocalFree(pfx.pbData);
  404. }
  405. return(hr);
  406. }
  407. HRESULT
  408. SavePFXToFile(
  409. IN CERT_CONTEXT const *pCert,
  410. IN WCHAR const *pwszfnOut,
  411. IN BOOL fFirst,
  412. IN WCHAR const *pwszPassword,
  413. IN OUT WCHAR **ppwszPassword)
  414. {
  415. HRESULT hr;
  416. HCERTSTORE hTempMemoryStore = NULL;
  417. hTempMemoryStore = CertOpenStore(
  418. CERT_STORE_PROV_MEMORY,
  419. X509_ASN_ENCODING,
  420. NULL,
  421. CERT_STORE_NO_CRYPT_RELEASE_FLAG |
  422. CERT_STORE_ENUM_ARCHIVED_FLAG,
  423. NULL);
  424. if (NULL == hTempMemoryStore)
  425. {
  426. hr = myHLastError();
  427. _JumpError(hr, error, "CertOpenStore");
  428. }
  429. // Begin Chain Building
  430. hr = myAddChainToMemoryStore(hTempMemoryStore, pCert, g_dwmsTimeout);
  431. _JumpIfError(hr, error, "myAddChainToMemoryStore");
  432. // End Chain Building
  433. hr = SavePFXStoreToFile(
  434. hTempMemoryStore,
  435. pwszfnOut,
  436. NULL, // pwszNewCSP
  437. NULL, // pwszSalt
  438. NULL, // pwszV3CACertId
  439. TRUE, // fSaveAsPFX
  440. 0, // dwEPFAlg
  441. pwszPassword,
  442. ppwszPassword);
  443. _JumpIfError(hr, error, "SavePFXStoreToFile");
  444. error:
  445. if (NULL != hTempMemoryStore)
  446. {
  447. CertCloseStore(hTempMemoryStore, CERT_CLOSE_STORE_CHECK_FLAG);
  448. }
  449. return(hr);
  450. }
  451. HRESULT
  452. SavePVKToFile(
  453. IN CERT_CONTEXT const *pCert,
  454. IN WCHAR const *pwszfnOut,
  455. IN BOOL fFirst)
  456. {
  457. return(S_OK);
  458. }
  459. HRESULT
  460. cuDumpCTLProperties(
  461. IN CTL_CONTEXT const *pCTL)
  462. {
  463. HRESULT hr;
  464. DWORD dwPropId;
  465. BYTE *pb = NULL;
  466. DWORD cb;
  467. dwPropId = 0;
  468. while (TRUE)
  469. {
  470. if (NULL != pb)
  471. {
  472. LocalFree(pb);
  473. pb = NULL;
  474. }
  475. dwPropId = CertEnumCTLContextProperties(pCTL, dwPropId);
  476. if (0 == dwPropId)
  477. {
  478. break;
  479. }
  480. while (TRUE)
  481. {
  482. if (!CertGetCTLContextProperty(pCTL, dwPropId, pb, &cb))
  483. {
  484. hr = myHLastError();
  485. _JumpError(hr, error, "CertGetCTLContextProperty");
  486. }
  487. if (NULL != pb)
  488. {
  489. break; // memory alloc'd, property fetched
  490. }
  491. pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  492. if (NULL == pb)
  493. {
  494. hr = E_OUTOFMEMORY;
  495. _JumpError(hr, error, "LocalAlloc");
  496. }
  497. }
  498. hr = cuDumpFormattedProperty(dwPropId, NULL, pb, cb);
  499. _PrintIfError(hr, "cuDumpFormattedProperty");
  500. }
  501. hr = S_OK;
  502. error:
  503. if (NULL != pb)
  504. {
  505. LocalFree(pb);
  506. }
  507. return(hr);
  508. }
  509. HRESULT
  510. cuDumpCRLProperties(
  511. IN CRL_CONTEXT const *pCRL)
  512. {
  513. HRESULT hr;
  514. DWORD dwPropId;
  515. BYTE *pb = NULL;
  516. DWORD cb;
  517. dwPropId = 0;
  518. while (TRUE)
  519. {
  520. if (NULL != pb)
  521. {
  522. LocalFree(pb);
  523. pb = NULL;
  524. }
  525. dwPropId = CertEnumCRLContextProperties(pCRL, dwPropId);
  526. if (0 == dwPropId)
  527. {
  528. break;
  529. }
  530. while (TRUE)
  531. {
  532. if (!CertGetCRLContextProperty(pCRL, dwPropId, pb, &cb))
  533. {
  534. hr = myHLastError();
  535. _JumpError(hr, error, "CertGetCRLContextProperty");
  536. }
  537. if (NULL != pb)
  538. {
  539. break; // memory alloc'd, property fetched
  540. }
  541. pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  542. if (NULL == pb)
  543. {
  544. hr = E_OUTOFMEMORY;
  545. _JumpError(hr, error, "LocalAlloc");
  546. }
  547. }
  548. hr = cuDumpFormattedProperty(dwPropId, NULL, pb, cb);
  549. _PrintIfError(hr, "cuDumpFormattedProperty");
  550. }
  551. hr = S_OK;
  552. error:
  553. if (NULL != pb)
  554. {
  555. LocalFree(pb);
  556. }
  557. return(hr);
  558. }
  559. HRESULT
  560. cuDumpCertProperties(
  561. IN CERT_CONTEXT const *pCert)
  562. {
  563. HRESULT hr;
  564. DWORD dwPropId;
  565. BYTE *pb = NULL;
  566. DWORD cb;
  567. dwPropId = 0;
  568. while (TRUE)
  569. {
  570. dwPropId = CertEnumCertificateContextProperties(pCert, dwPropId);
  571. if (0 == dwPropId)
  572. {
  573. break;
  574. }
  575. if (NULL != pb)
  576. {
  577. LocalFree(pb);
  578. pb = NULL;
  579. }
  580. while (TRUE)
  581. {
  582. if (!CertGetCertificateContextProperty(pCert, dwPropId, pb, &cb))
  583. {
  584. hr = myHLastError();
  585. _JumpError(hr, error, "CertGetCertificateContextProperty");
  586. }
  587. if (NULL != pb)
  588. {
  589. break; // memory alloc'd, property fetched
  590. }
  591. pb = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  592. if (NULL == pb)
  593. {
  594. hr = E_OUTOFMEMORY;
  595. _JumpError(hr, error, "LocalAlloc");
  596. }
  597. }
  598. hr = cuDumpFormattedProperty(dwPropId, NULL, pb, cb);
  599. _PrintIfError(hr, "cuDumpFormattedProperty");
  600. }
  601. hr = S_OK;
  602. error:
  603. if (NULL != pb)
  604. {
  605. LocalFree(pb);
  606. }
  607. return(hr);
  608. }
  609. HRESULT
  610. SetCertificateKeyProvInfo(
  611. IN CERT_CONTEXT const *pCert,
  612. IN CRYPT_KEY_PROV_INFO const *pkpi,
  613. IN CERT_PUBLIC_KEY_INFO const *pPubKeyInfo)
  614. {
  615. HRESULT hr;
  616. if (!myCertComparePublicKeyInfo(
  617. X509_ASN_ENCODING,
  618. CERT_V1 == pCert->pCertInfo->dwVersion,
  619. pPubKeyInfo,
  620. &pCert->pCertInfo->SubjectPublicKeyInfo))
  621. {
  622. // by design, (my)CertComparePublicKeyInfo doesn't set last error!
  623. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  624. _JumpError2(hr, error, "myCertComparePublicKeyInfo", hr);
  625. }
  626. if (!CertSetCertificateContextProperty(
  627. pCert,
  628. CERT_KEY_PROV_INFO_PROP_ID,
  629. 0,
  630. pkpi))
  631. {
  632. hr = myHLastError();
  633. _JumpError(hr, error, "CertSetCertificateContextProperty");
  634. }
  635. hr = S_OK;
  636. error:
  637. return(hr);
  638. }
  639. HRESULT
  640. cuFindCertificateKeyProvInfo(
  641. IN CERT_CONTEXT const *pCert)
  642. {
  643. HRESULT hr;
  644. HCRYPTPROV hProv = NULL;
  645. KEY_LIST *pKeyList = NULL;
  646. CERT_PUBLIC_KEY_INFO *pPubKeyInfoSig = NULL;
  647. CERT_PUBLIC_KEY_INFO *pPubKeyInfoXchg = NULL;
  648. if (NULL != g_pwszCSP)
  649. {
  650. DWORD dwKeySpec;
  651. DWORD dwProvType;
  652. KEY_LIST *pKeyT;
  653. hr = csiGetProviderTypeFromProviderName(g_pwszCSP, &dwProvType);
  654. _JumpIfErrorStr(hr, error, "csiGetProviderTypeFromProviderName", g_pwszCSP);
  655. if (!CryptAcquireCertificatePrivateKey(
  656. pCert,
  657. CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
  658. NULL, // pvReserved
  659. &hProv,
  660. &dwKeySpec,
  661. NULL)) // pfCallerFreeProv
  662. {
  663. hr = myHLastError();
  664. _PrintError(hr, "CryptFindCertificateKeyProvInfo");
  665. }
  666. else
  667. {
  668. hr = CRYPT_E_EXISTS;
  669. _PrintError2(hr, "Key Exists!", hr);
  670. if (!g_fForce)
  671. {
  672. goto error;
  673. }
  674. }
  675. hr = csiGetKeyList(
  676. dwProvType, // dwProvType
  677. g_pwszCSP, // pwszProvName
  678. !g_fUserRegistry, // fMachineKeyset
  679. !g_fCryptSilent, // inverted fSilent: default is Silent!
  680. &pKeyList);
  681. _JumpIfErrorStr(hr, error, "csiGetKeyList", g_pwszCSP);
  682. for (pKeyT = pKeyList; NULL != pKeyT; pKeyT = pKeyT->next)
  683. {
  684. DWORD dwProvTypeT;
  685. dwProvTypeT = dwProvType;
  686. hr = cuLoadKeys(
  687. g_pwszCSP,
  688. &dwProvTypeT,
  689. pKeyT->pwszName,
  690. !g_fUserRegistry, // fMachineKeyset
  691. TRUE,
  692. NULL,
  693. &pPubKeyInfoSig,
  694. &pPubKeyInfoXchg);
  695. if (S_OK != hr)
  696. {
  697. cuPrintError(IDS_ERR_FORMAT_LOADKEYS, hr);
  698. }
  699. else
  700. {
  701. CRYPT_KEY_PROV_INFO kpi;
  702. ZeroMemory(&kpi, sizeof(kpi));
  703. kpi.pwszContainerName = pKeyT->pwszName;
  704. kpi.pwszProvName = g_pwszCSP;
  705. kpi.dwProvType = dwProvTypeT;
  706. kpi.dwFlags = g_fUserRegistry? 0 : CRYPT_MACHINE_KEYSET;
  707. if (NULL != pPubKeyInfoSig)
  708. {
  709. kpi.dwKeySpec = AT_SIGNATURE;
  710. hr = SetCertificateKeyProvInfo(
  711. pCert,
  712. &kpi,
  713. pPubKeyInfoSig);
  714. if (S_OK == hr)
  715. {
  716. break;
  717. }
  718. _PrintError2(hr, "SetCertificateKeyProvInfo", hr);
  719. }
  720. if (NULL != pPubKeyInfoXchg)
  721. {
  722. kpi.dwKeySpec = AT_KEYEXCHANGE;
  723. hr = SetCertificateKeyProvInfo(
  724. pCert,
  725. &kpi,
  726. pPubKeyInfoXchg);
  727. if (S_OK == hr)
  728. {
  729. break;
  730. }
  731. _PrintError2(hr, "SetCertificateKeyProvInfo", hr);
  732. }
  733. }
  734. if (NULL != pPubKeyInfoSig)
  735. {
  736. LocalFree(pPubKeyInfoSig);
  737. pPubKeyInfoSig = NULL;
  738. }
  739. if (NULL != pPubKeyInfoXchg)
  740. {
  741. LocalFree(pPubKeyInfoXchg);
  742. pPubKeyInfoXchg = NULL;
  743. }
  744. }
  745. if (NULL == pKeyT)
  746. {
  747. hr = CRYPT_E_NOT_FOUND;
  748. _JumpError(hr, error, "cuFindCertificateKeyProvInfo");
  749. }
  750. }
  751. else
  752. {
  753. if (!CryptFindCertificateKeyProvInfo(
  754. pCert,
  755. 0, // dwFlags
  756. NULL)) // pvReserved
  757. {
  758. hr = myHLastError();
  759. _JumpError(hr, error, "CryptFindCertificateKeyProvInfo");
  760. }
  761. }
  762. hr = S_OK;
  763. error:
  764. if (NULL != pPubKeyInfoSig)
  765. {
  766. LocalFree(pPubKeyInfoSig);
  767. }
  768. if (NULL != pPubKeyInfoXchg)
  769. {
  770. LocalFree(pPubKeyInfoXchg);
  771. }
  772. if (NULL != pKeyList)
  773. {
  774. csiFreeKeyList(pKeyList);
  775. }
  776. if (NULL != hProv)
  777. {
  778. CryptReleaseContext(hProv, 0);
  779. }
  780. return(hr);
  781. }
  782. HRESULT
  783. EnumCertsInStore(
  784. IN HCERTSTORE hStore,
  785. IN DWORD Mode,
  786. IN DWORD iCertSave,
  787. OPTIONAL IN WCHAR const *pwszCertName,
  788. IN DWORD cbHash,
  789. OPTIONAL IN BYTE *pbHash,
  790. OPTIONAL IN WCHAR const *pwszfnOut,
  791. OPTIONAL IN WCHAR const *pwszPasswordArg,
  792. IN OUT WCHAR **ppwszPassword,
  793. OUT DWORD *pcCert)
  794. {
  795. HRESULT hr;
  796. HRESULT hr2;
  797. DWORD iCert;
  798. CERT_CONTEXT const *pCert = NULL;
  799. BSTR strSerialNumber = NULL;
  800. *pcCert = 0;
  801. hr2 = S_OK;
  802. if (NULL != pwszCertName)
  803. {
  804. hr = myMakeSerialBstr(pwszCertName, &strSerialNumber);
  805. _PrintIfError2(hr, "myMakeSerialBstr", hr);
  806. }
  807. for (iCert = 0; ; iCert++)
  808. {
  809. DWORD VerifyState;
  810. BOOL fSigningKey;
  811. BOOL fMatchingKey;
  812. pCert = CertEnumCertificatesInStore(hStore, pCert);
  813. if (NULL == pCert)
  814. {
  815. break;
  816. }
  817. if (MAXDWORD == iCertSave || iCert == iCertSave)
  818. {
  819. DWORD cb;
  820. if (NULL != pwszCertName)
  821. {
  822. BOOL fMatch;
  823. hr = myCertMatch(
  824. pCert,
  825. pwszCertName,
  826. FALSE, // fAllowMissingCN
  827. pbHash,
  828. cbHash,
  829. strSerialNumber,
  830. &fMatch);
  831. _PrintIfError(hr, "myCertMatch");
  832. if (S_OK == hr2)
  833. {
  834. hr2 = hr;
  835. }
  836. if (S_OK != hr || !fMatch)
  837. {
  838. continue;
  839. }
  840. }
  841. if (0 != *pcCert)
  842. {
  843. wprintf(wszNewLine);
  844. }
  845. wprintf(
  846. myLoadResourceString(IDS_FORMAT_DUMP_CERT_INDEX), // "================ Certificate %d ================"
  847. iCert);
  848. wprintf(wszNewLine);
  849. if (CertGetCertificateContextProperty(
  850. pCert,
  851. CERT_ARCHIVED_PROP_ID,
  852. NULL,
  853. &cb))
  854. {
  855. wprintf(myLoadResourceString(IDS_ARCHIVED)); // "Archived!"
  856. wprintf(wszNewLine);
  857. }
  858. if ((iCert == iCertSave || NULL != pwszCertName) &&
  859. NULL != pwszfnOut &&
  860. (DVNS_SAVECERT & Mode))
  861. {
  862. hr = EncodeToFileW(
  863. pwszfnOut,
  864. pCert->pbCertEncoded,
  865. pCert->cbCertEncoded,
  866. CRYPT_STRING_BINARY | g_EncodeFlags);
  867. _PrintIfError(hr, "EncodeToFileW");
  868. if (S_OK == hr2)
  869. {
  870. hr2 = hr;
  871. }
  872. }
  873. hr = cuDumpAsnBinary(
  874. pCert->pbCertEncoded,
  875. pCert->cbCertEncoded,
  876. MAXDWORD);
  877. _PrintIfError(hr, "cuDumpAsnBinary");
  878. if (S_OK == hr2)
  879. {
  880. hr2 = hr;
  881. }
  882. if (DVNS_REPAIRKPI & Mode)
  883. {
  884. hr = cuFindCertificateKeyProvInfo(pCert);
  885. _PrintIfError(hr, "cuFindCertificateKeyProvInfo");
  886. if (S_OK == hr2)
  887. {
  888. hr2 = hr;
  889. }
  890. }
  891. if ((DVNS_DUMPPROPERTIES & Mode) && !g_fQuiet)
  892. {
  893. hr = cuDumpCertProperties(pCert);
  894. _PrintIfError(hr, "cuDumpCertProperties");
  895. if (S_OK == hr2)
  896. {
  897. hr2 = hr;
  898. }
  899. }
  900. if (DVNS_DUMPKEYS & Mode)
  901. {
  902. if (0 == (DVNS_DUMPPROPERTIES & Mode) || g_fQuiet)
  903. {
  904. hr = cuDumpCertKeyProviderInfo(
  905. g_wszPad2,
  906. pCert,
  907. NULL,
  908. NULL);
  909. _PrintIfError(hr, "cuDumpCertKeyProviderInfo");
  910. if (S_OK == hr2)
  911. {
  912. hr2 = hr;
  913. }
  914. }
  915. hr = cuDumpPrivateKey(pCert, &fSigningKey, &fMatchingKey);
  916. if (!IsHrSkipPrivateKey(hr))
  917. {
  918. if (S_OK != hr)
  919. {
  920. wprintf(myLoadResourceString(
  921. fSigningKey?
  922. IDS_SIGNATURE_BAD : // "Signature test FAILED"
  923. IDS_ENCRYPTION_BAD)); // "Encryption test FAILED"
  924. wprintf(wszNewLine);
  925. _PrintError(hr, "cuDumpPrivateKey");
  926. fMatchingKey = FALSE;
  927. }
  928. if (fMatchingKey)
  929. {
  930. wprintf(myLoadResourceString(
  931. fSigningKey?
  932. IDS_SIGNATURE_OK : // "Signature test passed"
  933. IDS_ENCRYPTION_OK)); // "Encryption test passed"
  934. wprintf(wszNewLine);
  935. }
  936. }
  937. }
  938. if (DVNS_VERIFYCERT & Mode)
  939. {
  940. hr = cuVerifyCertContext(
  941. pCert,
  942. (DVNS_CASTORE & Mode)? hStore : NULL,
  943. 0, // cApplicationPolicies
  944. NULL, // apszApplicationPolicies
  945. 0, // cIssuancePolicies
  946. NULL, // apszIssuancePolicies
  947. FALSE, // fNTAuth
  948. &VerifyState);
  949. if (S_OK != hr)
  950. {
  951. cuPrintError(IDS_ERR_FORMAT_BAD_CERT, hr);
  952. _PrintError(hr, "cuVerifyCertContext");
  953. if (S_OK == hr2)
  954. {
  955. hr2 = hr; // Save first error
  956. }
  957. }
  958. else if (0 == (VS_ERRORMASK & VerifyState))
  959. {
  960. wprintf(myLoadResourceString(IDS_CERT_VERIFIES)); // "Certificate is valid"
  961. }
  962. wprintf(wszNewLine);
  963. }
  964. if (DVNS_SAVEPFX & Mode)
  965. {
  966. hr = SavePFXToFile(
  967. pCert,
  968. pwszfnOut,
  969. 0 == *pcCert,
  970. pwszPasswordArg,
  971. ppwszPassword);
  972. _PrintIfError(hr, "SavePFXToFile");
  973. if (S_OK == hr2)
  974. {
  975. hr2 = hr;
  976. }
  977. }
  978. if (DVNS_SAVEPVK & Mode)
  979. {
  980. hr = SavePVKToFile(pCert, pwszfnOut, 0 == *pcCert);
  981. _PrintIfError(hr, "SavePVKToFile");
  982. if (S_OK == hr2)
  983. {
  984. hr2 = hr;
  985. }
  986. }
  987. (*pcCert)++;
  988. }
  989. }
  990. hr = hr2;
  991. _JumpIfError(hr, error, "EnumCertsInStore");
  992. error:
  993. if (NULL != pCert)
  994. {
  995. CertFreeCertificateContext(pCert);
  996. }
  997. if (NULL != strSerialNumber)
  998. {
  999. SysFreeString(strSerialNumber);
  1000. }
  1001. return(hr);
  1002. }
  1003. HRESULT
  1004. EnumCRLsInStore(
  1005. IN HCERTSTORE hStore,
  1006. IN DWORD Mode,
  1007. IN DWORD iCRLSave,
  1008. OPTIONAL IN WCHAR const *pwszCertName,
  1009. IN DWORD cbHash,
  1010. OPTIONAL IN BYTE *pbHash,
  1011. OPTIONAL IN WCHAR const *pwszfnOut,
  1012. OUT DWORD *pcCRL)
  1013. {
  1014. HRESULT hr;
  1015. HRESULT hr2;
  1016. DWORD iCRL;
  1017. CRL_CONTEXT const *pCRL = NULL;
  1018. *pcCRL = 0;
  1019. hr2 = S_OK;
  1020. for (iCRL = 0; ; iCRL++)
  1021. {
  1022. pCRL = CertEnumCRLsInStore(hStore, pCRL);
  1023. if (NULL == pCRL)
  1024. {
  1025. break;
  1026. }
  1027. if (MAXDWORD == iCRLSave || iCRL == iCRLSave)
  1028. {
  1029. if (NULL != pwszCertName)
  1030. {
  1031. BOOL fMatch;
  1032. hr = myCRLMatch(
  1033. pCRL,
  1034. pwszCertName,
  1035. FALSE, // fAllowMissingCN
  1036. pbHash,
  1037. cbHash,
  1038. &fMatch);
  1039. _PrintIfError(hr, "myCRLMatch");
  1040. if (S_OK == hr2)
  1041. {
  1042. hr2 = hr;
  1043. }
  1044. if (S_OK != hr || !fMatch)
  1045. {
  1046. continue;
  1047. }
  1048. }
  1049. if (0 != *pcCRL)
  1050. {
  1051. wprintf(wszNewLine);
  1052. }
  1053. wprintf(
  1054. myLoadResourceString(IDS_FORMAT_DUMP_CRL_INDEX), // "================ CRL %d ================"
  1055. iCRL);
  1056. wprintf(wszNewLine);
  1057. if ((iCRL == iCRLSave || NULL != pwszCertName) &&
  1058. NULL != pwszfnOut &&
  1059. (DVNS_SAVECRL & Mode))
  1060. {
  1061. hr = EncodeToFileW(
  1062. pwszfnOut,
  1063. pCRL->pbCrlEncoded,
  1064. pCRL->cbCrlEncoded,
  1065. CRYPT_STRING_BINARY | g_EncodeFlags);
  1066. _PrintIfError(hr, "EncodeToFileW");
  1067. if (S_OK == hr2)
  1068. {
  1069. hr2 = hr;
  1070. }
  1071. }
  1072. hr = cuDumpAsnBinary(
  1073. pCRL->pbCrlEncoded,
  1074. pCRL->cbCrlEncoded,
  1075. MAXDWORD);
  1076. _PrintIfError(hr, "cuDumpAsnBinary");
  1077. if (S_OK == hr2)
  1078. {
  1079. hr2 = hr;
  1080. }
  1081. if ((DVNS_DUMPPROPERTIES & Mode) && !g_fQuiet)
  1082. {
  1083. hr = cuDumpCRLProperties(pCRL);
  1084. _PrintIfError(hr, "cuDumpCRLProperties");
  1085. if (S_OK == hr2)
  1086. {
  1087. hr2 = hr;
  1088. }
  1089. }
  1090. (*pcCRL)++;
  1091. }
  1092. }
  1093. hr = hr2;
  1094. _JumpIfError(hr, error, "EnumCRLsInStore");
  1095. error:
  1096. if (NULL != pCRL)
  1097. {
  1098. CertFreeCRLContext(pCRL);
  1099. }
  1100. return(hr);
  1101. }
  1102. HRESULT
  1103. EnumCTLsInStore(
  1104. IN HCERTSTORE hStore,
  1105. IN DWORD Mode,
  1106. IN DWORD iCTLSave,
  1107. OPTIONAL IN WCHAR const *pwszCertName,
  1108. IN DWORD cbHash,
  1109. OPTIONAL IN BYTE *pbHash,
  1110. OPTIONAL IN WCHAR const *pwszfnOut,
  1111. OUT DWORD *pcCTL)
  1112. {
  1113. HRESULT hr;
  1114. HRESULT hr2;
  1115. DWORD iCTL;
  1116. CTL_CONTEXT const *pCTL = NULL;
  1117. *pcCTL = 0;
  1118. hr2 = S_OK;
  1119. for (iCTL = 0; ; iCTL++)
  1120. {
  1121. pCTL = CertEnumCTLsInStore(hStore, pCTL);
  1122. if (NULL == pCTL)
  1123. {
  1124. break;
  1125. }
  1126. if (MAXDWORD == iCTLSave || iCTL == iCTLSave)
  1127. {
  1128. DWORD cb;
  1129. if (NULL != pwszCertName)
  1130. {
  1131. BOOL fMatch;
  1132. hr = myCTLMatch(pCTL, pbHash, cbHash, &fMatch);
  1133. _PrintIfError(hr, "myCTLMatch");
  1134. if (S_OK == hr2)
  1135. {
  1136. hr2 = hr;
  1137. }
  1138. if (S_OK != hr || !fMatch)
  1139. {
  1140. continue;
  1141. }
  1142. }
  1143. if (0 != *pcCTL)
  1144. {
  1145. wprintf(wszNewLine);
  1146. }
  1147. wprintf(
  1148. myLoadResourceString(IDS_FORMAT_DUMP_CTL_INDEX), // "================ CTL %d ================"
  1149. iCTL);
  1150. wprintf(wszNewLine);
  1151. if (CertGetCTLContextProperty(
  1152. pCTL,
  1153. CERT_ARCHIVED_PROP_ID,
  1154. NULL,
  1155. &cb))
  1156. {
  1157. wprintf(myLoadResourceString(IDS_ARCHIVED)); // "Archived!"
  1158. wprintf(wszNewLine);
  1159. }
  1160. if ((iCTL == iCTLSave || NULL != pwszCertName) &&
  1161. NULL != pwszfnOut &&
  1162. (DVNS_SAVECTL & Mode))
  1163. {
  1164. hr = EncodeToFileW(
  1165. pwszfnOut,
  1166. pCTL->pbCtlEncoded,
  1167. pCTL->cbCtlEncoded,
  1168. CRYPT_STRING_BINARY | g_EncodeFlags);
  1169. _PrintIfError(hr, "EncodeToFileW");
  1170. if (S_OK == hr2)
  1171. {
  1172. hr2 = hr;
  1173. }
  1174. }
  1175. hr = cuDumpAsnBinary(
  1176. pCTL->pbCtlEncoded,
  1177. pCTL->cbCtlEncoded,
  1178. MAXDWORD);
  1179. _PrintIfError(hr, "cuDumpAsnBinary");
  1180. if (S_OK == hr2)
  1181. {
  1182. hr2 = hr;
  1183. }
  1184. if ((DVNS_DUMPPROPERTIES & Mode) && !g_fQuiet)
  1185. {
  1186. hr = cuDumpCTLProperties(pCTL);
  1187. _PrintIfError(hr, "cuDumpCTLProperties");
  1188. if (S_OK == hr2)
  1189. {
  1190. hr2 = hr;
  1191. }
  1192. }
  1193. #if 0
  1194. if (DVNS_VERIFYCERT & Mode)
  1195. {
  1196. hr = cuVerifyCertContext(
  1197. pCTL,
  1198. (DVNS_CASTORE & Mode)? hStore : NULL,
  1199. NULL, // apszPolicies
  1200. 0, // cPolicies
  1201. FALSE, // fNTAuth
  1202. &VerifyState);
  1203. if (S_OK != hr)
  1204. {
  1205. cuPrintError(IDS_ERR_FORMAT_BAD_CTL, hr);
  1206. _PrintError(hr, "cuVerifyCertContext");
  1207. if (S_OK == hr2)
  1208. {
  1209. hr2 = hr; // Save first error
  1210. }
  1211. }
  1212. else
  1213. {
  1214. wprintf(myLoadResourceString(IDS_CTL_VERIFIES)); // "CTL is valid"
  1215. }
  1216. wprintf(wszNewLine);
  1217. }
  1218. #endif
  1219. (*pcCTL)++;
  1220. }
  1221. }
  1222. hr = hr2;
  1223. _JumpIfError(hr, error, "EnumCTLsInStore");
  1224. error:
  1225. if (NULL != pCTL)
  1226. {
  1227. CertFreeCTLContext(pCTL);
  1228. }
  1229. return(hr);
  1230. }
  1231. HRESULT
  1232. cuDumpAndVerifyStore(
  1233. IN HCERTSTORE hStore,
  1234. IN DWORD Mode,
  1235. OPTIONAL IN WCHAR const *pwszCertName,
  1236. IN DWORD iCertSave,
  1237. IN DWORD iCRLSave,
  1238. IN DWORD iCTLSave,
  1239. OPTIONAL IN WCHAR const *pwszfnOut,
  1240. OPTIONAL IN WCHAR const *pwszPasswordArg)
  1241. {
  1242. HRESULT hr;
  1243. HRESULT hr2;
  1244. BYTE *pbHash = NULL;
  1245. DWORD cbHash;
  1246. BOOL fVerboseOld = g_fVerbose;
  1247. BOOL fQuietOld = g_fQuiet;
  1248. WCHAR *pwszPassword = NULL;
  1249. DWORD cCert = 0;
  1250. DWORD cCRL = 0;
  1251. DWORD cCTL = 0;
  1252. if (g_fVerbose)
  1253. {
  1254. g_fVerbose--;
  1255. }
  1256. else
  1257. {
  1258. g_fQuiet = TRUE;
  1259. }
  1260. hr2 = S_OK;
  1261. if (NULL != pwszCertName)
  1262. {
  1263. hr = WszToMultiByteInteger(TRUE, pwszCertName, &cbHash, &pbHash);
  1264. _PrintIfError2(hr, "WszToMultiByteInteger", hr);
  1265. }
  1266. if (NULL != pwszCertName ||
  1267. MAXDWORD != iCertSave ||
  1268. (MAXDWORD == iCRLSave && MAXDWORD == iCTLSave))
  1269. {
  1270. hr = EnumCertsInStore(
  1271. hStore,
  1272. Mode,
  1273. iCertSave,
  1274. pwszCertName,
  1275. cbHash,
  1276. pbHash,
  1277. pwszfnOut,
  1278. pwszPasswordArg,
  1279. &pwszPassword,
  1280. &cCert);
  1281. _PrintIfError(hr, "EnumCertsInStore");
  1282. if (S_OK == hr2)
  1283. {
  1284. hr2 = hr;
  1285. }
  1286. }
  1287. if (NULL != pwszCertName ||
  1288. MAXDWORD != iCRLSave ||
  1289. (MAXDWORD == iCertSave && MAXDWORD == iCTLSave))
  1290. {
  1291. hr = EnumCRLsInStore(
  1292. hStore,
  1293. Mode,
  1294. iCRLSave,
  1295. pwszCertName,
  1296. cbHash,
  1297. pbHash,
  1298. pwszfnOut,
  1299. &cCRL);
  1300. _PrintIfError(hr, "EnumCRLsInStore");
  1301. if (S_OK == hr2)
  1302. {
  1303. hr2 = hr;
  1304. }
  1305. }
  1306. if (NULL != pwszCertName ||
  1307. MAXDWORD != iCTLSave ||
  1308. (MAXDWORD == iCertSave && MAXDWORD == iCRLSave))
  1309. {
  1310. hr = EnumCTLsInStore(
  1311. hStore,
  1312. Mode,
  1313. iCTLSave,
  1314. pwszCertName,
  1315. cbHash,
  1316. pbHash,
  1317. pwszfnOut,
  1318. &cCTL);
  1319. _PrintIfError(hr, "EnumCTLsInStore");
  1320. if (S_OK == hr2)
  1321. {
  1322. hr2 = hr;
  1323. }
  1324. }
  1325. hr = hr2;
  1326. if (S_OK == hr && NULL != pwszCertName && 0 == (cCert + cCRL + cCTL))
  1327. {
  1328. hr = NTE_NOT_FOUND;
  1329. _JumpError(hr, error, "cuDumpAndVerifyStore");
  1330. }
  1331. error:
  1332. g_fVerbose = fVerboseOld;
  1333. g_fQuiet = fQuietOld;
  1334. if (NULL != pbHash)
  1335. {
  1336. LocalFree(pbHash);
  1337. }
  1338. if (NULL != pwszPassword)
  1339. {
  1340. myZeroDataString(pwszPassword); // password data
  1341. LocalFree(pwszPassword);
  1342. }
  1343. return(hr);
  1344. }
  1345. // Reorder LDAP URL paramaters as per RFC 2255:
  1346. // Attribute list: ?attribute,...
  1347. // Scope: ?sub or ?one or ?base
  1348. // Search filter: ?objectClass=*,...
  1349. HRESULT
  1350. PatchLdapURL(
  1351. IN WCHAR const *pwszURLIn,
  1352. OUT WCHAR **ppwszURLOut)
  1353. {
  1354. HRESULT hr;
  1355. DWORD cParm;
  1356. DWORD iParm;
  1357. WCHAR *pwsz;
  1358. WCHAR *pwszT = NULL;
  1359. WCHAR *pwszURLOut = NULL;
  1360. WCHAR **apwsz = NULL;
  1361. *ppwszURLOut = NULL;
  1362. hr = myDupString(pwszURLIn, &pwszT);
  1363. _JumpIfError(hr, error, "myDupString");
  1364. pwsz = pwszT;
  1365. for (cParm = 0; ; cParm++)
  1366. {
  1367. pwsz = wcschr(pwsz, L'?');
  1368. if (NULL == pwsz)
  1369. {
  1370. break;
  1371. }
  1372. pwsz++;
  1373. }
  1374. if (1 < cParm)
  1375. {
  1376. apwsz = (WCHAR **) LocalAlloc(LMEM_FIXED, sizeof(apwsz[0]) * cParm);
  1377. if (NULL == apwsz)
  1378. {
  1379. hr = E_OUTOFMEMORY;
  1380. _JumpError(hr, error, "LocalAlloc");
  1381. }
  1382. pwsz = pwszT;
  1383. for (iParm = 0; iParm < cParm; iParm++)
  1384. {
  1385. pwsz = wcschr(pwsz, L'?');
  1386. CSASSERT(NULL != pwsz);
  1387. *pwsz++ = L'\0';
  1388. apwsz[iParm] = pwsz;
  1389. }
  1390. CSASSERT(cParm == iParm);
  1391. CSASSERT(NULL == wcschr(pwsz, L'?'));
  1392. hr = myDupString(pwszURLIn, &pwszURLOut);
  1393. _JumpIfError(hr, error, "myDupString");
  1394. pwsz = wcschr(pwszURLOut, L'?');
  1395. if (NULL != pwsz)
  1396. {
  1397. DWORD i;
  1398. *pwsz = L'\0';
  1399. for (i = 0; i < 3; i++)
  1400. {
  1401. for (iParm = 0; iParm < cParm; iParm++)
  1402. {
  1403. BOOL fScope;
  1404. BOOL fFilter;
  1405. BOOL fCopy;
  1406. fScope =
  1407. 0 == mylstrcmpiS(apwsz[iParm], &wszDSSUBSEARCH[1]) ||
  1408. 0 == mylstrcmpiS(apwsz[iParm], &wszDSBASESEARCH[1]) ||
  1409. 0 == mylstrcmpiS(apwsz[iParm], &wszDSONESEARCH[1]);
  1410. fFilter = NULL != wcschr(apwsz[iParm], L'=');
  1411. switch (i)
  1412. {
  1413. case 0: fCopy = !fScope && !fFilter; break;
  1414. case 1: fCopy = fScope; break;
  1415. default: fCopy = fFilter; break;
  1416. }
  1417. if (fCopy)
  1418. {
  1419. wcscat(pwszURLOut, L"?");
  1420. wcscat(pwszURLOut, apwsz[iParm]);
  1421. }
  1422. }
  1423. }
  1424. CSASSERT(wcslen(pwszURLOut) == wcslen(pwszURLIn));
  1425. // If the URL was reordered, return the patched URL.
  1426. if (0 != lstrcmp(pwszURLIn, pwszURLOut))
  1427. {
  1428. *ppwszURLOut = pwszURLOut;
  1429. pwszURLOut = NULL;
  1430. }
  1431. }
  1432. }
  1433. hr = NULL == *ppwszURLOut? S_FALSE : S_OK;
  1434. error:
  1435. if (NULL != apwsz)
  1436. {
  1437. LocalFree(apwsz);
  1438. }
  1439. if (NULL != pwszT)
  1440. {
  1441. LocalFree(pwszT);
  1442. }
  1443. if (NULL != pwszURLOut)
  1444. {
  1445. LocalFree(pwszURLOut);
  1446. }
  1447. return(hr);
  1448. }
  1449. #define wszLDAPCOLONSLASH L"ldap:/"
  1450. #define wszFMTLDAPPREFIX L"ldap://%ws/"
  1451. HRESULT
  1452. cuOpenCertStore(
  1453. IN WCHAR const *pwszStoreName,
  1454. IN OUT DWORD *pMode,
  1455. OPTIONAL OUT WCHAR **ppwszStoreNameOut,
  1456. OUT HCERTSTORE *phStore)
  1457. {
  1458. HRESULT hr;
  1459. WCHAR awcLdap[ARRAYSIZE(wszLDAPCOLONSLASH)];
  1460. LPCSTR pszStoreProvider = CERT_STORE_PROV_SYSTEM_REGISTRY_W;
  1461. WCHAR *pwszStoreAlloc = NULL;
  1462. WCHAR *pwszStoreAlloc2 = NULL;
  1463. WCHAR *pwszStoreNameOut = NULL;
  1464. if (NULL != ppwszStoreNameOut)
  1465. {
  1466. *ppwszStoreNameOut = NULL;
  1467. }
  1468. if (NULL == pwszStoreName ||
  1469. 0 == wcscmp(L"*", pwszStoreName) ||
  1470. 0 == LSTRCMPIS(pwszStoreName, wszCA_CERTSTORE))
  1471. {
  1472. pwszStoreName = wszCA_CERTSTORE;
  1473. *pMode |= DVNS_CASTORE;
  1474. }
  1475. wcsncpy(awcLdap, pwszStoreName, ARRAYSIZE(awcLdap) - 1);
  1476. awcLdap[ARRAYSIZE(awcLdap) - 1] = L'\0';
  1477. if (0 == LSTRCMPIS(awcLdap, wszLDAPCOLONSLASH))
  1478. {
  1479. pszStoreProvider = CERT_STORE_PROV_LDAP_W;
  1480. *pMode |= DVNS_DSSTORE;
  1481. }
  1482. else
  1483. {
  1484. CSASSERT(3 < ARRAYSIZE(awcLdap));
  1485. awcLdap[3] = L'\0';
  1486. if (0 == LSTRCMPIS(awcLdap, L"CN="))
  1487. {
  1488. DWORD cwc = WSZARRAYSIZE(wszFMTLDAPPREFIX) + wcslen(pwszStoreName);
  1489. if (NULL != g_pwszDC)
  1490. {
  1491. cwc += wcslen (g_pwszDC);
  1492. }
  1493. pwszStoreAlloc = (WCHAR *) LocalAlloc(
  1494. LMEM_FIXED,
  1495. (cwc + 1) * sizeof(WCHAR));
  1496. if (NULL == pwszStoreAlloc)
  1497. {
  1498. hr = E_OUTOFMEMORY;
  1499. _JumpError(hr, error, "LocalAlloc");
  1500. }
  1501. swprintf(
  1502. pwszStoreAlloc,
  1503. wszFMTLDAPPREFIX,
  1504. NULL != g_pwszDC? g_pwszDC : g_wszEmpty);
  1505. wcscat(pwszStoreAlloc, pwszStoreName);
  1506. pwszStoreName = pwszStoreAlloc;
  1507. pszStoreProvider = CERT_STORE_PROV_LDAP_W;
  1508. *pMode |= DVNS_DSSTORE;
  1509. }
  1510. }
  1511. if (DVNS_DSSTORE & *pMode)
  1512. {
  1513. hr = PatchLdapURL(pwszStoreName, &pwszStoreAlloc2);
  1514. if (S_FALSE != hr)
  1515. {
  1516. _JumpIfError(hr, error, "PatchLdapURL");
  1517. pwszStoreName = pwszStoreAlloc2;
  1518. }
  1519. }
  1520. if (NULL != ppwszStoreNameOut)
  1521. {
  1522. hr = myDupString(pwszStoreName, &pwszStoreNameOut);
  1523. _JumpIfError(hr, error, "myDupString");
  1524. }
  1525. if ((DVNS_DSSTORE & *pMode) &&
  1526. 0 == ((DVNS_REPAIRKPI | DVNS_WRITESTORE) & *pMode))
  1527. {
  1528. wprintf(L"%ws\n", pwszStoreName);
  1529. *phStore = myUrlCertOpenStore(
  1530. CRYPT_WIRE_ONLY_RETRIEVAL |
  1531. CRYPT_RETRIEVE_MULTIPLE_OBJECTS,
  1532. pwszStoreName);
  1533. if (NULL == *phStore)
  1534. {
  1535. hr = myHLastError();
  1536. _PrintErrorStr(hr, "myUrlCertOpenStore", pwszStoreName);
  1537. if (CRYPT_E_NOT_FOUND != hr)
  1538. {
  1539. _JumpError(hr, error, "myUrlCertOpenStore");
  1540. }
  1541. }
  1542. }
  1543. if (NULL == *phStore)
  1544. {
  1545. *phStore = CertOpenStore(
  1546. pszStoreProvider,
  1547. X509_ASN_ENCODING,
  1548. NULL, // hProv
  1549. CERT_STORE_NO_CRYPT_RELEASE_FLAG |
  1550. CERT_STORE_ENUM_ARCHIVED_FLAG |
  1551. (((DVNS_REPAIRKPI | DVNS_WRITESTORE) & *pMode)?
  1552. 0 : CERT_STORE_READONLY_FLAG) |
  1553. (g_fForce? 0 : CERT_STORE_OPEN_EXISTING_FLAG) |
  1554. cuGetSystemStoreFlags(),
  1555. pwszStoreName);
  1556. if (NULL == *phStore)
  1557. {
  1558. hr = myHLastError();
  1559. _JumpErrorStr(hr, error, "CertOpenStore", pwszStoreName);
  1560. }
  1561. }
  1562. if (NULL != ppwszStoreNameOut)
  1563. {
  1564. *ppwszStoreNameOut = pwszStoreNameOut;
  1565. pwszStoreNameOut = NULL;
  1566. }
  1567. hr = S_OK;
  1568. error:
  1569. if (NULL != pwszStoreAlloc)
  1570. {
  1571. LocalFree(pwszStoreAlloc);
  1572. }
  1573. if (NULL != pwszStoreAlloc2)
  1574. {
  1575. LocalFree(pwszStoreAlloc2);
  1576. }
  1577. if (NULL != pwszStoreNameOut)
  1578. {
  1579. LocalFree(pwszStoreNameOut);
  1580. }
  1581. return(hr);
  1582. }
  1583. HRESULT
  1584. DumpAndVerifyNamedStore(
  1585. IN WCHAR const *pwszStoreName,
  1586. IN DWORD Mode,
  1587. OPTIONAL IN WCHAR const *pwszCertName,
  1588. IN DWORD iCertSave,
  1589. IN DWORD iCRLSave,
  1590. IN DWORD iCTLSave,
  1591. OPTIONAL IN WCHAR const *pwszfnOut,
  1592. OPTIONAL IN WCHAR const *pwszPassword)
  1593. {
  1594. HRESULT hr;
  1595. HCERTSTORE hStore = NULL;
  1596. hr = cuOpenCertStore(pwszStoreName, &Mode, NULL, &hStore);
  1597. _JumpIfError(hr, error, "cuOpenCertStore");
  1598. hr = cuDumpAndVerifyStore(
  1599. hStore,
  1600. Mode,
  1601. pwszCertName,
  1602. iCertSave,
  1603. iCRLSave,
  1604. iCTLSave,
  1605. pwszfnOut,
  1606. pwszPassword);
  1607. _JumpIfError(hr, error, "cuDumpAndVerifyStore");
  1608. error:
  1609. if (NULL != hStore)
  1610. {
  1611. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  1612. }
  1613. return(hr);
  1614. }
  1615. HRESULT
  1616. myDupStringN(
  1617. IN WCHAR const *pwszIn,
  1618. IN DWORD cwc,
  1619. OUT WCHAR **ppwszOut)
  1620. {
  1621. HRESULT hr;
  1622. CSASSERT(wcslen(pwszIn) >= cwc);
  1623. *ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
  1624. if (NULL == *ppwszOut)
  1625. {
  1626. hr = E_OUTOFMEMORY;
  1627. _JumpError(hr, error, "LocalAlloc");
  1628. }
  1629. CopyMemory(*ppwszOut, pwszIn, cwc * sizeof(WCHAR));
  1630. (*ppwszOut)[cwc] = L'\0';
  1631. hr = S_OK;
  1632. error:
  1633. return(hr);
  1634. }
  1635. #define URLI_DC 0
  1636. #define URLI_DN 1
  1637. #define URLI_ATTRIBUTE 2
  1638. #define URLI_SCOPE 3
  1639. #define URLI_CLASS 4
  1640. #define URLI_MAX 5
  1641. HRESULT
  1642. ParseLdapUrl(
  1643. IN WCHAR const *pwszIn,
  1644. OUT WCHAR *ppwszOut[URLI_MAX])
  1645. {
  1646. HRESULT hr;
  1647. WCHAR *pwszAlloc = NULL;
  1648. WCHAR awcLdap[ARRAYSIZE(wszLDAPCOLONSLASH)];
  1649. DWORD cSlash;
  1650. WCHAR const *pwsz;
  1651. DWORD i;
  1652. ZeroMemory(ppwszOut, URLI_MAX * sizeof(*ppwszOut));
  1653. wcsncpy(awcLdap, pwszIn, ARRAYSIZE(awcLdap) - 1);
  1654. awcLdap[ARRAYSIZE(awcLdap) - 1] = L'\0';
  1655. if (0 != LSTRCMPIS(awcLdap, wszLDAPCOLONSLASH))
  1656. {
  1657. hr = E_INVALIDARG;
  1658. _JumpError(hr, error, "ldap:URL");
  1659. }
  1660. hr = myInternetUncanonicalizeURL(pwszIn, &pwszAlloc);
  1661. _JumpIfError(hr, error, "myInternetUncanonicalizeURL");
  1662. pwszIn = pwszAlloc;
  1663. pwszIn += WSZARRAYSIZE(wszLDAPCOLONSLASH);
  1664. cSlash = 1;
  1665. while (L'/' == *pwszIn)
  1666. {
  1667. pwszIn++;
  1668. cSlash++;
  1669. }
  1670. if (2 == cSlash)
  1671. {
  1672. pwsz = pwszIn;
  1673. while (L'\0' != *pwszIn && L'/' != *pwszIn)
  1674. {
  1675. pwszIn++;
  1676. }
  1677. hr = myDupStringN(
  1678. pwsz,
  1679. SAFE_SUBTRACT_POINTERS(pwszIn, pwsz),
  1680. &ppwszOut[0]);
  1681. _JumpIfError(hr, error, "myDupStringN");
  1682. if (L'\0' != *pwszIn)
  1683. {
  1684. pwszIn++;
  1685. }
  1686. }
  1687. for (i = 1; i < URLI_MAX; i++)
  1688. {
  1689. pwsz = pwszIn;
  1690. while (L'\0' != *pwszIn && L'?' != *pwszIn)
  1691. {
  1692. pwszIn++;
  1693. }
  1694. hr = myDupStringN(
  1695. pwsz,
  1696. SAFE_SUBTRACT_POINTERS(pwszIn, pwsz),
  1697. &ppwszOut[i]);
  1698. _JumpIfError(hr, error, "myDupStringN");
  1699. if (L'\0' == *pwszIn)
  1700. {
  1701. break;
  1702. }
  1703. pwszIn++;
  1704. }
  1705. hr = S_OK;
  1706. error:
  1707. for (i = 0; i < ARRAYSIZE(ppwszOut); i++)
  1708. {
  1709. wprintf(L"DeleteLastLdapValue[%u](%ws)\n", i, ppwszOut[i]);
  1710. }
  1711. if (S_OK != hr)
  1712. {
  1713. for (i = 0; i < URLI_MAX; i++)
  1714. {
  1715. if (NULL != ppwszOut[i])
  1716. {
  1717. LocalFree(ppwszOut[i]);
  1718. ppwszOut[i] = NULL;
  1719. }
  1720. }
  1721. }
  1722. if (NULL != pwszAlloc)
  1723. {
  1724. LocalFree(pwszAlloc);
  1725. }
  1726. return(hr);
  1727. }
  1728. HRESULT
  1729. myLdapDeleteLastValue(
  1730. IN LDAP *pld,
  1731. IN WCHAR const *pwszDN,
  1732. IN WCHAR const *pwszAttribute,
  1733. OPTIONAL IN BYTE const *pb,
  1734. IN DWORD cb,
  1735. OUT DWORD *pdwDisposition,
  1736. OPTIONAL OUT WCHAR **ppwszError)
  1737. {
  1738. HRESULT hr;
  1739. DWORD cres;
  1740. DWORD cber;
  1741. DWORD iber;
  1742. DWORD i;
  1743. LDAP_TIMEVAL timeval;
  1744. LDAPMessage *pmsg = NULL;
  1745. LDAPMessage *pres;
  1746. WCHAR *apwszAttrs[2];
  1747. struct berval **ppberval = NULL;
  1748. struct berval *rgpberVals[2];
  1749. struct berval certberval;
  1750. LDAPMod *mods[2];
  1751. LDAPMod certmod;
  1752. char chZero = '\0';
  1753. *pdwDisposition = LDAP_OTHER;
  1754. if (NULL != ppwszError)
  1755. {
  1756. *ppwszError = NULL;
  1757. }
  1758. apwszAttrs[0] = const_cast<WCHAR *>(pwszAttribute);
  1759. apwszAttrs[1] = NULL;
  1760. timeval.tv_sec = csecLDAPTIMEOUT;
  1761. timeval.tv_usec = 0;
  1762. hr = ldap_search_st(
  1763. pld, // ld
  1764. const_cast<WCHAR *>(pwszDN), // base
  1765. LDAP_SCOPE_BASE, // scope
  1766. NULL, // filter
  1767. apwszAttrs, // attrs
  1768. FALSE, // attrsonly
  1769. &timeval, // timeout
  1770. &pmsg); // res
  1771. if (S_OK != hr)
  1772. {
  1773. *pdwDisposition = hr;
  1774. hr = myHLdapError(pld, hr, NULL);
  1775. _JumpErrorStr(hr, error, "ldap_search_st", pwszDN);
  1776. }
  1777. cres = ldap_count_entries(pld, pmsg);
  1778. if (1 != cres)
  1779. {
  1780. // Exactly one entry was not found.
  1781. hr = NTE_NOT_FOUND;
  1782. _JumpError(hr, error, "ldap_count_entries");
  1783. }
  1784. pres = ldap_first_entry(pld, pmsg);
  1785. if (NULL == pres)
  1786. {
  1787. hr = NTE_NOT_FOUND;
  1788. _JumpError(hr, error, "ldap_first_entry");
  1789. }
  1790. ppberval = ldap_get_values_len(
  1791. pld,
  1792. pres,
  1793. const_cast<WCHAR *>(pwszAttribute));
  1794. hr = NTE_NOT_FOUND;
  1795. if (NULL == ppberval)
  1796. {
  1797. _JumpError(hr, error, "ppberval");
  1798. }
  1799. cber = 0;
  1800. while (NULL != ppberval[cber])
  1801. {
  1802. cber++;
  1803. }
  1804. if (NULL != pb)
  1805. {
  1806. if (1 != cber)
  1807. {
  1808. _JumpError(hr, error, "cber");
  1809. }
  1810. if (ppberval[0]->bv_len != cb ||
  1811. 0 != memcmp(ppberval[0]->bv_val, pb, cb))
  1812. {
  1813. _JumpError(hr, error, "memcmp");
  1814. }
  1815. }
  1816. // set disposition assuming there's nothing to do:
  1817. *pdwDisposition = LDAP_ATTRIBUTE_OR_VALUE_EXISTS;
  1818. mods[0] = &certmod;
  1819. mods[1] = NULL;
  1820. certmod.mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE;
  1821. certmod.mod_type = const_cast<WCHAR *>(pwszAttribute);
  1822. certmod.mod_bvalues = rgpberVals;
  1823. rgpberVals[0] = &certberval;
  1824. rgpberVals[1] = NULL;
  1825. certberval.bv_val = &chZero;
  1826. certberval.bv_len = sizeof(chZero);
  1827. hr = ldap_modify_ext_s(
  1828. pld,
  1829. const_cast<WCHAR *>(pwszDN), // base
  1830. mods,
  1831. NULL,
  1832. NULL);
  1833. *pdwDisposition = hr;
  1834. if (hr != S_OK)
  1835. {
  1836. hr = myHLdapError(pld, hr, ppwszError);
  1837. _JumpError(hr, error, "ldap_modify_ext_s");
  1838. }
  1839. hr = S_OK;
  1840. error:
  1841. if (NULL != ppberval)
  1842. {
  1843. ldap_value_free_len(ppberval);
  1844. }
  1845. if (NULL != pmsg)
  1846. {
  1847. ldap_msgfree(pmsg);
  1848. }
  1849. return(hr);
  1850. }
  1851. HRESULT
  1852. DeleteLastLdapValue(
  1853. IN WCHAR const *pwszURL,
  1854. OPTIONAL IN BYTE const *pb,
  1855. IN DWORD cb)
  1856. {
  1857. HRESULT hr;
  1858. WCHAR *rgpwsz[URLI_MAX];
  1859. DWORD i;
  1860. DWORD dwDisposition;
  1861. WCHAR *pwszError = NULL;
  1862. LDAP *pld = NULL;
  1863. ZeroMemory(rgpwsz, sizeof(rgpwsz));
  1864. hr = ParseLdapUrl(pwszURL, rgpwsz);
  1865. _JumpIfErrorStr(hr, error, "ParseLdapUrl", pwszURL);
  1866. if (NULL != rgpwsz[URLI_SCOPE] &&
  1867. 0 != mylstrcmpiS(rgpwsz[URLI_SCOPE], &wszDSBASESEARCH[1]))
  1868. {
  1869. hr = E_INVALIDARG;
  1870. _JumpErrorStr(hr, error, "ldap scope", rgpwsz[URLI_SCOPE]);
  1871. }
  1872. hr = myLdapOpen(rgpwsz[URLI_DC], 0, &pld, NULL, NULL);
  1873. _JumpIfError(hr, error, "myLdapOpen");
  1874. hr = myLdapDeleteLastValue(
  1875. pld,
  1876. rgpwsz[URLI_DN],
  1877. rgpwsz[URLI_ATTRIBUTE],
  1878. pb,
  1879. cb,
  1880. &dwDisposition,
  1881. &pwszError);
  1882. _JumpIfErrorStr(hr, error, "myLdapDeleteLastValue", pwszError);
  1883. error:
  1884. if (NULL != pwszError)
  1885. {
  1886. LocalFree(pwszError);
  1887. }
  1888. for (i = 0; i < ARRAYSIZE(rgpwsz); i++)
  1889. {
  1890. if (NULL != rgpwsz[i])
  1891. {
  1892. wprintf(L"DeleteLastLdapValue[%u](%ws)\n", i, rgpwsz[i]);
  1893. LocalFree(rgpwsz[i]);
  1894. }
  1895. }
  1896. myLdapClose(pld, NULL, NULL);
  1897. return(hr);
  1898. }
  1899. HRESULT
  1900. CommitStore(
  1901. IN HCERTSTORE hStore,
  1902. IN WCHAR const *pwszStoreName,
  1903. IN DWORD Mode,
  1904. OPTIONAL IN BYTE const *pb,
  1905. IN DWORD cb)
  1906. {
  1907. HRESULT hr;
  1908. if (!CertControlStore(hStore, 0, CERT_STORE_CTRL_COMMIT, NULL))
  1909. {
  1910. // Add workaround for LdapMapErrorToWin32 incorrect mapping
  1911. // LDAP_OBJECT_CLASS_VIOLATION -> E_INVALIDARG. Mapping it to
  1912. // the correct code should be pretty safe, CertControlStore
  1913. // shouldn't otherwise fail with this error code since we know
  1914. // our code passes the right parameters.
  1915. hr = myHLastError();
  1916. _PrintError(hr, "CertControlStore");
  1917. if (DVNS_DSSTORE & Mode)
  1918. {
  1919. if (E_INVALIDARG == HRESULT_FROM_WIN32(hr))
  1920. {
  1921. hr = HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION);
  1922. _PrintError(hr, "CertControlStore");
  1923. }
  1924. if (HRESULT_FROM_WIN32(ERROR_DS_OBJ_CLASS_VIOLATION) == hr)
  1925. {
  1926. hr = DeleteLastLdapValue(pwszStoreName, pb, cb);
  1927. _JumpIfError(hr, error, "DeleteLastLdapValue");
  1928. }
  1929. }
  1930. _JumpIfError(hr, error, "CertControlStore");
  1931. }
  1932. hr = S_OK;
  1933. error:
  1934. return(hr);
  1935. }
  1936. HRESULT
  1937. verbViewOrDeleteStore(
  1938. IN WCHAR const *pwszOption,
  1939. OPTIONAL IN WCHAR const *pwszStoreName,
  1940. OPTIONAL IN WCHAR const *pwszCertId,
  1941. OPTIONAL IN WCHAR const *pwszfnOut,
  1942. IN WCHAR const *pwszArg4)
  1943. {
  1944. HRESULT hr;
  1945. WCHAR *pwszCertName = NULL;
  1946. WCHAR *pwszStoreNameNew = NULL;
  1947. DWORD Mode;
  1948. DWORD iCert;
  1949. DWORD iCRL;
  1950. DWORD iCTL;
  1951. HCERTSTORE hStore = NULL;
  1952. CERT_CONTEXT const *pCert = NULL;
  1953. CERT_CONTEXT const *pCertDeleted = NULL;
  1954. BOOL fDelete = g_wszViewDelStore == pwszOption;
  1955. WCHAR *pwszSubject = NULL;
  1956. hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
  1957. _JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
  1958. Mode = DVNS_SAVECERT;
  1959. if (fDelete)
  1960. {
  1961. Mode |= DVNS_WRITESTORE;
  1962. }
  1963. hr = cuOpenCertStore(pwszStoreName, &Mode, &pwszStoreNameNew, &hStore);
  1964. _JumpIfError(hr, error, "cuOpenCertStore");
  1965. hr = myGetCertificateFromPicker(
  1966. g_hInstance, // hInstance
  1967. NULL, // hwndParent
  1968. IDS_VIEWSTORE_TITLE, // idTitle
  1969. fDelete? IDS_VIEWSTORE_SUBTITLE_DELETE :
  1970. IDS_VIEWSTORE_SUBTITLE, // idSubTitle
  1971. 0, // dwFlags -- CUCS_*
  1972. pwszCertName, // pwszCommonName
  1973. 1, // cStore
  1974. &hStore, // rghStore
  1975. 0, // cpszObjId
  1976. NULL, // apszObjId
  1977. &pCert); // ppCert
  1978. _JumpIfError(hr, error, "myGetCertificateFromPicker");
  1979. if (NULL != pCert)
  1980. {
  1981. hr = myCertNameToStr(
  1982. X509_ASN_ENCODING,
  1983. &pCert->pCertInfo->Subject,
  1984. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  1985. &pwszSubject);
  1986. _JumpIfError(hr, error, "myCertNameToStr");
  1987. if (NULL != pwszfnOut)
  1988. {
  1989. hr = EncodeToFileW(
  1990. pwszfnOut,
  1991. pCert->pbCertEncoded,
  1992. pCert->cbCertEncoded,
  1993. CRYPT_STRING_BINARY | g_EncodeFlags);
  1994. _JumpIfError(hr, error, "EncodeToFileW");
  1995. wprintf(
  1996. myLoadResourceString(
  1997. IDS_FORMAT_SAVED_CERT_NAME), // "Saved certificate %ws"
  1998. pwszSubject);
  1999. wprintf(L": %ws\n", pwszfnOut);
  2000. }
  2001. if (fDelete)
  2002. {
  2003. pCertDeleted = CertDuplicateCertificateContext(pCert);
  2004. if (!CertDeleteCertificateFromStore(pCert))
  2005. {
  2006. hr = myHLastError();
  2007. _JumpError(hr, error, "CertDeleteCertificateFromStore");
  2008. }
  2009. pCert = NULL;
  2010. hr = CommitStore(
  2011. hStore,
  2012. pwszStoreNameNew,
  2013. Mode,
  2014. pCertDeleted->pbCertEncoded,
  2015. pCertDeleted->cbCertEncoded);
  2016. _JumpIfError(hr, error, "CommitStore");
  2017. wprintf(
  2018. myLoadResourceString(
  2019. IDS_FORMAT_DELETED_CERT_NAME), // "Deleted certificate %ws"
  2020. pwszSubject);
  2021. wprintf(wszNewLine);
  2022. }
  2023. }
  2024. hr = S_OK;
  2025. error:
  2026. if (NULL != pwszSubject)
  2027. {
  2028. LocalFree(pwszSubject);
  2029. }
  2030. if (NULL != pwszCertName)
  2031. {
  2032. LocalFree(pwszCertName);
  2033. }
  2034. if (NULL != pwszStoreNameNew)
  2035. {
  2036. LocalFree(pwszStoreNameNew);
  2037. }
  2038. if (NULL != pCert)
  2039. {
  2040. CertFreeCertificateContext(pCert);
  2041. }
  2042. if (NULL != pCertDeleted)
  2043. {
  2044. CertFreeCertificateContext(pCertDeleted);
  2045. }
  2046. if (NULL != hStore)
  2047. {
  2048. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2049. }
  2050. return(hr);
  2051. }
  2052. HRESULT
  2053. verbStore(
  2054. IN WCHAR const *pwszOption,
  2055. IN WCHAR const *pwszStoreName,
  2056. IN WCHAR const *pwszCertId,
  2057. IN WCHAR const *pwszfnOut,
  2058. IN WCHAR const *pwszArg4)
  2059. {
  2060. HRESULT hr;
  2061. WCHAR *pwszCertName = NULL;
  2062. DWORD iCert;
  2063. DWORD iCRL;
  2064. DWORD iCTL;
  2065. hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
  2066. _JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
  2067. hr = DumpAndVerifyNamedStore(
  2068. pwszStoreName,
  2069. DVNS_SAVECERT |
  2070. DVNS_SAVECRL |
  2071. DVNS_SAVECTL |
  2072. DVNS_DUMP |
  2073. DVNS_DUMPKEYS |
  2074. DVNS_DUMPPROPERTIES,
  2075. pwszCertName,
  2076. iCert,
  2077. iCRL,
  2078. iCTL,
  2079. pwszfnOut,
  2080. NULL);
  2081. _JumpIfError(hr, error, "DumpAndVerifyNamedStore");
  2082. error:
  2083. if (NULL != pwszCertName)
  2084. {
  2085. LocalFree(pwszCertName);
  2086. }
  2087. return(hr);
  2088. }
  2089. HRESULT
  2090. DisplayAddResult(
  2091. OPTIONAL IN CERT_NAME_BLOB const *pName,
  2092. IN DWORD Index,
  2093. IN DWORD idsMsg)
  2094. {
  2095. HRESULT hr = S_OK;
  2096. WCHAR *pwszName = NULL;
  2097. WCHAR wszIndex[cwcDWORDSPRINTF];
  2098. if (NULL != pName)
  2099. {
  2100. hr = myCertNameToStr(
  2101. X509_ASN_ENCODING,
  2102. pName,
  2103. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  2104. &pwszName);
  2105. _JumpIfError(hr, error, "myCertNameToStr");
  2106. }
  2107. else
  2108. {
  2109. swprintf(wszIndex, L"%u", Index);
  2110. }
  2111. wprintf(myLoadResourceString(idsMsg), NULL != pName? pwszName : wszIndex);
  2112. wprintf(wszNewLine);
  2113. error:
  2114. if (NULL != pwszName)
  2115. {
  2116. LocalFree(pwszName);
  2117. }
  2118. return(hr);
  2119. }
  2120. HRESULT
  2121. AddCertToStore(
  2122. IN HCERTSTORE hStore,
  2123. IN WCHAR const *pwszStoreName,
  2124. IN CERT_CONTEXT const *pccAdd,
  2125. IN DWORD Index)
  2126. {
  2127. HRESULT hr;
  2128. BOOL fRoot = FALSE;
  2129. CERT_CONTEXT const *pcc = NULL;
  2130. DWORD cDup;
  2131. DWORD cDisplay;
  2132. DWORD i;
  2133. if (CertCompareCertificateName(
  2134. X509_ASN_ENCODING,
  2135. &pccAdd->pCertInfo->Issuer,
  2136. &pccAdd->pCertInfo->Subject))
  2137. {
  2138. hr = cuVerifySignature(
  2139. pccAdd->pbCertEncoded,
  2140. pccAdd->cbCertEncoded,
  2141. &pccAdd->pCertInfo->SubjectPublicKeyInfo,
  2142. FALSE,
  2143. FALSE);
  2144. fRoot = S_OK == hr;
  2145. _PrintIfError(hr, "cuVerifySignature");
  2146. }
  2147. if (0 == LSTRCMPIS(pwszStoreName, wszROOT_CERTSTORE) &&
  2148. !fRoot &&
  2149. !g_fForce)
  2150. {
  2151. wprintf(myLoadResourceString(IDS_ROOT_STORE_NEEDS_ROOT_CERT)); // "Cannot add a non-root certificate to the root store"
  2152. wprintf(wszNewLine);
  2153. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2154. _JumpError(hr, error, "Non-root cert");
  2155. }
  2156. cDup = 0;
  2157. cDisplay = 0;
  2158. for (i = 0; ; i++)
  2159. {
  2160. pcc = CertEnumCertificatesInStore(hStore, pcc);
  2161. if (NULL == pcc)
  2162. {
  2163. break;
  2164. }
  2165. // Skip Certs for other Subjects
  2166. if (!CertCompareCertificateName(
  2167. X509_ASN_ENCODING,
  2168. &pcc->pCertInfo->Issuer,
  2169. &pccAdd->pCertInfo->Issuer))
  2170. {
  2171. continue;
  2172. }
  2173. // Skip Certs with different public keys
  2174. if (!CertComparePublicKeyInfo(
  2175. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  2176. &pcc->pCertInfo->SubjectPublicKeyInfo,
  2177. &pccAdd->pCertInfo->SubjectPublicKeyInfo))
  2178. {
  2179. continue;
  2180. }
  2181. if (0 == cDisplay++)
  2182. {
  2183. wprintf(myLoadResourceString(IDS_RELATED_CERTS_COLON)); // "Related Certificates:"
  2184. wprintf(wszNewLine);
  2185. }
  2186. wprintf(wszNewLine);
  2187. // Remember if an exact match exists
  2188. if (pcc->cbCertEncoded == pccAdd->cbCertEncoded &&
  2189. 0 == memcmp(
  2190. pcc->pbCertEncoded,
  2191. pccAdd->pbCertEncoded,
  2192. pcc->cbCertEncoded))
  2193. {
  2194. cDup++;
  2195. wprintf(myLoadResourceString(IDS_EXACT_MATCH_COLON)); // "Exact match:"
  2196. wprintf(wszNewLine);
  2197. }
  2198. hr = cuDumpAsnBinaryQuiet(
  2199. pcc->pbCertEncoded,
  2200. pcc->cbCertEncoded,
  2201. i);
  2202. _PrintIfError(hr, "cuDumpAsnBinaryQuiet");
  2203. }
  2204. if (0 == cDup)
  2205. {
  2206. if (!CertAddCertificateContextToStore(
  2207. hStore,
  2208. pccAdd,
  2209. CERT_STORE_ADD_ALWAYS,
  2210. NULL))
  2211. {
  2212. hr = myHLastError();
  2213. _JumpError(hr, error, "CertAddCertificateContextToStore");
  2214. }
  2215. }
  2216. else
  2217. {
  2218. wprintf(wszNewLine);
  2219. }
  2220. hr = DisplayAddResult(
  2221. &pccAdd->pCertInfo->Subject,
  2222. Index,
  2223. 0 != cDup?
  2224. IDS_FORMAT_CERT_ALREADY_IN_STORE : // "Certificate ""%ws"" already in store."
  2225. IDS_FORMAT_CERT_ADDED_TO_STORE); // "Certificate ""%ws"" added to store."
  2226. _JumpIfError(hr, error, "DisplayAddResult");
  2227. error:
  2228. if (NULL != pcc)
  2229. {
  2230. CertFreeCertificateContext(pcc);
  2231. }
  2232. return(hr);
  2233. }
  2234. HRESULT
  2235. AddCRLToStore(
  2236. IN HCERTSTORE hStore,
  2237. IN CRL_CONTEXT const *pCRLAdd,
  2238. IN DWORD Index)
  2239. {
  2240. HRESULT hr;
  2241. CRL_CONTEXT const *pCRL = NULL;
  2242. DWORD cDup;
  2243. DWORD cDisplay;
  2244. BOOL fDeltaAdd;
  2245. BOOL fDelta;
  2246. DWORD NameId;
  2247. DWORD NameIdAdd;
  2248. DWORD i;
  2249. hr = myIsDeltaCRL(pCRLAdd, &fDeltaAdd);
  2250. _JumpIfError(hr, error, "myIsDeltaCRL");
  2251. hr = myGetCRLNameId(pCRLAdd, &NameIdAdd);
  2252. _PrintIfError2(hr, "DisplayAddResult", hr);
  2253. cDup = 0;
  2254. cDisplay = 0;
  2255. for (i = 0; ; i++)
  2256. {
  2257. pCRL = CertEnumCRLsInStore(hStore, pCRL);
  2258. if (NULL == pCRL)
  2259. {
  2260. break;
  2261. }
  2262. hr = myIsDeltaCRL(pCRL, &fDelta);
  2263. _JumpIfError(hr, error, "myIsDeltaCRL");
  2264. // Skip base or delta CRLs when we're looking for the other.
  2265. if (fDeltaAdd ^ fDelta)
  2266. {
  2267. continue;
  2268. }
  2269. // Skip CRLs for other Issuers
  2270. if (!CertCompareCertificateName(
  2271. X509_ASN_ENCODING,
  2272. &pCRL->pCrlInfo->Issuer,
  2273. &pCRLAdd->pCrlInfo->Issuer))
  2274. {
  2275. continue;
  2276. }
  2277. hr = myGetCRLNameId(pCRL, &NameId);
  2278. _PrintIfError2(hr, "DisplayAddResult", hr);
  2279. // Skip CRLs for different CA keys
  2280. if (MAXDWORD != NameIdAdd && MAXDWORD != NameId)
  2281. {
  2282. if (CANAMEIDTOIKEY(NameIdAdd) != CANAMEIDTOIKEY(NameId))
  2283. {
  2284. continue;
  2285. }
  2286. }
  2287. if (0 == cDisplay++)
  2288. {
  2289. wprintf(myLoadResourceString(IDS_RELATED_CRLS_COLON)); // "Related CRLs:"
  2290. wprintf(wszNewLine);
  2291. }
  2292. wprintf(wszNewLine);
  2293. // Remember if an exact match exists
  2294. if (pCRL->cbCrlEncoded == pCRLAdd->cbCrlEncoded &&
  2295. 0 == memcmp(
  2296. pCRL->pbCrlEncoded,
  2297. pCRLAdd->pbCrlEncoded,
  2298. pCRL->cbCrlEncoded))
  2299. {
  2300. cDup++;
  2301. wprintf(myLoadResourceString(IDS_EXACT_MATCH_COLON)); // "Exact match:"
  2302. wprintf(wszNewLine);
  2303. }
  2304. hr = cuDumpAsnBinaryQuiet(
  2305. pCRL->pbCrlEncoded,
  2306. pCRL->cbCrlEncoded,
  2307. i);
  2308. _PrintIfError(hr, "cuDumpAsnBinaryQuiet");
  2309. }
  2310. if (0 == cDup)
  2311. {
  2312. if (!CertAddCRLContextToStore(
  2313. hStore,
  2314. pCRLAdd,
  2315. CERT_STORE_ADD_ALWAYS,
  2316. NULL))
  2317. {
  2318. hr = myHLastError();
  2319. _JumpError(hr, error, "CertAddCRLContextToStore");
  2320. }
  2321. }
  2322. else
  2323. {
  2324. wprintf(wszNewLine);
  2325. }
  2326. hr = DisplayAddResult(
  2327. &pCRLAdd->pCrlInfo->Issuer,
  2328. Index,
  2329. 0 != cDup?
  2330. IDS_FORMAT_CRL_ALREADY_IN_STORE : // "CRL ""%ws"" already in store."
  2331. IDS_FORMAT_CRL_ADDED_TO_STORE); // "CRL ""%ws"" added to store."
  2332. _JumpIfError(hr, error, "DisplayAddResult");
  2333. error:
  2334. if (NULL != pCRL)
  2335. {
  2336. CertFreeCRLContext(pCRL);
  2337. }
  2338. return(hr);
  2339. }
  2340. HRESULT
  2341. AddCTLToStore(
  2342. IN HCERTSTORE hStore,
  2343. IN CTL_CONTEXT const *pCTL,
  2344. IN DWORD Index)
  2345. {
  2346. HRESULT hr;
  2347. BOOL fDup = FALSE;
  2348. if (!CertAddCTLContextToStore(hStore, pCTL, CERT_STORE_ADD_NEW, NULL))
  2349. {
  2350. hr = myHLastError();
  2351. if (CRYPT_E_EXISTS != hr)
  2352. {
  2353. _JumpError(hr, error, "CertAddCTLContextToStore");
  2354. }
  2355. fDup = TRUE;
  2356. }
  2357. hr = DisplayAddResult(
  2358. NULL,
  2359. Index,
  2360. fDup?
  2361. IDS_FORMAT_CTL_ALREADY_IN_STORE : // "CTL ""%ws"" already in store."
  2362. IDS_FORMAT_CTL_ADDED_TO_STORE); // "CTL ""%ws"" added to store."
  2363. _JumpIfError(hr, error, "DisplayAddResult");
  2364. error:
  2365. return(hr);
  2366. }
  2367. HRESULT
  2368. AddCertToStoreFromFile(
  2369. IN HCERTSTORE hStore,
  2370. IN WCHAR const *pwszStoreName,
  2371. IN WCHAR const *pwszfnIn,
  2372. OUT BOOL *pfBadAsn)
  2373. {
  2374. HRESULT hr;
  2375. CERT_CONTEXT const *pCert = NULL;
  2376. BOOL fRoot = FALSE;
  2377. *pfBadAsn = FALSE;
  2378. // Load and decode certificate
  2379. hr = cuLoadCert(pwszfnIn, &pCert);
  2380. if (CRYPT_E_ASN1_BADTAG == hr)
  2381. {
  2382. *pfBadAsn = TRUE;
  2383. }
  2384. _JumpIfError(hr, error, "cuLoadCert");
  2385. hr = AddCertToStore(hStore, pwszStoreName, pCert, 0);
  2386. _JumpIfError(hr, error, "AddCertToStore");
  2387. error:
  2388. cuUnloadCert(&pCert);
  2389. return(hr);
  2390. }
  2391. HRESULT
  2392. AddCRLToStoreFromFile(
  2393. IN HCERTSTORE hStore,
  2394. IN WCHAR const *pwszfnIn,
  2395. OUT BOOL *pfBadAsn)
  2396. {
  2397. HRESULT hr;
  2398. CRL_CONTEXT const *pCRL = NULL;
  2399. *pfBadAsn = FALSE;
  2400. hr = cuLoadCRL(pwszfnIn, &pCRL);
  2401. if (CRYPT_E_ASN1_BADTAG == hr)
  2402. {
  2403. *pfBadAsn = TRUE;
  2404. }
  2405. _JumpIfError(hr, error, "cuLoadCRL");
  2406. hr = AddCRLToStore(hStore, pCRL, 0);
  2407. _JumpIfError(hr, error, "AddCRLToStore");
  2408. error:
  2409. cuUnloadCRL(&pCRL);
  2410. return(hr);
  2411. }
  2412. HRESULT
  2413. AddPKCS7ToStoreFromFile(
  2414. IN HCERTSTORE hStore,
  2415. IN WCHAR const *pwszStoreName,
  2416. IN WCHAR const *pwszfnIn)
  2417. {
  2418. HRESULT hr;
  2419. BYTE *pb = NULL;
  2420. DWORD cb;
  2421. HCERTSTORE hStorePKCS7 = NULL;
  2422. DWORD i;
  2423. CERT_CONTEXT const *pCert = NULL;
  2424. CRL_CONTEXT const *pCRL = NULL;
  2425. CTL_CONTEXT const *pCTL = NULL;
  2426. hr = DecodeFileW(pwszfnIn, &pb, &cb, CRYPT_STRING_ANY);
  2427. if (S_OK != hr)
  2428. {
  2429. cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr);
  2430. goto error;
  2431. }
  2432. hr = myDecodePKCS7(
  2433. pb,
  2434. cb,
  2435. NULL, // ppbContents
  2436. NULL, // pcbContents
  2437. NULL, // pdwMsgType
  2438. NULL, // ppszInnerContentObjId
  2439. NULL, // pcSigner
  2440. NULL, // pcRecipient
  2441. &hStore,
  2442. NULL); // phMsg
  2443. _JumpIfError(hr, error, "myDecodePKCS7");
  2444. for (i = 0; ; i++)
  2445. {
  2446. pCert = CertEnumCertificatesInStore(hStore, pCert);
  2447. if (NULL == pCert)
  2448. {
  2449. break;
  2450. }
  2451. hr = AddCertToStore(hStore, pwszStoreName, pCert, i);
  2452. _JumpIfError(hr, error, "AddCertToStore");
  2453. }
  2454. for (i = 0; ; i++)
  2455. {
  2456. pCRL = CertEnumCRLsInStore(hStore, pCRL);
  2457. if (NULL == pCRL)
  2458. {
  2459. break;
  2460. }
  2461. hr = AddCRLToStore(hStore, pCRL, i);
  2462. _JumpIfError(hr, error, "AddCRLToStore");
  2463. }
  2464. for (i = 0; ; i++)
  2465. {
  2466. pCTL = CertEnumCTLsInStore(hStore, pCTL);
  2467. if (NULL == pCTL)
  2468. {
  2469. break;
  2470. }
  2471. hr = AddCTLToStore(hStore, pCTL, i);
  2472. _JumpIfError(hr, error, "AddCTLToStore");
  2473. }
  2474. hr = S_OK;
  2475. error:
  2476. if (NULL != pCert)
  2477. {
  2478. CertFreeCertificateContext(pCert);
  2479. }
  2480. if (NULL != pCRL)
  2481. {
  2482. CertFreeCRLContext(pCRL);
  2483. }
  2484. if (NULL != pCTL)
  2485. {
  2486. CertFreeCTLContext(pCTL);
  2487. }
  2488. if (NULL != hStorePKCS7)
  2489. {
  2490. CertCloseStore(hStorePKCS7, CERT_CLOSE_STORE_CHECK_FLAG);
  2491. }
  2492. if (NULL != pb)
  2493. {
  2494. LocalFree(pb);
  2495. }
  2496. return(hr);
  2497. }
  2498. HRESULT
  2499. verbAddStore(
  2500. IN WCHAR const *pwszOption,
  2501. IN WCHAR const *pwszStoreName,
  2502. IN WCHAR const *pwszfnIn,
  2503. IN WCHAR const *pwszArg3,
  2504. IN WCHAR const *pwszArg4)
  2505. {
  2506. HRESULT hr;
  2507. DWORD Mode;
  2508. HCERTSTORE hStore = NULL;
  2509. BOOL fBadAsn;
  2510. Mode = DVNS_WRITESTORE; // force open for write
  2511. hr = cuOpenCertStore(pwszStoreName, &Mode, NULL, &hStore);
  2512. if (S_OK != hr)
  2513. {
  2514. wprintf(
  2515. myLoadResourceString(
  2516. g_fForce?
  2517. IDS_CANNOT_CREATE_STORE : // "Cannot open Cert store."
  2518. IDS_CANNOT_OPEN_STORE),
  2519. L"-f"); // "Cannot open existing Cert store. Use %ws switch to force Cert store creation."
  2520. wprintf(wszNewLine);
  2521. _JumpErrorStr(hr, error, "cuOpenCertStore", pwszStoreName);
  2522. }
  2523. hr = AddCertToStoreFromFile(hStore, pwszStoreName, pwszfnIn, &fBadAsn);
  2524. if (S_OK != hr)
  2525. {
  2526. if (!fBadAsn)
  2527. {
  2528. _JumpError(hr, error, "AddCertToStoreFromFile");
  2529. }
  2530. hr = AddCRLToStoreFromFile(hStore, pwszfnIn, &fBadAsn);
  2531. if (S_OK != hr)
  2532. {
  2533. if (!fBadAsn)
  2534. {
  2535. _JumpError(hr, error, "AddCRLToStoreFromFile");
  2536. }
  2537. hr = AddPKCS7ToStoreFromFile(hStore, pwszStoreName, pwszfnIn);
  2538. _JumpIfError(hr, error, "AddPKCS7ToStoreFromFile");
  2539. }
  2540. }
  2541. CSASSERT(S_OK == hr);
  2542. error:
  2543. if (NULL != hStore)
  2544. {
  2545. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2546. }
  2547. return(hr);
  2548. }
  2549. HRESULT
  2550. SaveFirstBlob(
  2551. IN BYTE const *pbEncoded,
  2552. IN DWORD cbEncoded,
  2553. IN OUT BYTE **ppbDeleted,
  2554. IN OUT DWORD *pcbDeleted)
  2555. {
  2556. HRESULT hr;
  2557. if (NULL == *ppbDeleted)
  2558. {
  2559. *pcbDeleted = cbEncoded;
  2560. *ppbDeleted = (BYTE *) LocalAlloc(LMEM_FIXED, cbEncoded);
  2561. if (NULL == *ppbDeleted)
  2562. {
  2563. hr = E_OUTOFMEMORY;
  2564. _JumpError(hr, error, "LocalAlloc");
  2565. }
  2566. CopyMemory(*ppbDeleted, pbEncoded, cbEncoded);
  2567. }
  2568. hr = S_OK;
  2569. error:
  2570. return(hr);
  2571. }
  2572. HRESULT
  2573. verbDelStore(
  2574. IN WCHAR const *pwszOption,
  2575. IN WCHAR const *pwszStoreName,
  2576. IN WCHAR const *pwszCertId,
  2577. IN WCHAR const *pwszArg3,
  2578. IN WCHAR const *pwszArg4)
  2579. {
  2580. HRESULT hr;
  2581. WCHAR *pwszStore = NULL;
  2582. HCERTSTORE hStore = NULL;
  2583. CERT_CONTEXT const *pCert = NULL;
  2584. CRL_CONTEXT const *pCRL = NULL;
  2585. WCHAR *pwszCertName = NULL;
  2586. BYTE *pbHash = NULL;
  2587. DWORD cbHash;
  2588. BSTR strSerialNumber = NULL;
  2589. DWORD Mode;
  2590. DWORD iCert;
  2591. DWORD iCertDel;
  2592. DWORD iCRL;
  2593. DWORD iCRLDel;
  2594. DWORD iCTL;
  2595. DWORD iCTLDel;
  2596. DWORD cCertDeleted;
  2597. DWORD cCRLDeleted;
  2598. BYTE *pbDeleted = NULL;
  2599. DWORD cbDeleted;
  2600. if (NULL == pwszStoreName || 0 == wcscmp(L"*", pwszStoreName))
  2601. {
  2602. pwszStoreName = wszCA_CERTSTORE;
  2603. }
  2604. hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCertDel, &iCRLDel, &iCTLDel);
  2605. _JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
  2606. if (MAXDWORD == iCertDel && NULL == pwszCertName && MAXDWORD == iCRLDel)
  2607. {
  2608. hr = E_INVALIDARG;
  2609. _JumpErrorStr(hr, error, "incomplete Index arg", pwszCertId);
  2610. }
  2611. if (NULL != pwszCertName)
  2612. {
  2613. hr = WszToMultiByteInteger(TRUE, pwszCertName, &cbHash, &pbHash);
  2614. _PrintIfError2(hr, "WszToMultiByteInteger", hr);
  2615. hr = myMakeSerialBstr(pwszCertName, &strSerialNumber);
  2616. _PrintIfError2(hr, "myMakeSerialBstr", hr);
  2617. }
  2618. Mode = DVNS_WRITESTORE; // force open for write
  2619. hr = cuOpenCertStore(pwszStoreName, &Mode, NULL, &hStore);
  2620. _JumpIfError(hr, error, "cuOpenCertStore");
  2621. cCertDeleted = 0;
  2622. cCRLDeleted = 0;
  2623. if (MAXDWORD != iCertDel || NULL != pwszCertName)
  2624. {
  2625. for (iCert = 0; ; iCert++)
  2626. {
  2627. pCert = CertEnumCertificatesInStore(hStore, pCert);
  2628. if (NULL == pCert)
  2629. {
  2630. break;
  2631. }
  2632. if (iCert == iCertDel ||
  2633. (MAXDWORD == iCertDel && NULL != pwszCertName))
  2634. {
  2635. CERT_CONTEXT const *pCertT;
  2636. if (NULL != pwszCertName)
  2637. {
  2638. BOOL fMatch;
  2639. hr = myCertMatch(
  2640. pCert,
  2641. pwszCertName,
  2642. FALSE, // fAllowMissingCN
  2643. pbHash,
  2644. cbHash,
  2645. strSerialNumber,
  2646. &fMatch);
  2647. _JumpIfError(hr, error, "myCertMatch");
  2648. if (!fMatch)
  2649. {
  2650. continue;
  2651. }
  2652. }
  2653. wprintf(
  2654. myLoadResourceString(IDS_FORMAT_DELETE_CERT_INDEX), // "Deleting Certificate %d"
  2655. iCert);
  2656. wprintf(wszNewLine);
  2657. cCertDeleted++;
  2658. SaveFirstBlob(
  2659. pCert->pbCertEncoded,
  2660. pCert->cbCertEncoded,
  2661. &pbDeleted,
  2662. &cbDeleted);
  2663. pCertT = CertDuplicateCertificateContext(pCert);
  2664. if (!CertDeleteCertificateFromStore(pCertT))
  2665. {
  2666. hr = myHLastError();
  2667. _JumpError(hr, error, "CertDeleteCertificateFromStore");
  2668. }
  2669. if (iCert == iCertDel)
  2670. {
  2671. break;
  2672. }
  2673. }
  2674. }
  2675. }
  2676. if (MAXDWORD != iCRLDel || NULL != pwszCertName)
  2677. {
  2678. for (iCRL = 0; ; iCRL++)
  2679. {
  2680. pCRL = CertEnumCRLsInStore(hStore, pCRL);
  2681. if (NULL == pCRL)
  2682. {
  2683. break;
  2684. }
  2685. if (iCRL == iCRLDel ||
  2686. (MAXDWORD == iCRLDel && NULL != pwszCertName))
  2687. {
  2688. CRL_CONTEXT const *pCRLT;
  2689. if (NULL != pwszCertName)
  2690. {
  2691. BOOL fMatch;
  2692. hr = myCRLMatch(
  2693. pCRL,
  2694. pwszCertName,
  2695. FALSE, // fAllowMissingCN
  2696. pbHash,
  2697. cbHash,
  2698. &fMatch);
  2699. _JumpIfError(hr, error, "myCRLMatch");
  2700. if (!fMatch)
  2701. {
  2702. continue;
  2703. }
  2704. }
  2705. wprintf(
  2706. myLoadResourceString(IDS_FORMAT_DELETE_CRL_INDEX), // "Deleting CRL %d"
  2707. iCRL);
  2708. wprintf(wszNewLine);
  2709. cCRLDeleted++;
  2710. SaveFirstBlob(
  2711. pCRL->pbCrlEncoded,
  2712. pCRL->cbCrlEncoded,
  2713. &pbDeleted,
  2714. &cbDeleted);
  2715. pCRLT = CertDuplicateCRLContext(pCRL);
  2716. if (!CertDeleteCRLFromStore(pCRLT))
  2717. {
  2718. hr = myHLastError();
  2719. _JumpError(hr, error, "CertDeleteCRLFromStore");
  2720. }
  2721. if (iCRL == iCRLDel)
  2722. {
  2723. break;
  2724. }
  2725. }
  2726. }
  2727. }
  2728. if (0 != cCertDeleted + cCRLDeleted)
  2729. {
  2730. BOOL fSingle = 1 == cCertDeleted + cCRLDeleted;
  2731. hr = CommitStore(
  2732. hStore,
  2733. pwszStoreName,
  2734. Mode,
  2735. fSingle? pbDeleted : NULL,
  2736. fSingle? cbDeleted : 0);
  2737. _JumpIfError(hr, error, "CommitStore");
  2738. }
  2739. hr = S_OK;
  2740. error:
  2741. if (NULL != strSerialNumber)
  2742. {
  2743. SysFreeString(strSerialNumber);
  2744. }
  2745. if (NULL != pbDeleted)
  2746. {
  2747. LocalFree(pbDeleted);
  2748. }
  2749. if (NULL != pbHash)
  2750. {
  2751. LocalFree(pbHash);
  2752. }
  2753. if (NULL != pwszCertName)
  2754. {
  2755. LocalFree(pwszCertName);
  2756. }
  2757. if (NULL != pwszStore)
  2758. {
  2759. LocalFree(pwszStore);
  2760. }
  2761. if (NULL != pCert)
  2762. {
  2763. CertFreeCertificateContext(pCert);
  2764. }
  2765. if (NULL != pCRL)
  2766. {
  2767. CertFreeCRLContext(pCRL);
  2768. }
  2769. if (NULL != hStore)
  2770. {
  2771. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2772. }
  2773. return(hr);
  2774. }
  2775. HRESULT
  2776. verbVerifyStore(
  2777. IN WCHAR const *pwszOption,
  2778. IN WCHAR const *pwszStoreName,
  2779. IN WCHAR const *pwszCertId,
  2780. IN WCHAR const *pwszArg3,
  2781. IN WCHAR const *pwszArg4)
  2782. {
  2783. HRESULT hr;
  2784. WCHAR *pwszCertName = NULL;
  2785. DWORD iCert;
  2786. DWORD iCRL;
  2787. DWORD iCTL;
  2788. hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
  2789. _JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
  2790. hr = DumpAndVerifyNamedStore(
  2791. pwszStoreName,
  2792. DVNS_SAVECERT |
  2793. DVNS_SAVECRL |
  2794. DVNS_SAVECTL |
  2795. DVNS_VERIFYCERT |
  2796. DVNS_DUMPKEYS |
  2797. DVNS_DUMPPROPERTIES,
  2798. pwszCertName,
  2799. iCert,
  2800. iCRL,
  2801. iCTL,
  2802. NULL,
  2803. NULL);
  2804. _JumpIfError(hr, error, "DumpAndVerifyNamedStore");
  2805. error:
  2806. if (NULL != pwszCertName)
  2807. {
  2808. LocalFree(pwszCertName);
  2809. }
  2810. return(hr);
  2811. }
  2812. HRESULT
  2813. verbRepairStore(
  2814. IN WCHAR const *pwszOption,
  2815. IN WCHAR const *pwszStoreName,
  2816. IN WCHAR const *pwszCertId,
  2817. IN WCHAR const *pwszArg3,
  2818. IN WCHAR const *pwszArg4)
  2819. {
  2820. HRESULT hr;
  2821. WCHAR *pwszCertName = NULL;
  2822. DWORD iCert;
  2823. DWORD iCRL;
  2824. DWORD iCTL;
  2825. hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
  2826. _JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
  2827. hr = DumpAndVerifyNamedStore(
  2828. pwszStoreName,
  2829. DVNS_SAVECERT |
  2830. DVNS_SAVECRL |
  2831. DVNS_SAVECTL |
  2832. DVNS_REPAIRKPI |
  2833. DVNS_DUMPKEYS,
  2834. pwszCertName,
  2835. iCert,
  2836. iCRL,
  2837. iCTL,
  2838. NULL,
  2839. NULL);
  2840. _JumpIfError(hr, error, "DumpAndVerifyNamedStore");
  2841. error:
  2842. if (NULL != pwszCertName)
  2843. {
  2844. LocalFree(pwszCertName);
  2845. }
  2846. return(hr);
  2847. }
  2848. HRESULT
  2849. verbExportPVK(
  2850. IN WCHAR const *pwszOption,
  2851. IN WCHAR const *pwszCertId,
  2852. IN WCHAR const *pwszfnPVKBaseName,
  2853. IN WCHAR const *pwszArg3,
  2854. IN WCHAR const *pwszArg4)
  2855. {
  2856. HRESULT hr;
  2857. WCHAR *pwszCertName = NULL;
  2858. DWORD iCert;
  2859. DWORD iCRL;
  2860. DWORD iCTL;
  2861. hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
  2862. _JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
  2863. hr = DumpAndVerifyNamedStore(
  2864. wszMY_CERTSTORE,
  2865. DVNS_SAVEPVK | DVNS_DUMPKEYS,
  2866. pwszCertName,
  2867. iCert,
  2868. iCRL,
  2869. iCTL,
  2870. pwszfnPVKBaseName,
  2871. g_pwszPassword);
  2872. _JumpIfError(hr, error, "DumpAndVerifyNamedStore");
  2873. error:
  2874. if (NULL != pwszCertName)
  2875. {
  2876. LocalFree(pwszCertName);
  2877. }
  2878. return(hr);
  2879. }
  2880. HRESULT
  2881. verbExportPFX(
  2882. IN WCHAR const *pwszOption,
  2883. IN WCHAR const *pwszCertId,
  2884. IN WCHAR const *pwszfnPFX,
  2885. IN WCHAR const *pwszArg3,
  2886. IN WCHAR const *pwszArg4)
  2887. {
  2888. HRESULT hr;
  2889. WCHAR *pwszCertName = NULL;
  2890. DWORD iCert;
  2891. DWORD iCRL;
  2892. DWORD iCTL;
  2893. hr = ParseCertCRLIndex(pwszCertId, &pwszCertName, &iCert, &iCRL, &iCTL);
  2894. _JumpIfErrorStr(hr, error, "ParseCertCRLIndex", pwszCertId);
  2895. hr = DumpAndVerifyNamedStore(
  2896. wszMY_CERTSTORE,
  2897. DVNS_SAVEPFX | DVNS_DUMPKEYS,
  2898. pwszCertName,
  2899. iCert,
  2900. iCRL,
  2901. iCTL,
  2902. pwszfnPFX,
  2903. g_pwszPassword);
  2904. _JumpIfError(hr, error, "DumpAndVerifyNamedStore");
  2905. error:
  2906. if (NULL != pwszCertName)
  2907. {
  2908. LocalFree(pwszCertName);
  2909. }
  2910. return(hr);
  2911. }
  2912. HRESULT
  2913. cuGenerateKeyContainerName(
  2914. IN CERT_CONTEXT const *pcc,
  2915. OUT WCHAR **ppwszKeyContainerName)
  2916. {
  2917. HRESULT hr;
  2918. GUID guid;
  2919. WCHAR *pwszGUID = NULL;
  2920. WCHAR *pwszSimpleName = NULL;
  2921. WCHAR *pwszRawContainerName = NULL;
  2922. DWORD cwc;
  2923. *ppwszKeyContainerName = NULL;
  2924. hr = myCertGetNameString(
  2925. pcc,
  2926. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  2927. &pwszSimpleName);
  2928. _JumpIfError(hr, error, "myCertGetNameString");
  2929. myUuidCreate(&guid);
  2930. hr = myCLSIDToWsz(&guid, &pwszGUID);
  2931. _JumpIfError(hr, error, "myCLSIDToWsz");
  2932. cwc = wcslen(pwszSimpleName) + 1 + wcslen(pwszGUID);
  2933. pwszRawContainerName = (WCHAR *) LocalAlloc(
  2934. LMEM_FIXED,
  2935. (cwc + 1) * sizeof(WCHAR));
  2936. if (NULL == pwszRawContainerName)
  2937. {
  2938. hr = E_OUTOFMEMORY;
  2939. _JumpError(hr, error, "LocalAlloc");
  2940. }
  2941. wcscpy(pwszRawContainerName, pwszSimpleName);
  2942. wcscat(pwszRawContainerName, L"-");
  2943. wcscat(pwszRawContainerName, pwszGUID);
  2944. hr = mySanitizeName(pwszRawContainerName, ppwszKeyContainerName);
  2945. _JumpIfError(hr, error, "mySanitizeName");
  2946. wprintf(L"%ws -- %ws\n", pwszSimpleName, *ppwszKeyContainerName);
  2947. error:
  2948. if (NULL != pwszGUID)
  2949. {
  2950. LocalFree(pwszGUID);
  2951. }
  2952. if (NULL != pwszSimpleName)
  2953. {
  2954. LocalFree(pwszSimpleName);
  2955. }
  2956. if (NULL != pwszRawContainerName)
  2957. {
  2958. LocalFree(pwszRawContainerName);
  2959. }
  2960. return(hr);
  2961. }
  2962. HRESULT
  2963. cuImportChainAndKeys(
  2964. IN CERT_CHAIN_CONTEXT const *pChain,
  2965. OPTIONAL IN WCHAR const *pwszNewCSP,
  2966. IN BOOL fUser,
  2967. OPTIONAL IN WCHAR const *pwszStoreName)
  2968. {
  2969. HRESULT hr;
  2970. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  2971. WCHAR *pwszKeyContainerName = NULL;
  2972. CERT_CONTEXT const *pcc;
  2973. if (NULL == pwszStoreName)
  2974. {
  2975. pwszStoreName = wszMY_CERTSTORE;
  2976. }
  2977. pcc = pChain->rgpChain[0]->rgpElement[0]->pCertContext;
  2978. hr = myCertGetKeyProviderInfo(pcc, &pkpi);
  2979. _JumpIfError(hr, error, "myCertGetKeyProviderInfo");
  2980. hr = cuGenerateKeyContainerName(pcc, &pwszKeyContainerName);
  2981. _JumpIfError(hr, error, "cuGenerateKeyContainerName");
  2982. if (NULL == pwszNewCSP)
  2983. {
  2984. pwszNewCSP = pkpi->pwszProvName;
  2985. }
  2986. hr = myCopyKeys(
  2987. pkpi,
  2988. pkpi->pwszContainerName, // pwszOldContainer
  2989. pwszKeyContainerName, // pwszNewContainer
  2990. pwszNewCSP, // pwszNewCSP
  2991. fUser, // fOldUserKey
  2992. fUser, // fNewUserKey
  2993. g_fProtect,
  2994. g_fForce);
  2995. _JumpIfError(hr, error, "myCopyKeys");
  2996. pkpi->pwszContainerName = pwszKeyContainerName;
  2997. pkpi->pwszProvName = const_cast<WCHAR *>(pwszNewCSP);
  2998. hr = mySaveChainAndKeys(
  2999. pChain->rgpChain[0],
  3000. pwszStoreName,
  3001. cuGetSystemStoreFlags(),
  3002. pkpi,
  3003. NULL);
  3004. _JumpIfError(hr, error, "mySaveChainAndKeys");
  3005. error:
  3006. if (NULL != pkpi)
  3007. {
  3008. LocalFree(pkpi);
  3009. }
  3010. if (NULL != pwszKeyContainerName)
  3011. {
  3012. LocalFree(pwszKeyContainerName);
  3013. }
  3014. return(hr);
  3015. }
  3016. HRESULT
  3017. ReadPFXOrEPFIntoCertStore(
  3018. IN WCHAR const *pwszfnPFXOrEPF,
  3019. IN BOOL fUser,
  3020. OUT HCERTSTORE *phStore)
  3021. {
  3022. HRESULT hr;
  3023. CRYPT_DATA_BLOB pfx;
  3024. WCHAR const *pwszPassword;
  3025. WCHAR wszPassword[MAX_PATH];
  3026. HCERTSTORE hStore = NULL;
  3027. pfx.pbData = NULL;
  3028. *phStore = NULL;
  3029. hr = cuGetPassword(
  3030. 0, // idsPrompt
  3031. NULL, // pwszfn
  3032. g_pwszPassword,
  3033. FALSE, // fVerify
  3034. wszPassword,
  3035. ARRAYSIZE(wszPassword),
  3036. &pwszPassword);
  3037. _JumpIfError(hr, error, "cuGetPassword");
  3038. hr = DecodeFileW(
  3039. pwszfnPFXOrEPF,
  3040. &pfx.pbData,
  3041. &pfx.cbData,
  3042. CRYPT_STRING_ANY);
  3043. _JumpIfError(hr, error, "DecodeFileW");
  3044. CSASSERT(NULL != pfx.pbData);
  3045. if (PFXIsPFXBlob(&pfx))
  3046. {
  3047. hStore = myPFXImportCertStore(
  3048. &pfx,
  3049. pwszPassword,
  3050. CRYPT_EXPORTABLE |
  3051. (fUser? CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET));
  3052. if (NULL == hStore)
  3053. {
  3054. hr = myHLastError();
  3055. _JumpError(hr, error, "myPFXImportCertStore");
  3056. }
  3057. }
  3058. else
  3059. {
  3060. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3061. _PrintError(hr, "PFXIsPFXBlob");
  3062. hStore = CertOpenStore(
  3063. CERT_STORE_PROV_MEMORY,
  3064. X509_ASN_ENCODING,
  3065. NULL,
  3066. CERT_STORE_NO_CRYPT_RELEASE_FLAG |
  3067. CERT_STORE_ENUM_ARCHIVED_FLAG,
  3068. NULL);
  3069. if (NULL == hStore)
  3070. {
  3071. hr = myHLastError();
  3072. _JumpError(hr, error, "CertOpenStore");
  3073. }
  3074. hr = EPFFileDump(pwszfnPFXOrEPF, pwszPassword, hStore);
  3075. if (S_FALSE == hr) // if not an EPF file
  3076. {
  3077. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3078. }
  3079. _JumpIfErrorStr(hr, error, "EPFFileDump", pwszfnPFXOrEPF);
  3080. }
  3081. *phStore = hStore;
  3082. hStore = NULL;
  3083. hr = S_OK;
  3084. error:
  3085. SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
  3086. if (NULL != hStore)
  3087. {
  3088. myDeleteGuidKeys(hStore, !fUser);
  3089. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  3090. }
  3091. if (NULL != pfx.pbData)
  3092. {
  3093. LocalFree(pfx.pbData);
  3094. }
  3095. return(hr);
  3096. }
  3097. HRESULT
  3098. verbImportPFX(
  3099. IN WCHAR const *pwszOption,
  3100. IN WCHAR const *pwszfnPFXOrEPF,
  3101. IN WCHAR const *pwszArg2,
  3102. IN WCHAR const *pwszArg3,
  3103. IN WCHAR const *pwszArg4)
  3104. {
  3105. HRESULT hr;
  3106. HCERTSTORE hStorePFX = NULL;
  3107. RESTORECHAIN *paRestoreChain = NULL;
  3108. DWORD cRestoreChain;
  3109. DWORD iChain;
  3110. BOOL fUser = !g_fEnterpriseRegistry && g_fUserRegistry;
  3111. hr = ReadPFXOrEPFIntoCertStore(pwszfnPFXOrEPF, fUser, &hStorePFX);
  3112. _JumpIfError(hr, error, "ReadPFXOrEPFIntoCertStore");
  3113. cRestoreChain = 0;
  3114. hr = myGetChainArrayFromStore(
  3115. hStorePFX,
  3116. FALSE,
  3117. fUser,
  3118. NULL, // ppwszCommonName
  3119. &cRestoreChain,
  3120. NULL);
  3121. _JumpIfError(hr, error, "myGetChainArrayFromStore");
  3122. if (0 == cRestoreChain)
  3123. {
  3124. hr = HRESULT_FROM_WIN32(CRYPT_E_SELF_SIGNED);
  3125. _JumpError(hr, error, "myGetChainArrayFromStore <no chain>");
  3126. }
  3127. paRestoreChain = (RESTORECHAIN *) LocalAlloc(
  3128. LMEM_FIXED | LMEM_ZEROINIT,
  3129. cRestoreChain * sizeof(paRestoreChain[0]));
  3130. if (NULL == paRestoreChain)
  3131. {
  3132. hr = E_OUTOFMEMORY;
  3133. _JumpError(hr, error, "LocalAlloc");
  3134. }
  3135. hr = myGetChainArrayFromStore(
  3136. hStorePFX,
  3137. FALSE,
  3138. fUser,
  3139. NULL, // ppwszCommonName
  3140. &cRestoreChain,
  3141. paRestoreChain);
  3142. _JumpIfError(hr, error, "myGetChainArrayFromStore");
  3143. for (iChain = 0; iChain < cRestoreChain; iChain++)
  3144. {
  3145. CERT_CHAIN_CONTEXT const *pChain = paRestoreChain[iChain].pChain;
  3146. CERT_PUBLIC_KEY_INFO *pPublicKeyInfo;
  3147. if (1 > pChain->cChain)
  3148. {
  3149. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3150. _JumpError(hr, error, "No Chain Context");
  3151. }
  3152. hr = cuImportChainAndKeys(pChain, g_pwszCSP, fUser, wszMY_CERTSTORE);
  3153. _JumpIfError(hr, error, "cuImportChainAndKeys");
  3154. }
  3155. hr = S_OK;
  3156. error:
  3157. if (NULL != paRestoreChain)
  3158. {
  3159. for (iChain = 0; iChain < cRestoreChain; iChain++)
  3160. {
  3161. if (NULL != paRestoreChain[iChain].pChain)
  3162. {
  3163. CertFreeCertificateChain(paRestoreChain[iChain].pChain);
  3164. }
  3165. }
  3166. LocalFree(paRestoreChain);
  3167. }
  3168. if (NULL != hStorePFX)
  3169. {
  3170. myDeleteGuidKeys(hStorePFX, !fUser);
  3171. CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
  3172. }
  3173. return(hr);
  3174. }
  3175. HRESULT
  3176. AddStringToList(
  3177. IN WCHAR const *pwszNew,
  3178. IN OUT WCHAR ***papwsz)
  3179. {
  3180. HRESULT hr;
  3181. WCHAR *pwszAlloc = NULL;
  3182. WCHAR **ppwsz;
  3183. DWORD i;
  3184. // Count the strings in the existing list.
  3185. // If the new string matches an existing string, return imemdiately.
  3186. ppwsz = *papwsz;
  3187. i = 0;
  3188. if (NULL != ppwsz)
  3189. {
  3190. for ( ; NULL != ppwsz[i]; i++)
  3191. {
  3192. if (0 == lstrcmp(pwszNew, ppwsz[i]))
  3193. {
  3194. hr = S_OK;
  3195. goto error;
  3196. }
  3197. }
  3198. }
  3199. hr = myDupString(pwszNew, &pwszAlloc);
  3200. _JumpIfError(hr, error, "myDupString");
  3201. ppwsz = (WCHAR **) LocalAlloc(LMEM_FIXED, (i + 2) * sizeof(*ppwsz));
  3202. if (NULL == ppwsz)
  3203. {
  3204. hr = E_OUTOFMEMORY;
  3205. _JumpError(hr, error, "LocalAlloc");
  3206. }
  3207. // Insert the new string at the head of the list.
  3208. ppwsz[0] = pwszAlloc;
  3209. pwszAlloc = NULL;
  3210. if (0 != i)
  3211. {
  3212. CopyMemory(&ppwsz[1], *papwsz, i * sizeof(*ppwsz));
  3213. LocalFree(*papwsz);
  3214. }
  3215. ppwsz[i + 1] = NULL;
  3216. *papwsz = ppwsz;
  3217. hr = S_OK;
  3218. error:
  3219. if (NULL != pwszAlloc)
  3220. {
  3221. LocalFree(pwszAlloc);
  3222. }
  3223. return(hr);
  3224. }
  3225. HRESULT
  3226. AddPFXOrEPFToStoreSub(
  3227. IN WCHAR const *pwszfn,
  3228. IN WCHAR const *pwszPassword,
  3229. OPTIONAL IN CRYPT_DATA_BLOB *ppfx,
  3230. IN HCERTSTORE hStoreMerge)
  3231. {
  3232. HRESULT hr;
  3233. HCERTSTORE hStorePFX = NULL;
  3234. CERT_CONTEXT const *pCert = NULL;
  3235. if (NULL == ppfx)
  3236. {
  3237. hr = EPFFileDump(pwszfn, pwszPassword, hStoreMerge);
  3238. if (S_FALSE == hr) // if not an EPF file
  3239. {
  3240. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3241. }
  3242. _JumpIfErrorStr(hr, error, "EPFFileDump", pwszfn);
  3243. }
  3244. else
  3245. {
  3246. hStorePFX = myPFXImportCertStore(
  3247. ppfx,
  3248. pwszPassword,
  3249. CRYPT_EXPORTABLE |
  3250. (g_fUserRegistry?
  3251. CRYPT_USER_KEYSET : CRYPT_MACHINE_KEYSET));
  3252. if (NULL == hStorePFX)
  3253. {
  3254. hr = myHLastError();
  3255. _JumpErrorStr2(
  3256. hr,
  3257. error,
  3258. "myPFXImportCertStore",
  3259. pwszfn,
  3260. HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD));
  3261. }
  3262. while (TRUE)
  3263. {
  3264. pCert = CertEnumCertificatesInStore(hStorePFX, pCert);
  3265. if (NULL == pCert)
  3266. {
  3267. break;
  3268. }
  3269. if (!CertAddCertificateContextToStore(
  3270. hStoreMerge,
  3271. pCert,
  3272. CERT_STORE_ADD_REPLACE_EXISTING,
  3273. NULL))
  3274. {
  3275. hr = myHLastError();
  3276. _JumpError(hr, error, "CertAddCertificateContextToStore");
  3277. }
  3278. if (!CertDeleteCertificateFromStore(pCert))
  3279. {
  3280. hr = myHLastError();
  3281. _JumpError(hr, error, "CertDeleteCertificateFromStore");
  3282. }
  3283. pCert = NULL;
  3284. }
  3285. }
  3286. hr = S_OK;
  3287. error:
  3288. if (NULL != pCert)
  3289. {
  3290. CertFreeCertificateContext(pCert);
  3291. }
  3292. if (NULL != hStorePFX)
  3293. {
  3294. myDeleteGuidKeys(hStorePFX, !g_fUserRegistry);
  3295. CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
  3296. }
  3297. return(hr);
  3298. }
  3299. HRESULT
  3300. myCryptGetDefaultProvider(
  3301. DWORD dwProvType,
  3302. DWORD dwFlags,
  3303. WCHAR **ppwszProvName)
  3304. {
  3305. HRESULT hr;
  3306. DWORD cb;
  3307. *ppwszProvName = NULL;
  3308. cb = 0;
  3309. while (TRUE)
  3310. {
  3311. if (!CryptGetDefaultProvider(
  3312. dwProvType,
  3313. NULL, // pdwReserved
  3314. dwFlags,
  3315. *ppwszProvName,
  3316. &cb))
  3317. {
  3318. hr = myHLastError();
  3319. _JumpError(hr, error, "CryptGetDefaultProvider");
  3320. }
  3321. if (NULL != *ppwszProvName)
  3322. {
  3323. break;
  3324. }
  3325. *ppwszProvName = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
  3326. if (NULL == *ppwszProvName)
  3327. {
  3328. hr = E_OUTOFMEMORY;
  3329. _JumpError(hr, error, "LocalAlloc");
  3330. }
  3331. }
  3332. hr = S_OK;
  3333. error:
  3334. return(hr);
  3335. }
  3336. #define cuSIGN_KEY_USAGE \
  3337. (CERT_DIGITAL_SIGNATURE_KEY_USAGE | \
  3338. CERT_NON_REPUDIATION_KEY_USAGE | \
  3339. CERT_KEY_CERT_SIGN_KEY_USAGE | \
  3340. CERT_OFFLINE_CRL_SIGN_KEY_USAGE | \
  3341. CERT_CRL_SIGN_KEY_USAGE)
  3342. #define cuENCRYPT_KEY_USAGE \
  3343. (CERT_KEY_ENCIPHERMENT_KEY_USAGE | \
  3344. CERT_DATA_ENCIPHERMENT_KEY_USAGE | \
  3345. CERT_KEY_AGREEMENT_KEY_USAGE | \
  3346. CERT_ENCIPHER_ONLY_KEY_USAGE)
  3347. static CHAR const *s_cuapszObjIdSign[] =
  3348. {
  3349. szOID_PKIX_KP_CLIENT_AUTH,
  3350. szOID_PKIX_KP_CODE_SIGNING,
  3351. szOID_PKIX_KP_TIMESTAMP_SIGNING,
  3352. szOID_KP_TIME_STAMP_SIGNING,
  3353. szOID_KP_QUALIFIED_SUBORDINATION,
  3354. szOID_KP_DOCUMENT_SIGNING,
  3355. szOID_KP_SMARTCARD_LOGON,
  3356. };
  3357. static CHAR const *s_cuapszObjIdEncrypt[] =
  3358. {
  3359. szOID_PKIX_KP_EMAIL_PROTECTION,
  3360. szOID_KP_KEY_RECOVERY_AGENT,
  3361. szOID_KP_KEY_RECOVERY,
  3362. szOID_PKIX_KP_SERVER_AUTH,
  3363. };
  3364. BOOL
  3365. IsSigningCert(
  3366. IN CERT_CONTEXT const *pcc)
  3367. {
  3368. HRESULT hr;
  3369. BOOL fSigningCert = TRUE;
  3370. CERT_EXTENSION const *pExt;
  3371. DWORD cb;
  3372. BOOL fMatch;
  3373. pExt = CertFindExtension(
  3374. szOID_KEY_USAGE,
  3375. pcc->pCertInfo->cExtension,
  3376. pcc->pCertInfo->rgExtension);
  3377. if (NULL != pExt)
  3378. {
  3379. CRYPT_DATA_BLOB aBlob[1 + BLOB_ROUND(2)];
  3380. cb = sizeof(aBlob);
  3381. if (CryptDecodeObject(
  3382. X509_ASN_ENCODING,
  3383. X509_KEY_USAGE,
  3384. pExt->Value.pbData,
  3385. pExt->Value.cbData,
  3386. 0,
  3387. aBlob,
  3388. &cb))
  3389. {
  3390. if (1 <= aBlob[0].cbData)
  3391. {
  3392. if (cuSIGN_KEY_USAGE & aBlob[0].pbData[0])
  3393. {
  3394. goto done;
  3395. }
  3396. if (cuENCRYPT_KEY_USAGE & aBlob[0].pbData[0])
  3397. {
  3398. fSigningCert = FALSE;
  3399. goto done;
  3400. }
  3401. }
  3402. }
  3403. }
  3404. hr = myCertMatchEKUOrApplicationPolicies(
  3405. pcc,
  3406. ARRAYSIZE(s_cuapszObjIdSign),
  3407. s_cuapszObjIdSign,
  3408. FALSE, // fUsageRequired
  3409. &fMatch);
  3410. if (S_OK == hr && fMatch)
  3411. {
  3412. goto done;
  3413. }
  3414. hr = myCertMatchEKUOrApplicationPolicies(
  3415. pcc,
  3416. ARRAYSIZE(s_cuapszObjIdEncrypt),
  3417. s_cuapszObjIdEncrypt,
  3418. FALSE, // fUsageRequired
  3419. &fMatch);
  3420. if (S_OK == hr && fMatch)
  3421. {
  3422. fSigningCert = FALSE;
  3423. goto done;
  3424. }
  3425. done:
  3426. return(fSigningCert);
  3427. }
  3428. HRESULT
  3429. AddCertAndKeyBlobToStore(
  3430. IN HCERTSTORE hStore,
  3431. IN CERT_CONTEXT const *pcc,
  3432. IN BYTE const *pbKey,
  3433. IN DWORD cbKey,
  3434. IN ALG_ID aiKeyAlg)
  3435. {
  3436. HRESULT hr;
  3437. BYTE *pbKeyAlloc = NULL;
  3438. DWORD cbKeyAlloc;
  3439. HCRYPTPROV hProv = NULL;
  3440. HCRYPTKEY hKey = NULL;
  3441. CRYPT_KEY_PROV_INFO kpi;
  3442. WCHAR *pwszProviderName = NULL;
  3443. WCHAR *pwszKeyContainerName = NULL;
  3444. BOOL fSigningKey;
  3445. BOOL fMatchingKey;
  3446. BOOL fQuiet;
  3447. #if 0
  3448. wprintf(wszNewLine);
  3449. DumpHex(
  3450. DH_NOTABPREFIX | DH_NOASCIIHEX | DH_PRIVATEDATA | 4,
  3451. pbKey,
  3452. cbKey);
  3453. #endif
  3454. hr = cuGenerateKeyContainerName(pcc, &pwszKeyContainerName);
  3455. _JumpIfError(hr, error, "cuGenerateKeyContainerName");
  3456. hr = myCryptGetDefaultProvider(
  3457. PROV_RSA_FULL,
  3458. g_fUserRegistry?
  3459. CRYPT_USER_DEFAULT : CRYPT_MACHINE_DEFAULT,
  3460. &pwszProviderName);
  3461. _JumpIfError(hr, error, "myCryptGetDefaultProvider");
  3462. if (!CryptAcquireContext(
  3463. &hProv,
  3464. pwszKeyContainerName,
  3465. pwszProviderName,
  3466. PROV_RSA_FULL,
  3467. CRYPT_NEWKEYSET))
  3468. {
  3469. hr = myHLastError();
  3470. _JumpError(hr, error, "CryptAcquireContext");
  3471. }
  3472. if (PRIVATEKEYBLOB == ((PUBLICKEYSTRUC const *) pbKey)->bType &&
  3473. CUR_BLOB_VERSION == ((PUBLICKEYSTRUC const *) pbKey)->bVersion &&
  3474. RSAPRIV_MAGIC ==
  3475. ((RSAPUBKEY const *) &pbKey[sizeof(PUBLICKEYSTRUC)])->magic)
  3476. {
  3477. if (0 == aiKeyAlg)
  3478. {
  3479. aiKeyAlg = ((PUBLICKEYSTRUC const *) pbKey)->aiKeyAlg;
  3480. }
  3481. else
  3482. if (aiKeyAlg != ((PUBLICKEYSTRUC const *) pbKey)->aiKeyAlg)
  3483. {
  3484. ((PUBLICKEYSTRUC *) pbKey)->aiKeyAlg = aiKeyAlg;
  3485. }
  3486. }
  3487. if (0 == aiKeyAlg)
  3488. {
  3489. aiKeyAlg = IsSigningCert(pcc)? CALG_RSA_SIGN : CALG_RSA_KEYX;
  3490. }
  3491. if (!CryptImportKey(hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey))
  3492. {
  3493. hr = myHLastError();
  3494. _PrintError(hr, "CryptImportKey");
  3495. hr = myDecodeKMSRSAKey(
  3496. pbKey,
  3497. cbKey,
  3498. aiKeyAlg,
  3499. &pbKeyAlloc,
  3500. &cbKeyAlloc);
  3501. _JumpIfError(hr, error, "myDecodeKMSRSAKey");
  3502. pbKey = pbKeyAlloc;
  3503. cbKey = cbKeyAlloc;
  3504. //cuDumpPrivateKeyBlob(pbKey, cbKey, FALSE);
  3505. if (!CryptImportKey(hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey))
  3506. {
  3507. hr = myHLastError();
  3508. _JumpError(hr, error, "CryptImportKey");
  3509. }
  3510. }
  3511. ZeroMemory(&kpi, sizeof(kpi));
  3512. kpi.pwszContainerName = pwszKeyContainerName;
  3513. kpi.pwszProvName = pwszProviderName;
  3514. kpi.dwProvType = PROV_RSA_FULL;
  3515. kpi.dwKeySpec = CALG_RSA_SIGN == aiKeyAlg? AT_SIGNATURE : AT_KEYEXCHANGE;
  3516. if (!CertSetCertificateContextProperty(
  3517. pcc,
  3518. CERT_KEY_PROV_INFO_PROP_ID,
  3519. 0,
  3520. &kpi))
  3521. {
  3522. hr = myHLastError();
  3523. _JumpError(hr, error, "CertSetCertificateContextProperty");
  3524. }
  3525. if (!CertAddCertificateContextToStore(
  3526. hStore,
  3527. pcc,
  3528. CERT_STORE_ADD_NEW,
  3529. NULL))
  3530. {
  3531. hr = myHLastError();
  3532. _JumpError(hr, error, "CertAddCertificateContextToStore");
  3533. }
  3534. fQuiet = g_fQuiet;
  3535. g_fQuiet = TRUE;
  3536. hr = cuDumpPrivateKey(pcc, &fSigningKey, &fMatchingKey);
  3537. g_fQuiet = fQuiet;
  3538. if (!IsHrSkipPrivateKey(hr))
  3539. {
  3540. if (S_OK != hr)
  3541. {
  3542. wprintf(myLoadResourceString(
  3543. fSigningKey?
  3544. IDS_SIGNATURE_BAD : // "Signature test FAILED"
  3545. IDS_ENCRYPTION_BAD)); // "Encryption test FAILED"
  3546. wprintf(wszNewLine);
  3547. _PrintError(hr, "cuDumpPrivateKey");
  3548. fMatchingKey = FALSE;
  3549. }
  3550. if (fMatchingKey)
  3551. {
  3552. wprintf(myLoadResourceString(
  3553. fSigningKey?
  3554. IDS_SIGNATURE_OK : // "Signature test passed"
  3555. IDS_ENCRYPTION_OK)); // "Encryption test passed"
  3556. wprintf(wszNewLine);
  3557. }
  3558. }
  3559. hr = S_OK;
  3560. error:
  3561. if (NULL != pwszProviderName)
  3562. {
  3563. LocalFree(pwszProviderName);
  3564. }
  3565. if (NULL != pwszKeyContainerName)
  3566. {
  3567. LocalFree(pwszKeyContainerName);
  3568. }
  3569. if (NULL != hKey)
  3570. {
  3571. CryptDestroyKey(hKey);
  3572. }
  3573. if (NULL != hProv)
  3574. {
  3575. CryptReleaseContext(hProv, 0);
  3576. }
  3577. if (NULL != pbKeyAlloc)
  3578. {
  3579. SecureZeroMemory(pbKeyAlloc, cbKeyAlloc); // Key material
  3580. LocalFree(pbKeyAlloc);
  3581. }
  3582. return(hr);
  3583. }
  3584. #define cwcEXTMAX 4
  3585. typedef struct _KEYEXTENSION {
  3586. WCHAR const *pwszExt;
  3587. ALG_ID aiKeyAlg;
  3588. } KEYEXTENSION;
  3589. KEYEXTENSION s_akePrivate[] =
  3590. {
  3591. { L".sig", CALG_RSA_SIGN },
  3592. { L".enc", CALG_RSA_KEYX },
  3593. { L".key", 0 },
  3594. { L".pri", 0 },
  3595. };
  3596. HRESULT
  3597. AddCertAndKeyToStore(
  3598. IN CERT_CONTEXT const *pcc,
  3599. IN WCHAR const *pwszfn,
  3600. IN HCERTSTORE hStore,
  3601. IN BYTE const *pbCert,
  3602. IN DWORD cbCert)
  3603. {
  3604. HRESULT hr;
  3605. WCHAR *pwszfnKey = NULL;
  3606. WCHAR *pwszfnExt;
  3607. KEYEXTENSION const *pke;
  3608. BYTE *pbKey = NULL;
  3609. DWORD cbKey;
  3610. pwszfnKey = (WCHAR *) LocalAlloc(
  3611. LMEM_FIXED,
  3612. (wcslen(pwszfn) + cwcEXTMAX + 1) * sizeof(WCHAR));
  3613. if (NULL == pwszfnKey)
  3614. {
  3615. hr = E_OUTOFMEMORY;
  3616. _JumpError(hr, error, "LocalAlloc");
  3617. }
  3618. wcscpy(pwszfnKey, pwszfn);
  3619. pwszfnExt = wcsrchr(pwszfnKey, L'.');
  3620. if (NULL == pwszfnExt || NULL != wcschr(pwszfnExt, L'\\'))
  3621. {
  3622. pwszfnExt = &pwszfnKey[wcslen(pwszfnKey)];
  3623. }
  3624. for (pke = s_akePrivate; ; pke++)
  3625. {
  3626. if (pke >= &s_akePrivate[ARRAYSIZE(s_akePrivate)])
  3627. {
  3628. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  3629. _JumpErrorStr(hr, error, "No private key file", pwszfnKey);
  3630. }
  3631. CSASSERT(cwcEXTMAX >= wcslen(pke->pwszExt));
  3632. wcscpy(pwszfnExt, pke->pwszExt);
  3633. hr = DecodeFileW(pwszfnKey, &pbKey, &cbKey, CRYPT_STRING_ANY);
  3634. if (S_OK == hr)
  3635. {
  3636. break;
  3637. }
  3638. _PrintErrorStr2(hr, "DecodeFileW", pwszfnKey, hr);
  3639. }
  3640. hr = AddCertAndKeyBlobToStore(hStore, pcc, pbKey, cbKey, pke->aiKeyAlg);
  3641. _JumpIfError(hr, error, "AddCertAndKeyBlobToStore");
  3642. error:
  3643. if (NULL != pbKey)
  3644. {
  3645. LocalFree(pbKey);
  3646. }
  3647. if (NULL != pwszfnKey)
  3648. {
  3649. LocalFree(pwszfnKey);
  3650. }
  3651. return(hr);
  3652. }
  3653. HRESULT
  3654. AddSimplePKCS8WithCertToSTore(
  3655. IN HCERTSTORE hStoreMerge,
  3656. IN BYTE *pbIn,
  3657. IN DWORD cbIn)
  3658. {
  3659. HRESULT hr;
  3660. DWORD i;
  3661. DWORD cbKey;
  3662. CERT_CONTEXT const *pcc = NULL;
  3663. i = myASNGetDataIndex(
  3664. BER_SEQUENCE,
  3665. 0,
  3666. pbIn,
  3667. cbIn,
  3668. &cbKey);
  3669. if (MAXDWORD == i)
  3670. {
  3671. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3672. _JumpError(hr, error, "myASNGetDataIndex");
  3673. }
  3674. cbKey += i;
  3675. pcc = CertCreateCertificateContext(
  3676. X509_ASN_ENCODING,
  3677. &pbIn[cbKey],
  3678. cbIn - cbKey);
  3679. if (NULL == pcc)
  3680. {
  3681. hr = myHLastError();
  3682. _JumpError(hr, error, "CertCreateCertificateContext");
  3683. }
  3684. hr = AddCertAndKeyBlobToStore(
  3685. hStoreMerge,
  3686. pcc,
  3687. pbIn,
  3688. cbKey,
  3689. 0); // aiKeyAlg
  3690. _JumpIfError(hr, error, "AddCertAndKeyBlobToStore");
  3691. error:
  3692. if (NULL != pcc)
  3693. {
  3694. CertFreeCertificateContext(pcc);
  3695. }
  3696. return(hr);
  3697. }
  3698. HRESULT
  3699. AddPFXOrEPFToStore(
  3700. IN WCHAR const *pwszfn,
  3701. IN HCERTSTORE hStoreMerge,
  3702. IN OUT WCHAR ***papwszPasswordList)
  3703. {
  3704. HRESULT hr;
  3705. WCHAR const * const *ppwszPasswordList = *papwszPasswordList;
  3706. BOOL fPFX;
  3707. DWORD i;
  3708. CRYPT_DATA_BLOB pfx;
  3709. WCHAR wszPassword[MAX_PATH];
  3710. WCHAR const *pwszPassword;
  3711. BOOL fLoaded;
  3712. CERT_CONTEXT const *pcc = NULL;
  3713. pfx.pbData = NULL;
  3714. hr = DecodeFileW(pwszfn, &pfx.pbData, &pfx.cbData, CRYPT_STRING_ANY);
  3715. _JumpIfError(hr, error, "DecodeFileW");
  3716. fPFX = PFXIsPFXBlob(&pfx);
  3717. if (!fPFX)
  3718. {
  3719. pcc = CertCreateCertificateContext(
  3720. X509_ASN_ENCODING,
  3721. pfx.pbData,
  3722. pfx.cbData);
  3723. if (NULL != pcc)
  3724. {
  3725. hr = AddCertAndKeyToStore(
  3726. pcc,
  3727. pwszfn,
  3728. hStoreMerge,
  3729. pfx.pbData,
  3730. pfx.cbData);
  3731. _PrintIfError(hr, "AddCertAndKeyToStore");
  3732. // File was a cert. If we found the key, hr is S_OK & we're done.
  3733. // If we didn't found the key, hr is set & we're done.
  3734. goto error;
  3735. }
  3736. else
  3737. {
  3738. // File was not a cert. See if it's a simple PKCS8 w/appended Cert.
  3739. hr = AddSimplePKCS8WithCertToSTore(
  3740. hStoreMerge,
  3741. pfx.pbData,
  3742. pfx.cbData);
  3743. _PrintIfError(hr, "AddSimplePKCS8WithCertToSTore");
  3744. if (S_OK == hr)
  3745. {
  3746. // If we succeeded, we're done.
  3747. goto error;
  3748. }
  3749. }
  3750. }
  3751. // Try all of the passwords collected so far.
  3752. fLoaded = FALSE;
  3753. if (NULL != ppwszPasswordList)
  3754. {
  3755. for (i = 0; NULL != ppwszPasswordList[i]; i++)
  3756. {
  3757. hr = AddPFXOrEPFToStoreSub(
  3758. pwszfn,
  3759. ppwszPasswordList[i],
  3760. fPFX? &pfx : NULL,
  3761. hStoreMerge);
  3762. if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD) != hr)
  3763. {
  3764. _JumpIfErrorStr(hr, error, "AddPFXOrEPFToStoreSub", pwszfn);
  3765. fLoaded = TRUE;
  3766. break; // success
  3767. }
  3768. }
  3769. }
  3770. // Try the unparsed command line password, or collect a new one.
  3771. pwszPassword = g_pwszPassword;
  3772. if (!fLoaded)
  3773. {
  3774. while (TRUE)
  3775. {
  3776. if (NULL != pwszPassword)
  3777. {
  3778. hr = AddPFXOrEPFToStoreSub(
  3779. pwszfn,
  3780. pwszPassword,
  3781. fPFX? &pfx : NULL,
  3782. hStoreMerge);
  3783. if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD) != hr)
  3784. {
  3785. _JumpIfErrorStr(hr, error, "AddPFXOrEPFToStoreSub", pwszfn);
  3786. break; // success
  3787. }
  3788. }
  3789. hr = cuGetPassword(
  3790. IDS_FORMAT_ENTER_PASSWORD,
  3791. pwszfn,
  3792. NULL, // pwszPasswordIn
  3793. FALSE, // fVerify
  3794. wszPassword,
  3795. ARRAYSIZE(wszPassword),
  3796. &pwszPassword);
  3797. _JumpIfError(hr, error, "cuGetPassword");
  3798. hr = AddStringToList(pwszPassword, papwszPasswordList);
  3799. _JumpIfError(hr, error, "AddStringToList");
  3800. }
  3801. }
  3802. hr = S_OK;
  3803. error:
  3804. SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
  3805. if (NULL != pcc)
  3806. {
  3807. CertFreeCertificateContext(pcc);
  3808. }
  3809. if (NULL != pfx.pbData)
  3810. {
  3811. LocalFree(pfx.pbData);
  3812. }
  3813. return(hr);
  3814. }
  3815. HRESULT
  3816. LoadAndSavePFXFiles(
  3817. IN BOOL fSaveAsPFX,
  3818. IN BOOL dwEPFAlg,
  3819. IN WCHAR const *pwszfnPFXInFileList,
  3820. IN WCHAR const *pwszfnOutFile,
  3821. OPTIONAL IN WCHAR const *pwszNewCSP,
  3822. OPTIONAL IN WCHAR const *pwszSalt,
  3823. OPTIONAL IN WCHAR const *pwszV3CACertId)
  3824. {
  3825. HRESULT hr;
  3826. WCHAR **ppwszfnList = NULL;
  3827. WCHAR **ppwszPasswordList = NULL;
  3828. DWORD i;
  3829. HCERTSTORE hStoreMerge = NULL;
  3830. WCHAR *pwszPasswordAlloc = NULL;
  3831. WCHAR *pwszPasswordOut;
  3832. hr = cuParseStrings(
  3833. pwszfnPFXInFileList,
  3834. FALSE,
  3835. NULL,
  3836. NULL,
  3837. &ppwszfnList,
  3838. NULL);
  3839. _JumpIfError(hr, error, "cuParseStrings");
  3840. pwszPasswordOut = NULL;
  3841. if (NULL != g_pwszPassword)
  3842. {
  3843. hr = cuParseStrings(
  3844. g_pwszPassword,
  3845. FALSE,
  3846. NULL,
  3847. NULL,
  3848. &ppwszPasswordList,
  3849. NULL);
  3850. _JumpIfError(hr, error, "cuParseStrings");
  3851. if (NULL != ppwszPasswordList)
  3852. {
  3853. if (NULL != g_pwszPassword &&
  3854. (L',' == *g_pwszPassword ||
  3855. NULL != wcsstr(g_pwszPassword, L",,")))
  3856. {
  3857. hr = AddStringToList(g_wszEmpty, &ppwszPasswordList);
  3858. _JumpIfError(hr, error, "AddStringToList");
  3859. // make sure it was added at the head of the list
  3860. CSASSERT(L'\0' == ppwszPasswordList[0][0]);
  3861. }
  3862. for (i = 0; NULL != ppwszPasswordList[i]; i++)
  3863. {
  3864. }
  3865. if (i > 1 && 0 != lstrcmp(L"*", ppwszPasswordList[i - 1]))
  3866. {
  3867. pwszPasswordOut = ppwszPasswordList[i - 1];
  3868. }
  3869. }
  3870. }
  3871. hStoreMerge = CertOpenStore(
  3872. CERT_STORE_PROV_MEMORY,
  3873. X509_ASN_ENCODING,
  3874. NULL,
  3875. CERT_STORE_NO_CRYPT_RELEASE_FLAG |
  3876. CERT_STORE_ENUM_ARCHIVED_FLAG,
  3877. NULL);
  3878. if (NULL == hStoreMerge)
  3879. {
  3880. hr = myHLastError();
  3881. _JumpError(hr, error, "CertOpenStore");
  3882. }
  3883. if (NULL != ppwszfnList)
  3884. {
  3885. for (i = 0; NULL != ppwszfnList[i]; i++)
  3886. {
  3887. hr = AddPFXOrEPFToStore(
  3888. ppwszfnList[i],
  3889. hStoreMerge,
  3890. &ppwszPasswordList);
  3891. _JumpIfError(hr, error, "AddPFXOrEPFToStore");
  3892. }
  3893. }
  3894. else
  3895. {
  3896. hr = AddPFXOrEPFToStore(
  3897. pwszfnPFXInFileList,
  3898. hStoreMerge,
  3899. &ppwszPasswordList);
  3900. _JumpIfError(hr, error, "AddPFXOrEPFToStore");
  3901. }
  3902. hr = SavePFXStoreToFile(
  3903. hStoreMerge,
  3904. pwszfnOutFile,
  3905. pwszNewCSP,
  3906. pwszSalt,
  3907. pwszV3CACertId,
  3908. fSaveAsPFX,
  3909. dwEPFAlg,
  3910. pwszPasswordOut,
  3911. &pwszPasswordAlloc);
  3912. _JumpIfError(hr, error, "SavePFXStoreToFile");
  3913. error:
  3914. if (NULL != hStoreMerge)
  3915. {
  3916. myDeleteGuidKeys(hStoreMerge, !g_fUserRegistry);
  3917. CertCloseStore(hStoreMerge, CERT_CLOSE_STORE_CHECK_FLAG);
  3918. }
  3919. cuFreeStringArray(ppwszPasswordList);
  3920. cuFreeStringArray(ppwszfnList);
  3921. if (NULL != pwszPasswordAlloc)
  3922. {
  3923. myZeroDataString(pwszPasswordAlloc); // password data
  3924. LocalFree(pwszPasswordAlloc);
  3925. }
  3926. return(hr);
  3927. }
  3928. HRESULT
  3929. verbMergePFX(
  3930. IN WCHAR const *pwszOption,
  3931. IN WCHAR const *pwszfnPFXInFileList,
  3932. IN WCHAR const *pwszfnPFXOutFile,
  3933. IN WCHAR const *pwszArg3,
  3934. IN WCHAR const *pwszArg4)
  3935. {
  3936. HRESULT hr;
  3937. hr = LoadAndSavePFXFiles(
  3938. TRUE, // fSaveAsPFX
  3939. 0, // dwEPFAlg
  3940. pwszfnPFXInFileList,
  3941. pwszfnPFXOutFile,
  3942. g_pwszCSP,
  3943. NULL, // pwszSalt
  3944. NULL); // pwszV3CACertId
  3945. _JumpIfError(hr, error, "LoadAndSavePFXFiles");
  3946. error:
  3947. return(hr);
  3948. }
  3949. HRESULT
  3950. verbConvertEPF(
  3951. IN WCHAR const *pwszOption,
  3952. IN WCHAR const *pwszfnPFXInFileList,
  3953. IN WCHAR const *pwszfnEPFOutFile,
  3954. OPTIONAL IN WCHAR const *pwszV3CACertId,
  3955. OPTIONAL IN WCHAR const *pwszAlg)
  3956. {
  3957. HRESULT hr;
  3958. DWORD dwEPFAlg = EPFALG_DEFAULT;
  3959. WCHAR *pwszDup = NULL;
  3960. WCHAR const *pwsz;
  3961. WCHAR *pwszSalt = NULL;
  3962. if (NULL != pwszV3CACertId &&
  3963. (0 == LSTRCMPIS(pwszV3CACertId, L"cast-") ||
  3964. 0 == LSTRCMPIS(pwszV3CACertId, L"cast")))
  3965. {
  3966. pwsz = pwszV3CACertId;
  3967. pwszV3CACertId = pwszAlg;
  3968. pwszAlg = pwsz;
  3969. }
  3970. if (NULL != pwszV3CACertId && NULL != wcsrchr(pwszV3CACertId, L','))
  3971. {
  3972. hr = myDupString(pwszV3CACertId, &pwszDup);
  3973. _JumpIfError(hr, error, "myDupString");
  3974. pwszV3CACertId = pwszDup;
  3975. pwszSalt = wcsrchr(pwszV3CACertId, L',');
  3976. *pwszSalt++ = L'\0';
  3977. if (L'\0' == *pwszSalt)
  3978. {
  3979. pwszSalt = NULL;
  3980. }
  3981. if (L'\0' == *pwszV3CACertId)
  3982. {
  3983. pwszV3CACertId = NULL;
  3984. }
  3985. }
  3986. if (NULL != pwszAlg)
  3987. {
  3988. if (0 == LSTRCMPIS(pwszAlg, L"cast-"))
  3989. {
  3990. dwEPFAlg = EPFALG_CASTEXPORT;
  3991. }
  3992. else if (0 == LSTRCMPIS(pwszAlg, L"cast"))
  3993. {
  3994. dwEPFAlg = EPFALG_CAST;
  3995. }
  3996. else
  3997. {
  3998. hr = E_INVALIDARG;
  3999. _JumpErrorStr(hr, error, "pwszAlg", pwszAlg);
  4000. }
  4001. }
  4002. hr = LoadAndSavePFXFiles(
  4003. FALSE, // fSaveAsPFX
  4004. dwEPFAlg,
  4005. pwszfnPFXInFileList,
  4006. pwszfnEPFOutFile,
  4007. g_pwszCSP,
  4008. pwszSalt,
  4009. pwszV3CACertId);
  4010. _JumpIfError(hr, error, "LoadAndSavePFXFiles");
  4011. error:
  4012. if (NULL != pwszDup)
  4013. {
  4014. LocalFree(pwszDup);
  4015. }
  4016. return(hr);
  4017. }
  4018. HRESULT
  4019. GetMarshaledDword(
  4020. IN BOOL fFetchLength,
  4021. IN OUT BYTE const **ppb,
  4022. IN OUT DWORD *pcb,
  4023. OUT DWORD *pdw)
  4024. {
  4025. HRESULT hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
  4026. if (sizeof(*pdw) > *pcb)
  4027. {
  4028. _JumpError(hr, error, "input buffer too small");
  4029. }
  4030. *pdw = *(DWORD UNALIGNED *) *ppb;
  4031. *ppb += sizeof(*pdw);
  4032. *pcb -= sizeof(*pdw);
  4033. if (fFetchLength && *pdw > *pcb)
  4034. {
  4035. _JumpError(hr, error, "input buffer too small for length");
  4036. }
  4037. hr = S_OK;
  4038. error:
  4039. return(hr);
  4040. }
  4041. HRESULT
  4042. cuDecodeSequence(
  4043. IN BYTE const *pbSeq,
  4044. IN DWORD cbSeq,
  4045. IN DWORD cSeq,
  4046. OUT CRYPT_SEQUENCE_OF_ANY **ppSeq)
  4047. {
  4048. HRESULT hr;
  4049. DWORD cb;
  4050. DWORD i;
  4051. CRYPT_SEQUENCE_OF_ANY *pSeq = NULL;
  4052. *ppSeq = NULL;
  4053. if (!myDecodeObject(
  4054. X509_ASN_ENCODING,
  4055. X509_SEQUENCE_OF_ANY,
  4056. pbSeq,
  4057. cbSeq,
  4058. CERTLIB_USE_LOCALALLOC,
  4059. (VOID **) &pSeq,
  4060. &cb))
  4061. {
  4062. hr = myHLastError();
  4063. _JumpError(hr, error, "myDecodeObject");
  4064. }
  4065. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4066. if (cSeq != pSeq->cValue)
  4067. {
  4068. _JumpError(hr, error, "Sequence count");
  4069. }
  4070. for (i = 0; i < cSeq; i++)
  4071. {
  4072. if (NULL == pSeq->rgValue[i].pbData || 0 == pSeq->rgValue[i].cbData)
  4073. {
  4074. _JumpError(hr, error, "Empty Sequence");
  4075. }
  4076. }
  4077. *ppSeq = pSeq;
  4078. pSeq = NULL;
  4079. hr = S_OK;
  4080. error:
  4081. if (NULL != pSeq)
  4082. {
  4083. LocalFree(pSeq);
  4084. }
  4085. return(hr);
  4086. }
  4087. #define k_PrivateKeyVersion 0
  4088. HRESULT
  4089. VerifyKeyVersion(
  4090. IN BYTE const *pbIn,
  4091. IN DWORD cbIn)
  4092. {
  4093. HRESULT hr;
  4094. DWORD dwKeyVersion;
  4095. DWORD cb;
  4096. dwKeyVersion = MAXDWORD;
  4097. cb = sizeof(dwKeyVersion);
  4098. if (!CryptDecodeObject(
  4099. X509_ASN_ENCODING,
  4100. X509_INTEGER,
  4101. pbIn,
  4102. cbIn,
  4103. 0,
  4104. &dwKeyVersion,
  4105. &cb))
  4106. {
  4107. hr = myHLastError();
  4108. _JumpError(hr, error, "CryptDecodeObject");
  4109. }
  4110. if (k_PrivateKeyVersion != dwKeyVersion)
  4111. {
  4112. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4113. _JumpError(hr, error, "Public key version");
  4114. }
  4115. hr = S_OK;
  4116. error:
  4117. return(hr);
  4118. }
  4119. HRESULT
  4120. EncodeKeyVersion(
  4121. OUT BYTE **ppbOut,
  4122. OUT DWORD *pcbOut)
  4123. {
  4124. HRESULT hr;
  4125. DWORD dwKeyVersion;
  4126. *ppbOut = NULL;
  4127. dwKeyVersion = k_PrivateKeyVersion;
  4128. if (!myEncodeObject(
  4129. X509_ASN_ENCODING,
  4130. X509_INTEGER,
  4131. &dwKeyVersion,
  4132. 0,
  4133. CERTLIB_USE_LOCALALLOC,
  4134. ppbOut,
  4135. pcbOut))
  4136. {
  4137. hr = myHLastError();
  4138. _JumpError(hr, error, "myEncodeObject");
  4139. }
  4140. hr = S_OK;
  4141. error:
  4142. return(hr);
  4143. }
  4144. //+-------------------------------------------------------------------------
  4145. // Inputs a private key in PKCS PrivateKeyInfo format:
  4146. // RSAPrivateKeyInfo ::= SEQUENCE {
  4147. // version Version, -- only 0 supported
  4148. // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
  4149. // privateKey PrivateKey
  4150. // }
  4151. //
  4152. // Version ::= INTEGER
  4153. //
  4154. // PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
  4155. //
  4156. // PrivateKey ::= OCTET STRING -- contains an RSAPrivateKey
  4157. //
  4158. // RSAPrivateKey ::= SEQUENCE {
  4159. // version Version, -- only 0 supported
  4160. // modulus INTEGER, -- n
  4161. // publicExponent INTEGER, -- e
  4162. // privateExponent INTEGER, -- d
  4163. // prime1 INTEGER, -- p
  4164. // prime2 INTEGER, -- q
  4165. // exponent1 INTEGER, -- d mod (p-1)
  4166. // exponent2 INTEGER, -- d mod (q-1)
  4167. // coefficient INTEGER -- (inverse of q) mod p
  4168. // }
  4169. //
  4170. // returns a PRIVATEKEYBLOB
  4171. //--------------------------------------------------------------------------
  4172. // Indexes into pSeqOuter:
  4173. #define ISO_VERSION 0
  4174. #define ISO_ALG 1
  4175. #define ISO_KEY 2
  4176. #define ISO_MAX 3 // number of elements
  4177. // Indexes into pSeqAlg:
  4178. #define ISA_OID 0
  4179. #define ISA_PARM 1
  4180. #define ISA_MAX 2 // number of elements
  4181. // Indexes into pSeqKey:
  4182. #define ISK_VERSION 0
  4183. #define ISK_MODULUS 1 // public key
  4184. #define ISK_PUBEXP 2
  4185. #define ISK_PRIVEXP 3
  4186. #define ISK_PRIME1 4
  4187. #define ISK_PRIME2 5
  4188. #define ISK_EXP1 6
  4189. #define ISK_EXP2 7
  4190. #define ISK_COEFF 8
  4191. #define ISK_MAX 9 // number of elements
  4192. typedef struct _KEYBLOBMAP
  4193. {
  4194. DWORD dwisk; // index into pSeqKey: ISK_*
  4195. DWORD dwdivisor; // cbitKey/dwDivisor is expected byte count
  4196. } KEYBLOBMAP;
  4197. // The KEYBLOBMAP array defines the order and expected size of the key element
  4198. // integers as they will appear in the RSA PRIVATEKEYBLOB.
  4199. KEYBLOBMAP g_akbm[] = {
  4200. { ISK_MODULUS, 8 }, // public key
  4201. { ISK_PRIME1, 16 },
  4202. { ISK_PRIME2, 16 },
  4203. { ISK_EXP1, 16 },
  4204. { ISK_EXP2, 16 },
  4205. { ISK_COEFF, 16 },
  4206. { ISK_PRIVEXP, 8 },
  4207. };
  4208. HRESULT
  4209. myDecodeKMSRSAKey(
  4210. IN BYTE const *pbKMSRSAKey,
  4211. IN DWORD cbKMSRSAKey,
  4212. IN ALG_ID aiKeyAlg,
  4213. OUT BYTE **ppbKey,
  4214. OUT DWORD *pcbKey)
  4215. {
  4216. HRESULT hr;
  4217. CRYPT_SEQUENCE_OF_ANY *pSeqOuter = NULL;
  4218. CRYPT_SEQUENCE_OF_ANY *pSeqAlg = NULL;
  4219. CRYPT_SEQUENCE_OF_ANY *pSeqKey = NULL;
  4220. DWORD cb;
  4221. DWORD i;
  4222. BYTE *pb;
  4223. BYTE *pbKey = NULL;
  4224. DWORD cbKey;
  4225. DWORD cbitKey;
  4226. char *pszObjId = NULL;
  4227. CRYPT_DATA_BLOB *pBlobKey = NULL;
  4228. CRYPT_INTEGER_BLOB *apIntKey[ISK_MAX];
  4229. DWORD dwPubExp;
  4230. *ppbKey = NULL;
  4231. ZeroMemory(apIntKey, sizeof(apIntKey));
  4232. hr = cuDecodeSequence(pbKMSRSAKey, cbKMSRSAKey, ISO_MAX, &pSeqOuter);
  4233. _JumpIfError(hr, error, "cuDecodeSequence");
  4234. hr = VerifyKeyVersion(
  4235. pSeqOuter->rgValue[ISO_VERSION].pbData,
  4236. pSeqOuter->rgValue[ISO_VERSION].cbData);
  4237. _JumpIfError(hr, error, "VerifyKeyVersion");
  4238. hr = cuDecodeSequence(
  4239. pSeqOuter->rgValue[ISO_ALG].pbData,
  4240. pSeqOuter->rgValue[ISO_ALG].cbData,
  4241. ISA_MAX,
  4242. &pSeqAlg);
  4243. _JumpIfError(hr, error, "cuDecodeSequence");
  4244. hr = cuDecodeObjId(
  4245. pSeqAlg->rgValue[ISA_OID].pbData,
  4246. pSeqAlg->rgValue[ISA_OID].cbData,
  4247. &pszObjId);
  4248. _JumpIfError(hr, error, "cuDecodeObjId");
  4249. // key algorithm must be szOID_RSA_RSA
  4250. if (0 != strcmp(szOID_RSA_RSA, pszObjId))
  4251. {
  4252. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4253. _JumpError(hr, error, "Bad key alg ObjId");
  4254. }
  4255. // key algorithm parms must be NULL (BER_NULL, cb == 0)
  4256. if (2 != pSeqAlg->rgValue[ISA_PARM].cbData ||
  4257. BER_NULL != pSeqAlg->rgValue[ISA_PARM].pbData[0] ||
  4258. 0 != pSeqAlg->rgValue[ISA_PARM].pbData[1])
  4259. {
  4260. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4261. _JumpError(hr, error, "Bad key alg parameters");
  4262. }
  4263. if (!myDecodeObject(
  4264. X509_ASN_ENCODING,
  4265. X509_OCTET_STRING,
  4266. pSeqOuter->rgValue[ISO_KEY].pbData,
  4267. pSeqOuter->rgValue[ISO_KEY].cbData,
  4268. CERTLIB_USE_LOCALALLOC,
  4269. (VOID **) &pBlobKey,
  4270. &cb))
  4271. {
  4272. hr = myHLastError();
  4273. _JumpError(hr, error, "myDecodeObject");
  4274. }
  4275. hr = cuDecodeSequence(
  4276. pBlobKey->pbData,
  4277. pBlobKey->cbData,
  4278. ARRAYSIZE(apIntKey),
  4279. &pSeqKey);
  4280. _JumpIfError(hr, error, "cuDecodeSequence");
  4281. hr = VerifyKeyVersion(
  4282. pSeqKey->rgValue[ISK_VERSION].pbData,
  4283. pSeqKey->rgValue[ISK_VERSION].cbData);
  4284. _JumpIfError(hr, error, "VerifyKeyVersion");
  4285. cb = sizeof(dwPubExp);
  4286. if (!CryptDecodeObject(
  4287. X509_ASN_ENCODING,
  4288. X509_INTEGER,
  4289. pSeqKey->rgValue[ISK_PUBEXP].pbData,
  4290. pSeqKey->rgValue[ISK_PUBEXP].cbData,
  4291. 0,
  4292. &dwPubExp,
  4293. &cb))
  4294. {
  4295. hr = myHLastError();
  4296. _JumpError(hr, error, "CryptDecodeObject");
  4297. }
  4298. for (i = 0; i < ARRAYSIZE(apIntKey); i++)
  4299. {
  4300. if (!myDecodeObject(
  4301. X509_ASN_ENCODING,
  4302. X509_MULTI_BYTE_INTEGER,
  4303. pSeqKey->rgValue[i].pbData,
  4304. pSeqKey->rgValue[i].cbData,
  4305. CERTLIB_USE_LOCALALLOC,
  4306. (VOID **) &apIntKey[i],
  4307. &cb))
  4308. {
  4309. hr = myHLastError();
  4310. _JumpError(hr, error, "myDecodeObject");
  4311. }
  4312. }
  4313. cb = apIntKey[ISK_MODULUS]->cbData;
  4314. if (0 < cb && 0 == apIntKey[ISK_MODULUS]->pbData[cb - 1])
  4315. {
  4316. cb--;
  4317. }
  4318. cbitKey = 8 * cb;
  4319. #if 0
  4320. wprintf(L"cbitKey = %u\n", cbitKey);
  4321. for (i = 0; i < ARRAYSIZE(apIntKey); i++)
  4322. {
  4323. wprintf(wszNewLine);
  4324. DumpHex(
  4325. DH_NOTABPREFIX | DH_NOASCIIHEX | DH_PRIVATEDATA | 4,
  4326. apIntKey[i]->pbData,
  4327. apIntKey[i]->cbData);
  4328. }
  4329. #endif
  4330. cbKey = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY);
  4331. for (i = 0; i < ARRAYSIZE(g_akbm); i++)
  4332. {
  4333. cbKey += cbitKey / g_akbm[i].dwdivisor;
  4334. }
  4335. pbKey = (BYTE *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cbKey);
  4336. if (NULL == pbKey)
  4337. {
  4338. hr = E_OUTOFMEMORY;
  4339. _JumpError(hr, error, "LocalAlloc");
  4340. }
  4341. pb = pbKey;
  4342. ((PUBLICKEYSTRUC *) pb)->bType = PRIVATEKEYBLOB;
  4343. ((PUBLICKEYSTRUC *) pb)->bVersion = CUR_BLOB_VERSION;
  4344. ((PUBLICKEYSTRUC *) pb)->aiKeyAlg = aiKeyAlg;
  4345. pb += sizeof(PUBLICKEYSTRUC);
  4346. ((RSAPUBKEY *) pb)->magic = RSAPRIV_MAGIC; // "RSA2"
  4347. ((RSAPUBKEY *) pb)->bitlen = cbitKey;
  4348. ((RSAPUBKEY *) pb)->pubexp = dwPubExp;
  4349. pb += sizeof(RSAPUBKEY);
  4350. for (i = 0; i < ARRAYSIZE(g_akbm); i++)
  4351. {
  4352. DWORD cbcopy;
  4353. BYTE const *pbcopy;
  4354. CSASSERT(ISK_MAX > g_akbm[i].dwisk);
  4355. cb = cbitKey / g_akbm[i].dwdivisor;
  4356. cbcopy = apIntKey[g_akbm[i].dwisk]->cbData;
  4357. pbcopy = apIntKey[g_akbm[i].dwisk]->pbData;
  4358. if (cb < cbcopy)
  4359. {
  4360. if (cb + 1 != cbcopy || 0 != pbcopy[cb])
  4361. {
  4362. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4363. _JumpError(hr, error, "Bad key element size");
  4364. }
  4365. //DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbcopy, cbcopy);
  4366. cbcopy--;
  4367. }
  4368. CopyMemory(pb, pbcopy, cbcopy);
  4369. if (cb > cbcopy)
  4370. {
  4371. ZeroMemory(&pb[cbcopy], cb - cbcopy); // Add trailing zeros
  4372. }
  4373. pb += cb;
  4374. //DumpHex(DH_NOTABPREFIX | DH_NOASCIIHEX | DH_PRIVATEDATA | 4, pb - cb, cb);
  4375. }
  4376. CSASSERT(pb = &pbKey[cbKey]);
  4377. if (g_fVerbose)
  4378. {
  4379. wprintf(myLoadResourceString(IDS_FORMAT_BIT_KEY), cbitKey);
  4380. wprintf(wszNewLine);
  4381. if (1 < g_fVerbose)
  4382. {
  4383. DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbKey, cbKey);
  4384. }
  4385. }
  4386. *pcbKey = cbKey;
  4387. *ppbKey = pbKey;
  4388. pbKey = NULL;
  4389. hr = S_OK;
  4390. error:
  4391. if (NULL != pSeqOuter)
  4392. {
  4393. LocalFree(pSeqOuter);
  4394. }
  4395. if (NULL != pSeqAlg)
  4396. {
  4397. LocalFree(pSeqAlg);
  4398. }
  4399. if (NULL != pSeqKey)
  4400. {
  4401. LocalFree(pSeqKey);
  4402. }
  4403. if (NULL != pszObjId)
  4404. {
  4405. LocalFree(pszObjId);
  4406. }
  4407. if (NULL != pBlobKey)
  4408. {
  4409. LocalFree(pBlobKey);
  4410. }
  4411. for (i = 0; i < ARRAYSIZE(apIntKey); i++)
  4412. {
  4413. if (NULL != apIntKey[i])
  4414. {
  4415. LocalFree(apIntKey[i]);
  4416. }
  4417. }
  4418. if (NULL != pbKey)
  4419. {
  4420. LocalFree(pbKey);
  4421. }
  4422. return(hr);
  4423. }
  4424. //+-------------------------------------------------------------------------
  4425. // Inputs a private key in PRIVATEKEYBLOB format.
  4426. // returns a PKCS PrivateKeyInfo
  4427. //--------------------------------------------------------------------------
  4428. HRESULT
  4429. myEncodeKMSRSAKey(
  4430. IN BYTE const *pbKey,
  4431. IN DWORD cbKey,
  4432. OUT BYTE **ppbKMSRSAKey,
  4433. OUT DWORD *pcbKMSRSAKey)
  4434. {
  4435. HRESULT hr;
  4436. DWORD i;
  4437. BYTE const *pb;
  4438. CRYPT_SEQUENCE_OF_ANY SeqOuter;
  4439. CRYPT_SEQUENCE_OF_ANY SeqAlg;
  4440. CRYPT_SEQUENCE_OF_ANY SeqKey;
  4441. CRYPT_DER_BLOB rgBlobOuter[ISO_MAX];
  4442. CRYPT_DER_BLOB rgBlobAlg[ISA_MAX];
  4443. CRYPT_DER_BLOB rgBlobKey[ISK_MAX];
  4444. CRYPT_DER_BLOB BlobKey;
  4445. DWORD cbitKey;
  4446. DWORD dwPubExp;
  4447. BYTE rgbNull[] = { BER_NULL, 0 };
  4448. ZeroMemory(rgBlobOuter, sizeof(rgBlobOuter));
  4449. ZeroMemory(rgBlobAlg, sizeof(rgBlobAlg));
  4450. ZeroMemory(rgBlobKey, sizeof(rgBlobKey));
  4451. BlobKey.pbData = NULL;
  4452. pb = pbKey;
  4453. if (PRIVATEKEYBLOB != ((PUBLICKEYSTRUC const *) pb)->bType ||
  4454. CUR_BLOB_VERSION != ((PUBLICKEYSTRUC const *) pb)->bVersion)
  4455. {
  4456. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4457. _JumpError(hr, error, "Bad RSA key type/version");
  4458. }
  4459. // aiKeyAlg = ((PUBLICKEYSTRUC const *) pb)->aiKeyAlg;
  4460. pb += sizeof(PUBLICKEYSTRUC);
  4461. if (RSAPRIV_MAGIC != ((RSAPUBKEY const *) pb)->magic) // "RSA2"
  4462. {
  4463. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4464. _JumpError(hr, error, "Bad RSA key magic");
  4465. }
  4466. cbitKey = ((RSAPUBKEY const *) pb)->bitlen;
  4467. dwPubExp = ((RSAPUBKEY const *) pb)->pubexp;
  4468. pb += sizeof(RSAPUBKEY);
  4469. hr = EncodeKeyVersion(
  4470. &rgBlobKey[ISK_VERSION].pbData,
  4471. &rgBlobKey[ISK_VERSION].cbData);
  4472. _JumpIfError(hr, error, "EncodeKeyVersion");
  4473. if (!myEncodeObject(
  4474. X509_ASN_ENCODING,
  4475. X509_INTEGER,
  4476. &dwPubExp,
  4477. 0,
  4478. CERTLIB_USE_LOCALALLOC,
  4479. &rgBlobKey[ISK_PUBEXP].pbData,
  4480. &rgBlobKey[ISK_PUBEXP].cbData))
  4481. {
  4482. hr = myHLastError();
  4483. _JumpError(hr, error, "myEncodeObject");
  4484. }
  4485. for (i = 0; i < ARRAYSIZE(g_akbm); i++)
  4486. {
  4487. DWORD dwisk = g_akbm[i].dwisk;
  4488. CRYPT_DER_BLOB Blob;
  4489. CSASSERT(ISK_MAX > dwisk);
  4490. CSASSERT(NULL == rgBlobKey[dwisk].pbData);
  4491. Blob.pbData = const_cast<BYTE *>(pb);
  4492. Blob.cbData = cbitKey / g_akbm[i].dwdivisor;
  4493. pb += Blob.cbData;
  4494. while (1 < Blob.cbData && 0 == Blob.pbData[Blob.cbData - 1])
  4495. {
  4496. Blob.cbData--;
  4497. }
  4498. if (!myEncodeObject(
  4499. X509_ASN_ENCODING,
  4500. X509_MULTI_BYTE_INTEGER,
  4501. &Blob,
  4502. 0,
  4503. CERTLIB_USE_LOCALALLOC,
  4504. &rgBlobKey[dwisk].pbData,
  4505. &rgBlobKey[dwisk].cbData))
  4506. {
  4507. hr = myHLastError();
  4508. _JumpError(hr, error, "myEncodeObject");
  4509. }
  4510. }
  4511. SeqKey.cValue = ARRAYSIZE(rgBlobKey);
  4512. SeqKey.rgValue = rgBlobKey;
  4513. if (!myEncodeObject(
  4514. X509_ASN_ENCODING,
  4515. X509_SEQUENCE_OF_ANY,
  4516. &SeqKey,
  4517. 0,
  4518. CERTLIB_USE_LOCALALLOC,
  4519. &BlobKey.pbData,
  4520. &BlobKey.cbData))
  4521. {
  4522. hr = myHLastError();
  4523. _JumpError(hr, error, "myEncodeObject");
  4524. }
  4525. if (!myEncodeObject(
  4526. X509_ASN_ENCODING,
  4527. X509_OCTET_STRING,
  4528. &BlobKey,
  4529. 0,
  4530. CERTLIB_USE_LOCALALLOC,
  4531. &rgBlobOuter[ISO_KEY].pbData,
  4532. &rgBlobOuter[ISO_KEY].cbData))
  4533. {
  4534. hr = myHLastError();
  4535. _JumpError(hr, error, "myEncodeObject");
  4536. }
  4537. // set key algorithm to szOID_RSA_RSA
  4538. hr = cuEncodeObjId(
  4539. szOID_RSA_RSA,
  4540. &rgBlobAlg[ISA_OID].pbData,
  4541. &rgBlobAlg[ISA_OID].cbData);
  4542. _JumpIfError(hr, error, "cuEncodeObjId");
  4543. // set key algorithm parms to NULL (BER_NULL, cb == 0)
  4544. rgBlobAlg[ISA_PARM].cbData = ARRAYSIZE(rgbNull);
  4545. rgBlobAlg[ISA_PARM].pbData = rgbNull;
  4546. SeqAlg.cValue = ARRAYSIZE(rgBlobAlg);
  4547. SeqAlg.rgValue = rgBlobAlg;
  4548. if (!myEncodeObject(
  4549. X509_ASN_ENCODING,
  4550. X509_SEQUENCE_OF_ANY,
  4551. &SeqAlg,
  4552. 0,
  4553. CERTLIB_USE_LOCALALLOC,
  4554. &rgBlobOuter[ISO_ALG].pbData,
  4555. &rgBlobOuter[ISO_ALG].cbData))
  4556. {
  4557. hr = myHLastError();
  4558. _JumpError(hr, error, "myEncodeObject");
  4559. }
  4560. hr = EncodeKeyVersion(
  4561. &rgBlobOuter[ISO_VERSION].pbData,
  4562. &rgBlobOuter[ISO_VERSION].cbData);
  4563. _JumpIfError(hr, error, "EncodeKeyVersion");
  4564. SeqOuter.cValue = ARRAYSIZE(rgBlobOuter);
  4565. SeqOuter.rgValue = rgBlobOuter;
  4566. if (!myEncodeObject(
  4567. X509_ASN_ENCODING,
  4568. X509_SEQUENCE_OF_ANY,
  4569. &SeqOuter,
  4570. 0,
  4571. CERTLIB_USE_LOCALALLOC,
  4572. ppbKMSRSAKey,
  4573. pcbKMSRSAKey))
  4574. {
  4575. hr = myHLastError();
  4576. _JumpError(hr, error, "myEncodeObject");
  4577. }
  4578. hr = S_OK;
  4579. error:
  4580. if (NULL != BlobKey.pbData)
  4581. {
  4582. LocalFree(BlobKey.pbData);
  4583. }
  4584. for (i = 0; i < ARRAYSIZE(rgBlobKey); i++)
  4585. {
  4586. if (NULL != rgBlobKey[i].pbData)
  4587. {
  4588. LocalFree(rgBlobKey[i].pbData);
  4589. }
  4590. }
  4591. for (i = 0; i < ARRAYSIZE(rgBlobOuter); i++)
  4592. {
  4593. if (NULL != rgBlobOuter[i].pbData)
  4594. {
  4595. LocalFree(rgBlobOuter[i].pbData);
  4596. }
  4597. }
  4598. if (NULL != rgBlobAlg[ISA_OID].pbData)
  4599. {
  4600. LocalFree(rgBlobAlg[ISA_OID].pbData);
  4601. }
  4602. return(hr);
  4603. }
  4604. HRESULT
  4605. myVerifyKMSKey(
  4606. IN BYTE const *pbCert,
  4607. IN DWORD cbCert,
  4608. IN BYTE const *pbKey,
  4609. IN DWORD cbKey,
  4610. IN DWORD dwKeySpec,
  4611. IN BOOL fQuiet)
  4612. {
  4613. HRESULT hr;
  4614. CERT_CONTEXT const *pCert;
  4615. HCRYPTPROV hProv = NULL;
  4616. HCRYPTKEY hKey = NULL;
  4617. CERT_PUBLIC_KEY_INFO *pPublicKeyInfo = NULL;
  4618. DWORD cb;
  4619. pCert = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  4620. if (NULL == pCert)
  4621. {
  4622. hr = myHLastError();
  4623. _JumpError(hr, error, "CertCreateCertificateContext");
  4624. }
  4625. if (!CryptAcquireContext(
  4626. &hProv,
  4627. NULL,
  4628. NULL,
  4629. PROV_RSA_FULL,
  4630. CRYPT_VERIFYCONTEXT))
  4631. {
  4632. hr = myHLastError();
  4633. _JumpError(hr, error, "CryptAcquireContext");
  4634. }
  4635. if (!CryptImportKey(hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey))
  4636. {
  4637. hr = myHLastError();
  4638. _JumpError(hr, error, "CryptImportKey");
  4639. }
  4640. if (!myCryptExportPublicKeyInfo(
  4641. hProv,
  4642. dwKeySpec,
  4643. CERTLIB_USE_LOCALALLOC,
  4644. &pPublicKeyInfo,
  4645. &cb))
  4646. {
  4647. hr = myHLastError();
  4648. _JumpError(hr, error, "myCryptExportPublicKeyInfo");
  4649. }
  4650. if (g_fVerbose)
  4651. {
  4652. cuDumpVersion(pCert->pCertInfo->dwVersion + 1);
  4653. if (1 < g_fVerbose)
  4654. {
  4655. cuDumpPublicKey(&pCert->pCertInfo->SubjectPublicKeyInfo);
  4656. cuDisplayKeyId(&pCert->pCertInfo->SubjectPublicKeyInfo, 0, NULL);
  4657. cuDumpPublicKey(pPublicKeyInfo);
  4658. }
  4659. }
  4660. cuDisplayKeyId(pPublicKeyInfo, 0, NULL);
  4661. if (!myCertComparePublicKeyInfo(
  4662. X509_ASN_ENCODING,
  4663. CERT_V1 == pCert->pCertInfo->dwVersion,
  4664. pPublicKeyInfo,
  4665. &pCert->pCertInfo->SubjectPublicKeyInfo))
  4666. {
  4667. // by design, (my)CertComparePublicKeyInfo doesn't set last error!
  4668. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4669. if (!fQuiet)
  4670. {
  4671. wprintf(myLoadResourceString(IDS_ERR_PUBLICKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match stored keyset"
  4672. wprintf(wszNewLine);
  4673. }
  4674. _JumpError2(hr, error, "myCertComparePublicKeyInfo", fQuiet? hr : S_OK);
  4675. }
  4676. if (AT_SIGNATURE == dwKeySpec)
  4677. {
  4678. hr = myValidateKeyForSigning(
  4679. hProv,
  4680. &pCert->pCertInfo->SubjectPublicKeyInfo,
  4681. CALG_SHA1);
  4682. }
  4683. else
  4684. {
  4685. hr = myValidateKeyForEncrypting(
  4686. hProv,
  4687. &pCert->pCertInfo->SubjectPublicKeyInfo,
  4688. CALG_RC4);
  4689. }
  4690. if (S_OK != hr)
  4691. {
  4692. wprintf(myLoadResourceString(IDS_ERR_PRIVATEKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match private key"
  4693. wprintf(wszNewLine);
  4694. _JumpError(hr, error, "myValidateKeyForEncrypting");
  4695. }
  4696. if (g_fVerbose)
  4697. {
  4698. wprintf(myLoadResourceString(IDS_PRIVATEKEY_VERIFIES));
  4699. wprintf(wszNewLine);
  4700. }
  4701. error:
  4702. if (NULL != pCert)
  4703. {
  4704. CertFreeCertificateContext(pCert);
  4705. }
  4706. if (NULL != pPublicKeyInfo)
  4707. {
  4708. LocalFree(pPublicKeyInfo);
  4709. }
  4710. if (NULL != hKey)
  4711. {
  4712. CryptDestroyKey(hKey);
  4713. }
  4714. if (NULL != hProv)
  4715. {
  4716. CryptReleaseContext(hProv, 0);
  4717. }
  4718. return(hr);
  4719. }
  4720. HRESULT
  4721. cuDumpAsnBinaryQuiet(
  4722. IN BYTE const *pb,
  4723. IN DWORD cb,
  4724. IN DWORD iElement)
  4725. {
  4726. HRESULT hr;
  4727. BOOL fVerboseOld = g_fVerbose;
  4728. BOOL fQuietOld = g_fQuiet;
  4729. if (g_fVerbose)
  4730. {
  4731. g_fVerbose--;
  4732. }
  4733. else
  4734. {
  4735. g_fQuiet = TRUE;
  4736. }
  4737. hr = cuDumpAsnBinary(pb, cb, iElement);
  4738. _JumpIfError(hr, error, "cuDumpAsnBinary");
  4739. error:
  4740. g_fVerbose = fVerboseOld;
  4741. g_fQuiet = fQuietOld;
  4742. return(hr);
  4743. }
  4744. HRESULT
  4745. ReadTaggedBlob(
  4746. IN HANDLE hFile,
  4747. IN DWORD cbRemain,
  4748. OUT TagHeader *pth,
  4749. OUT BYTE **ppb)
  4750. {
  4751. HRESULT hr;
  4752. DWORD cbRead;
  4753. *ppb = NULL;
  4754. if (!ReadFile(hFile, pth, sizeof(*pth), &cbRead, NULL))
  4755. {
  4756. hr = myHLastError();
  4757. _JumpError(hr, error, "ReadFile");
  4758. }
  4759. hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
  4760. if (cbRead != sizeof(*pth))
  4761. {
  4762. DBGPRINT((
  4763. DBG_SS_ERROR,
  4764. "ReadFile read %u bytes, requested %u\n",
  4765. cbRead,
  4766. sizeof(*pth)));
  4767. _JumpError(hr, error, "ReadFile(cbRead)");
  4768. }
  4769. if (cbRead + pth->cbSize > cbRemain)
  4770. {
  4771. DBGPRINT((
  4772. DBG_SS_ERROR,
  4773. "Header size %u bytes, cbRemain %u\n",
  4774. sizeof(*pth) + pth->cbSize,
  4775. cbRemain));
  4776. _JumpError(hr, error, "cbRemain");
  4777. }
  4778. *ppb = (BYTE *) LocalAlloc(LMEM_FIXED, pth->cbSize);
  4779. if (NULL == *ppb)
  4780. {
  4781. hr = E_OUTOFMEMORY;
  4782. _JumpError(hr, error, "LocalAlloc");
  4783. }
  4784. if (!ReadFile(hFile, *ppb, pth->cbSize, &cbRead, NULL))
  4785. {
  4786. hr = myHLastError();
  4787. _JumpError(hr, error, "ReadFile");
  4788. }
  4789. if (cbRead != pth->cbSize)
  4790. {
  4791. hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
  4792. DBGPRINT((
  4793. DBG_SS_ERROR,
  4794. "ReadFile read %u bytes, requested %u\n",
  4795. cbRead,
  4796. pth->cbSize));
  4797. _JumpError(hr, error, "ReadFile(cbRead)");
  4798. }
  4799. hr = S_OK;
  4800. error:
  4801. if (S_OK != hr && NULL != *ppb)
  4802. {
  4803. LocalFree(*ppb);
  4804. *ppb = NULL;
  4805. }
  4806. return(hr);
  4807. }
  4808. BOOL
  4809. DumpKMSTag(
  4810. IN TagHeader const *pth)
  4811. {
  4812. WCHAR const *pwsz;
  4813. WCHAR awctag[cwcDWORDSPRINTF];
  4814. pwsz = NULL;
  4815. switch (pth->tag)
  4816. {
  4817. case KMS_LOCKBOX_TAG: pwsz = L"KMS_LOCKBOX_TAG"; break;
  4818. case KMS_SIGNING_CERT_TAG: pwsz = L"KMS_SIGNING_CERT_TAG"; break;
  4819. case KMS_SIGNATURE_TAG: pwsz = L"KMS_SIGNATURE_TAG"; break;
  4820. case KMS_USER_RECORD_TAG: pwsz = L"KMS_USER_RECORD_TAG"; break;
  4821. default:
  4822. swprintf(awctag, L"%u", pth->tag);
  4823. pwsz = awctag;
  4824. break;
  4825. }
  4826. if (1 < g_fVerbose)
  4827. {
  4828. wprintf(
  4829. L"%ws: %x (%u) %ws\n",
  4830. pwsz,
  4831. pth->cbSize,
  4832. pth->cbSize,
  4833. myLoadResourceString(IDS_BYTES)); // "Bytes"
  4834. }
  4835. return(pwsz != awctag); // TRUE if tag is valid
  4836. }
  4837. HRESULT
  4838. VerifyKMSExportFile(
  4839. IN HANDLE hFile,
  4840. IN DWORD cbFile,
  4841. OUT CERT_CONTEXT const **ppccSigner)
  4842. {
  4843. HRESULT hr;
  4844. DWORD cbRemain;
  4845. DWORD cbRead;
  4846. TagHeader th;
  4847. BYTE *pb = NULL;
  4848. CERT_CONTEXT const *pccSigner = NULL;
  4849. HCRYPTPROV hProv = NULL;
  4850. HCRYPTHASH hHash = NULL;
  4851. HCRYPTKEY hkeyPub = NULL;
  4852. BOOL fVerified = FALSE;
  4853. WCHAR *pwszSubject = NULL;
  4854. *ppccSigner = NULL;
  4855. if (!CryptAcquireContext(
  4856. &hProv,
  4857. NULL, // pszContainer
  4858. NULL, // pszProvider
  4859. PROV_RSA_FULL,
  4860. CRYPT_VERIFYCONTEXT))
  4861. {
  4862. hr = myHLastError();
  4863. _JumpError(hr, error, "CryptAcquireContext");
  4864. }
  4865. if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
  4866. {
  4867. hr = myHLastError();
  4868. _JumpError(hr, error, "CryptCreateHash");
  4869. }
  4870. cbRemain = cbFile;
  4871. while (0 < cbRemain)
  4872. {
  4873. fVerified = FALSE;
  4874. CSASSERT(NULL == pb);
  4875. hr = ReadTaggedBlob(hFile, cbRemain, &th, &pb);
  4876. _JumpIfError(hr, error, "ReadTaggedBlob");
  4877. if (!DumpKMSTag(&th))
  4878. {
  4879. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4880. _JumpError(hr, error, "invalid tag");
  4881. }
  4882. switch (th.tag)
  4883. {
  4884. case KMS_SIGNING_CERT_TAG:
  4885. if (g_fVerbose || g_fSplitASN)
  4886. {
  4887. hr = cuDumpAsnBinaryQuiet(pb, th.cbSize, MAXDWORD);
  4888. _JumpIfError(hr, error, "cuDumpAsnBinaryQuiet");
  4889. }
  4890. if (NULL != pccSigner)
  4891. {
  4892. hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  4893. _JumpError(hr, error, "too many signers");
  4894. }
  4895. pccSigner = CertCreateCertificateContext(
  4896. X509_ASN_ENCODING,
  4897. pb,
  4898. th.cbSize);
  4899. if (NULL == pccSigner)
  4900. {
  4901. hr = myHLastError();
  4902. _JumpError(hr, error, "CertCreateCertificateContext");
  4903. }
  4904. hr = myCertNameToStr(
  4905. X509_ASN_ENCODING,
  4906. &pccSigner->pCertInfo->Subject,
  4907. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  4908. &pwszSubject);
  4909. _PrintIfError(hr, "myCertNameToStr");
  4910. wprintf(myLoadResourceString(IDS_PROCESSING_KMS_EXPORTS_COLON));
  4911. wprintf(L"\n %ws\n\n", pwszSubject);
  4912. break;
  4913. case KMS_SIGNATURE_TAG:
  4914. if (NULL != hkeyPub)
  4915. {
  4916. _JumpError(hr, error, "too many signatures");
  4917. }
  4918. if (NULL == pccSigner)
  4919. {
  4920. hr = TRUST_E_NO_SIGNER_CERT;
  4921. _JumpError(hr, error, "no signer");
  4922. }
  4923. if (!CryptImportPublicKeyInfo(
  4924. hProv,
  4925. X509_ASN_ENCODING,
  4926. &pccSigner->pCertInfo->SubjectPublicKeyInfo,
  4927. &hkeyPub))
  4928. {
  4929. hr = myHLastError();
  4930. _JumpError(hr, error, "CryptImportPublicKeyInfo");
  4931. }
  4932. if (!CryptVerifySignature(
  4933. hHash,
  4934. pb,
  4935. th.cbSize,
  4936. hkeyPub,
  4937. NULL,
  4938. 0))
  4939. {
  4940. hr = myHLastError();
  4941. _JumpError(hr, error, "CryptVerifySignature");
  4942. }
  4943. fVerified = TRUE;
  4944. wprintf(myLoadResourceString(IDS_KMSEXPORT_SIG_OK)); // "KMS export file signature verifies"
  4945. wprintf(wszNewLine);
  4946. break;
  4947. default:
  4948. if (!CryptHashData(hHash, (BYTE *) &th, sizeof(th), 0))
  4949. {
  4950. hr = myHLastError();
  4951. _JumpError(hr, error, "CryptHashData");
  4952. }
  4953. if (!CryptHashData(hHash, pb, th.cbSize, 0))
  4954. {
  4955. hr = myHLastError();
  4956. _JumpError(hr, error, "CryptHashData");
  4957. }
  4958. break;
  4959. }
  4960. LocalFree(pb);
  4961. pb = NULL;
  4962. CSASSERT(cbRemain >= sizeof(th) + sizeof(th.cbSize));
  4963. cbRemain -= sizeof(th) + th.cbSize;
  4964. }
  4965. if (!fVerified)
  4966. {
  4967. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  4968. _JumpError(hr, error, "unsigned data");
  4969. }
  4970. hr = S_OK;
  4971. error:
  4972. if (NULL != pwszSubject)
  4973. {
  4974. LocalFree(pwszSubject);
  4975. }
  4976. if (NULL != pb)
  4977. {
  4978. LocalFree(pb);
  4979. }
  4980. if (NULL != hkeyPub)
  4981. {
  4982. CryptDestroyKey(hkeyPub);
  4983. }
  4984. if (NULL != hHash)
  4985. {
  4986. CryptDestroyHash(hHash);
  4987. }
  4988. if (NULL != hProv)
  4989. {
  4990. CryptReleaseContext(hProv, 0);
  4991. }
  4992. return(hr);
  4993. }
  4994. HRESULT
  4995. myEncryptPrivateKey(
  4996. IN CERT_CONTEXT const *pccXchg,
  4997. IN BYTE const *pbKey,
  4998. IN DWORD cbKey,
  4999. OUT BYTE **ppbKeyEncrypted,
  5000. OUT DWORD *pcbKeyEncrypted)
  5001. {
  5002. HRESULT hr;
  5003. ALG_ID rgalgId[] = { CALG_3DES, CALG_RC4, CALG_RC2 };
  5004. DWORD i;
  5005. *ppbKeyEncrypted = NULL;
  5006. hr = CRYPT_E_NOT_FOUND;
  5007. for (i = 0; i < ARRAYSIZE(rgalgId); i++)
  5008. {
  5009. // encryt into pkcs7
  5010. hr = myCryptEncryptMessage(
  5011. rgalgId[i],
  5012. 1, // cCertRecipient
  5013. &pccXchg, // rgCertRecipient
  5014. pbKey,
  5015. cbKey,
  5016. NULL, // hCryptProv
  5017. ppbKeyEncrypted,
  5018. pcbKeyEncrypted);
  5019. if (S_OK == hr)
  5020. {
  5021. break; // done
  5022. }
  5023. _PrintError2(hr, "myCryptEncryptMessage", hr);
  5024. }
  5025. _JumpIfError(hr, error, "myCryptEncryptMessage");
  5026. error:
  5027. return(hr);
  5028. }
  5029. #define CB_IV 8
  5030. typedef struct _KMSSTATS {
  5031. HRESULT hr;
  5032. DWORD cRecUser;
  5033. DWORD cCertWithoutKeys;
  5034. DWORD cCertTotal;
  5035. DWORD cCertNotSaved;
  5036. DWORD cCertAlreadySaved;
  5037. DWORD cCertSaved;
  5038. DWORD cCertSavedForeign;
  5039. DWORD cKeyTotal;
  5040. DWORD cKeyNotSaved;
  5041. DWORD cKeyAlreadySaved;
  5042. DWORD cKeySaved;
  5043. DWORD cKeySavedOverwrite;
  5044. } KMSSTATS;
  5045. HRESULT
  5046. ArchiveCertAndKey(
  5047. IN DISPATCHINTERFACE *pdiAdmin,
  5048. IN CERT_CONTEXT const *pccXchg,
  5049. IN BYTE const *pbCert,
  5050. IN DWORD cbCert,
  5051. IN BYTE const *pbKey,
  5052. IN DWORD cbKey,
  5053. IN BOOL fSigningKey,
  5054. IN OUT KMSSTATS *pkmsStats)
  5055. {
  5056. HRESULT hr;
  5057. LONG RequestId;
  5058. BYTE *pbKeyEncrypted = NULL;
  5059. DWORD cbKeyEncrypted;
  5060. CERT_CONTEXT const *pcc = NULL;
  5061. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  5062. DWORD cbHash;
  5063. BSTR strHash = NULL;
  5064. BOOL fCertSaved = FALSE;
  5065. DWORD ids;
  5066. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  5067. if (NULL == pcc)
  5068. {
  5069. hr = myHLastError();
  5070. _JumpError(hr, error, "CertCreateCertificateContext");
  5071. }
  5072. ids = 0;
  5073. hr = Admin_ImportCertificate(
  5074. pdiAdmin,
  5075. g_pwszConfig,
  5076. (WCHAR const *) pbCert,
  5077. cbCert,
  5078. CR_IN_BINARY,
  5079. &RequestId);
  5080. if (g_fForce &&
  5081. S_OK != hr &&
  5082. HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) != hr)
  5083. {
  5084. hr = Admin_ImportCertificate(
  5085. pdiAdmin,
  5086. g_pwszConfig,
  5087. (WCHAR const *) pbCert,
  5088. cbCert,
  5089. ICF_ALLOWFOREIGN | CR_IN_BINARY,
  5090. &RequestId);
  5091. if (S_OK == hr)
  5092. {
  5093. pkmsStats->cCertSavedForeign++;
  5094. ids = IDS_IMPORT_CERT_FOREIGN; // "Imported foreign certificate"
  5095. }
  5096. }
  5097. if (HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) != hr)
  5098. {
  5099. _JumpIfError2(hr, error, "Admin_ImportCertificate", NTE_BAD_SIGNATURE);
  5100. //wprintf(L"RequestId = %u\n", RequestId);
  5101. pkmsStats->cCertSaved++;
  5102. if (0 == ids)
  5103. {
  5104. ids = IDS_IMPORT_CERT_DOMESTIC; // "Imported certificate"
  5105. }
  5106. }
  5107. else
  5108. {
  5109. RequestId = MAXDWORD;
  5110. pkmsStats->cCertAlreadySaved++;
  5111. ids = IDS_IMPORT_CERT_EXISTS; // "Certificate exists"
  5112. cbHash = sizeof(abHash);
  5113. if (!CertGetCertificateContextProperty(
  5114. pcc,
  5115. CERT_SHA1_HASH_PROP_ID,
  5116. abHash,
  5117. &cbHash))
  5118. {
  5119. hr = myHLastError();
  5120. _JumpError(hr, error, "CertGetCertificateContextProperty");
  5121. }
  5122. hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
  5123. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  5124. }
  5125. fCertSaved = TRUE;
  5126. if (g_fVerbose)
  5127. {
  5128. wprintf(myLoadResourceString(ids));
  5129. wprintf(wszNewLine);
  5130. }
  5131. else
  5132. {
  5133. wprintf(L".");
  5134. }
  5135. hr = myEncryptPrivateKey(
  5136. pccXchg,
  5137. pbKey,
  5138. cbKey,
  5139. &pbKeyEncrypted,
  5140. &cbKeyEncrypted);
  5141. _JumpIfError(hr, error, "myEncryptPrivateKey");
  5142. ids = 0;
  5143. hr = Admin2_ImportKey(
  5144. pdiAdmin,
  5145. g_pwszConfig,
  5146. RequestId,
  5147. strHash,
  5148. CR_IN_BINARY,
  5149. (WCHAR const *) pbKeyEncrypted,
  5150. cbKeyEncrypted);
  5151. if (g_fForce && HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr)
  5152. {
  5153. hr = Admin2_ImportKey(
  5154. pdiAdmin,
  5155. g_pwszConfig,
  5156. RequestId,
  5157. strHash,
  5158. IKF_OVERWRITE | CR_IN_BINARY,
  5159. (WCHAR const *) pbKeyEncrypted,
  5160. cbKeyEncrypted);
  5161. if (S_OK == hr)
  5162. {
  5163. pkmsStats->cKeySavedOverwrite++;
  5164. ids = IDS_IMPORT_KEY_REPLACED; // "Archived key replaced"
  5165. }
  5166. }
  5167. if (HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) != hr)
  5168. {
  5169. _JumpIfError(hr, error, "Admin2_ImportKey");
  5170. pkmsStats->cKeySaved++;
  5171. if (0 == ids)
  5172. {
  5173. ids = IDS_IMPORT_KEY_SAVED; // "Archived key"
  5174. }
  5175. }
  5176. else
  5177. {
  5178. pkmsStats->cKeyAlreadySaved++;
  5179. ids = IDS_IMPORT_KEY_EXISTS; // "Key already archived"
  5180. }
  5181. if (g_fVerbose)
  5182. {
  5183. wprintf(myLoadResourceString(ids));
  5184. wprintf(wszNewLine);
  5185. }
  5186. else
  5187. {
  5188. wprintf(L".");
  5189. }
  5190. hr = S_OK;
  5191. error:
  5192. if (S_OK != hr)
  5193. {
  5194. cuPrintErrorMessageText(hr);
  5195. if (!fCertSaved)
  5196. {
  5197. pkmsStats->cCertNotSaved++;
  5198. }
  5199. pkmsStats->cKeyNotSaved++;
  5200. if (fSigningKey && NTE_BAD_KEY_STATE == hr)
  5201. {
  5202. hr = S_OK;
  5203. }
  5204. else
  5205. if (S_OK == pkmsStats->hr)
  5206. {
  5207. pkmsStats->hr = hr;
  5208. }
  5209. }
  5210. if (NULL != pbKeyEncrypted)
  5211. {
  5212. LocalFree(pbKeyEncrypted);
  5213. }
  5214. if (NULL != strHash)
  5215. {
  5216. SysFreeString(strHash);
  5217. }
  5218. if (NULL != pcc)
  5219. {
  5220. CertFreeCertificateContext(pcc);
  5221. }
  5222. return(hr);
  5223. }
  5224. HRESULT
  5225. ImportOneKMSUser(
  5226. IN DISPATCHINTERFACE *pdiAdmin,
  5227. IN CERT_CONTEXT const *pccXchg,
  5228. IN BYTE const *pbRecUser,
  5229. IN DWORD cbRecUser,
  5230. IN HCRYPTKEY hkeySym,
  5231. IN OUT KMSSTATS *pkmsStats)
  5232. {
  5233. HRESULT hr;
  5234. BYTE const *pbT = pbRecUser;
  5235. WCHAR *pwszUser = NULL;
  5236. DWORD cbT = cbRecUser;
  5237. DWORD cb;
  5238. DWORD dw;
  5239. CLSID clsid;
  5240. WCHAR *pwszGUID = NULL;
  5241. BYTE *pbKeyASN = NULL;
  5242. DWORD cbKeyASN;
  5243. DWORD cbStream;
  5244. pkmsStats->cRecUser++;
  5245. // Get the user's directory GUID
  5246. CopyMemory(&clsid, pbT, sizeof(clsid));
  5247. hr = myCLSIDToWsz(&clsid, &pwszGUID);
  5248. _JumpIfError(hr, error, "myCLSIDToWsz");
  5249. pbT += sizeof(GUID);
  5250. cbT -= sizeof(GUID);
  5251. // Get the user's name length
  5252. hr = GetMarshaledDword(TRUE, &pbT, &cbT, &cb);
  5253. _JumpIfError(hr, error, "GetMarshaledDword");
  5254. pwszUser = (WCHAR *) LocalAlloc(
  5255. LMEM_FIXED,
  5256. ((cb / sizeof(WCHAR)) + 1) * sizeof(WCHAR));
  5257. if (NULL == pwszUser)
  5258. {
  5259. hr = E_OUTOFMEMORY;
  5260. _JumpError(hr, error, "LocalAlloc");
  5261. }
  5262. CopyMemory(pwszUser, pbT, cb);
  5263. pwszUser[cb / sizeof(WCHAR)] = L'\0';
  5264. if (g_fVerbose)
  5265. {
  5266. wprintf(L"\n----------------------\n");
  5267. wprintf(myLoadResourceString(IDS_USER_COLON));
  5268. wprintf(L" %ws -- %ws\n", pwszUser, pwszGUID);
  5269. }
  5270. pbT += cb;
  5271. cbT -= cb;
  5272. // for each User cert:
  5273. while (0 < cbT)
  5274. {
  5275. DWORD CertStatus;
  5276. FILETIME ftRevoke;
  5277. BYTE const *pbCert;
  5278. DWORD cbCert;
  5279. if (g_fVerbose)
  5280. {
  5281. wprintf(wszNewLine);
  5282. }
  5283. hr = GetMarshaledDword(FALSE, &pbT, &cbT, &CertStatus);
  5284. _JumpIfError(hr, error, "GetMarshaledDword");
  5285. if (1 < g_fVerbose)
  5286. {
  5287. wprintf(wszNewLine);
  5288. cuRegPrintDwordValue(
  5289. TRUE,
  5290. wszKMSCERTSTATUS,
  5291. wszKMSCERTSTATUS,
  5292. CertStatus);
  5293. }
  5294. hr = GetMarshaledDword(TRUE, &pbT, &cbT, &cb);
  5295. _JumpIfError(hr, error, "GetMarshaledDword");
  5296. // Dump one user cert:
  5297. pbCert = pbT;
  5298. cbCert = cb;
  5299. if (g_fSplitASN)
  5300. {
  5301. wprintf(wszNewLine);
  5302. hr = cuDumpAsnBinaryQuiet(pbCert, cbCert, MAXDWORD);
  5303. _JumpIfError(hr, error, "cuDumpAsnBinaryQuiet");
  5304. }
  5305. pbT += cb;
  5306. cbT -= cb;
  5307. // Get the revocation date (KMS export date):
  5308. hr = GetMarshaledDword(
  5309. FALSE,
  5310. &pbT,
  5311. &cbT,
  5312. &ftRevoke.dwLowDateTime);
  5313. _JumpIfError(hr, error, "GetMarshaledDword");
  5314. hr = GetMarshaledDword(
  5315. FALSE,
  5316. &pbT,
  5317. &cbT,
  5318. &ftRevoke.dwHighDateTime);
  5319. _JumpIfError(hr, error, "GetMarshaledDword");
  5320. if (g_fVerbose)
  5321. {
  5322. hr = cuDumpFileTime(IDS_REVOCATIONDATE, NULL, &ftRevoke);
  5323. _PrintIfError(hr, "cuDumpFileTime");
  5324. }
  5325. // Only encryption certs have archived keys:
  5326. if (0 == (CERTFLAGS_SEALING & CertStatus))
  5327. {
  5328. pkmsStats->cCertWithoutKeys++;
  5329. if (g_fVerbose)
  5330. {
  5331. wprintf(myLoadResourceString(IDS_IMPORT_CERT_SKIPPED_SIGNING)); // "Ignored signing certificate"
  5332. wprintf(wszNewLine);
  5333. }
  5334. continue;
  5335. }
  5336. pkmsStats->cCertTotal++;
  5337. pkmsStats->cKeyTotal++;
  5338. // get encrypted private key size
  5339. hr = GetMarshaledDword(TRUE, &pbT, &cbT, &cb);
  5340. _JumpIfError(hr, error, "GetMarshaledDword");
  5341. // get 8 byte RC2 IV
  5342. if (1 < g_fVerbose)
  5343. {
  5344. wprintf(L"IV:\n");
  5345. DumpHex(
  5346. DH_NOADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 4,
  5347. pbT,
  5348. CB_IV);
  5349. }
  5350. if (NULL != hkeySym)
  5351. {
  5352. // Set IV
  5353. if (!CryptSetKeyParam(
  5354. hkeySym,
  5355. KP_IV,
  5356. const_cast<BYTE *>(pbT),
  5357. 0))
  5358. {
  5359. hr = GetLastError();
  5360. _JumpIfError(hr, error, "CryptSetKeyParam");
  5361. }
  5362. }
  5363. pbT += CB_IV;
  5364. cbT -= CB_IV;
  5365. cb -= CB_IV;
  5366. if (1 < g_fVerbose)
  5367. {
  5368. wprintf(wszNewLine);
  5369. wprintf(myLoadResourceString(IDS_ENCRYPTED_KEY_COLON));
  5370. wprintf(wszNewLine);
  5371. DumpHex(0, pbT, cb);
  5372. }
  5373. // decrypt key using hkeySym
  5374. // in-place decode is Ok because the size of the
  5375. // original data is always less than or equal to that
  5376. // of the encrypted data
  5377. cbStream = cb; // save off the real stream size first
  5378. if (NULL != hkeySym)
  5379. {
  5380. cbKeyASN = cb;
  5381. pbKeyASN = (BYTE *) LocalAlloc(LMEM_FIXED, cb);
  5382. if (NULL == pbKeyASN)
  5383. {
  5384. hr = E_OUTOFMEMORY;
  5385. _JumpError(hr, error, "LocalAlloc");
  5386. }
  5387. CopyMemory(pbKeyASN, pbT, cbKeyASN);
  5388. if (!CryptDecrypt(hkeySym, NULL, TRUE, 0, pbKeyASN, &cb))
  5389. {
  5390. hr = GetLastError();
  5391. _PrintError(hr, "CryptDecrypt");
  5392. }
  5393. else
  5394. {
  5395. BYTE *pbKey;
  5396. DWORD cbKey;
  5397. if (1 < g_fVerbose)
  5398. {
  5399. wprintf(wszNewLine);
  5400. wprintf(myLoadResourceString(IDS_DECRYPTED_KEY_COLON));
  5401. wprintf(wszNewLine);
  5402. DumpHex(DH_PRIVATEDATA, pbKeyASN, cb);
  5403. }
  5404. hr = myDecodeKMSRSAKey(
  5405. pbKeyASN,
  5406. cbKeyASN,
  5407. CALG_RSA_KEYX,
  5408. &pbKey,
  5409. &cbKey);
  5410. _JumpIfError(hr, error, "myDecodeKMSRSAKey");
  5411. hr = myVerifyKMSKey(
  5412. pbCert,
  5413. cbCert,
  5414. pbKey,
  5415. cbKey,
  5416. AT_KEYEXCHANGE,
  5417. FALSE);
  5418. _PrintIfError(hr, "myVerifyKMSKey");
  5419. hr = ArchiveCertAndKey(
  5420. pdiAdmin,
  5421. pccXchg,
  5422. pbCert,
  5423. cbCert,
  5424. pbKey,
  5425. cbKey,
  5426. FALSE, // fSigningKey
  5427. pkmsStats);
  5428. _PrintIfError2(hr, "ArchiveCertAndKey", NTE_BAD_SIGNATURE);
  5429. SecureZeroMemory(pbKey, cbKey); // Key material
  5430. LocalFree(pbKey);
  5431. }
  5432. SecureZeroMemory(pbKeyASN, cbKeyASN); // Key material
  5433. LocalFree(pbKeyASN);
  5434. pbKeyASN = NULL;
  5435. }
  5436. // skip cbStream bytes, not cb
  5437. pbT += cbStream;
  5438. cbT -= cbStream;
  5439. }
  5440. hr = S_OK;
  5441. error:
  5442. if (NULL != pwszGUID)
  5443. {
  5444. LocalFree(pwszGUID);
  5445. }
  5446. if (NULL != pbKeyASN)
  5447. {
  5448. SecureZeroMemory(pbKeyASN, cbKeyASN); // Key material
  5449. LocalFree(pbKeyASN);
  5450. }
  5451. return(hr);
  5452. }
  5453. HRESULT
  5454. GetCAXchgCert(
  5455. IN DISPATCHINTERFACE *pdiAdmin,
  5456. OUT CERT_CONTEXT const **ppccXchg)
  5457. {
  5458. HRESULT hr;
  5459. BSTR strCert = NULL;
  5460. *ppccXchg = NULL;
  5461. hr = Admin2_GetCAProperty(
  5462. pdiAdmin,
  5463. g_pwszConfig,
  5464. CR_PROP_CAXCHGCERT,
  5465. 0, // PropIndex
  5466. PROPTYPE_BINARY,
  5467. CR_OUT_BINARY,
  5468. &strCert);
  5469. _JumpIfError(hr, error, "Admin2_GetCAProperty");
  5470. *ppccXchg = CertCreateCertificateContext(
  5471. X509_ASN_ENCODING,
  5472. (BYTE const *) strCert,
  5473. SysStringByteLen(strCert));
  5474. if (NULL == *ppccXchg)
  5475. {
  5476. hr = myHLastError();
  5477. _JumpError(hr, error, "CertCreateCertificateContext");
  5478. }
  5479. hr = S_OK;
  5480. error:
  5481. if (NULL != strCert)
  5482. {
  5483. SysFreeString(strCert);
  5484. }
  5485. return(hr);
  5486. }
  5487. typedef struct _KMSMAP {
  5488. DWORD dwFieldOffset;
  5489. DWORD idMsg;
  5490. } KMSMAP;
  5491. KMSMAP g_akmUsers[] = {
  5492. { FIELD_OFFSET(KMSSTATS, cRecUser), IDS_KMS_USERS, },
  5493. };
  5494. KMSMAP g_akmCerts[] = {
  5495. { FIELD_OFFSET(KMSSTATS, cCertWithoutKeys), IDS_KMS_CERTS_SKIPPED, },
  5496. { FIELD_OFFSET(KMSSTATS, cCertTotal), IDS_KMS_CERTS_TOTAL, },
  5497. { FIELD_OFFSET(KMSSTATS, cCertSavedForeign), IDS_KMS_CERTS_FOREIGN, },
  5498. { FIELD_OFFSET(KMSSTATS, cCertAlreadySaved), IDS_KMS_CERTS_ALREADYSAVED, },
  5499. { FIELD_OFFSET(KMSSTATS, cCertSaved), IDS_KMS_CERTS_SAVED, },
  5500. { FIELD_OFFSET(KMSSTATS, cCertNotSaved), IDS_KMS_CERTS_NOTSAVED, },
  5501. };
  5502. KMSMAP g_akmKeys[] = {
  5503. { FIELD_OFFSET(KMSSTATS, cKeyTotal), IDS_KMS_KEYS_TOTAL, },
  5504. { FIELD_OFFSET(KMSSTATS, cKeyAlreadySaved), IDS_KMS_KEYS_ALREADYSAVED, },
  5505. { FIELD_OFFSET(KMSSTATS, cKeySavedOverwrite), IDS_KMS_KEYS_UPDATED, },
  5506. { FIELD_OFFSET(KMSSTATS, cKeySaved), IDS_KMS_KEYS_SAVED, },
  5507. { FIELD_OFFSET(KMSSTATS, cKeyNotSaved), IDS_KMS_KEYS_NOTSAVED, },
  5508. };
  5509. VOID
  5510. DumpKMSMap(
  5511. IN KMSSTATS const *pkmsStats,
  5512. IN KMSMAP const *pkm,
  5513. IN DWORD ckm)
  5514. {
  5515. DWORD i;
  5516. BOOL fFirst = TRUE;
  5517. DWORD count;
  5518. for (i = 0; i < ckm; i++)
  5519. {
  5520. count = *(DWORD *) Add2ConstPtr(pkmsStats, pkm[i].dwFieldOffset);
  5521. if (g_fVerbose || 0 != count)
  5522. {
  5523. if (fFirst)
  5524. {
  5525. wprintf(wszNewLine);
  5526. fFirst = FALSE;
  5527. }
  5528. wprintf(myLoadResourceString(pkm[i].idMsg));
  5529. wprintf(L": %u\n", count);
  5530. }
  5531. }
  5532. }
  5533. HRESULT
  5534. DumpKMSStats(
  5535. IN KMSSTATS const *pkmsStats)
  5536. {
  5537. DumpKMSMap(pkmsStats, g_akmUsers, ARRAYSIZE(g_akmUsers));
  5538. DumpKMSMap(pkmsStats, g_akmCerts, ARRAYSIZE(g_akmCerts));
  5539. DumpKMSMap(pkmsStats, g_akmKeys, ARRAYSIZE(g_akmKeys));
  5540. return(pkmsStats->hr);
  5541. }
  5542. HRESULT
  5543. ImportKMSExportedUsers(
  5544. IN HANDLE hFile,
  5545. IN DWORD cbFile,
  5546. IN HCRYPTPROV hProvKMS,
  5547. IN HCRYPTKEY hkeyKMS)
  5548. {
  5549. HRESULT hr;
  5550. HRESULT hrImport = S_OK;
  5551. DWORD cbRemain;
  5552. DWORD cbRead;
  5553. TagHeader th;
  5554. BYTE *pb = NULL;
  5555. HCRYPTKEY hkeySym = NULL;
  5556. KMSSTATS kmsStats;
  5557. DISPATCHINTERFACE diAdmin;
  5558. BOOL fMustRelease = FALSE;
  5559. CERT_CONTEXT const *pccXchg = NULL;
  5560. DWORD cImportFailures;
  5561. ZeroMemory(&kmsStats, sizeof(kmsStats));
  5562. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  5563. _JumpIfError(hr, error, "Admin_Init");
  5564. fMustRelease = TRUE;
  5565. hr = GetCAXchgCert(&diAdmin, &pccXchg);
  5566. _JumpIfError(hr, error, "GetCAXchgCert");
  5567. cImportFailures = 0;
  5568. cbRemain = cbFile;
  5569. while (0 < cbRemain)
  5570. {
  5571. CSASSERT(NULL == pb);
  5572. hr = ReadTaggedBlob(hFile, cbRemain, &th, &pb);
  5573. _JumpIfError(hr, error, "ReadTaggedBlob");
  5574. if (!DumpKMSTag(&th))
  5575. {
  5576. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  5577. _JumpError(hr, error, "invalid tag");
  5578. }
  5579. switch (th.tag)
  5580. {
  5581. case KMS_LOCKBOX_TAG:
  5582. {
  5583. if (1 < g_fVerbose)
  5584. {
  5585. hr = cuDumpPrivateKeyBlob(pb, th.cbSize, FALSE);
  5586. _PrintIfError(hr, "cuDumpPrivateKeyBlob");
  5587. }
  5588. // only need one symmetric key per file
  5589. if (NULL == hkeySym)
  5590. {
  5591. // 0x0000660c ALG_ID CALG_RC2_128
  5592. //
  5593. // CALG_RC2_128:
  5594. // ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC2_128
  5595. //
  5596. // CALG_CYLINK_MEK:
  5597. // ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_CYLINK_MEK
  5598. //
  5599. // UGH! Exchange's CALG_RC2_128 #define collides with
  5600. // wincrypt.h's CALG_CYLINK_MEK -- fix it up to be the
  5601. // correct CALG_RC2 algid from wincrypt.h.
  5602. ((PUBLICKEYSTRUC *) pb)->aiKeyAlg = CALG_RC2;
  5603. // dump the fixed-up blob
  5604. if (1 < g_fVerbose)
  5605. {
  5606. hr = cuDumpPrivateKeyBlob(pb, th.cbSize, FALSE);
  5607. _PrintIfError(hr, "cuDumpPrivateKeyBlob");
  5608. }
  5609. // import 128 bit key
  5610. if (!CryptImportKey(
  5611. hProvKMS,
  5612. pb,
  5613. th.cbSize,
  5614. hkeyKMS,
  5615. 0,
  5616. &hkeySym))
  5617. {
  5618. hrImport = myHLastError();
  5619. _PrintError2(hrImport, "CryptImportKey", hrImport);
  5620. if (0 < cImportFailures++)
  5621. {
  5622. wprintf(myLoadResourceString(IDS_ERROR_SYMMETRIC_KEY));
  5623. wprintf(wszNewLine);
  5624. _PrintError(hrImport, "CryptImportKey");
  5625. }
  5626. }
  5627. else
  5628. {
  5629. // We found the right lockbox. Effective keylen is
  5630. // still 40 bits in our CSP, reset to 128
  5631. DWORD dwEffectiveKeylen = 128;
  5632. if (!CryptSetKeyParam(
  5633. hkeySym,
  5634. KP_EFFECTIVE_KEYLEN,
  5635. (BYTE *) &dwEffectiveKeylen,
  5636. 0))
  5637. {
  5638. hr = myHLastError();
  5639. _JumpError(hr, error, "CryptSetKeyParam(KP_EFFECTIVE_KEYLEN)");
  5640. }
  5641. wprintf(myLoadResourceString(IDS_SYMMETRIC_KEY_IMPORTED));
  5642. wprintf(wszNewLine);
  5643. hrImport = S_OK;
  5644. }
  5645. }
  5646. break;
  5647. }
  5648. case KMS_USER_RECORD_TAG:
  5649. hr = ImportOneKMSUser(
  5650. &diAdmin,
  5651. pccXchg,
  5652. pb,
  5653. th.cbSize,
  5654. hkeySym,
  5655. &kmsStats);
  5656. _JumpIfError(hr, error, "ImportOneKMSUser");
  5657. break;
  5658. default:
  5659. break;
  5660. }
  5661. LocalFree(pb);
  5662. pb = NULL;
  5663. CSASSERT(cbRemain >= sizeof(th) + sizeof(th.cbSize));
  5664. cbRemain -= sizeof(th) + th.cbSize;
  5665. }
  5666. if (!g_fVerbose)
  5667. {
  5668. wprintf(wszNewLine);
  5669. }
  5670. hr = DumpKMSStats(&kmsStats);
  5671. _PrintIfError(hr, "DumpKMSStats");
  5672. if (S_OK != hrImport)
  5673. {
  5674. hr = hrImport;
  5675. }
  5676. _JumpIfError(hr, error, "hrImport");
  5677. error:
  5678. if (NULL != pccXchg)
  5679. {
  5680. CertFreeCertificateContext(pccXchg);
  5681. }
  5682. if (fMustRelease)
  5683. {
  5684. Admin_Release(&diAdmin);
  5685. }
  5686. if (NULL != hkeySym)
  5687. {
  5688. CryptDestroyKey(hkeySym);
  5689. }
  5690. return(hr);
  5691. }
  5692. HRESULT
  5693. LoadKMSCert(
  5694. IN WCHAR const *pwszCertIdDecrypt,
  5695. OUT CERT_CONTEXT const **ppccKMS,
  5696. OUT HCRYPTPROV *phProvKMS,
  5697. OUT HCRYPTKEY *phkeyKMS)
  5698. {
  5699. HRESULT hr;
  5700. CRYPT_KEY_PROV_INFO *pkpiKMS = NULL;
  5701. DWORD cbkpiKMS;
  5702. BYTE *pbKey = NULL;
  5703. DWORD cbKey;
  5704. HCRYPTKEY hkeyKMSSig = NULL;
  5705. *ppccKMS = NULL;
  5706. *phProvKMS = NULL;
  5707. *phkeyKMS = NULL;
  5708. hr = myGetCertificateFromPicker(
  5709. g_hInstance,
  5710. NULL, // hwndParent
  5711. IDS_GETCERT_TITLE, // "Certificate List"
  5712. IDS_GETDECRYPTCERT_SUBTITLE,
  5713. // dwFlags: HKLM+HKCU My store
  5714. CUCS_MYSTORE |
  5715. CUCS_MACHINESTORE |
  5716. CUCS_USERSTORE |
  5717. CUCS_PRIVATEKEYREQUIRED |
  5718. (g_fCryptSilent? CUCS_SILENT : 0),
  5719. pwszCertIdDecrypt,
  5720. 0, // cStore
  5721. NULL, // rghStore
  5722. 0, // cpszObjId
  5723. NULL, // apszObjId
  5724. ppccKMS); // ppCert
  5725. _JumpIfError(hr, error, "myGetCertificateFromPicker");
  5726. if (NULL == *ppccKMS)
  5727. {
  5728. hr = ERROR_CANCELLED;
  5729. _JumpError(hr, error, "myGetCertificateFromPicker");
  5730. }
  5731. if (!myCertGetCertificateContextProperty(
  5732. *ppccKMS,
  5733. CERT_KEY_PROV_INFO_PROP_ID,
  5734. CERTLIB_USE_LOCALALLOC,
  5735. (VOID **) &pkpiKMS,
  5736. &cbkpiKMS))
  5737. {
  5738. hr = myHLastError();
  5739. _JumpError(hr, error, "myCertGetCertificateContextProperty");
  5740. }
  5741. if (0 == LSTRCMPIS(pkpiKMS->pwszProvName, MS_DEF_PROV_W))
  5742. {
  5743. pkpiKMS->pwszProvName = MS_STRONG_PROV_W;
  5744. }
  5745. if (g_fVerbose)
  5746. {
  5747. wprintf(
  5748. L"CryptAcquireContext(%ws, %ws)\n",
  5749. pkpiKMS->pwszContainerName,
  5750. pkpiKMS->pwszProvName);
  5751. }
  5752. if (!CryptAcquireContext(
  5753. phProvKMS,
  5754. pkpiKMS->pwszContainerName,
  5755. pkpiKMS->pwszProvName,
  5756. pkpiKMS->dwProvType,
  5757. pkpiKMS->dwFlags))
  5758. {
  5759. hr = myHLastError();
  5760. wprintf(L"CryptAcquireContext() --> %x\n", hr);
  5761. _JumpError(hr, error, "CryptAcquireContext");
  5762. }
  5763. if (!CryptGetUserKey(*phProvKMS, AT_KEYEXCHANGE, phkeyKMS))
  5764. {
  5765. hr = myHLastError();
  5766. if (hr != NTE_NO_KEY)
  5767. {
  5768. _JumpError(hr, error, "CryptGetUserKey");
  5769. }
  5770. if (!CryptGetUserKey(*phProvKMS, AT_SIGNATURE, &hkeyKMSSig))
  5771. {
  5772. hr = myHLastError();
  5773. _JumpError(hr, error, "CryptGetUserKey - sig");
  5774. }
  5775. // UGH! migrate from AT_SIGNATURE container!
  5776. cbKey = 0;
  5777. hr = myCryptExportKey(
  5778. hkeyKMSSig, // hKey
  5779. NULL, // hKeyExp
  5780. PRIVATEKEYBLOB, // dwBlobType
  5781. 0, // dwFlags
  5782. &pbKey,
  5783. &cbKey);
  5784. _JumpIfError(hr, error, "myCryptExportKey");
  5785. // UGH! fix up the algid to signature...
  5786. ((PUBLICKEYSTRUC *) pbKey)->aiKeyAlg = CALG_RSA_KEYX;
  5787. // and re-import it
  5788. if (!CryptImportKey(
  5789. *phProvKMS,
  5790. pbKey,
  5791. cbKey,
  5792. NULL,
  5793. CRYPT_EXPORTABLE,
  5794. phkeyKMS))
  5795. {
  5796. hr = myHLastError();
  5797. _JumpError(hr, error, "CryptImportKey");
  5798. }
  5799. wprintf(myLoadResourceString(IDS_MOVED_SIGNATURE_KEY));
  5800. wprintf(wszNewLine);
  5801. }
  5802. hr = S_OK;
  5803. error:
  5804. if (S_OK != hr)
  5805. {
  5806. if (NULL != *ppccKMS)
  5807. {
  5808. CertFreeCertificateContext(*ppccKMS);
  5809. *ppccKMS = NULL;
  5810. }
  5811. if (NULL != *phProvKMS)
  5812. {
  5813. CryptReleaseContext(*phProvKMS, 0);
  5814. *phProvKMS = NULL;
  5815. }
  5816. }
  5817. if (NULL != pbKey)
  5818. {
  5819. LocalFree(pbKey);
  5820. }
  5821. if (NULL != pkpiKMS)
  5822. {
  5823. LocalFree(pkpiKMS);
  5824. }
  5825. if (NULL != hkeyKMSSig)
  5826. {
  5827. CryptDestroyKey(hkeyKMSSig);
  5828. }
  5829. return(hr);
  5830. }
  5831. HRESULT
  5832. ImportOnePFXCert(
  5833. IN DISPATCHINTERFACE *pdiAdmin,
  5834. IN CERT_CONTEXT const *pccXchg,
  5835. IN CERT_CONTEXT const *pCert,
  5836. IN OUT KMSSTATS *pkmsStats)
  5837. {
  5838. HRESULT hr;
  5839. CRYPT_KEY_PROV_INFO *pkpi = NULL;
  5840. HCRYPTPROV hProv = NULL;
  5841. HCRYPTKEY hKey = NULL;
  5842. BYTE *pbKey = NULL;
  5843. DWORD cbKey;
  5844. hr = myCertGetKeyProviderInfo(pCert, &pkpi);
  5845. if (S_OK != hr)
  5846. {
  5847. _PrintError(hr, "myCertGetKeyProviderInfo");
  5848. pkmsStats->cCertWithoutKeys++;
  5849. hr = S_OK;
  5850. goto error;
  5851. }
  5852. pkmsStats->cCertTotal++;
  5853. if (!CryptAcquireContext(
  5854. &hProv,
  5855. pkpi->pwszContainerName,
  5856. pkpi->pwszProvName,
  5857. pkpi->dwProvType,
  5858. pkpi->dwFlags))
  5859. {
  5860. hr = myHLastError();
  5861. _JumpError(hr, error, "CryptAcquireContext");
  5862. }
  5863. if (!CryptGetUserKey(hProv, pkpi->dwKeySpec, &hKey))
  5864. {
  5865. hr = myHLastError();
  5866. _JumpIfError(hr, error, "CryptGetUserKey");
  5867. }
  5868. hr = myCryptExportPrivateKey(hKey, &pbKey, &cbKey);
  5869. _JumpIfError(hr, error, "myCryptExportPrivateKey");
  5870. pkmsStats->cKeyTotal++;
  5871. hr = myVerifyKMSKey(
  5872. pCert->pbCertEncoded,
  5873. pCert->cbCertEncoded,
  5874. pbKey,
  5875. cbKey,
  5876. pkpi->dwKeySpec,
  5877. FALSE);
  5878. _JumpIfError(hr, error, "myVerifyKMSKey");
  5879. hr = ArchiveCertAndKey(
  5880. pdiAdmin,
  5881. pccXchg,
  5882. pCert->pbCertEncoded,
  5883. pCert->cbCertEncoded,
  5884. pbKey,
  5885. cbKey,
  5886. AT_KEYEXCHANGE != pkpi->dwKeySpec, // fSigningKey
  5887. pkmsStats);
  5888. _JumpIfError(hr, error, "ArchiveCertAndKey");
  5889. error:
  5890. if (NULL != pbKey)
  5891. {
  5892. SecureZeroMemory(pbKey, cbKey); // Key material
  5893. LocalFree(pbKey);
  5894. }
  5895. if (NULL != hProv)
  5896. {
  5897. CryptReleaseContext(hProv, 0);
  5898. }
  5899. if (NULL != pkpi)
  5900. {
  5901. LocalFree(pkpi);
  5902. }
  5903. return(hr);
  5904. }
  5905. HRESULT
  5906. ImportKMSPFXOrEPFFile(
  5907. IN WCHAR const *pwszfn)
  5908. {
  5909. HRESULT hr;
  5910. CERT_CONTEXT const *pccXchg = NULL;
  5911. HCERTSTORE hStorePFX = NULL;
  5912. CERT_CONTEXT const *pCert = NULL;
  5913. DISPATCHINTERFACE diAdmin;
  5914. BOOL fMustRelease = FALSE;
  5915. KMSSTATS kmsStats;
  5916. BOOL fUser = TRUE;
  5917. ZeroMemory(&kmsStats, sizeof(kmsStats));
  5918. hr = ReadPFXOrEPFIntoCertStore(pwszfn, fUser, &hStorePFX);
  5919. _JumpIfError(hr, error, "ReadPFXOrEPFIntoCertStore");
  5920. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  5921. _JumpIfError(hr, error, "Admin_Init");
  5922. fMustRelease = TRUE;
  5923. hr = GetCAXchgCert(&diAdmin, &pccXchg);
  5924. _JumpIfError(hr, error, "GetCAXchgCert");
  5925. while (TRUE)
  5926. {
  5927. pCert = CertEnumCertificatesInStore(hStorePFX, pCert);
  5928. if (NULL == pCert)
  5929. {
  5930. break;
  5931. }
  5932. hr = ImportOnePFXCert(&diAdmin, pccXchg, pCert, &kmsStats);
  5933. _PrintIfError(hr, "ImportOnePFXCert");
  5934. }
  5935. hr = DumpKMSStats(&kmsStats);
  5936. _JumpIfError(hr, error, "DumpKMSStats");
  5937. error:
  5938. if (NULL != hStorePFX)
  5939. {
  5940. myDeleteGuidKeys(hStorePFX, !fUser);
  5941. CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG);
  5942. }
  5943. if (NULL != pccXchg)
  5944. {
  5945. CertFreeCertificateContext(pccXchg);
  5946. }
  5947. if (fMustRelease)
  5948. {
  5949. Admin_Release(&diAdmin);
  5950. }
  5951. return(hr);
  5952. }
  5953. HRESULT
  5954. ImportKMSExportFile(
  5955. IN WCHAR const *pwszfnKMS,
  5956. IN WCHAR const *pwszCertIdDecrypt,
  5957. OUT BOOL *pfBadTag)
  5958. {
  5959. HRESULT hr;
  5960. CERT_CONTEXT const *pccKMS = NULL;
  5961. HCRYPTPROV hProvKMS = NULL;
  5962. HCRYPTKEY hkeyKMS = NULL;
  5963. HANDLE hFile = INVALID_HANDLE_VALUE;
  5964. DWORD cbFile;
  5965. CERT_CONTEXT const *pccSigner = NULL;
  5966. *pfBadTag = TRUE;
  5967. hFile = CreateFile(
  5968. pwszfnKMS,
  5969. GENERIC_READ,
  5970. FILE_SHARE_READ,
  5971. NULL,
  5972. OPEN_EXISTING,
  5973. FILE_FLAG_SEQUENTIAL_SCAN,
  5974. NULL);
  5975. if (INVALID_HANDLE_VALUE == hFile)
  5976. {
  5977. hr = myHLastError();
  5978. _JumpError(hr, error, "CreateFile");
  5979. }
  5980. cbFile = GetFileSize(hFile, NULL);
  5981. if (MAXDWORD == cbFile)
  5982. {
  5983. hr = myHLastError();
  5984. _JumpError(hr, error, "GetFileSize");
  5985. }
  5986. // verify the KMS data signature
  5987. hr = VerifyKMSExportFile(hFile, cbFile, &pccSigner);
  5988. _JumpIfError(hr, error, "VerifyKMSExportFile");
  5989. *pfBadTag = FALSE;
  5990. if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
  5991. {
  5992. hr = myHLastError();
  5993. _JumpError(hr, error, "SetFilePointer");
  5994. }
  5995. // Load the KMS recipient cert to be used to decrypt user keys
  5996. hr = LoadKMSCert(pwszCertIdDecrypt, &pccKMS, &hProvKMS, &hkeyKMS);
  5997. _JumpIfError(hr, error, "LoadKMSCert");
  5998. // import the KMS data
  5999. hr = ImportKMSExportedUsers(hFile, cbFile, hProvKMS, hkeyKMS);
  6000. _JumpIfError(hr, error, "ImportKMSExportedUsers");
  6001. error:
  6002. if (NULL != pccKMS)
  6003. {
  6004. CertFreeCertificateContext(pccKMS);
  6005. }
  6006. if (NULL != pccSigner)
  6007. {
  6008. CertFreeCertificateContext(pccSigner);
  6009. }
  6010. if (NULL != hkeyKMS)
  6011. {
  6012. CryptDestroyKey(hkeyKMS);
  6013. }
  6014. if (NULL != hProvKMS)
  6015. {
  6016. CryptReleaseContext(hProvKMS, 0);
  6017. }
  6018. if (INVALID_HANDLE_VALUE != hFile)
  6019. {
  6020. CloseHandle(hFile);
  6021. }
  6022. return(hr);
  6023. }
  6024. HRESULT
  6025. verbImportKMS(
  6026. IN WCHAR const *pwszOption,
  6027. IN WCHAR const *pwszfnKMS,
  6028. IN WCHAR const *pwszCertIdDecrypt,
  6029. IN WCHAR const *pwszArg3,
  6030. IN WCHAR const *pwszArg4)
  6031. {
  6032. HRESULT hr;
  6033. BOOL fBadTag;
  6034. hr = ImportKMSExportFile(pwszfnKMS, pwszCertIdDecrypt, &fBadTag);
  6035. if (S_OK != hr)
  6036. {
  6037. _PrintError(hr, "ImportKMSExportFile");
  6038. if (!fBadTag)
  6039. {
  6040. goto error;
  6041. }
  6042. if (NULL != pwszCertIdDecrypt)
  6043. {
  6044. hr = E_INVALIDARG;
  6045. _JumpErrorStr(hr, error, "unexpected arg", pwszCertIdDecrypt);
  6046. }
  6047. hr = ImportKMSPFXOrEPFFile(pwszfnKMS);
  6048. _JumpIfError(hr, error, "ImportKMSPFXOrEPFFile");
  6049. }
  6050. error:
  6051. return(hr);
  6052. }
  6053. HRESULT
  6054. storeDumpPrivateKey(
  6055. IN HCRYPTPROV hProv,
  6056. IN DWORD dwKeySpec)
  6057. {
  6058. HRESULT hr;
  6059. HCRYPTKEY hKey = NULL;
  6060. CRYPT_BIT_BLOB PrivateKey;
  6061. ZeroMemory(&PrivateKey, sizeof(PrivateKey));
  6062. if (!CryptGetUserKey(hProv, dwKeySpec, &hKey))
  6063. {
  6064. hr = myHLastError();
  6065. _PrintError(hr, "CryptGetUserKey");
  6066. cuPrintError(IDS_ERR_FORMAT_LOADKEY, hr);
  6067. goto error;
  6068. }
  6069. hr = myCryptExportPrivateKey(
  6070. hKey,
  6071. &PrivateKey.pbData,
  6072. &PrivateKey.cbData);
  6073. if (NTE_BAD_KEY_STATE == hr || NTE_PERM == hr)
  6074. {
  6075. wprintf(myLoadResourceString(IDS_PRIVATE_KEY_NOT_EXPORTABLE)); // "Private key is NOT exportable"
  6076. wprintf(wszNewLine);
  6077. }
  6078. else
  6079. {
  6080. _JumpIfError(hr, error, "myCryptExportPrivateKey");
  6081. }
  6082. if (NULL != PrivateKey.pbData)
  6083. {
  6084. hr = cuDumpPrivateKeyBlob(
  6085. PrivateKey.pbData,
  6086. PrivateKey.cbData,
  6087. FALSE);
  6088. _JumpIfError(hr, error, "cuDumpPrivateKeyBlob");
  6089. }
  6090. hr = S_OK;
  6091. error:
  6092. if (NULL != PrivateKey.pbData)
  6093. {
  6094. SecureZeroMemory(PrivateKey.pbData, PrivateKey.cbData); // Key material
  6095. LocalFree(PrivateKey.pbData);
  6096. }
  6097. if (NULL != hKey)
  6098. {
  6099. CryptDestroyKey(hKey);
  6100. }
  6101. return(hr);
  6102. }
  6103. HRESULT
  6104. myCryptGetProvParamToUnicode(
  6105. IN HCRYPTPROV hProv,
  6106. IN DWORD dwParam,
  6107. OUT WCHAR **ppwszOut,
  6108. IN DWORD dwFlags);
  6109. HRESULT
  6110. DisplayUniqueContainer(
  6111. IN HCRYPTPROV hProv)
  6112. {
  6113. HRESULT hr;
  6114. WCHAR *pwszUniqueContainer = NULL;
  6115. hr = myCryptGetProvParamToUnicode(
  6116. hProv,
  6117. PP_UNIQUE_CONTAINER,
  6118. &pwszUniqueContainer,
  6119. 0);
  6120. _JumpIfError(hr, error, "myCryptGetProvParamToUnicode");
  6121. wprintf(L" %ws\n", pwszUniqueContainer);
  6122. error:
  6123. if (NULL != pwszUniqueContainer)
  6124. {
  6125. LocalFree(pwszUniqueContainer);
  6126. }
  6127. return(hr);
  6128. }
  6129. HRESULT
  6130. EnumKeys(
  6131. IN WCHAR const *pwszProvName,
  6132. IN DWORD dwProvType,
  6133. IN BOOL fSkipKeys,
  6134. OPTIONAL IN WCHAR const *pwszKeyContainerName)
  6135. {
  6136. HRESULT hr;
  6137. KEY_LIST *pKeyList = NULL;
  6138. KEY_LIST *pKeyT;
  6139. WCHAR *pwszRevert = NULL;
  6140. CERT_PUBLIC_KEY_INFO *pPubKeyInfoSig = NULL;
  6141. CERT_PUBLIC_KEY_INFO *pPubKeyInfoXchg = NULL;
  6142. WCHAR const *pwszPrefix;
  6143. if (!fSkipKeys)
  6144. {
  6145. hr = csiGetKeyList(
  6146. dwProvType, // dwProvType
  6147. pwszProvName, // pwszProvName
  6148. !g_fUserRegistry, // fMachineKeyset
  6149. !g_fCryptSilent, // inverted fSilent: default is Silent!
  6150. &pKeyList);
  6151. _JumpIfErrorStr(hr, error, "csiGetKeyList", pwszProvName);
  6152. }
  6153. if (fSkipKeys || NULL != pKeyList)
  6154. {
  6155. wprintf(L"%ws:\n", pwszProvName);
  6156. }
  6157. for (pKeyT = pKeyList; NULL != pKeyT; pKeyT = pKeyT->next)
  6158. {
  6159. DWORD dwProvTypeT;
  6160. hr = myRevertSanitizeName(pKeyT->pwszName, &pwszRevert);
  6161. _JumpIfError(hr, error, "myRevertSanitizeName");
  6162. if (NULL == pwszKeyContainerName ||
  6163. 0 == mylstrcmpiL(pwszKeyContainerName, pwszRevert) ||
  6164. 0 == mylstrcmpiL(pwszKeyContainerName, pKeyT->pwszName))
  6165. {
  6166. HCRYPTPROV hProv = NULL;
  6167. wprintf(L" %ws", pwszRevert);
  6168. if (g_fVerbose && 0 != lstrcmp(pKeyT->pwszName, pwszRevert))
  6169. {
  6170. wprintf(L" -- %ws", pKeyT->pwszName);
  6171. }
  6172. wprintf(wszNewLine);
  6173. dwProvTypeT = dwProvType;
  6174. hr = cuLoadKeys(
  6175. pwszProvName,
  6176. &dwProvTypeT,
  6177. pKeyT->pwszName,
  6178. !g_fUserRegistry, // fMachineKeyset
  6179. TRUE,
  6180. &hProv,
  6181. &pPubKeyInfoSig,
  6182. &pPubKeyInfoXchg);
  6183. if (S_OK != hr)
  6184. {
  6185. cuPrintError(IDS_ERR_FORMAT_LOADKEYS, hr);
  6186. }
  6187. else if (g_fVerbose && NULL != hProv)
  6188. {
  6189. DisplayUniqueContainer(hProv);
  6190. }
  6191. if (NULL != pPubKeyInfoSig || NULL != pPubKeyInfoXchg)
  6192. {
  6193. pwszPrefix = g_wszPad4;
  6194. if (NULL != pPubKeyInfoSig)
  6195. {
  6196. if (g_fVerbose)
  6197. {
  6198. wprintf(wszNewLine);
  6199. }
  6200. wprintf(L"%wsAT_SIGNATURE", pwszPrefix);
  6201. pwszPrefix = L", ";
  6202. if (g_fVerbose)
  6203. {
  6204. wprintf(L":\n");
  6205. cuDisplayKeyId(pPubKeyInfoSig, 0, NULL);
  6206. wprintf(myLoadResourceString(IDS_CONTAINER_PUBLIC_KEY)); // "Container Public Key:"
  6207. wprintf(wszNewLine);
  6208. DumpHex(
  6209. DH_NOTABPREFIX | DH_NOASCIIHEX | 2,
  6210. pPubKeyInfoSig->PublicKey.pbData,
  6211. pPubKeyInfoSig->PublicKey.cbData);
  6212. wprintf(wszNewLine);
  6213. storeDumpPrivateKey(hProv, AT_SIGNATURE);
  6214. pwszPrefix = L" ";
  6215. }
  6216. LocalFree(pPubKeyInfoSig);
  6217. pPubKeyInfoSig = NULL;
  6218. }
  6219. if (NULL != pPubKeyInfoXchg)
  6220. {
  6221. if (g_fVerbose)
  6222. {
  6223. wprintf(wszNewLine);
  6224. }
  6225. wprintf(L"%wsAT_KEYEXCHANGE", pwszPrefix);
  6226. if (g_fVerbose)
  6227. {
  6228. wprintf(L":\n");
  6229. cuDisplayKeyId(pPubKeyInfoXchg, 0, NULL);
  6230. wprintf(myLoadResourceString(IDS_CONTAINER_PUBLIC_KEY)); // "Container Public Key:"
  6231. wprintf(wszNewLine);
  6232. DumpHex(
  6233. DH_NOTABPREFIX | DH_NOASCIIHEX | 2,
  6234. pPubKeyInfoXchg->PublicKey.pbData,
  6235. pPubKeyInfoXchg->PublicKey.cbData);
  6236. wprintf(wszNewLine);
  6237. storeDumpPrivateKey(hProv, AT_KEYEXCHANGE);
  6238. }
  6239. LocalFree(pPubKeyInfoXchg);
  6240. pPubKeyInfoXchg = NULL;
  6241. }
  6242. wprintf(wszNewLine);
  6243. }
  6244. if (NULL != hProv)
  6245. {
  6246. CryptReleaseContext(hProv, 0);
  6247. }
  6248. if (NULL == pwszKeyContainerName)
  6249. {
  6250. wprintf(wszNewLine);
  6251. }
  6252. }
  6253. LocalFree(pwszRevert);
  6254. pwszRevert = NULL;
  6255. }
  6256. hr = S_OK;
  6257. error:
  6258. if (NULL != pPubKeyInfoSig)
  6259. {
  6260. LocalFree(pPubKeyInfoSig);
  6261. }
  6262. if (NULL != pPubKeyInfoXchg)
  6263. {
  6264. LocalFree(pPubKeyInfoXchg);
  6265. }
  6266. if (NULL != pwszRevert)
  6267. {
  6268. LocalFree(pwszRevert);
  6269. }
  6270. if (NULL != pKeyList)
  6271. {
  6272. csiFreeKeyList(pKeyList);
  6273. }
  6274. return(hr);
  6275. }
  6276. HRESULT
  6277. verbKey(
  6278. IN WCHAR const *pwszOption,
  6279. OPTIONAL IN WCHAR const *pwszKeyContainerName,
  6280. IN WCHAR const *pwszArg2,
  6281. IN WCHAR const *pwszArg3,
  6282. IN WCHAR const *pwszArg4)
  6283. {
  6284. HRESULT hr;
  6285. WCHAR *pwszProvider = g_pwszCSP;
  6286. WCHAR *pwszProvName = NULL;
  6287. WCHAR *pwszProvNameDefault = NULL;
  6288. DWORD i;
  6289. DWORD dwProvType;
  6290. BOOL fSkipKeys = FALSE;
  6291. if (NULL == pwszProvider)
  6292. {
  6293. hr = myCryptGetDefaultProvider(
  6294. PROV_RSA_FULL,
  6295. g_fUserRegistry?
  6296. CRYPT_USER_DEFAULT : CRYPT_MACHINE_DEFAULT,
  6297. &pwszProvNameDefault);
  6298. _JumpIfError(hr, error, "myCryptGetDefaultProvider");
  6299. pwszProvider = pwszProvNameDefault;
  6300. }
  6301. else if (0 == lstrcmp(L"*", pwszProvider))
  6302. {
  6303. pwszProvider = NULL; // all CSPs
  6304. }
  6305. if (NULL != pwszKeyContainerName)
  6306. {
  6307. if (myIsMinusSignString(pwszKeyContainerName))
  6308. {
  6309. pwszKeyContainerName = NULL; // all keys
  6310. fSkipKeys = TRUE;
  6311. }
  6312. }
  6313. if (NULL != pwszProvider)
  6314. {
  6315. hr = csiGetProviderTypeFromProviderName(pwszProvider, &dwProvType);
  6316. _JumpIfErrorStr(hr, error, "csiGetProviderTypeFromProviderName", pwszProvider);
  6317. hr = EnumKeys(
  6318. pwszProvider,
  6319. dwProvType,
  6320. fSkipKeys,
  6321. pwszKeyContainerName);
  6322. _JumpIfErrorStr(hr, error, "EnumKeys", pwszProvider);
  6323. }
  6324. else
  6325. {
  6326. for (i = 0; ; i++)
  6327. {
  6328. CSASSERT(NULL == pwszProvName);
  6329. hr = myEnumProviders(i, NULL, 0, &dwProvType, &pwszProvName);
  6330. if (S_OK != hr)
  6331. {
  6332. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr ||
  6333. NTE_FAIL == hr)
  6334. {
  6335. // no more providers under type, out of i loop
  6336. break;
  6337. }
  6338. // invalid csp entry, skip it
  6339. wprintf(myLoadResourceString(IDS_FORMAT_SKIP_CSP_ENUM), i);
  6340. wprintf(wszNewLine);
  6341. }
  6342. else
  6343. {
  6344. hr = EnumKeys(
  6345. pwszProvName,
  6346. dwProvType,
  6347. fSkipKeys,
  6348. pwszKeyContainerName);
  6349. _JumpIfErrorStr(hr, error, "EnumKeys", pwszProvName);
  6350. LocalFree(pwszProvName);
  6351. pwszProvName = NULL;
  6352. }
  6353. }
  6354. }
  6355. hr = S_OK;
  6356. error:
  6357. if (NULL != pwszProvName)
  6358. {
  6359. LocalFree(pwszProvName);
  6360. }
  6361. if (NULL != pwszProvNameDefault)
  6362. {
  6363. LocalFree(pwszProvNameDefault);
  6364. }
  6365. return(hr);
  6366. }
  6367. HRESULT
  6368. cuSanitizeNameWithSuffix(
  6369. IN WCHAR const *pwszName,
  6370. OUT WCHAR **ppwszNameOut)
  6371. {
  6372. HRESULT hr;
  6373. WCHAR const *pwszSuffix;
  6374. WCHAR const *pwsz;
  6375. WCHAR *pwszBase = NULL;
  6376. WCHAR *pwszSanitizedName = NULL;
  6377. DWORD cwc;
  6378. pwsz = wcsrchr(pwszName, wcLPAREN);
  6379. pwszSuffix = pwsz;
  6380. if (NULL != pwsz)
  6381. {
  6382. BOOL fSawDigit = FALSE;
  6383. pwsz++;
  6384. while (iswdigit(*pwsz))
  6385. {
  6386. pwsz++;
  6387. fSawDigit = TRUE;
  6388. }
  6389. if (fSawDigit &&
  6390. wcRPAREN == *pwsz &&
  6391. (L'.' == pwsz[1] || L'\0' == pwsz[1]))
  6392. {
  6393. cwc = SAFE_SUBTRACT_POINTERS(pwszSuffix, pwszName);
  6394. pwszBase = (WCHAR *) LocalAlloc(
  6395. LMEM_FIXED,
  6396. (cwc + 1) * sizeof(WCHAR));
  6397. if (NULL == pwszBase)
  6398. {
  6399. hr = E_OUTOFMEMORY;
  6400. _JumpError(hr, error, "LocalAlloc");
  6401. }
  6402. CopyMemory(pwszBase, pwszName, cwc * sizeof(WCHAR));
  6403. pwszBase[cwc] = L'\0';
  6404. pwszName = pwszBase;
  6405. }
  6406. else
  6407. {
  6408. pwszSuffix = NULL;
  6409. }
  6410. }
  6411. hr = mySanitizeName(pwszName, &pwszSanitizedName);
  6412. _JumpIfError(hr, error, "mySanitizeName");
  6413. if (NULL == pwszSuffix)
  6414. {
  6415. *ppwszNameOut = pwszSanitizedName;
  6416. pwszSanitizedName = NULL;
  6417. }
  6418. else
  6419. {
  6420. *ppwszNameOut = (WCHAR *) LocalAlloc(
  6421. LMEM_FIXED,
  6422. (wcslen(pwszSanitizedName) +
  6423. wcslen(pwszSuffix) +
  6424. 1) * sizeof(WCHAR));
  6425. if (NULL == *ppwszNameOut)
  6426. {
  6427. hr = E_OUTOFMEMORY;
  6428. _JumpError(hr, error, "LocalAlloc");
  6429. }
  6430. wcscpy(*ppwszNameOut, pwszSanitizedName);
  6431. wcscat(*ppwszNameOut, pwszSuffix);
  6432. }
  6433. hr = S_OK;
  6434. error:
  6435. if (NULL != pwszSanitizedName)
  6436. {
  6437. LocalFree(pwszSanitizedName);
  6438. }
  6439. if (NULL != pwszBase)
  6440. {
  6441. LocalFree(pwszBase);
  6442. }
  6443. return(hr);
  6444. }
  6445. HRESULT
  6446. verbDelKey(
  6447. IN WCHAR const *pwszOption,
  6448. IN WCHAR const *pwszKeyContainerName,
  6449. IN WCHAR const *pwszArg2,
  6450. IN WCHAR const *pwszArg3,
  6451. IN WCHAR const *pwszArg4)
  6452. {
  6453. HRESULT hr;
  6454. HCRYPTPROV hProv = NULL;
  6455. WCHAR *pwszProvider = g_pwszCSP;
  6456. WCHAR *pwszProvNameDefault = NULL;
  6457. WCHAR *apwszKeyContainer[3];
  6458. DWORD i;
  6459. DWORD dwProviderType;
  6460. DWORD dwFlags = CRYPT_DELETEKEYSET;
  6461. // If supplied provider is NULL, use the default provider.
  6462. if (pwszProvider == NULL)
  6463. {
  6464. hr = myCryptGetDefaultProvider(
  6465. PROV_RSA_FULL,
  6466. g_fUserRegistry?
  6467. CRYPT_USER_DEFAULT : CRYPT_MACHINE_DEFAULT,
  6468. &pwszProvNameDefault);
  6469. _JumpIfError(hr, error, "myCryptGetDefaultProvider");
  6470. pwszProvider = pwszProvNameDefault;
  6471. }
  6472. apwszKeyContainer[0] = const_cast<WCHAR *>(pwszKeyContainerName);
  6473. apwszKeyContainer[1] = NULL;
  6474. apwszKeyContainer[2] = NULL;
  6475. hr = mySanitizeName(pwszKeyContainerName, &apwszKeyContainer[1]);
  6476. _JumpIfError(hr, error, "mySanitizeName");
  6477. hr = cuSanitizeNameWithSuffix(pwszKeyContainerName, &apwszKeyContainer[2]);
  6478. _JumpIfError(hr, error, "cuSanitizeNameWithSuffix");
  6479. hr = csiGetProviderTypeFromProviderName(pwszProvider, &dwProviderType);
  6480. _JumpIfError(hr, error, "csiGetProviderTypeFromProviderName");
  6481. if (g_fCryptSilent)
  6482. {
  6483. dwFlags |= CRYPT_SILENT;
  6484. }
  6485. for (i = 0; i < ARRAYSIZE(apwszKeyContainer); i++)
  6486. {
  6487. if (!myCertSrvCryptAcquireContext(
  6488. &hProv,
  6489. apwszKeyContainer[i],
  6490. pwszProvider,
  6491. dwProviderType,
  6492. dwFlags,
  6493. !g_fUserRegistry)) // fMachineKeyset
  6494. {
  6495. hr = myHLastError();
  6496. _PrintErrorStr2(
  6497. hr,
  6498. "myCertSrvCryptAcquireContext",
  6499. apwszKeyContainer[i],
  6500. hr);
  6501. }
  6502. else
  6503. {
  6504. DWORD j;
  6505. wprintf(L" %ws", apwszKeyContainer[i]);
  6506. if (g_fVerbose)
  6507. {
  6508. wprintf(L" --");
  6509. for (j = 0; j < ARRAYSIZE(apwszKeyContainer); j++)
  6510. {
  6511. wprintf(L" %ws", apwszKeyContainer[j]);
  6512. }
  6513. }
  6514. wprintf(wszNewLine);
  6515. hr = S_OK;
  6516. break;
  6517. }
  6518. }
  6519. _JumpIfError(hr, error, "myCertSrvCryptAcquireContext");
  6520. error:
  6521. for (i = 1; i < ARRAYSIZE(apwszKeyContainer); i++)
  6522. {
  6523. if (NULL != apwszKeyContainer[i])
  6524. {
  6525. LocalFree(apwszKeyContainer[i]);
  6526. }
  6527. }
  6528. if (NULL != pwszProvNameDefault)
  6529. {
  6530. LocalFree(pwszProvNameDefault);
  6531. }
  6532. return(hr);
  6533. }