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.

4112 lines
92 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1999
  6. //
  7. // File: admin.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <pch.cpp>
  11. #pragma hdrstop
  12. #include <setupapi.h>
  13. #include <ocmanage.h>
  14. #include "initcert.h"
  15. #include "cscsp.h"
  16. #define __dwFILE__ __dwFILE_CERTUTIL_ADMIN_CPP__
  17. #define wszV1SUFFIX L"-v1"
  18. #define wszP12SUFFIX L".p12"
  19. #define wszRECSUFFIX L".rec"
  20. #define wszEPFSUFFIX L".epf"
  21. HRESULT
  22. verbDenyRequest(
  23. IN WCHAR const *pwszOption,
  24. IN WCHAR const *pwszRequestId,
  25. IN WCHAR const *pwszArg2,
  26. IN WCHAR const *pwszArg3,
  27. IN WCHAR const *pwszArg4)
  28. {
  29. HRESULT hr;
  30. DISPATCHINTERFACE diAdmin;
  31. LONG RequestId;
  32. BOOL fMustRelease = FALSE;
  33. hr = myGetLong(pwszRequestId, &RequestId);
  34. _JumpIfError(hr, error, "RequestId must be a number");
  35. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  36. _JumpIfError(hr, error, "Admin_Init");
  37. fMustRelease = TRUE;
  38. hr = Admin_DenyRequest(&diAdmin, g_pwszConfig, RequestId);
  39. _JumpIfError(hr, error, "Admin_DenyRequest");
  40. error:
  41. if (fMustRelease)
  42. {
  43. Admin_Release(&diAdmin);
  44. }
  45. return(hr);
  46. }
  47. WCHAR const *
  48. wszFromSubmitDisposition(
  49. LONG Disposition)
  50. {
  51. DWORD idMsg;
  52. switch (Disposition)
  53. {
  54. case CR_DISP_INCOMPLETE: idMsg = IDS_CR_DISP_INCOMPLETE; break;
  55. case CR_DISP_ERROR: idMsg = IDS_CR_DISP_ERROR; break;
  56. case CR_DISP_DENIED: idMsg = IDS_CR_DISP_DENIED; break;
  57. case CR_DISP_ISSUED: idMsg = IDS_CR_DISP_ISSUED; break;
  58. case CR_DISP_ISSUED_OUT_OF_BAND:
  59. idMsg = IDS_CR_DISP_ISSUED_OUT_OF_BAND; break;
  60. case CR_DISP_UNDER_SUBMISSION:
  61. idMsg = IDS_CR_DISP_UNDER_SUBMISSION; break;
  62. case CR_DISP_REVOKED: idMsg = IDS_CR_DISP_REVOKED; break;
  63. default: idMsg = IDS_UNKNOWN; break;
  64. }
  65. return(myLoadResourceString(idMsg));
  66. }
  67. HRESULT
  68. verbResubmitRequest(
  69. IN WCHAR const *pwszOption,
  70. IN WCHAR const *pwszRequestId,
  71. IN WCHAR const *pwszArg2,
  72. IN WCHAR const *pwszArg3,
  73. IN WCHAR const *pwszArg4)
  74. {
  75. HRESULT hr;
  76. DISPATCHINTERFACE diAdmin;
  77. LONG RequestId;
  78. LONG Disposition;
  79. BOOL fMustRelease = FALSE;
  80. hr = myGetLong(pwszRequestId, &RequestId);
  81. _JumpIfError(hr, error, "RequestId must be a number");
  82. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  83. _JumpIfError(hr, error, "Admin_Init");
  84. fMustRelease = TRUE;
  85. hr = Admin_ResubmitRequest(&diAdmin, g_pwszConfig, RequestId, &Disposition);
  86. _JumpIfError(hr, error, "Admin_ResubmitRequest");
  87. if (CR_DISP_UNDER_SUBMISSION == Disposition)
  88. {
  89. wprintf(
  90. myLoadResourceString(IDS_FORMAT_PENDING_REQUESTID), // "Certificate request is pending: RequestId: %u"
  91. RequestId);
  92. wprintf(wszNewLine);
  93. }
  94. else if (CR_DISP_ISSUED == Disposition)
  95. {
  96. wprintf(myLoadResourceString(IDS_CERT_ISSUED)); // "Certificate issued."
  97. wprintf(wszNewLine);
  98. }
  99. else
  100. {
  101. if (FAILED(Disposition))
  102. {
  103. hr = Disposition;
  104. Disposition = CR_DISP_DENIED;
  105. }
  106. wprintf(
  107. myLoadResourceString(IDS_CERT_NOT_ISSUED_DISPOSITION), // "Certificate has not been issued: Disposition: %d -- %ws"
  108. Disposition,
  109. wszFromSubmitDisposition(Disposition));
  110. wprintf(wszNewLine);
  111. if (S_OK != hr)
  112. {
  113. WCHAR const *pwszMessage;
  114. pwszMessage = myGetErrorMessageText(hr, FALSE);
  115. if (NULL != pwszMessage)
  116. {
  117. wprintf(L"%ws\n", pwszMessage);
  118. LocalFree(const_cast<WCHAR *>(pwszMessage));
  119. }
  120. }
  121. }
  122. error:
  123. if (fMustRelease)
  124. {
  125. Admin_Release(&diAdmin);
  126. }
  127. return(hr);
  128. }
  129. typedef struct _cuCRLREASON
  130. {
  131. WCHAR *pwszReason;
  132. LONG lReason;
  133. int idReason;
  134. } cuCRLREASON;
  135. #define cuREASON(r, id) { L#r, (r), (id) }
  136. cuCRLREASON g_cuReason[] =
  137. {
  138. cuREASON(CRL_REASON_UNSPECIFIED, IDS_CRL_REASON_UNSPECIFIED),
  139. cuREASON(CRL_REASON_KEY_COMPROMISE, IDS_CRL_REASON_KEY_COMPROMISE),
  140. cuREASON(CRL_REASON_CA_COMPROMISE, IDS_CRL_REASON_CA_COMPROMISE),
  141. cuREASON(CRL_REASON_AFFILIATION_CHANGED, IDS_CRL_REASON_AFFILIATION_CHANGED),
  142. cuREASON(CRL_REASON_SUPERSEDED, IDS_CRL_REASON_SUPERSEDED),
  143. cuREASON(CRL_REASON_CESSATION_OF_OPERATION,
  144. IDS_CRL_REASON_CESSATION_OF_OPERATION),
  145. cuREASON(CRL_REASON_CERTIFICATE_HOLD, IDS_CRL_REASON_CERTIFICATE_HOLD),
  146. cuREASON(CRL_REASON_REMOVE_FROM_CRL, IDS_CRL_REASON_REMOVE_FROM_CRL),
  147. { L"Unrevoke", MAXDWORD, IDS_CRL_REASON_UNREVOKE },
  148. { NULL, MAXDWORD, IDS_CRL_REASON_UNRECOGNIZED },
  149. };
  150. #define wszCRLPREFIX L"CRL_REASON_"
  151. HRESULT
  152. cuParseReason(
  153. IN WCHAR const *pwszReason,
  154. OUT LONG *plReason)
  155. {
  156. HRESULT hr;
  157. hr = myGetSignedLong(pwszReason, plReason);
  158. if (S_OK != hr)
  159. {
  160. cuCRLREASON const *pr;
  161. for (pr = g_cuReason; ; pr++)
  162. {
  163. if (NULL == pr->pwszReason)
  164. {
  165. hr = E_INVALIDARG;
  166. _JumpIfError(hr, error, "Invalid Reason string");
  167. }
  168. if (0 == mylstrcmpiS(pr->pwszReason, pwszReason))
  169. {
  170. break;
  171. }
  172. if (wcslen(pr->pwszReason) > WSZARRAYSIZE(wszCRLPREFIX) &&
  173. 0 == memcmp(
  174. pr->pwszReason,
  175. wszCRLPREFIX,
  176. WSZARRAYSIZE(wszCRLPREFIX) * sizeof(WCHAR)) &&
  177. 0 == LSTRCMPIS(
  178. pwszReason,
  179. &pr->pwszReason[WSZARRAYSIZE(wszCRLPREFIX)]))
  180. {
  181. break;
  182. }
  183. }
  184. *plReason = pr->lReason;
  185. hr = S_OK;
  186. }
  187. CSASSERT(S_OK == hr);
  188. error:
  189. return(hr);
  190. }
  191. int
  192. cuidCRLReason(
  193. IN LONG Reason)
  194. {
  195. cuCRLREASON const *pr;
  196. for (pr = g_cuReason; NULL != pr->pwszReason; pr++)
  197. {
  198. if (pr->lReason == Reason)
  199. {
  200. break;
  201. }
  202. }
  203. return(pr->idReason);
  204. }
  205. WCHAR const *
  206. wszCRLReason(
  207. IN LONG Reason)
  208. {
  209. return(myLoadResourceString(cuidCRLReason(Reason)));
  210. }
  211. HRESULT
  212. verbRevokeCertificate(
  213. IN WCHAR const *pwszOption,
  214. IN WCHAR const *pwszSerialNumberList,
  215. IN WCHAR const *pwszReason,
  216. IN WCHAR const *pwszArg3,
  217. IN WCHAR const *pwszArg4)
  218. {
  219. HRESULT hr;
  220. HRESULT hr2;
  221. DISPATCHINTERFACE diAdmin;
  222. WCHAR **ppwszSerialList = NULL;
  223. BSTR strSerialNumber = NULL;
  224. LONG Reason = CRL_REASON_UNSPECIFIED;
  225. SYSTEMTIME st;
  226. FILETIME ft;
  227. DATE Date;
  228. BOOL fMustRelease = FALSE;
  229. GetSystemTime(&st);
  230. if (!SystemTimeToFileTime(&st, &ft))
  231. {
  232. hr = myHLastError();
  233. _JumpIfError(hr, error, "SystemTimeToFileTime");
  234. }
  235. hr = myFileTimeToDate(&ft, &Date);
  236. _JumpIfError(hr, error, "myFileTimeToDate");
  237. //Date -= 1.0; // Revoke effective yesterday
  238. if (NULL != pwszReason)
  239. {
  240. hr = cuParseReason(pwszReason, &Reason);
  241. _JumpIfError(hr, error, "Invalid Reason");
  242. }
  243. hr = cuParseStrings(
  244. pwszSerialNumberList,
  245. FALSE,
  246. NULL,
  247. NULL,
  248. &ppwszSerialList,
  249. NULL);
  250. _JumpIfError(hr, error, "cuParseStrings");
  251. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  252. _JumpIfError(hr, error, "Admin_Init");
  253. fMustRelease = TRUE;
  254. if (NULL != ppwszSerialList)
  255. {
  256. DWORD i;
  257. for (i = 0; NULL != ppwszSerialList[i]; i++)
  258. {
  259. hr2 = myMakeSerialBstr(ppwszSerialList[i], &strSerialNumber);
  260. if (S_OK == hr)
  261. {
  262. hr = hr2;
  263. }
  264. _JumpIfError(hr2, error, "myMakeSerialBstr");
  265. wprintf(myLoadResourceString(IDS_REVOKING), strSerialNumber); // "Revoking "%ws""
  266. wprintf(L" -- %ws", wszCRLReason(Reason)); // "Reason: xxxx"
  267. wprintf(wszNewLine);
  268. hr2 = Admin_RevokeCertificate(
  269. &diAdmin,
  270. g_pwszConfig,
  271. strSerialNumber,
  272. Reason,
  273. Date);
  274. if (S_OK != hr2)
  275. {
  276. cuPrintAPIError(L"ICertAdmin::RevokeCertificate", hr2);
  277. _PrintError(hr2, "Admin_RevokeCertificate");
  278. if (S_OK == hr)
  279. {
  280. hr = hr2;
  281. }
  282. }
  283. SysFreeString(strSerialNumber);
  284. strSerialNumber = NULL;
  285. }
  286. }
  287. _JumpIfError(hr, error, "Admin_RevokeCertificate");
  288. error:
  289. cuFreeStringArray(ppwszSerialList);
  290. if (fMustRelease)
  291. {
  292. Admin_Release(&diAdmin);
  293. }
  294. if (NULL != strSerialNumber)
  295. {
  296. SysFreeString(strSerialNumber);
  297. }
  298. return(hr);
  299. }
  300. HRESULT
  301. cuParseDaysHours(
  302. IN WCHAR const *pwszDaysHours,
  303. OUT FILETIME *pft)
  304. {
  305. HRESULT hr;
  306. WCHAR *pwszDays = NULL;
  307. WCHAR *pwszHours;
  308. DWORD dwDays;
  309. DWORD dwHours;
  310. BOOL fValid;
  311. LONGLONG delta;
  312. hr = myDupString(pwszDaysHours, &pwszDays);
  313. _JumpIfError(hr, error, "myDupString");
  314. hr = E_INVALIDARG;
  315. pwszHours = wcschr(pwszDays, L':');
  316. if (NULL == pwszHours)
  317. {
  318. _JumpError(hr, error, "missing colon");
  319. }
  320. *pwszHours++ = L'\0';
  321. dwDays = myWtoI(pwszDays, &fValid);
  322. if (!fValid)
  323. {
  324. _JumpError(hr, error, "bad day count");
  325. }
  326. dwHours = myWtoI(pwszHours, &fValid);
  327. if (!fValid)
  328. {
  329. _JumpError(hr, error, "bad hour count");
  330. }
  331. if (0 == dwDays && 0 == dwHours)
  332. {
  333. _JumpError(hr, error, "zero day+hour counts");
  334. }
  335. GetSystemTimeAsFileTime(pft);
  336. // add specified days and hours to compute expiration date
  337. delta = dwDays * CVT_DAYS;
  338. delta += dwHours * CVT_HOURS;
  339. myAddToFileTime(pft, delta * CVT_BASE);
  340. hr = S_OK;
  341. error:
  342. if (NULL != pwszDays)
  343. {
  344. LocalFree(pwszDays);
  345. }
  346. return(hr);
  347. }
  348. HRESULT
  349. verbPublishCRL(
  350. IN WCHAR const *pwszOption,
  351. OPTIONAL IN WCHAR const *pwszDaysHours,
  352. OPTIONAL IN WCHAR const *pwszDelta,
  353. IN WCHAR const *pwszArg3,
  354. IN WCHAR const *pwszArg4)
  355. {
  356. HRESULT hr;
  357. DISPATCHINTERFACE diAdmin;
  358. BOOL fMustRelease = FALSE;
  359. DATE Date;
  360. DWORD Flags = 0;
  361. if (NULL != pwszDaysHours && 0 == LSTRCMPIS(pwszDaysHours, L"delta"))
  362. {
  363. WCHAR const *pwsz = pwszDaysHours;
  364. pwszDaysHours = pwszDelta;
  365. pwszDelta = pwsz;
  366. }
  367. Date = 0.0;
  368. if (NULL != pwszDaysHours)
  369. {
  370. if (0 == LSTRCMPIS(pwszDaysHours, L"republish"))
  371. {
  372. Flags |= CA_CRL_REPUBLISH;
  373. }
  374. else
  375. {
  376. FILETIME ft;
  377. hr = cuParseDaysHours(pwszDaysHours, &ft);
  378. _JumpIfError(hr, error, "cuParseDaysHours");
  379. hr = myFileTimeToDate(&ft, &Date);
  380. _JumpIfError(hr, error, "myFileTimeToDate");
  381. }
  382. }
  383. if (NULL != pwszDelta)
  384. {
  385. if (0 != LSTRCMPIS(pwszDelta, L"delta"))
  386. {
  387. hr = E_INVALIDARG;
  388. _JumpError(hr, error, "bad delta arg");
  389. }
  390. Flags |= CA_CRL_DELTA;
  391. }
  392. if (0 == (CA_CRL_DELTA & Flags))
  393. {
  394. Flags |= CA_CRL_BASE;
  395. }
  396. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  397. _JumpIfError(hr, error, "Admin_Init");
  398. fMustRelease = TRUE;
  399. if ((CA_CRL_DELTA | CA_CRL_REPUBLISH) & Flags)
  400. {
  401. hr = Admin2_PublishCRLs(&diAdmin, g_pwszConfig, Date, Flags);
  402. _JumpIfError(hr, error, "Admin2_PublishCRLs");
  403. }
  404. else
  405. {
  406. BOOL fV1 = g_fV1Interface;
  407. if (!fV1)
  408. {
  409. hr = Admin2_PublishCRLs(&diAdmin, g_pwszConfig, Date, Flags);
  410. if (E_NOTIMPL != hr && RPC_E_VERSION_MISMATCH != hr)
  411. {
  412. _JumpIfError(hr, error, "Admin2_PublishCRLs");
  413. }
  414. else
  415. {
  416. _PrintError(hr, "Admin2_PublishCRLs down level server");
  417. fV1 = TRUE;
  418. }
  419. }
  420. if (fV1)
  421. {
  422. hr = Admin_PublishCRL(&diAdmin, g_pwszConfig, Date);
  423. _JumpIfError(hr, error, "Admin_PublishCRL");
  424. }
  425. }
  426. error:
  427. if (fMustRelease)
  428. {
  429. Admin_Release(&diAdmin);
  430. }
  431. return(hr);
  432. }
  433. HRESULT
  434. verbGetCRL(
  435. IN WCHAR const *pwszOption,
  436. IN WCHAR const *pwszfnOut,
  437. OPTIONAL IN WCHAR const *pwszDelta,
  438. OPTIONAL IN WCHAR const *pwszIndex,
  439. IN WCHAR const *pwszArg4)
  440. {
  441. HRESULT hr;
  442. DISPATCHINTERFACE diAdmin;
  443. BOOL fMustRelease = FALSE;
  444. BOOL fDelta = FALSE;
  445. DWORD Index = MAXDWORD; // default to latest CRL
  446. BSTR strCRL = NULL;
  447. if (NULL != pwszDelta && 0 != LSTRCMPIS(pwszDelta, L"delta"))
  448. {
  449. WCHAR const *pwsz = pwszIndex;
  450. pwszIndex = pwszDelta;
  451. pwszDelta = pwsz;
  452. }
  453. if (NULL != pwszDelta && 0 == LSTRCMPIS(pwszDelta, L"delta"))
  454. {
  455. fDelta = TRUE;
  456. }
  457. if (NULL != pwszIndex)
  458. {
  459. hr = myGetSignedLong(pwszIndex, (LONG *) &Index);
  460. _JumpIfErrorStr(hr, error, "Cert index not a number", pwszIndex);
  461. }
  462. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  463. _JumpIfError(hr, error, "Admin_Init");
  464. fMustRelease = TRUE;
  465. if (fDelta)
  466. {
  467. hr = Admin2_GetCAProperty(
  468. &diAdmin,
  469. g_pwszConfig,
  470. CR_PROP_DELTACRL,
  471. Index,
  472. PROPTYPE_BINARY,
  473. CR_OUT_BINARY,
  474. &strCRL);
  475. _JumpIfError(hr, error, "Admin2_GetCAProperty");
  476. }
  477. else
  478. {
  479. BOOL fV1 = g_fV1Interface;
  480. if (!fV1)
  481. {
  482. hr = Admin2_GetCAProperty(
  483. &diAdmin,
  484. g_pwszConfig,
  485. CR_PROP_BASECRL,
  486. Index,
  487. PROPTYPE_BINARY,
  488. CR_OUT_BINARY,
  489. &strCRL);
  490. if (E_NOTIMPL != hr && RPC_E_VERSION_MISMATCH != hr)
  491. {
  492. _JumpIfError(hr, error, "Admin2_GetCAProperty");
  493. }
  494. else
  495. {
  496. _PrintError(hr, "Admin2_CAProperty down level server");
  497. fV1 = TRUE;
  498. }
  499. }
  500. if (fV1)
  501. {
  502. if (NULL != pwszIndex)
  503. {
  504. hr = cuGetCAInfo(
  505. pwszOption,
  506. pwszfnOut,
  507. g_wszCAInfoCRL,
  508. pwszIndex);
  509. _JumpIfError(hr, error, "cuGetCAInfo");
  510. }
  511. else
  512. {
  513. hr = Admin_GetCRL(
  514. &diAdmin,
  515. g_pwszConfig,
  516. CR_OUT_BINARY,
  517. &strCRL);
  518. _JumpIfError(hr, error, "Admin_GetCRL");
  519. }
  520. }
  521. }
  522. // if not already saved by cuGetCAInfo
  523. if (NULL != strCRL)
  524. {
  525. hr = EncodeToFileW(
  526. pwszfnOut,
  527. (BYTE const *) strCRL,
  528. SysStringByteLen(strCRL),
  529. CRYPT_STRING_BINARY | g_EncodeFlags);
  530. _JumpIfError(hr, error, "EncodeToFileW");
  531. }
  532. error:
  533. if (fMustRelease)
  534. {
  535. Admin_Release(&diAdmin);
  536. }
  537. if (NULL != strCRL)
  538. {
  539. SysFreeString(strCRL);
  540. }
  541. return(hr);
  542. }
  543. HRESULT
  544. BuildDummyCert(
  545. IN CERT_CONTEXT const *pCert,
  546. IN WCHAR const *pwszSerialNumber,
  547. IN CHAR const *pszObjId,
  548. OUT BYTE **ppbCert,
  549. OUT DWORD *pcbCert)
  550. {
  551. HRESULT hr;
  552. CERT_INFO CertInfoOut;
  553. CERT_INFO const *pCertInfo;
  554. BYTE *pbUnsigned = NULL;
  555. DWORD cbUnsigned;
  556. CERT_CONTEXT CertContext;
  557. WCHAR *pwszContainer = NULL;
  558. HCRYPTPROV hProv = NULL;
  559. CERT_PUBLIC_KEY_INFO *pPubKey = NULL;
  560. DWORD cbPubKey;
  561. CERT_EXTENSION extSKI = {szOID_SUBJECT_KEY_IDENTIFIER, FALSE, 0, NULL};
  562. CERT_EXTENSION extAKI = {szOID_AUTHORITY_KEY_IDENTIFIER2, FALSE, 0, NULL};
  563. CERT_EXTENSION aExt[2];
  564. CERT_EXTENSION *pExt;
  565. CRYPT_DATA_BLOB *pBlob = NULL;
  566. DWORD cb;
  567. *ppbCert = NULL;
  568. ZeroMemory(&CertInfoOut, sizeof(CertInfoOut));
  569. pCertInfo = pCert->pCertInfo;
  570. CertInfoOut.Issuer = pCertInfo->Issuer;
  571. CertInfoOut.NotBefore = pCertInfo->NotBefore;
  572. CertInfoOut.NotAfter = pCertInfo->NotAfter;
  573. CertInfoOut.SignatureAlgorithm.pszObjId = const_cast<CHAR *>(pszObjId);
  574. hr = WszToMultiByteInteger(
  575. FALSE,
  576. pwszSerialNumber,
  577. &CertInfoOut.SerialNumber.cbData,
  578. &CertInfoOut.SerialNumber.pbData);
  579. _JumpIfError(hr, error, "WszToMultiByteInteger");
  580. hr = myCertStrToName(
  581. X509_ASN_ENCODING,
  582. L"CN=Dummy", // pszX500
  583. CERT_NAME_STR_REVERSE_FLAG,
  584. NULL, // pvReserved
  585. &CertInfoOut.Subject.pbData,
  586. &CertInfoOut.Subject.cbData,
  587. NULL); // ppszError
  588. _JumpIfError(hr, error, "myCertStrToName");
  589. ZeroMemory(&CertContext, sizeof(CertContext));
  590. CertContext.dwCertEncodingType = X509_ASN_ENCODING;
  591. CertContext.pCertInfo = &CertInfoOut;
  592. hr = cuGenerateKeyContainerName(&CertContext, &pwszContainer);
  593. _JumpIfError(hr, error, "cuGenerateKeyContainerName");
  594. hr = myGenerateKeys(
  595. pwszContainer,
  596. NULL, // pwszProvName
  597. 0, // dwFlags
  598. FALSE, // fMachineKeySet
  599. AT_SIGNATURE,
  600. PROV_RSA_FULL,
  601. 0, // dwKeySize (use default)
  602. &hProv);
  603. _JumpIfError(hr, error, "myGenerateKeys");
  604. if (!myCryptExportPublicKeyInfo(
  605. hProv,
  606. AT_SIGNATURE,
  607. CERTLIB_USE_LOCALALLOC,
  608. &pPubKey,
  609. &cbPubKey))
  610. {
  611. hr = myHLastError();
  612. _JumpError(hr, error, "myCryptExportPublicKeyInfo");
  613. }
  614. CertInfoOut.SubjectPublicKeyInfo = *pPubKey; // Structure assignment
  615. // Subject Key Identifier extension:
  616. hr = myCreateSubjectKeyIdentifierExtension(
  617. pPubKey,
  618. &extSKI.Value.pbData,
  619. &extSKI.Value.cbData);
  620. _JumpIfError(hr, error, "myCreateSubjectKeyIdentifierExtension");
  621. CertInfoOut.rgExtension = aExt;
  622. aExt[CertInfoOut.cExtension] = extSKI;
  623. CertInfoOut.cExtension++;
  624. //AKI extension?
  625. pExt = CertFindExtension(
  626. szOID_SUBJECT_KEY_IDENTIFIER,
  627. pCertInfo->cExtension,
  628. pCertInfo->rgExtension);
  629. if (NULL != pExt)
  630. {
  631. CERT_AUTHORITY_KEY_ID2_INFO AKI;
  632. if (!myDecodeObject(
  633. X509_ASN_ENCODING,
  634. X509_OCTET_STRING,
  635. pExt->Value.pbData,
  636. pExt->Value.cbData,
  637. CERTLIB_USE_LOCALALLOC,
  638. (VOID **) &pBlob,
  639. &cb))
  640. {
  641. hr = myHLastError();
  642. _JumpError(hr, error, "myDecodeObject");
  643. }
  644. ZeroMemory(&AKI, sizeof(AKI));
  645. AKI.KeyId = *pBlob;
  646. if (!myEncodeKeyAuthority2(
  647. X509_ASN_ENCODING,
  648. &AKI,
  649. CERTLIB_USE_LOCALALLOC,
  650. &extAKI.Value.pbData,
  651. &extAKI.Value.cbData))
  652. {
  653. hr = myHLastError();
  654. _JumpError(hr, error, "myEncodeKeyAuthority2");
  655. }
  656. aExt[CertInfoOut.cExtension] = extAKI;
  657. CertInfoOut.cExtension++;
  658. }
  659. CertInfoOut.dwVersion = CERT_V3;
  660. if (!myEncodeObject(
  661. X509_ASN_ENCODING,
  662. X509_CERT_TO_BE_SIGNED,
  663. &CertInfoOut,
  664. 0,
  665. CERTLIB_USE_LOCALALLOC,
  666. &pbUnsigned, // pbEncoded
  667. &cbUnsigned))
  668. {
  669. hr = myHLastError();
  670. _JumpError(hr, error, "myEncodeObject");
  671. }
  672. *ppbCert = pbUnsigned;
  673. pbUnsigned = NULL;
  674. *pcbCert = cbUnsigned;
  675. hr = S_OK;
  676. error:
  677. if (NULL != pbUnsigned)
  678. {
  679. LocalFree(pbUnsigned);
  680. }
  681. if (NULL != pBlob)
  682. {
  683. LocalFree(pBlob);
  684. }
  685. if (NULL != extSKI.Value.pbData)
  686. {
  687. LocalFree(extSKI.Value.pbData);
  688. }
  689. if (NULL != extAKI.Value.pbData)
  690. {
  691. LocalFree(extAKI.Value.pbData);
  692. }
  693. if (NULL != CertInfoOut.SerialNumber.pbData)
  694. {
  695. LocalFree(CertInfoOut.SerialNumber.pbData);
  696. }
  697. if (NULL != CertInfoOut.Subject.pbData)
  698. {
  699. LocalFree(CertInfoOut.Subject.pbData);
  700. }
  701. if (NULL != pPubKey)
  702. {
  703. LocalFree(pPubKey);
  704. }
  705. if (NULL != hProv)
  706. {
  707. CryptReleaseContext(hProv, 0);
  708. if (NULL != pwszContainer)
  709. {
  710. CryptAcquireContext(
  711. &hProv,
  712. pwszContainer,
  713. NULL, // pwszProvName
  714. PROV_RSA_FULL,
  715. CRYPT_DELETEKEYSET);
  716. }
  717. }
  718. if (NULL != pwszContainer)
  719. {
  720. LocalFree(pwszContainer);
  721. }
  722. return(hr);
  723. }
  724. HRESULT
  725. FindCertAndSign(
  726. OPTIONAL IN CERT_EXTENSION const *pExtKeyId,
  727. OPTIONAL IN BYTE const *pbHash,
  728. IN DWORD cbHash,
  729. OPTIONAL IN BYTE const *pbUnsigned,
  730. IN DWORD cbUnsigned,
  731. OPTIONAL IN WCHAR const *pwszSerialNumber,
  732. OUT BYTE **ppbOut,
  733. OUT DWORD *pcbOut)
  734. {
  735. HRESULT hr;
  736. CERT_AUTHORITY_KEY_ID2_INFO *pKeyId = NULL;
  737. DWORD cbKeyId;
  738. BSTR strKeyId = NULL;
  739. CERT_CONTEXT const *pCert = NULL;
  740. HCRYPTPROV hProv = NULL;
  741. DWORD dwKeySpec;
  742. BOOL fCallerFreeProv;
  743. CHAR *pszObjId = NULL;
  744. BYTE *pbCert = NULL;
  745. DWORD cbCert;
  746. *ppbOut = NULL;
  747. CSASSERT(NULL != pbUnsigned || NULL != pwszSerialNumber);
  748. if (NULL == pbHash && NULL != pExtKeyId)
  749. {
  750. if (!myDecodeObject(
  751. X509_ASN_ENCODING,
  752. X509_AUTHORITY_KEY_ID2,
  753. pExtKeyId->Value.pbData,
  754. pExtKeyId->Value.cbData,
  755. CERTLIB_USE_LOCALALLOC,
  756. (VOID **) &pKeyId,
  757. &cbKeyId))
  758. {
  759. hr = myHLastError();
  760. _JumpError(hr, error, "myDecodeObject");
  761. }
  762. pbHash = pKeyId->KeyId.pbData;
  763. cbHash = pKeyId->KeyId.cbData;
  764. }
  765. if (0 != cbHash && NULL != pbHash)
  766. {
  767. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strKeyId);
  768. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  769. }
  770. // Find CA cert by KeyId from the szOID_AUTHORITY_KEY_IDENTIFIER2 extension.
  771. // Look in HKLM and HKCU My and CA stores.
  772. hr = myGetCertificateFromPicker(
  773. g_hInstance,
  774. NULL, // hwndParent
  775. IDS_GETCERT_TITLE,
  776. IDS_GETCERT_SUBTITLE,
  777. // dwFlags: HKLM+HKCU My store
  778. CUCS_MYSTORE |
  779. CUCS_MACHINESTORE |
  780. CUCS_USERSTORE |
  781. CUCS_PRIVATEKEYREQUIRED |
  782. CUCS_ARCHIVED |
  783. (g_fCryptSilent? CUCS_SILENT : 0),
  784. strKeyId,
  785. 0,
  786. NULL,
  787. 0, // cpszObjId
  788. NULL, // apszObjId
  789. &pCert);
  790. _JumpIfError(hr, error, "myGetCertificateFromPicker");
  791. if (NULL == pCert)
  792. {
  793. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  794. _JumpError(hr, error, "no cert");
  795. }
  796. hr = cuDisplayCertName(
  797. TRUE,
  798. NULL,
  799. myLoadResourceString(IDS_SIGNINGSUBJECT), // "Signing certificate Subject"
  800. g_wszPad4,
  801. &pCert->pCertInfo->Subject,
  802. pCert->pCertInfo);
  803. _JumpIfError(hr, error, "cuDisplayCertName(Subject)");
  804. // Search for and load the cryptographic provider and private key.
  805. hr = myLoadPrivateKey(
  806. &pCert->pCertInfo->SubjectPublicKeyInfo,
  807. CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_MYSTORE | CUCS_ARCHIVED,
  808. &hProv,
  809. &dwKeySpec,
  810. &fCallerFreeProv);
  811. _JumpIfError(hr, error, "myLoadPrivateKey");
  812. if (AT_SIGNATURE != dwKeySpec)
  813. {
  814. hr = NTE_BAD_KEY_STATE;
  815. DBGPRINT((DBG_SS_CERTUTIL, "dwKeySpec = %u\n", dwKeySpec));
  816. _JumpError(hr, error, "dwKeySpec");
  817. }
  818. // The CA cert's private key is available -- use it to sign the data.
  819. // Sign the Cert or CRL and encode the signed info.
  820. hr = myGetSigningOID(hProv, NULL, 0, CALG_SHA1, &pszObjId);
  821. _JumpIfError(hr, error, "myGetSigningOID");
  822. if (NULL != pwszSerialNumber)
  823. {
  824. hr = BuildDummyCert(
  825. pCert,
  826. pwszSerialNumber,
  827. pszObjId,
  828. &pbCert,
  829. &cbCert);
  830. _JumpIfError(hr, error, "BuildDummyCert");
  831. pbUnsigned = pbCert;
  832. cbUnsigned = cbCert;
  833. }
  834. hr = myEncodeSignedContent(
  835. hProv,
  836. X509_ASN_ENCODING,
  837. pszObjId,
  838. const_cast<BYTE *>(pbUnsigned),
  839. cbUnsigned,
  840. CERTLIB_USE_LOCALALLOC,
  841. ppbOut,
  842. pcbOut);
  843. _JumpIfError(hr, error, "myEncodeSignedContent");
  844. error:
  845. if (NULL != pbCert)
  846. {
  847. LocalFree(pbCert);
  848. }
  849. if (NULL != pszObjId)
  850. {
  851. LocalFree(pszObjId);
  852. }
  853. if (NULL != pKeyId)
  854. {
  855. LocalFree(pKeyId);
  856. }
  857. if (NULL != strKeyId)
  858. {
  859. SysFreeString(strKeyId);
  860. }
  861. if (NULL != pCert)
  862. {
  863. CertFreeCertificateContext(pCert);
  864. }
  865. if (NULL != hProv && fCallerFreeProv)
  866. {
  867. CryptReleaseContext(hProv, 0);
  868. }
  869. return(hr);
  870. }
  871. VOID
  872. SetExpiration(
  873. OPTIONAL IN FILETIME const *pftNotAfterNew,
  874. IN OUT FILETIME *pftNotBefore,
  875. OPTIONAL IN OUT FILETIME *pftNotAfter)
  876. {
  877. if (NULL == pftNotAfterNew ||
  878. 0 != pftNotAfterNew->dwLowDateTime ||
  879. 0 != pftNotAfterNew->dwHighDateTime)
  880. {
  881. LLFILETIME llftNotBefore;
  882. LLFILETIME llft;
  883. LLFILETIME llftDelta;
  884. llftNotBefore.ft = *pftNotBefore; // Save orignal value
  885. // current time - clock skew
  886. GetSystemTimeAsFileTime(&llft.ft);
  887. llftDelta.ll = CCLOCKSKEWMINUTESDEFAULT * CVT_MINUTES;
  888. llftDelta.ll *= CVT_BASE;
  889. llft.ll -= llftDelta.ll;
  890. // NotBeforeOut = oldest of NotBefore, (CurrentTime - skew)
  891. if (llftNotBefore.ll > llft.ll)
  892. {
  893. *pftNotBefore = llft.ft;
  894. }
  895. if (NULL != pftNotAfter)
  896. {
  897. LLFILETIME llftNotAfter;
  898. llftNotAfter.ft = *pftNotAfter; // Save orignal value
  899. if (NULL != pftNotAfterNew)
  900. {
  901. *pftNotAfter = *pftNotAfterNew;
  902. }
  903. else
  904. {
  905. // NotAfterOut = (CurrentTime - skew) + (NotAfter - NotBefore);
  906. llft.ll += llftNotAfter.ll;
  907. llft.ll -= llftNotBefore.ll;
  908. *pftNotAfter = llft.ft;
  909. }
  910. }
  911. }
  912. }
  913. HRESULT
  914. RemoveExtensions(
  915. IN WCHAR const * const *ppwszObjIdList,
  916. IN BOOL fValidate,
  917. IN DWORD cExtensionIn,
  918. IN CERT_EXTENSION *rgExtensionIn,
  919. OUT DWORD *pcExtensionOut,
  920. OUT CERT_EXTENSION **prgExtensionOut)
  921. {
  922. HRESULT hr;
  923. DWORD cExtension = cExtensionIn;
  924. CERT_EXTENSION *rgExtension = NULL;
  925. *prgExtensionOut = NULL;
  926. rgExtension = (CERT_EXTENSION *) LocalAlloc(
  927. LMEM_FIXED,
  928. cExtension * sizeof(rgExtension[0]));
  929. if (NULL == rgExtension)
  930. {
  931. hr = E_OUTOFMEMORY;
  932. _JumpError(hr, error, "LocalAlloc");
  933. }
  934. CopyMemory(
  935. rgExtension,
  936. rgExtensionIn,
  937. cExtension * sizeof(rgExtension[0]));
  938. if (NULL != ppwszObjIdList)
  939. {
  940. DWORD i;
  941. for (i = 0; NULL != ppwszObjIdList[i]; i++)
  942. {
  943. WCHAR const *pwszObjId = ppwszObjIdList[i];
  944. char *pszObjId;
  945. CERT_EXTENSION *pExt;
  946. hr = myVerifyObjId(pwszObjId);
  947. if (S_OK != hr)
  948. {
  949. if (fValidate)
  950. {
  951. _JumpError(hr, error, "myVerifyObjId");
  952. }
  953. continue;
  954. }
  955. if (!myConvertWszToSz(&pszObjId, pwszObjId, -1))
  956. {
  957. hr = E_OUTOFMEMORY;
  958. _JumpError(hr, error, "myConvertWszToSz");
  959. }
  960. pExt = CertFindExtension(pszObjId, cExtension, rgExtension);
  961. if (NULL != pExt)
  962. {
  963. DWORD iDel = SAFE_SUBTRACT_POINTERS(pExt, rgExtension);
  964. // wprintf(L"iDel=%u cExt=%u\n", iDel, cExtension);
  965. if (iDel < cExtension)
  966. {
  967. // wprintf(L"copy %u to %u, len=%u\n", iDel + 1, iDel, cExtension - iDel - 1);
  968. MoveMemory(
  969. &rgExtension[iDel],
  970. &rgExtension[iDel + 1],
  971. (cExtension - iDel - 1) * sizeof(rgExtension[iDel]));
  972. }
  973. cExtension--;
  974. }
  975. LocalFree(pszObjId);
  976. }
  977. }
  978. *pcExtensionOut = cExtension;
  979. *prgExtensionOut = rgExtension;
  980. rgExtension = NULL;
  981. hr = S_OK;
  982. error:
  983. if (NULL != rgExtension)
  984. {
  985. LocalFree(rgExtension);
  986. }
  987. return(hr);
  988. }
  989. CRL_ENTRY *
  990. FindCRLEntry(
  991. IN DWORD cbSerial,
  992. IN BYTE const *pbSerial,
  993. IN DWORD cCRLEntry,
  994. IN CRL_ENTRY *rgCRLEntry)
  995. {
  996. CRL_ENTRY *pCRLEntry = NULL;
  997. CRL_ENTRY *rgCRLEntryEnd = &rgCRLEntry[cCRLEntry];
  998. for ( ; rgCRLEntry < rgCRLEntryEnd; rgCRLEntry++)
  999. {
  1000. if (cbSerial == rgCRLEntry->SerialNumber.cbData &&
  1001. 0 == memcmp(pbSerial, rgCRLEntry->SerialNumber.pbData, cbSerial))
  1002. {
  1003. pCRLEntry = rgCRLEntry;
  1004. break;
  1005. }
  1006. }
  1007. return(pCRLEntry);
  1008. }
  1009. HRESULT
  1010. AddRemoveSerial(
  1011. IN WCHAR const * const *ppwszSerialList,
  1012. IN BOOL fAdd,
  1013. IN DWORD cCRLEntryIn,
  1014. IN CRL_ENTRY *rgCRLEntryIn,
  1015. OUT DWORD *pcCRLEntryOut,
  1016. OUT CRL_ENTRY **prgCRLEntryOut,
  1017. OUT DWORD *pcSerialNew,
  1018. OUT BYTE ***prgpbSerialNew)
  1019. {
  1020. HRESULT hr;
  1021. DWORD cCRLEntry = cCRLEntryIn;
  1022. CRL_ENTRY *rgCRLEntry = NULL;
  1023. DWORD cAdd;
  1024. BYTE **rgpbSerialNew = NULL;
  1025. DWORD cSerialNew;
  1026. FILETIME ftCurrent;
  1027. *prgCRLEntryOut = NULL;
  1028. *prgpbSerialNew = NULL;
  1029. cAdd = 0;
  1030. if (fAdd)
  1031. {
  1032. for (cAdd = 0; NULL != ppwszSerialList[cAdd]; cAdd++)
  1033. ;
  1034. cSerialNew = 0;
  1035. rgpbSerialNew = (BYTE **) LocalAlloc(
  1036. LMEM_FIXED,
  1037. cAdd * sizeof(rgpbSerialNew[0]));
  1038. if (NULL == rgpbSerialNew)
  1039. {
  1040. hr = E_OUTOFMEMORY;
  1041. _JumpError(hr, error, "LocalAlloc");
  1042. }
  1043. GetSystemTimeAsFileTime(&ftCurrent);
  1044. }
  1045. rgCRLEntry = (CRL_ENTRY *) LocalAlloc(
  1046. LMEM_FIXED,
  1047. (cCRLEntry + cAdd) * sizeof(rgCRLEntry[0]));
  1048. if (NULL == rgCRLEntry)
  1049. {
  1050. hr = E_OUTOFMEMORY;
  1051. _JumpError(hr, error, "LocalAlloc");
  1052. }
  1053. CopyMemory(
  1054. rgCRLEntry,
  1055. rgCRLEntryIn,
  1056. cCRLEntry * sizeof(rgCRLEntry[0]));
  1057. if (NULL != ppwszSerialList)
  1058. {
  1059. DWORD i;
  1060. for (i = 0; NULL != ppwszSerialList[i]; i++)
  1061. {
  1062. WCHAR const *pwszSerial = ppwszSerialList[i];
  1063. CRL_ENTRY *pCRLEntry;
  1064. DWORD cbSerial;
  1065. BYTE *pbSerial;
  1066. hr = myVerifyObjId(pwszSerial);
  1067. if (S_OK == hr)
  1068. {
  1069. continue; // skip OIDs
  1070. }
  1071. hr = WszToMultiByteInteger(
  1072. FALSE,
  1073. pwszSerial,
  1074. &cbSerial,
  1075. &pbSerial);
  1076. _JumpIfErrorStr(hr, error, "WszToMultiByteInteger", pwszSerial);
  1077. pCRLEntry = FindCRLEntry(
  1078. cbSerial,
  1079. pbSerial,
  1080. cCRLEntry,
  1081. rgCRLEntry);
  1082. if (fAdd)
  1083. {
  1084. if (NULL == pCRLEntry)
  1085. {
  1086. pCRLEntry = &rgCRLEntry[cCRLEntry];
  1087. ZeroMemory(pCRLEntry, sizeof(*pCRLEntry));
  1088. pCRLEntry->SerialNumber.pbData = pbSerial;
  1089. pCRLEntry->SerialNumber.cbData = cbSerial;
  1090. pCRLEntry->RevocationDate = ftCurrent;
  1091. cCRLEntry++;
  1092. rgpbSerialNew[cSerialNew++] = pbSerial;
  1093. pbSerial = NULL;
  1094. }
  1095. }
  1096. else
  1097. {
  1098. if (NULL != pCRLEntry)
  1099. {
  1100. DWORD iDel = SAFE_SUBTRACT_POINTERS(pCRLEntry, rgCRLEntry);
  1101. if (iDel < cCRLEntry)
  1102. {
  1103. MoveMemory(
  1104. &rgCRLEntry[iDel],
  1105. &rgCRLEntry[iDel + 1],
  1106. (cCRLEntry - iDel - 1) * sizeof(rgCRLEntry[iDel]));
  1107. }
  1108. cCRLEntry--;
  1109. }
  1110. }
  1111. if (NULL != pbSerial)
  1112. {
  1113. LocalFree(pbSerial);
  1114. }
  1115. }
  1116. }
  1117. *pcCRLEntryOut = cCRLEntry;
  1118. *prgCRLEntryOut = rgCRLEntry;
  1119. rgCRLEntry = NULL;
  1120. *pcSerialNew = cSerialNew;
  1121. *prgpbSerialNew = rgpbSerialNew;
  1122. rgpbSerialNew = NULL;
  1123. hr = S_OK;
  1124. error:
  1125. if (NULL != rgCRLEntry)
  1126. {
  1127. LocalFree(rgCRLEntry);
  1128. }
  1129. if (NULL != rgpbSerialNew)
  1130. {
  1131. DWORD i;
  1132. for (i = 0; i < cSerialNew; i++)
  1133. {
  1134. if (NULL != rgpbSerialNew[i])
  1135. {
  1136. LocalFree(rgpbSerialNew[i]);
  1137. }
  1138. }
  1139. LocalFree(rgpbSerialNew);
  1140. }
  1141. return(hr);
  1142. }
  1143. HRESULT
  1144. SignCRL(
  1145. IN CRL_CONTEXT const *pCRLContext,
  1146. OPTIONAL IN FILETIME const *pftNextUpdate,
  1147. IN BOOL fAdd,
  1148. IN WCHAR const * const *ppwszSerialList,
  1149. OUT BYTE **ppbOut,
  1150. OUT DWORD *pcbOut)
  1151. {
  1152. HRESULT hr;
  1153. CRL_INFO const *pCRLInfo;
  1154. CRL_INFO CRLInfoOut;
  1155. BYTE *pbUnsigned = NULL;
  1156. DWORD cbUnsigned;
  1157. CERT_EXTENSION *pExtKeyId;
  1158. CERT_EXTENSION *rgExtension = NULL;
  1159. CRL_ENTRY *rgCRLEntry = NULL;
  1160. DWORD cSerialNew;
  1161. BYTE **rgpbSerialNew = NULL;
  1162. ZeroMemory(&CRLInfoOut, sizeof(CRLInfoOut));
  1163. *ppbOut = NULL;
  1164. // CRL extensions to strip out of the re-signed CRL:
  1165. static WCHAR const * const apwszObjIdFilter[] = {
  1166. TEXT(szOID_CRL_NEXT_PUBLISH),
  1167. NULL
  1168. };
  1169. static WCHAR const * const apwszObjIdFilterNull[] = {
  1170. NULL
  1171. };
  1172. pCRLInfo = pCRLContext->pCrlInfo;
  1173. CRLInfoOut = *pCRLInfo;
  1174. SetExpiration(
  1175. pftNextUpdate,
  1176. &CRLInfoOut.ThisUpdate,
  1177. (0 != CRLInfoOut.NextUpdate.dwLowDateTime ||
  1178. 0 != CRLInfoOut.NextUpdate.dwHighDateTime)?
  1179. &CRLInfoOut.NextUpdate : NULL);
  1180. hr = cuDumpFileTime(IDS_THISUPDATE, NULL, &CRLInfoOut.ThisUpdate);
  1181. _JumpIfError(hr, error, "cuDumpFileTime");
  1182. hr = cuDumpFileTime(IDS_NEXTUPDATE, NULL, &CRLInfoOut.NextUpdate);
  1183. _JumpIfError(hr, error, "cuDumpFileTime");
  1184. wprintf(myLoadResourceString(IDS_CRLENTRIES)); // "CRL Entries:"
  1185. wprintf(L" %u\n", pCRLInfo->cCRLEntry);
  1186. wprintf(wszNewLine);
  1187. pExtKeyId = CertFindExtension(
  1188. szOID_AUTHORITY_KEY_IDENTIFIER2,
  1189. pCRLInfo->cExtension,
  1190. pCRLInfo->rgExtension);
  1191. hr = RemoveExtensions(
  1192. (NULL == pftNextUpdate ||
  1193. 0 != pftNextUpdate->dwLowDateTime ||
  1194. 0 != pftNextUpdate->dwHighDateTime)?
  1195. apwszObjIdFilter : apwszObjIdFilterNull,
  1196. TRUE,
  1197. CRLInfoOut.cExtension,
  1198. CRLInfoOut.rgExtension,
  1199. &CRLInfoOut.cExtension,
  1200. &rgExtension);
  1201. _JumpIfError(hr, error, "RemoveExtensions");
  1202. CRLInfoOut.rgExtension = rgExtension;
  1203. if (!fAdd)
  1204. {
  1205. CERT_EXTENSION *rgExtension2 = rgExtension;
  1206. hr = RemoveExtensions(
  1207. ppwszSerialList,
  1208. FALSE,
  1209. CRLInfoOut.cExtension,
  1210. CRLInfoOut.rgExtension,
  1211. &CRLInfoOut.cExtension,
  1212. &rgExtension);
  1213. _JumpIfError(hr, error, "RemoveExtensions");
  1214. if (NULL != rgExtension2)
  1215. {
  1216. LocalFree(rgExtension2);
  1217. }
  1218. CRLInfoOut.rgExtension = rgExtension;
  1219. }
  1220. hr = AddRemoveSerial(
  1221. ppwszSerialList,
  1222. fAdd,
  1223. CRLInfoOut.cCRLEntry,
  1224. CRLInfoOut.rgCRLEntry,
  1225. &CRLInfoOut.cCRLEntry,
  1226. &rgCRLEntry,
  1227. &cSerialNew,
  1228. &rgpbSerialNew);
  1229. _JumpIfError(hr, error, "AddRemoveSerial");
  1230. CRLInfoOut.rgCRLEntry = rgCRLEntry;
  1231. if (!myEncodeObject(
  1232. X509_ASN_ENCODING,
  1233. X509_CERT_CRL_TO_BE_SIGNED,
  1234. &CRLInfoOut,
  1235. 0,
  1236. CERTLIB_USE_LOCALALLOC,
  1237. &pbUnsigned, // pbEncoded
  1238. &cbUnsigned))
  1239. {
  1240. hr = myHLastError();
  1241. _JumpError(hr, error, "myEncodeObject");
  1242. }
  1243. hr = FindCertAndSign(
  1244. pExtKeyId,
  1245. NULL,
  1246. 0,
  1247. pbUnsigned,
  1248. cbUnsigned,
  1249. NULL, // pwszSerialNumber
  1250. ppbOut,
  1251. pcbOut);
  1252. _JumpIfError(hr, error, "FindCertAndSign");
  1253. error:
  1254. if (NULL != rgpbSerialNew)
  1255. {
  1256. DWORD i;
  1257. for (i = 0; i < cSerialNew; i++)
  1258. {
  1259. if (NULL != rgpbSerialNew[i])
  1260. {
  1261. LocalFree(rgpbSerialNew[i]);
  1262. }
  1263. }
  1264. LocalFree(rgpbSerialNew);
  1265. }
  1266. if (NULL != rgCRLEntry)
  1267. {
  1268. LocalFree(rgCRLEntry);
  1269. }
  1270. if (NULL != rgExtension)
  1271. {
  1272. LocalFree(rgExtension);
  1273. }
  1274. if (NULL != pbUnsigned)
  1275. {
  1276. LocalFree(pbUnsigned);
  1277. }
  1278. return(hr);
  1279. }
  1280. HRESULT
  1281. SignCert(
  1282. IN CERT_CONTEXT const *pCertContext,
  1283. OPTIONAL IN WCHAR const *pwszSerialNumber,
  1284. OPTIONAL IN FILETIME const *pftNotAfter,
  1285. OPTIONAL IN WCHAR const * const *ppwszObjIdList,
  1286. OUT BYTE **ppbOut,
  1287. OUT DWORD *pcbOut)
  1288. {
  1289. HRESULT hr;
  1290. CERT_INFO const *pCertInfo;
  1291. BYTE *pbUnsigned = NULL;
  1292. DWORD cbUnsigned;
  1293. BYTE const *pbHash;
  1294. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  1295. DWORD cbHash;
  1296. CERT_EXTENSION *pExtKeyId;
  1297. CERT_EXTENSION *rgExtension = NULL;
  1298. *ppbOut = NULL;
  1299. pExtKeyId = NULL;
  1300. if (NULL != pCertContext)
  1301. {
  1302. CERT_INFO CertInfoOut;
  1303. ZeroMemory(&CertInfoOut, sizeof(CertInfoOut));
  1304. pCertInfo = pCertContext->pCertInfo;
  1305. CertInfoOut = *pCertInfo;
  1306. SetExpiration(pftNotAfter, &CertInfoOut.NotBefore, &CertInfoOut.NotAfter);
  1307. hr = cuDumpFileTime(IDS_NOTBEFORE, NULL, &CertInfoOut.NotBefore);
  1308. _JumpIfError(hr, error, "cuDumpFileTime");
  1309. hr = cuDumpFileTime(IDS_NOTAFTER, NULL, &CertInfoOut.NotAfter);
  1310. _JumpIfError(hr, error, "cuDumpFileTime");
  1311. wprintf(wszNewLine);
  1312. pbHash = NULL;
  1313. pExtKeyId = CertFindExtension(
  1314. szOID_AUTHORITY_KEY_IDENTIFIER2,
  1315. pCertInfo->cExtension,
  1316. pCertInfo->rgExtension);
  1317. if (NULL == pExtKeyId)
  1318. {
  1319. hr = cuVerifySignature(
  1320. pCertContext->pbCertEncoded,
  1321. pCertContext->cbCertEncoded,
  1322. &pCertContext->pCertInfo->SubjectPublicKeyInfo,
  1323. FALSE,
  1324. TRUE);
  1325. if (S_OK == hr)
  1326. {
  1327. if (CertGetCertificateContextProperty(
  1328. pCertContext,
  1329. CERT_KEY_IDENTIFIER_PROP_ID,
  1330. abHash,
  1331. &cbHash))
  1332. {
  1333. pbHash = abHash;
  1334. }
  1335. }
  1336. }
  1337. hr = RemoveExtensions(
  1338. ppwszObjIdList,
  1339. TRUE,
  1340. CertInfoOut.cExtension,
  1341. CertInfoOut.rgExtension,
  1342. &CertInfoOut.cExtension,
  1343. &rgExtension);
  1344. _JumpIfError(hr, error, "RemoveExtensions");
  1345. CertInfoOut.rgExtension = rgExtension;
  1346. if (0 == CertInfoOut.cExtension)
  1347. {
  1348. CertInfoOut.dwVersion = CERT_V1;
  1349. }
  1350. if (!myEncodeObject(
  1351. X509_ASN_ENCODING,
  1352. X509_CERT_TO_BE_SIGNED,
  1353. &CertInfoOut,
  1354. 0,
  1355. CERTLIB_USE_LOCALALLOC,
  1356. &pbUnsigned, // pbEncoded
  1357. &cbUnsigned))
  1358. {
  1359. hr = myHLastError();
  1360. _JumpError(hr, error, "myEncodeObject");
  1361. }
  1362. }
  1363. hr = FindCertAndSign(
  1364. pExtKeyId,
  1365. pbHash,
  1366. cbHash,
  1367. pbUnsigned,
  1368. cbUnsigned,
  1369. pwszSerialNumber,
  1370. ppbOut,
  1371. pcbOut);
  1372. _JumpIfError(hr, error, "FindCertAndSign");
  1373. error:
  1374. if (NULL != rgExtension)
  1375. {
  1376. LocalFree(rgExtension);
  1377. }
  1378. if (NULL != pbUnsigned)
  1379. {
  1380. LocalFree(pbUnsigned);
  1381. }
  1382. return(hr);
  1383. }
  1384. HRESULT
  1385. verbSign(
  1386. IN WCHAR const *pwszOption,
  1387. IN WCHAR const *pwszfnIn,
  1388. IN WCHAR const *pwszfnOut,
  1389. OPTIONAL IN WCHAR const *pwszDaysHours,
  1390. OPTIONAL IN WCHAR const *pwszChangeList)
  1391. {
  1392. HRESULT hr;
  1393. FILETIME ftNextUpdate;
  1394. FILETIME *pftNextUpdate;
  1395. CRL_CONTEXT const *pCRLContext = NULL;
  1396. CERT_CONTEXT const *pCertContext = NULL;
  1397. BYTE *pbOut = NULL;
  1398. DWORD cbOut;
  1399. BOOL fAdd = FALSE;
  1400. WCHAR **ppwszList = NULL;
  1401. BSTR strSerialNumber = NULL;
  1402. pftNextUpdate = NULL;
  1403. if (NULL != pwszDaysHours &&
  1404. (myIsMinusSign(*pwszDaysHours) || L'+' == *pwszDaysHours))
  1405. {
  1406. WCHAR const *pwsz = pwszDaysHours;
  1407. pwszDaysHours = pwszChangeList;
  1408. pwszChangeList = pwsz;
  1409. }
  1410. if (NULL != pwszChangeList)
  1411. {
  1412. if (!myIsMinusSign(*pwszChangeList) && L'+' != *pwszChangeList)
  1413. {
  1414. hr = E_INVALIDARG;
  1415. _JumpError(hr, error, "missing +/-");
  1416. }
  1417. fAdd = L'+' == *pwszChangeList++;
  1418. hr = cuParseStrings(
  1419. pwszChangeList,
  1420. FALSE,
  1421. NULL,
  1422. NULL,
  1423. &ppwszList,
  1424. NULL);
  1425. _JumpIfError(hr, error, "cuParseStrings");
  1426. }
  1427. if (NULL != pwszDaysHours)
  1428. {
  1429. if (0 == lstrcmp(L"0", pwszDaysHours))
  1430. {
  1431. ZeroMemory(&ftNextUpdate, sizeof(ftNextUpdate));
  1432. }
  1433. else
  1434. {
  1435. hr = cuParseDaysHours(pwszDaysHours, &ftNextUpdate);
  1436. _JumpIfError(hr, error, "cuParseDaysHours");
  1437. }
  1438. pftNextUpdate = &ftNextUpdate;
  1439. }
  1440. if (NULL == pwszDaysHours &&
  1441. NULL == pwszChangeList &&
  1442. !myDoesFileExist(pwszfnIn))
  1443. {
  1444. hr = myMakeSerialBstr(pwszfnIn, &strSerialNumber);
  1445. _JumpIfError(hr, error, "myMakeSerialBstr");
  1446. hr = SignCert(
  1447. NULL, // pCertContext
  1448. strSerialNumber,
  1449. pftNextUpdate,
  1450. NULL, // ppwszObjIdList
  1451. &pbOut,
  1452. &cbOut);
  1453. _JumpIfError(hr, error, "SignCert");
  1454. }
  1455. else
  1456. {
  1457. // Load and decode CRL and certificate
  1458. hr = cuLoadCRL(pwszfnIn, &pCRLContext);
  1459. if (S_OK == hr)
  1460. {
  1461. hr = SignCRL(
  1462. pCRLContext,
  1463. pftNextUpdate,
  1464. fAdd,
  1465. ppwszList,
  1466. &pbOut,
  1467. &cbOut);
  1468. _JumpIfError(hr, error, "SignCRL");
  1469. }
  1470. else
  1471. {
  1472. hr = cuLoadCert(pwszfnIn, &pCertContext);
  1473. if (S_OK == hr)
  1474. {
  1475. if (fAdd)
  1476. {
  1477. hr = E_INVALIDARG;
  1478. _JumpError(hr, error, "cannot add extensions to cert");
  1479. }
  1480. hr = SignCert(
  1481. pCertContext,
  1482. NULL, // pwszSerialNumber
  1483. pftNextUpdate,
  1484. ppwszList,
  1485. &pbOut,
  1486. &cbOut);
  1487. _JumpIfError(hr, error, "SignCert");
  1488. }
  1489. else
  1490. {
  1491. cuPrintError(IDS_FORMAT_LOADTESTCRL, hr);
  1492. goto error;
  1493. }
  1494. }
  1495. }
  1496. // Write encoded & signed CRL or Cert to file
  1497. hr = EncodeToFileW(
  1498. pwszfnOut,
  1499. pbOut,
  1500. cbOut,
  1501. CRYPT_STRING_BINARY | g_EncodeFlags);
  1502. if (S_OK != hr)
  1503. {
  1504. cuPrintError(IDS_ERR_FORMAT_ENCODETOFILE, hr);
  1505. goto error;
  1506. }
  1507. wprintf(
  1508. myLoadResourceString(IDS_FORMAT_OUTPUT_LENGTH), // "Output Length = %d"
  1509. cuFileSize(pwszfnOut));
  1510. wprintf(wszNewLine);
  1511. hr = S_OK;
  1512. error:
  1513. if (NULL != strSerialNumber)
  1514. {
  1515. SysFreeString(strSerialNumber);
  1516. }
  1517. cuFreeStringArray(ppwszList);
  1518. if (NULL != pbOut)
  1519. {
  1520. LocalFree(pbOut);
  1521. }
  1522. cuUnloadCRL(&pCRLContext);
  1523. cuUnloadCert(&pCertContext);
  1524. return(hr);
  1525. }
  1526. HRESULT
  1527. verbShutDownServer(
  1528. IN WCHAR const *pwszOption,
  1529. IN WCHAR const *pwszArg1,
  1530. IN WCHAR const *pwszArg2,
  1531. IN WCHAR const *pwszArg3,
  1532. IN WCHAR const *pwszArg4)
  1533. {
  1534. HRESULT hr;
  1535. hr = CertSrvServerControl(g_pwszConfig, CSCONTROL_SHUTDOWN, NULL, NULL);
  1536. _JumpIfError(hr, error, "CertSrvServerControl");
  1537. error:
  1538. if (E_ACCESSDENIED == hr)
  1539. {
  1540. g_uiExtraErrorInfo = IDS_ERROR_ACCESSDENIED_CAUSE;
  1541. }
  1542. return(hr);
  1543. }
  1544. HRESULT
  1545. verbIsValidCertificate(
  1546. IN WCHAR const *pwszOption,
  1547. IN WCHAR const *pwszSerialNumber,
  1548. IN WCHAR const *pwszArg2,
  1549. IN WCHAR const *pwszArg3,
  1550. IN WCHAR const *pwszArg4)
  1551. {
  1552. HRESULT hr;
  1553. DISPATCHINTERFACE diAdmin;
  1554. BSTR strSerialNumber = NULL;
  1555. LONG Reason = CRL_REASON_KEY_COMPROMISE;
  1556. BOOL fMustRelease = FALSE;
  1557. LONG Disposition;
  1558. hr = myMakeSerialBstr(pwszSerialNumber, &strSerialNumber);
  1559. _JumpIfError(hr, error, "myMakeSerialBstr");
  1560. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  1561. _JumpIfError(hr, error, "Admin_Init");
  1562. fMustRelease = TRUE;
  1563. hr = Admin_IsValidCertificate(
  1564. &diAdmin,
  1565. g_pwszConfig,
  1566. strSerialNumber,
  1567. &Disposition);
  1568. _JumpIfError(hr, error, "Admin_IsValidCertificate");
  1569. switch (Disposition)
  1570. {
  1571. case CA_DISP_INVALID:
  1572. wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_INVALID), strSerialNumber); // "Certificate disposition for "%ws" is invalid"
  1573. wprintf(wszNewLine);
  1574. break;
  1575. case CA_DISP_VALID:
  1576. wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_VALID), strSerialNumber); // "Certificate disposition for "%ws" is valid"
  1577. wprintf(wszNewLine);
  1578. break;
  1579. case CA_DISP_UNDER_SUBMISSION:
  1580. wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_PENDING), strSerialNumber); // "Certificate request for "%ws" is pending"
  1581. wprintf(wszNewLine);
  1582. break;
  1583. case CA_DISP_REVOKED:
  1584. hr = Admin_GetRevocationReason(&diAdmin, &Reason);
  1585. if (S_OK != hr)
  1586. {
  1587. _PrintIfError(hr, "Admin_GetRevocationReason");
  1588. Reason = CRL_REASON_UNSPECIFIED;
  1589. }
  1590. wprintf(
  1591. myLoadResourceString(IDS_CERT_DISPOSITION_REVOKED), // "Certificate disposition for "%ws" is revoked (%ws)"
  1592. strSerialNumber,
  1593. wszCRLReason(Reason));
  1594. wprintf(wszNewLine);
  1595. break;
  1596. }
  1597. error:
  1598. if (fMustRelease)
  1599. {
  1600. Admin_Release(&diAdmin);
  1601. }
  1602. if (NULL != strSerialNumber)
  1603. {
  1604. SysFreeString(strSerialNumber);
  1605. }
  1606. return(hr);
  1607. }
  1608. #define wszREQUEST L"Request"
  1609. #define wszCERT L"Cert"
  1610. HRESULT
  1611. verbDeleteRow(
  1612. IN WCHAR const *pwszOption,
  1613. IN WCHAR const *pwszRowIdOrDate,
  1614. OPTIONAL IN WCHAR const *pwszTable,
  1615. IN WCHAR const *pwszArg3,
  1616. IN WCHAR const *pwszArg4)
  1617. {
  1618. HRESULT hr;
  1619. WCHAR *pwszLocalTime = NULL;
  1620. DISPATCHINTERFACE diAdmin;
  1621. BOOL fMustRelease = FALSE;
  1622. DWORD Flags;
  1623. LONG RowId;
  1624. DATE date;
  1625. LONG Table;
  1626. LONG Count;
  1627. hr = myGetLong(pwszRowIdOrDate, &RowId);
  1628. if (S_OK != hr)
  1629. {
  1630. FILETIME ftCurrent;
  1631. FILETIME ftQuery;
  1632. RowId = 0;
  1633. hr = myWszLocalTimeToGMTDate(pwszRowIdOrDate, &date);
  1634. _JumpIfError(hr, error, "invalid RowId or date");
  1635. hr = myGMTDateToWszLocalTime(&date, g_fSeconds, &pwszLocalTime);
  1636. _JumpIfError(hr, error, "myGMTDateToWszLocalTime");
  1637. GetSystemTimeAsFileTime(&ftCurrent);
  1638. hr = myDateToFileTime(&date, &ftQuery);
  1639. _JumpIfError(hr, error, "myDateToFileTime");
  1640. if (0 > CompareFileTime(&ftCurrent, &ftQuery))
  1641. {
  1642. wprintf(
  1643. myLoadResourceString(IDS_FORMAT_DATE_IN_FUTURE), // "The date specified is in the future: %ws"
  1644. pwszLocalTime);
  1645. wprintf(wszNewLine);
  1646. if (!g_fForce)
  1647. {
  1648. hr = E_INVALIDARG;
  1649. _JumpError(hr, error, "date in future");
  1650. }
  1651. }
  1652. if (g_fVerbose)
  1653. {
  1654. wprintf(pwszLocalTime);
  1655. wprintf(wszNewLine);
  1656. }
  1657. }
  1658. else
  1659. {
  1660. if (0 == RowId)
  1661. {
  1662. hr = E_INVALIDARG;
  1663. _JumpError(hr, error, "zero RowId");
  1664. }
  1665. date = 0.0;
  1666. }
  1667. hr = E_INVALIDARG;
  1668. Table = CVRC_TABLE_REQCERT;
  1669. Flags = 0;
  1670. if (NULL == pwszTable)
  1671. {
  1672. if (0 == RowId)
  1673. {
  1674. wprintf(
  1675. myLoadResourceString(IDS_FORMAT_DATE_REQUIRES_TABLE), // "One of the following tables must be specified when deleting rows older than %ws:"
  1676. pwszLocalTime);
  1677. wprintf(wszNewLine);
  1678. wprintf(L" %ws\n", wszREQUEST);
  1679. wprintf(L" %ws\n", wszCERT);
  1680. wprintf(L" %ws\n", g_wszCRL);
  1681. _JumpError(hr, error, "date requires table");
  1682. }
  1683. }
  1684. else
  1685. if (0 == LSTRCMPIS(pwszTable, wszREQUEST))
  1686. {
  1687. Flags = CDR_REQUEST_LAST_CHANGED; // assume date query
  1688. }
  1689. else
  1690. if (0 == LSTRCMPIS(pwszTable, wszCERT))
  1691. {
  1692. Flags = CDR_EXPIRED; // assume date query
  1693. }
  1694. else
  1695. if (0 == mylstrcmpiS(pwszTable, g_wszExt))
  1696. {
  1697. Table = CVRC_TABLE_EXTENSIONS;
  1698. if (0 == RowId)
  1699. {
  1700. _JumpError(hr, error, "no date in Extension table");
  1701. }
  1702. }
  1703. else
  1704. if (0 == mylstrcmpiS(pwszTable, g_wszAttrib))
  1705. {
  1706. Table = CVRC_TABLE_ATTRIBUTES;
  1707. if (0 == RowId)
  1708. {
  1709. _JumpError(hr, error, "no date in Request Attribute table");
  1710. }
  1711. }
  1712. else
  1713. if (0 == mylstrcmpiS(pwszTable, g_wszCRL))
  1714. {
  1715. Table = CVRC_TABLE_CRL; // assume date query
  1716. }
  1717. else
  1718. {
  1719. _JumpError(hr, error, "bad table name");
  1720. }
  1721. if (0 != RowId)
  1722. {
  1723. Flags = 0; // not a date query
  1724. }
  1725. else if (g_fVerbose)
  1726. {
  1727. wprintf(L"%ws\n", pwszLocalTime);
  1728. }
  1729. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  1730. _JumpIfError(hr, error, "Admin_Init");
  1731. fMustRelease = TRUE;
  1732. Count = 0;
  1733. hr = Admin2_DeleteRow(
  1734. &diAdmin,
  1735. g_pwszConfig,
  1736. Flags,
  1737. date,
  1738. Table,
  1739. RowId,
  1740. &Count);
  1741. wprintf(myLoadResourceString(IDS_FORMAT_DELETED_ROW_COUNT), Count);
  1742. wprintf(wszNewLine);
  1743. _JumpIfError(hr, error, "Admin2_DeleteRow");
  1744. error:
  1745. if (fMustRelease)
  1746. {
  1747. Admin_Release(&diAdmin);
  1748. }
  1749. if (NULL != pwszLocalTime)
  1750. {
  1751. LocalFree(pwszLocalTime);
  1752. }
  1753. return(hr);
  1754. }
  1755. HRESULT
  1756. verbSetAttributes(
  1757. IN WCHAR const *pwszOption,
  1758. IN WCHAR const *pwszRequestId,
  1759. IN WCHAR const *pwszAttributes,
  1760. IN WCHAR const *pwszArg3,
  1761. IN WCHAR const *pwszArg4)
  1762. {
  1763. HRESULT hr;
  1764. DISPATCHINTERFACE diAdmin;
  1765. LONG RequestId;
  1766. BSTR strAttributes = NULL;
  1767. WCHAR *pwsz;
  1768. BOOL fMustRelease = FALSE;
  1769. if (!ConvertWszToBstr(&strAttributes, pwszAttributes, MAXDWORD))
  1770. {
  1771. hr = E_OUTOFMEMORY;
  1772. _JumpError(hr, error, "ConvertWszToBstr");
  1773. }
  1774. for (pwsz = strAttributes; L'\0' != *pwsz; pwsz++)
  1775. {
  1776. switch (*pwsz)
  1777. {
  1778. case L';':
  1779. *pwsz = L'\n';
  1780. break;
  1781. case L'\\':
  1782. if (L'n' == pwsz[1])
  1783. {
  1784. *pwsz++ = L'\r';
  1785. *pwsz = L'\n';
  1786. }
  1787. break;
  1788. }
  1789. }
  1790. hr = myGetLong(pwszRequestId, &RequestId);
  1791. _JumpIfError(hr, error, "RequestId must be a number");
  1792. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  1793. _JumpIfError(hr, error, "Admin_Init");
  1794. fMustRelease = TRUE;
  1795. hr = Admin_SetRequestAttributes(
  1796. &diAdmin,
  1797. g_pwszConfig,
  1798. RequestId,
  1799. strAttributes);
  1800. _JumpIfError(hr, error, "Admin_SetAttributes");
  1801. error:
  1802. if (fMustRelease)
  1803. {
  1804. Admin_Release(&diAdmin);
  1805. }
  1806. if (NULL != strAttributes)
  1807. {
  1808. SysFreeString(strAttributes);
  1809. }
  1810. return(hr);
  1811. }
  1812. HRESULT
  1813. verbSetExtension(
  1814. IN WCHAR const *pwszOption,
  1815. IN WCHAR const *pwszRequestId,
  1816. IN WCHAR const *pwszExtensionName,
  1817. IN WCHAR const *pwszFlags,
  1818. IN WCHAR const *pwszValue)
  1819. {
  1820. HRESULT hr;
  1821. DISPATCHINTERFACE diAdmin;
  1822. LONG RequestId;
  1823. LONG Flags;
  1824. BSTR strExtensionName = NULL;
  1825. BSTR strValue = NULL;
  1826. LONG PropType;
  1827. VARIANT var;
  1828. BOOL fMustRelease = FALSE;
  1829. BYTE *pbValue = NULL;
  1830. DWORD cbValue;
  1831. hr = myGetLong(pwszRequestId, &RequestId);
  1832. _JumpIfError(hr, error, "RequestId must be a number");
  1833. if (!ConvertWszToBstr(&strExtensionName, pwszExtensionName, MAXDWORD))
  1834. {
  1835. hr = E_OUTOFMEMORY;
  1836. _JumpError(hr, error, "ConvertWszToBstr");
  1837. }
  1838. hr = myGetLong(pwszFlags, &Flags);
  1839. _JumpIfError(hr, error, "Flags must be a number");
  1840. if (~EXTENSION_POLICY_MASK & Flags)
  1841. {
  1842. hr = E_INVALIDARG;
  1843. _JumpError(hr, error, "Flags must be <= 0xffff");
  1844. }
  1845. if (L'@' == *pwszValue)
  1846. {
  1847. pwszValue++;
  1848. // Read in and decode the extension from a file.
  1849. // Try Hex-Ascii, Base64 with and without a header, then binary.
  1850. hr = DecodeFileW(pwszValue, &pbValue, &cbValue, CRYPT_STRING_HEX_ANY);
  1851. if (S_OK != hr)
  1852. {
  1853. hr = DecodeFileW(pwszValue, &pbValue, &cbValue, CRYPT_STRING_ANY);
  1854. _JumpIfError(hr, error, "DecodeFileW");
  1855. }
  1856. CSASSERT(NULL != pbValue && 0 != cbValue);
  1857. var.vt = VT_BSTR;
  1858. PropType = PROPTYPE_BINARY;
  1859. DumpHex(0, pbValue, cbValue);
  1860. if (!ConvertWszToBstr(&strValue, (WCHAR const *) pbValue, cbValue))
  1861. {
  1862. hr = E_OUTOFMEMORY;
  1863. _JumpError(hr, error, "ConvertWszToBstr");
  1864. }
  1865. var.bstrVal = strValue;
  1866. }
  1867. else
  1868. {
  1869. hr = myGetLong(pwszValue, &var.lVal);
  1870. if (S_OK == hr)
  1871. {
  1872. var.vt = VT_I4;
  1873. PropType = PROPTYPE_LONG;
  1874. }
  1875. else
  1876. {
  1877. hr = myWszLocalTimeToGMTDate(pwszValue, &var.date);
  1878. if (S_OK == hr)
  1879. {
  1880. var.vt = VT_DATE;
  1881. PropType = PROPTYPE_DATE;
  1882. }
  1883. else
  1884. {
  1885. PropType = PROPTYPE_STRING;
  1886. if (!ConvertWszToBstr(&strValue, pwszValue, MAXDWORD))
  1887. {
  1888. hr = E_OUTOFMEMORY;
  1889. _JumpError(hr, error, "ConvertWszToBstr");
  1890. }
  1891. var.vt = VT_BSTR;
  1892. var.bstrVal = strValue;
  1893. }
  1894. }
  1895. }
  1896. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  1897. if (S_OK != hr)
  1898. {
  1899. _JumpError(hr, error, "Admin_Init");
  1900. }
  1901. fMustRelease = TRUE;
  1902. hr = Admin_SetCertificateExtension(
  1903. &diAdmin,
  1904. g_pwszConfig,
  1905. RequestId,
  1906. strExtensionName,
  1907. PropType,
  1908. Flags,
  1909. &var);
  1910. _JumpIfError(hr, error, "Admin_SetExtension");
  1911. error:
  1912. if (NULL != pbValue)
  1913. {
  1914. LocalFree(pbValue);
  1915. }
  1916. if (fMustRelease)
  1917. {
  1918. Admin_Release(&diAdmin);
  1919. }
  1920. if (NULL != strExtensionName)
  1921. {
  1922. SysFreeString(strExtensionName);
  1923. }
  1924. if (NULL != strValue)
  1925. {
  1926. SysFreeString(strValue);
  1927. }
  1928. return(hr);
  1929. }
  1930. HRESULT
  1931. verbImportCertificate(
  1932. IN WCHAR const *pwszOption,
  1933. IN WCHAR const *pwszCertificateFile,
  1934. IN WCHAR const *pwszArg2,
  1935. IN WCHAR const *pwszArg3,
  1936. IN WCHAR const *pwszArg4)
  1937. {
  1938. HRESULT hr;
  1939. LONG dwReqID;
  1940. CERT_CONTEXT const *pCertContext = NULL;
  1941. DISPATCHINTERFACE diAdmin;
  1942. BOOL fRelease = FALSE;
  1943. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  1944. _JumpIfError(hr, error, "Admin_Init");
  1945. fRelease = TRUE;
  1946. hr = cuLoadCert(pwszCertificateFile, &pCertContext);
  1947. _JumpIfError(hr, error, "cuLoadCert");
  1948. hr = Admin_ImportCertificate(
  1949. &diAdmin,
  1950. g_pwszConfig,
  1951. (WCHAR const *) pCertContext->pbCertEncoded,
  1952. pCertContext->cbCertEncoded,
  1953. (g_fForce? ICF_ALLOWFOREIGN : 0) | CR_IN_BINARY,
  1954. &dwReqID);
  1955. _JumpIfError(hr, error, "Admin_ImportCertificate");
  1956. wprintf(myLoadResourceString(IDS_FORMAT_IMPORTCERT), dwReqID);
  1957. wprintf(wszNewLine);
  1958. error:
  1959. cuUnloadCert(&pCertContext);
  1960. if (fRelease)
  1961. {
  1962. Admin_Release(&diAdmin);
  1963. }
  1964. return(hr);
  1965. }
  1966. HRESULT
  1967. DumpKeyRecipientInfo(
  1968. IN BYTE const *pbRecoveryBlob,
  1969. IN DWORD cbRecoveryBlob)
  1970. {
  1971. HRESULT hr;
  1972. BYTE *pbEncryptedKey = NULL;
  1973. DWORD cbEncryptedKey;
  1974. DWORD cRecipient;
  1975. HCERTSTORE hStore = NULL;
  1976. HCRYPTMSG hMsg = NULL;
  1977. DWORD dwMsgType;
  1978. BYTE abHash[CBMAX_CRYPT_HASH_LEN];
  1979. hr = myDecodePKCS7(
  1980. pbRecoveryBlob,
  1981. cbRecoveryBlob,
  1982. &pbEncryptedKey,
  1983. &cbEncryptedKey,
  1984. &dwMsgType,
  1985. NULL, // ppszInnerContentObjId
  1986. NULL, // pcSigner
  1987. NULL, // pcRecipient
  1988. &hStore,
  1989. NULL); // phMsg
  1990. _JumpIfError(hr, error, "myDecodePKCS7");
  1991. if (NULL == pbEncryptedKey)
  1992. {
  1993. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1994. _JumpError(hr, error, "No Content");
  1995. }
  1996. if (CMSG_SIGNED != dwMsgType)
  1997. {
  1998. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1999. _JumpError(hr, error, "Not Signed");
  2000. }
  2001. hr = myDecodePKCS7(
  2002. pbEncryptedKey,
  2003. cbEncryptedKey,
  2004. NULL, // ppbContent
  2005. NULL, // pcbContent
  2006. &dwMsgType,
  2007. NULL, // ppszInnerContentObjId
  2008. NULL, // pcSigner
  2009. &cRecipient,
  2010. NULL, // phStore
  2011. &hMsg);
  2012. _JumpIfError(hr, error, "myDecodePKCS7");
  2013. if (CMSG_ENVELOPED != dwMsgType)
  2014. {
  2015. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2016. _JumpError(hr, error, "Not Encrypted");
  2017. }
  2018. if (NULL == hMsg || 0 == cRecipient)
  2019. {
  2020. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  2021. _JumpError(hr, error, "No Msg or Recipients");
  2022. }
  2023. hr = cuDumpRecipients(hMsg, hStore, cRecipient, TRUE);
  2024. _JumpIfError(hr, error, "cuDumpRecipients");
  2025. error:
  2026. if (NULL != hMsg)
  2027. {
  2028. CryptMsgClose(hMsg);
  2029. }
  2030. if (NULL != hStore)
  2031. {
  2032. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2033. }
  2034. if (NULL != pbEncryptedKey)
  2035. {
  2036. LocalFree(pbEncryptedKey);
  2037. }
  2038. return(hr);
  2039. }
  2040. HRESULT
  2041. GetArchivedKey(
  2042. IN WCHAR const *pwszConfig,
  2043. IN DWORD RequestId,
  2044. OPTIONAL IN WCHAR const *pwszfnRecoveryBlob)
  2045. {
  2046. HRESULT hr;
  2047. DISPATCHINTERFACE diAdmin;
  2048. BOOL fRelease = FALSE;
  2049. BSTR strKey = NULL;
  2050. WCHAR *pwszT = NULL;
  2051. hr = Admin_Init(g_DispatchFlags, &diAdmin);
  2052. _JumpIfError(hr, error, "Admin_Init");
  2053. fRelease = TRUE;
  2054. hr = Admin2_GetArchivedKey(
  2055. &diAdmin,
  2056. pwszConfig,
  2057. RequestId,
  2058. CR_OUT_BINARY,
  2059. &strKey);
  2060. _JumpIfError(hr, error, "Admin_GetArchivedKey");
  2061. if (NULL == pwszfnRecoveryBlob)
  2062. {
  2063. hr = myCryptBinaryToString(
  2064. (BYTE const *) strKey,
  2065. SysStringByteLen(strKey),
  2066. CRYPT_STRING_BASE64HEADER,
  2067. &pwszT);
  2068. _JumpIfError(hr, error, "myCryptBinaryToString");
  2069. cuPrintCRLFString(NULL, pwszT);
  2070. }
  2071. else
  2072. {
  2073. hr = EncodeToFileW(
  2074. pwszfnRecoveryBlob,
  2075. (BYTE const *) strKey,
  2076. SysStringByteLen(strKey),
  2077. CRYPT_STRING_BINARY | g_EncodeFlags);
  2078. _JumpIfError(hr, error, "EncodeToFileW");
  2079. }
  2080. hr = DumpKeyRecipientInfo((BYTE const *) strKey, SysStringByteLen(strKey));
  2081. _PrintIfError(hr, "DumpKeyRecipientInfo");
  2082. hr = S_OK;
  2083. error:
  2084. if (NULL != pwszT)
  2085. {
  2086. LocalFree(pwszT);
  2087. }
  2088. if (NULL != strKey)
  2089. {
  2090. SysFreeString(strKey);
  2091. }
  2092. if (fRelease)
  2093. {
  2094. Admin_Release(&diAdmin);
  2095. }
  2096. return(hr);
  2097. }
  2098. typedef struct _GETKEYSERIAL {
  2099. struct _GETKEYSERIAL *Next;
  2100. DWORD dwVersion;
  2101. BSTR strConfig;
  2102. LONG RequestId;
  2103. BSTR strSerialNumber;
  2104. BSTR strCommonName;
  2105. BSTR strUPN;
  2106. BSTR strHash;
  2107. BSTR strCert;
  2108. } GETKEYSERIAL;
  2109. VOID
  2110. FreeKeySerialEntry(
  2111. IN OUT GETKEYSERIAL *pks)
  2112. {
  2113. if (NULL != pks->strConfig)
  2114. {
  2115. SysFreeString(pks->strConfig);
  2116. }
  2117. if (NULL != pks->strSerialNumber)
  2118. {
  2119. SysFreeString(pks->strSerialNumber);
  2120. }
  2121. if (NULL != pks->strCommonName)
  2122. {
  2123. SysFreeString(pks->strCommonName);
  2124. }
  2125. if (NULL != pks->strUPN)
  2126. {
  2127. SysFreeString(pks->strUPN);
  2128. }
  2129. if (NULL != pks->strHash)
  2130. {
  2131. SysFreeString(pks->strHash);
  2132. }
  2133. if (NULL != pks->strCert)
  2134. {
  2135. SysFreeString(pks->strCert);
  2136. }
  2137. LocalFree(pks);
  2138. }
  2139. HRESULT
  2140. AddKeySerialList(
  2141. IN WCHAR const *pwszConfig,
  2142. IN LONG RequestId,
  2143. IN WCHAR const *pwszSerialNumber,
  2144. IN WCHAR const *pwszCommonName,
  2145. IN WCHAR const *pwszUPN,
  2146. IN WCHAR const *pwszHash,
  2147. IN BYTE const *pbCert,
  2148. IN DWORD cbCert,
  2149. IN OUT GETKEYSERIAL **ppksList)
  2150. {
  2151. HRESULT hr;
  2152. CERT_CONTEXT const *pcc = NULL;
  2153. GETKEYSERIAL *pksNew = NULL;
  2154. GETKEYSERIAL *pksT;
  2155. GETKEYSERIAL *pksPrev;
  2156. BOOL fNewConfig = TRUE;
  2157. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  2158. if (NULL == pcc)
  2159. {
  2160. hr = myHLastError();
  2161. _JumpError(hr, error, "CertCreateCertificateContext");
  2162. }
  2163. pksNew = (GETKEYSERIAL *) LocalAlloc(
  2164. LMEM_FIXED | LMEM_ZEROINIT,
  2165. sizeof(*pksNew));
  2166. if (NULL == pksNew)
  2167. {
  2168. hr = E_OUTOFMEMORY;
  2169. _JumpError(hr, error, "LocalAlloc");
  2170. }
  2171. pksNew->RequestId = RequestId;
  2172. pksNew->dwVersion = pcc->pCertInfo->dwVersion;
  2173. pksNew->strConfig = SysAllocString(pwszConfig);
  2174. pksNew->strSerialNumber = SysAllocString(pwszSerialNumber);
  2175. pksNew->strCommonName = SysAllocString(pwszCommonName);
  2176. pksNew->strUPN = SysAllocString(pwszUPN);
  2177. pksNew->strHash = SysAllocString(pwszHash);
  2178. pksNew->strCert = SysAllocStringByteLen((char const *) pbCert, cbCert);
  2179. if (NULL == pksNew->strConfig ||
  2180. NULL == pksNew->strSerialNumber ||
  2181. (NULL != pwszCommonName && NULL == pksNew->strCommonName) ||
  2182. (NULL != pwszUPN && NULL == pksNew->strUPN) ||
  2183. NULL == pksNew->strHash ||
  2184. NULL == pksNew->strCert)
  2185. {
  2186. hr = E_OUTOFMEMORY;
  2187. _JumpError(hr, error, "LocalAlloc");
  2188. }
  2189. pksPrev = NULL;
  2190. for (pksT = *ppksList; NULL != pksT; pksT = pksT->Next)
  2191. {
  2192. if (NULL != pksT->strConfig)
  2193. {
  2194. fNewConfig = 0 != lstrcmp(pksT->strConfig, pksNew->strConfig);
  2195. }
  2196. pksPrev = pksT;
  2197. }
  2198. if (NULL == pksPrev)
  2199. {
  2200. *ppksList = pksNew;
  2201. }
  2202. else
  2203. {
  2204. pksPrev->Next = pksNew;
  2205. }
  2206. if (!fNewConfig)
  2207. {
  2208. SysFreeString(pksNew->strConfig);
  2209. pksNew->strConfig = NULL;
  2210. }
  2211. pksNew = NULL;
  2212. hr = S_OK;
  2213. error:
  2214. if (NULL != pcc)
  2215. {
  2216. CertFreeCertificateContext(pcc);
  2217. }
  2218. if (NULL != pksNew)
  2219. {
  2220. FreeKeySerialEntry(pksNew);
  2221. }
  2222. return(hr);
  2223. }
  2224. HRESULT
  2225. cuViewQueryWorker(
  2226. IN WCHAR const *pwszConfig,
  2227. IN WCHAR const *pwszColumn,
  2228. IN WCHAR const *pwszValue1,
  2229. OPTIONAL IN WCHAR const *pwszValue2,
  2230. IN OUT GETKEYSERIAL **ppksList,
  2231. OUT BOOL *pfConnectionFailed)
  2232. {
  2233. HRESULT hr;
  2234. DWORD cwc;
  2235. DISPATCHINTERFACE diView;
  2236. DISPATCHINTERFACE diViewRow;
  2237. DISPATCHINTERFACE diViewColumn;
  2238. BOOL fMustRelease = FALSE;
  2239. BOOL fMustReleaseRow = FALSE;
  2240. BOOL fMustReleaseColumn = FALSE;
  2241. LONG ColIndex;
  2242. LONG RowIndex;
  2243. DWORD cRow;
  2244. VARIANT var;
  2245. LONG RequestId;
  2246. DWORD i;
  2247. static WCHAR *apwszCol[] =
  2248. {
  2249. #define IV_REQUESTID 0
  2250. wszPROPCERTIFICATEREQUESTID,
  2251. #define IV_SERIALNUMBER 1
  2252. wszPROPCERTIFICATESERIALNUMBER,
  2253. #define IV_COMMONNAME 2
  2254. wszPROPCOMMONNAME,
  2255. #define IV_ARCHIVEDKEY 3
  2256. wszPROPREQUESTRAWARCHIVEDKEY,
  2257. #define IV_HASH 4
  2258. wszPROPCERTIFICATEHASH,
  2259. #define IV_CERT 5
  2260. wszPROPRAWCERTIFICATE,
  2261. #define IV_UPN 6
  2262. wszPROPCERTIFICATEUPN,
  2263. };
  2264. static LONG altype[] =
  2265. {
  2266. PROPTYPE_LONG,
  2267. PROPTYPE_STRING,
  2268. PROPTYPE_STRING,
  2269. PROPTYPE_BINARY,
  2270. PROPTYPE_STRING,
  2271. PROPTYPE_BINARY,
  2272. PROPTYPE_STRING,
  2273. };
  2274. BSTR astrValue[ARRAYSIZE(apwszCol)];
  2275. ZeroMemory(astrValue, sizeof(astrValue));
  2276. VariantInit(&var);
  2277. *pfConnectionFailed = TRUE;
  2278. DBGPRINT((
  2279. DBG_SS_CERTUTILI,
  2280. "Query(%ws, %ws == %ws + %ws)\n",
  2281. pwszConfig,
  2282. pwszColumn,
  2283. pwszValue1,
  2284. pwszValue2));
  2285. hr = View_Init(g_DispatchFlags, &diView);
  2286. _JumpIfError(hr, error, "View_Init");
  2287. fMustRelease = TRUE;
  2288. hr = View_OpenConnection(&diView, pwszConfig);
  2289. _JumpIfError(hr, error, "View_OpenConnection");
  2290. *pfConnectionFailed = FALSE;
  2291. hr = View_GetColumnIndex(
  2292. &diView,
  2293. CVRC_COLUMN_SCHEMA,
  2294. pwszColumn,
  2295. &ColIndex);
  2296. _JumpIfErrorStr(hr, error, "View_GetColumnIndex", pwszColumn);
  2297. cwc = wcslen(pwszValue1);
  2298. if (NULL != pwszValue2)
  2299. {
  2300. cwc += wcslen(pwszValue2);
  2301. }
  2302. var.bstrVal = SysAllocStringLen(NULL, cwc);
  2303. if (NULL == var.bstrVal)
  2304. {
  2305. hr = E_OUTOFMEMORY;
  2306. _JumpError(hr, error, "SysAllocString");
  2307. }
  2308. var.vt = VT_BSTR;
  2309. wcscpy(var.bstrVal, pwszValue1);
  2310. if (NULL != pwszValue2)
  2311. {
  2312. wcscat(var.bstrVal, pwszValue2);
  2313. }
  2314. hr = View_SetRestriction(
  2315. &diView,
  2316. ColIndex, // Restriction ColumnIndex
  2317. CVR_SEEK_EQ,
  2318. CVR_SORT_ASCEND,
  2319. &var); // pvarValue
  2320. _JumpIfError(hr, error, "View_SetRestriction");
  2321. hr = View_SetResultColumnCount(&diView, ARRAYSIZE(apwszCol));
  2322. _JumpIfError(hr, error, "View_SetResultColumnCount");
  2323. for (i = 0; i < ARRAYSIZE(apwszCol); i++)
  2324. {
  2325. hr = View_GetColumnIndex(
  2326. &diView,
  2327. CVRC_COLUMN_SCHEMA,
  2328. apwszCol[i],
  2329. &ColIndex);
  2330. _JumpIfErrorStr(
  2331. hr,
  2332. error,
  2333. "View_GetColumnIndex",
  2334. apwszCol[i]);
  2335. hr = View_SetResultColumn(&diView, ColIndex);
  2336. _JumpIfError(hr, error, "View_SetResultColumn");
  2337. }
  2338. hr = View_OpenView(&diView, &diViewRow);
  2339. _JumpIfError(hr, error, "View_OpenView");
  2340. fMustReleaseRow = TRUE;
  2341. for (cRow = 0; ; cRow++)
  2342. {
  2343. hr = ViewRow_Next(&diViewRow, &RowIndex);
  2344. if (S_FALSE == hr || (S_OK == hr && -1 == RowIndex))
  2345. {
  2346. break;
  2347. }
  2348. _JumpIfError(hr, error, "ViewRow_Next");
  2349. if (fMustReleaseColumn)
  2350. {
  2351. ViewColumn_Release(&diViewColumn);
  2352. fMustReleaseColumn = FALSE;
  2353. }
  2354. hr = ViewRow_EnumCertViewColumn(&diViewRow, &diViewColumn);
  2355. _JumpIfError(hr, error, "ViewRow_EnumCertViewColumn");
  2356. fMustReleaseColumn = TRUE;
  2357. for (i = 0; i < ARRAYSIZE(apwszCol); i++)
  2358. {
  2359. VOID *pv;
  2360. hr = ViewColumn_Next(&diViewColumn, &ColIndex);
  2361. if (S_FALSE == hr || (S_OK == hr && -1 == ColIndex))
  2362. {
  2363. break;
  2364. }
  2365. _JumpIfError(hr, error, "ViewColumn_Next");
  2366. pv = &RequestId;
  2367. if (PROPTYPE_LONG != altype[i])
  2368. {
  2369. pv = &astrValue[i];
  2370. }
  2371. hr = ViewColumn_GetValue(
  2372. &diViewColumn,
  2373. CV_OUT_BINARY,
  2374. altype[i],
  2375. pv);
  2376. if (S_OK != hr)
  2377. {
  2378. _PrintErrorStr2(
  2379. hr,
  2380. "ViewColumn_GetValue",
  2381. apwszCol[i],
  2382. CERTSRV_E_PROPERTY_EMPTY);
  2383. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  2384. {
  2385. goto error;
  2386. }
  2387. }
  2388. }
  2389. DBGPRINT((
  2390. DBG_SS_CERTUTILI,
  2391. "RequestId=%u Serial=%ws CN=%ws UPN=%ws Key=%u\n",
  2392. RequestId,
  2393. astrValue[IV_SERIALNUMBER],
  2394. astrValue[IV_COMMONNAME],
  2395. astrValue[IV_UPN],
  2396. NULL != astrValue[IV_ARCHIVEDKEY]));
  2397. if (NULL != astrValue[IV_SERIALNUMBER] &&
  2398. NULL != astrValue[IV_HASH] &&
  2399. NULL != astrValue[IV_CERT] &&
  2400. (g_fForce || NULL != astrValue[IV_ARCHIVEDKEY]))
  2401. {
  2402. hr = AddKeySerialList(
  2403. pwszConfig,
  2404. RequestId,
  2405. astrValue[IV_SERIALNUMBER],
  2406. astrValue[IV_COMMONNAME],
  2407. astrValue[IV_UPN],
  2408. astrValue[IV_HASH],
  2409. (BYTE const *) astrValue[IV_CERT],
  2410. SysStringByteLen(astrValue[IV_CERT]),
  2411. ppksList);
  2412. _JumpIfError(hr, error, "AddKeySerialList");
  2413. }
  2414. for (i = 0; i < ARRAYSIZE(astrValue); i++)
  2415. {
  2416. if (NULL != astrValue[i])
  2417. {
  2418. SysFreeString(astrValue[i]);
  2419. astrValue[i] = NULL;
  2420. }
  2421. }
  2422. }
  2423. hr = S_OK;
  2424. error:
  2425. if (fMustReleaseColumn)
  2426. {
  2427. ViewColumn_Release(&diViewColumn);
  2428. }
  2429. if (fMustReleaseRow)
  2430. {
  2431. ViewRow_Release(&diViewRow);
  2432. }
  2433. if (fMustRelease)
  2434. {
  2435. View_Release(&diView);
  2436. }
  2437. for (i = 0; i < ARRAYSIZE(astrValue); i++)
  2438. {
  2439. if (NULL != astrValue[i])
  2440. {
  2441. SysFreeString(astrValue[i]);
  2442. }
  2443. }
  2444. VariantClear(&var);
  2445. return(hr);
  2446. }
  2447. // Print the string, except for the newline at the start or end of the string.
  2448. VOID
  2449. PutStringStripNL(
  2450. IN WCHAR const *pwszValue)
  2451. {
  2452. DWORD cwc;
  2453. cwc = wcslen(pwszValue);
  2454. if (L'\n' == *pwszValue)
  2455. {
  2456. pwszValue++;
  2457. cwc--;
  2458. }
  2459. else if (NULL != wcschr(pwszValue, L'\n'))
  2460. {
  2461. cwc--;
  2462. CSASSERT('\n' == pwszValue[cwc]);
  2463. }
  2464. wprintf(L"%.*ws", cwc, pwszValue);
  2465. }
  2466. HRESULT
  2467. cuViewQuery(
  2468. IN WCHAR const *pwszConfig,
  2469. IN WCHAR const *pwszColumn,
  2470. IN WCHAR const *pwszValue1,
  2471. OPTIONAL IN WCHAR const *pwszValue2,
  2472. IN OUT GETKEYSERIAL **ppksList,
  2473. OUT BOOL *pfConnectionFailed)
  2474. {
  2475. HRESULT hr;
  2476. if (!g_fQuiet)
  2477. {
  2478. if (g_fVerbose)
  2479. {
  2480. wprintf(L" %ws: ", pwszColumn);
  2481. PutStringStripNL(pwszValue1);
  2482. if (NULL != pwszValue2)
  2483. {
  2484. wprintf(L" + ");
  2485. PutStringStripNL(pwszValue2);
  2486. }
  2487. wprintf(wszNewLine);
  2488. }
  2489. else
  2490. {
  2491. wprintf(L"...");
  2492. }
  2493. }
  2494. hr = cuViewQueryWorker(
  2495. pwszConfig,
  2496. pwszColumn,
  2497. pwszValue1,
  2498. pwszValue2,
  2499. ppksList,
  2500. pfConnectionFailed);
  2501. _JumpIfError(hr, error, "cuViewQueryWorker");
  2502. error:
  2503. return(hr);
  2504. }
  2505. #define wszCOMPUTERS L"Computers"
  2506. #define wszUSERS L"Users"
  2507. #define wszRECIPIENTS L"recipients"
  2508. #define wszCOMPUTERSNL wszCOMPUTERS L"\n"
  2509. #define wszUSERSNL wszUSERS L"\n"
  2510. #define wszRECIPIENTSNL wszRECIPIENTS L"\n"
  2511. #define wszNLRECIPIENTS L"\n" wszRECIPIENTS
  2512. HRESULT
  2513. GetKey(
  2514. IN WCHAR const *pwszConfig,
  2515. IN WCHAR const *pwszCommonName,
  2516. OPTIONAL IN WCHAR const *pwszRequesterName,
  2517. OPTIONAL IN WCHAR const *pwszUPN,
  2518. OPTIONAL IN WCHAR const *pwszSerialNumber,
  2519. OPTIONAL IN WCHAR const *pwszHash,
  2520. IN OUT GETKEYSERIAL **ppksList)
  2521. {
  2522. HRESULT hr;
  2523. BOOL fConnectionFailed;
  2524. if (!g_fQuiet)
  2525. {
  2526. wprintf(myLoadResourceString(IDS_FORMAT_QUERYING), pwszConfig);
  2527. if (g_fVerbose)
  2528. {
  2529. wprintf(wszNewLine);
  2530. }
  2531. }
  2532. hr = cuViewQuery(
  2533. pwszConfig,
  2534. wszPROPCOMMONNAME,
  2535. pwszCommonName,
  2536. NULL,
  2537. ppksList,
  2538. &fConnectionFailed);
  2539. _PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME);
  2540. if (S_OK != hr)
  2541. {
  2542. if (fConnectionFailed)
  2543. {
  2544. goto error;
  2545. }
  2546. }
  2547. if (NULL == wcschr(pwszCommonName, L'\n'))
  2548. {
  2549. hr = cuViewQuery(
  2550. pwszConfig,
  2551. wszPROPCOMMONNAME,
  2552. wszCOMPUTERSNL,
  2553. pwszCommonName,
  2554. ppksList,
  2555. &fConnectionFailed);
  2556. _PrintIfErrorStr(hr, "cuViewQuery", wszCOMPUTERS L"+" wszPROPSUBJECTCOMMONNAME );
  2557. hr = cuViewQuery(
  2558. pwszConfig,
  2559. wszPROPCOMMONNAME,
  2560. wszUSERSNL,
  2561. pwszCommonName,
  2562. ppksList,
  2563. &fConnectionFailed);
  2564. _PrintIfErrorStr(hr, "cuViewQuery", wszUSERS L"+" wszPROPSUBJECTCOMMONNAME );
  2565. hr = cuViewQuery(
  2566. pwszConfig,
  2567. wszPROPCOMMONNAME,
  2568. wszRECIPIENTSNL,
  2569. pwszCommonName,
  2570. ppksList,
  2571. &fConnectionFailed);
  2572. _PrintIfErrorStr(hr, "cuViewQuery", wszRECIPIENTS L"+" wszPROPSUBJECTCOMMONNAME);
  2573. hr = cuViewQuery(
  2574. pwszConfig,
  2575. wszPROPCOMMONNAME,
  2576. pwszCommonName,
  2577. wszNLRECIPIENTS,
  2578. ppksList,
  2579. &fConnectionFailed);
  2580. _PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME L"+" wszRECIPIENTS);
  2581. }
  2582. if (NULL != pwszSerialNumber)
  2583. {
  2584. hr = cuViewQuery(
  2585. pwszConfig,
  2586. wszPROPCERTIFICATESERIALNUMBER,
  2587. pwszSerialNumber,
  2588. NULL,
  2589. ppksList,
  2590. &fConnectionFailed);
  2591. _PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATESERIALNUMBER);
  2592. }
  2593. if (NULL != pwszHash)
  2594. {
  2595. hr = cuViewQuery(
  2596. pwszConfig,
  2597. wszPROPCERTIFICATEHASH,
  2598. pwszHash,
  2599. NULL,
  2600. ppksList,
  2601. &fConnectionFailed);
  2602. _PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATEHASH);
  2603. }
  2604. if (NULL != pwszRequesterName)
  2605. {
  2606. hr = cuViewQuery(
  2607. pwszConfig,
  2608. wszPROPREQUESTERNAME,
  2609. pwszRequesterName,
  2610. NULL,
  2611. ppksList,
  2612. &fConnectionFailed);
  2613. _PrintIfErrorStr(hr, "cuViewQuery", wszPROPREQUESTERNAME);
  2614. }
  2615. if (NULL != pwszUPN)
  2616. {
  2617. hr = cuViewQuery(
  2618. pwszConfig,
  2619. wszPROPCERTIFICATEUPN,
  2620. pwszUPN,
  2621. NULL,
  2622. ppksList,
  2623. &fConnectionFailed);
  2624. _PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATEUPN);
  2625. }
  2626. if (!g_fQuiet)
  2627. {
  2628. wprintf(wszNewLine);
  2629. }
  2630. hr = S_OK;
  2631. error:
  2632. return(hr);
  2633. }
  2634. VOID
  2635. cuConvertEscapeSequences(
  2636. IN OUT WCHAR *pwsz)
  2637. {
  2638. WCHAR *pwszSrc = pwsz;
  2639. WCHAR *pwszDst = pwsz;
  2640. while (L'\0' != *pwszSrc)
  2641. {
  2642. WCHAR wc = *pwszSrc++;
  2643. if (L'\\' == wc)
  2644. {
  2645. switch (*pwszSrc)
  2646. {
  2647. case 'n':
  2648. wc = L'\n';
  2649. pwszSrc++;
  2650. break;
  2651. case 'r':
  2652. wc = L'\r';
  2653. pwszSrc++;
  2654. break;
  2655. case 't':
  2656. wc = L'\t';
  2657. pwszSrc++;
  2658. break;
  2659. default:
  2660. break;
  2661. }
  2662. }
  2663. *pwszDst++ = wc;
  2664. }
  2665. *pwszDst = L'\0';
  2666. }
  2667. WCHAR *
  2668. SplitToken(
  2669. IN OUT WCHAR **ppwszIn,
  2670. IN WCHAR *pwcSeparator)
  2671. {
  2672. WCHAR *pwszOut = NULL;
  2673. WCHAR *pwszNext = NULL;
  2674. WCHAR *pwszIn;
  2675. WCHAR *pwsz;
  2676. pwszIn = *ppwszIn;
  2677. if (NULL != pwszIn)
  2678. {
  2679. pwszOut = pwszIn;
  2680. pwsz = wcschr(pwszIn, *pwcSeparator);
  2681. if (NULL != pwsz)
  2682. {
  2683. *pwsz++ = L'\0';
  2684. pwszNext = pwsz;
  2685. }
  2686. }
  2687. *ppwszIn = pwszNext;
  2688. return(pwszOut);
  2689. }
  2690. HRESULT
  2691. SimplifyCommonName(
  2692. OPTIONAL IN WCHAR const *pwszCommonName,
  2693. OUT WCHAR **ppwszSimpleName)
  2694. {
  2695. HRESULT hr;
  2696. WCHAR *pwszDup = NULL;
  2697. WCHAR *pwszRemain;
  2698. WCHAR const *pwszToken;
  2699. *ppwszSimpleName = NULL;
  2700. if (NULL == pwszCommonName)
  2701. {
  2702. pwszCommonName = L"EmptyCN";
  2703. }
  2704. hr = myDupString(pwszCommonName, &pwszDup);
  2705. _JumpIfError(hr, error, "myDupString");
  2706. pwszRemain = pwszDup;
  2707. while (TRUE)
  2708. {
  2709. pwszToken = SplitToken(&pwszRemain, wszNAMESEPARATORDEFAULT);
  2710. if (NULL == pwszToken)
  2711. {
  2712. pwszToken = pwszCommonName;
  2713. break;
  2714. }
  2715. if (0 != LSTRCMPIS(pwszToken, wszUSERS) &&
  2716. 0 != LSTRCMPIS(pwszToken, wszRECIPIENTS))
  2717. {
  2718. break;
  2719. }
  2720. }
  2721. hr = mySanitizeName(pwszToken, ppwszSimpleName);
  2722. _JumpIfError(hr, error, "mySanitizeName");
  2723. error:
  2724. if (NULL != pwszDup)
  2725. {
  2726. LocalFree(pwszDup);
  2727. }
  2728. return(hr);
  2729. }
  2730. WCHAR const *
  2731. wszBatchPassword(
  2732. IN DWORD Index,
  2733. OPTIONAL IN WCHAR const *pwszPassword)
  2734. {
  2735. static WCHAR wsz0[2 * cwcAUTOPASSWORDMAX + 1];
  2736. static WCHAR wsz1[2 * cwcAUTOPASSWORDMAX + 1];
  2737. WCHAR const *pwszRet;
  2738. WCHAR *pwsz = 0 == Index? wsz0 : wsz1;
  2739. CSASSERT(0 == Index || 1 == Index);
  2740. CSASSERT(ARRAYSIZE(wsz0) == ARRAYSIZE(wsz1));
  2741. if (NULL == pwszPassword)
  2742. {
  2743. SecureZeroMemory(pwsz, sizeof(wsz0)); // password data
  2744. pwszRet = NULL;
  2745. }
  2746. else
  2747. {
  2748. CSASSERT(ARRAYSIZE(wsz0) / 2 >= wcslen(pwszPassword));
  2749. if (NULL == wcschr(pwszPassword, L'%'))
  2750. {
  2751. pwszRet = pwszPassword;
  2752. }
  2753. else
  2754. {
  2755. WCHAR const *pwszIn;
  2756. WCHAR *pwszEnd;
  2757. pwszIn = pwszPassword;
  2758. pwszEnd = &pwsz[ARRAYSIZE(wsz0)];
  2759. pwszRet = pwsz;
  2760. while (pwsz < pwszEnd && L'\0' != (*pwsz = *pwszIn++))
  2761. {
  2762. if (L'%' == *pwsz++)
  2763. {
  2764. *pwsz++ = L'%';
  2765. }
  2766. }
  2767. if (L'\0' != *pwsz)
  2768. {
  2769. pwszRet = pwszPassword;
  2770. }
  2771. }
  2772. }
  2773. return(pwszRet);
  2774. }
  2775. HRESULT
  2776. DumpGetRecoverMergeCommandLine(
  2777. OPTIONAL IN BSTR const strConfig, // NULL -> -RecoverKey command line
  2778. IN BOOL fRecoverKey,
  2779. IN GETKEYSERIAL const *pks,
  2780. OPTIONAL IN WCHAR const *pwszPassword,
  2781. OPTIONAL IN WCHAR const *pwszSuffix,
  2782. OPTIONAL OUT WCHAR **ppwszSimpleName)
  2783. {
  2784. HRESULT hr;
  2785. CERT_CONTEXT const *pcc = NULL;
  2786. CERT_INFO *pCertInfo;
  2787. BSTR strSerialNumber = NULL;
  2788. WCHAR *pwszSimpleName = NULL;
  2789. if (NULL != ppwszSimpleName)
  2790. {
  2791. *ppwszSimpleName = NULL;
  2792. }
  2793. pcc = CertCreateCertificateContext(
  2794. X509_ASN_ENCODING,
  2795. (BYTE const *) pks->strCert,
  2796. SysStringByteLen(pks->strCert));
  2797. if (NULL == pcc)
  2798. {
  2799. hr = myHLastError();
  2800. _JumpError(hr, error, "CertCreateCertificateContext");
  2801. }
  2802. pCertInfo = pcc->pCertInfo;
  2803. // Convert serial number to string
  2804. hr = MultiByteIntegerToBstr(
  2805. FALSE,
  2806. pCertInfo->SerialNumber.cbData,
  2807. pCertInfo->SerialNumber.pbData,
  2808. &strSerialNumber);
  2809. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  2810. hr = SimplifyCommonName(pks->strCommonName, &pwszSimpleName);
  2811. _JumpIfError(hr, error, "SimplifyCommonName");
  2812. if (NULL != strConfig)
  2813. {
  2814. wprintf(
  2815. L"%ws -config \"%ws\" -getkey %ws \"%ws-%ws%ws\"\n\n",
  2816. g_pwszProg,
  2817. strConfig,
  2818. strSerialNumber,
  2819. pwszSimpleName,
  2820. strSerialNumber,
  2821. wszRECSUFFIX);
  2822. }
  2823. else if (fRecoverKey)
  2824. {
  2825. wprintf(
  2826. L"%ws -p \"%ws\" -recoverkey -user \"%ws-%ws%ws\" \"%ws-%ws%ws\"\n\n",
  2827. g_pwszProg,
  2828. wszBatchPassword(0, pwszPassword),
  2829. pwszSimpleName,
  2830. strSerialNumber,
  2831. wszRECSUFFIX,
  2832. pwszSimpleName,
  2833. strSerialNumber,
  2834. wszP12SUFFIX);
  2835. wszBatchPassword(0, NULL); // password data
  2836. }
  2837. else // else just print the filename (for -MergePFX or delete)
  2838. {
  2839. wprintf(
  2840. L"\"%ws-%ws%ws\"",
  2841. pwszSimpleName,
  2842. strSerialNumber,
  2843. pwszSuffix);
  2844. }
  2845. if (NULL != ppwszSimpleName)
  2846. {
  2847. *ppwszSimpleName = pwszSimpleName;
  2848. pwszSimpleName = NULL;
  2849. }
  2850. hr = S_OK;
  2851. error:
  2852. if (NULL != pcc)
  2853. {
  2854. CertFreeCertificateContext(pcc);
  2855. }
  2856. if (NULL != strSerialNumber)
  2857. {
  2858. SysFreeString(strSerialNumber);
  2859. }
  2860. if (NULL != pwszSimpleName)
  2861. {
  2862. LocalFree(pwszSimpleName);
  2863. }
  2864. return(hr);
  2865. }
  2866. HRESULT
  2867. DumpRecoveryCandidate(
  2868. IN GETKEYSERIAL const *pks)
  2869. {
  2870. HRESULT hr;
  2871. CERT_CONTEXT const *pcc = NULL;
  2872. CERT_INFO *pCertInfo;
  2873. pcc = CertCreateCertificateContext(
  2874. X509_ASN_ENCODING,
  2875. (BYTE const *) pks->strCert,
  2876. SysStringByteLen(pks->strCert));
  2877. if (NULL == pcc)
  2878. {
  2879. hr = myHLastError();
  2880. _JumpError(hr, error, "CertCreateCertificateContext");
  2881. }
  2882. pCertInfo = pcc->pCertInfo;
  2883. hr = cuDumpSerial(g_wszPad2, IDS_SERIAL, &pCertInfo->SerialNumber);
  2884. _JumpIfError(hr, error, "cuDumpSerial");
  2885. hr = cuDisplayCertName(
  2886. FALSE, // fMultiLine
  2887. g_wszPad2,
  2888. myLoadResourceString(IDS_SUBJECT), // "Subject"
  2889. g_wszPad2,
  2890. &pCertInfo->Subject,
  2891. pCertInfo);
  2892. _JumpIfError(hr, error, "cuDisplayCertName(Subject)");
  2893. if (NULL != pks->strUPN)
  2894. {
  2895. wprintf(g_wszPad2);
  2896. wprintf(myLoadResourceString(IDS_UPN_COLON)); // "UPN:"
  2897. wprintf(L"%ws\n", pks->strUPN);
  2898. }
  2899. wprintf(g_wszPad2);
  2900. hr = cuDumpFileTime(IDS_NOTBEFORE, NULL, &pCertInfo->NotBefore);
  2901. _JumpIfError(hr, error, "cuDumpFileTime");
  2902. wprintf(g_wszPad2);
  2903. hr = cuDumpFileTime(IDS_NOTAFTER, NULL, &pCertInfo->NotAfter);
  2904. _JumpIfError(hr, error, "cuDumpFileTime");
  2905. hr = cuDumpCertType(g_wszPad2, pCertInfo);
  2906. _PrintIfError(hr, "cuDumpCertType");
  2907. wprintf(g_wszPad2);
  2908. wprintf(
  2909. myLoadResourceString(IDS_FORMAT_VERSION), // "Version: %u"
  2910. 1 + pks->dwVersion);
  2911. wprintf(wszNewLine);
  2912. wprintf(g_wszPad2);
  2913. hr = cuDisplayHash(NULL, pcc, NULL, CERT_SHA1_HASH_PROP_ID, L"sha1");
  2914. _JumpIfError(hr, error, "cuDisplayHash");
  2915. error:
  2916. wprintf(wszNewLine);
  2917. if (NULL != pcc)
  2918. {
  2919. CertFreeCertificateContext(pcc);
  2920. }
  2921. return(hr);
  2922. }
  2923. VOID
  2924. DumpRecoveryCommandLines(
  2925. IN GETKEYSERIAL const *pksList,
  2926. IN DWORD dwVersion,
  2927. IN DWORD cCandidate,
  2928. IN WCHAR const *pwszPasswordIntermediate,
  2929. IN WCHAR const *pwszPasswordFinal)
  2930. {
  2931. GETKEYSERIAL const *pksT;
  2932. BSTR strConfigT;
  2933. DWORD cPFX;
  2934. WCHAR *pwszSimpleName = NULL;
  2935. strConfigT = NULL;
  2936. wprintf(L"\n@echo ");
  2937. wprintf(
  2938. myLoadResourceString(IDS_FORMAT_RECOVER_VERSIONX_KEYS_COLON), // "Version %u certificates and keys:"
  2939. 1 + dwVersion);
  2940. wprintf(wszNewLine);
  2941. // generate certutil -getkey commands:
  2942. for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
  2943. {
  2944. if (NULL != pksT->strConfig)
  2945. {
  2946. strConfigT = pksT->strConfig;
  2947. }
  2948. if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) ||
  2949. (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion))
  2950. {
  2951. DumpGetRecoverMergeCommandLine(
  2952. strConfigT,
  2953. FALSE, // fRecoverKey
  2954. pksT,
  2955. NULL, // pwszPassword
  2956. NULL, // pwszSuffix
  2957. NULL); // ppwszSimpleName
  2958. }
  2959. }
  2960. // generate certutil -recoverkey commands:
  2961. for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
  2962. {
  2963. if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) ||
  2964. (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion))
  2965. {
  2966. DumpGetRecoverMergeCommandLine(
  2967. NULL, // strConfig
  2968. TRUE, // fRecoverKey
  2969. pksT,
  2970. pwszPasswordIntermediate,
  2971. NULL, // pwszSuffix
  2972. NULL); // ppwszSimpleName
  2973. }
  2974. }
  2975. // generate certutil -MergePFX command:
  2976. cPFX = 0;
  2977. wprintf(
  2978. L"%ws -p \"%ws\",\"%ws\" -MergePFX -user ",
  2979. g_pwszProg,
  2980. wszBatchPassword(0, pwszPasswordIntermediate),
  2981. wszBatchPassword(1, CERT_V1 == dwVersion? pwszPasswordIntermediate : pwszPasswordFinal));
  2982. wszBatchPassword(0, NULL); // password data
  2983. wszBatchPassword(1, NULL); // password data
  2984. for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
  2985. {
  2986. if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) ||
  2987. (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion))
  2988. {
  2989. if (0 != cPFX)
  2990. {
  2991. wprintf(L",");
  2992. }
  2993. DumpGetRecoverMergeCommandLine(
  2994. NULL, // strConfig
  2995. FALSE, // fRecoverKey
  2996. pksT,
  2997. NULL, // pwszPassword
  2998. wszP12SUFFIX,
  2999. 0 == cPFX? &pwszSimpleName : NULL);
  3000. cPFX++;
  3001. }
  3002. }
  3003. CSASSERT(cCandidate == cPFX);
  3004. wprintf(
  3005. L" \"%ws%ws%ws\"\n\n",
  3006. pwszSimpleName,
  3007. CERT_V1 == dwVersion? wszV1SUFFIX : L"",
  3008. wszP12SUFFIX);
  3009. // generate intermediate file delete commands:
  3010. for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
  3011. {
  3012. if ((CERT_V1 == dwVersion && CERT_V1 == pksT->dwVersion) ||
  3013. (CERT_V1 != dwVersion && CERT_V1 != pksT->dwVersion))
  3014. {
  3015. wprintf(L"@del ");
  3016. DumpGetRecoverMergeCommandLine(
  3017. NULL, // strConfig
  3018. FALSE, // fRecoverKey
  3019. pksT,
  3020. NULL, // pwszPassword
  3021. wszRECSUFFIX,
  3022. NULL); // ppwszSimpleName
  3023. wprintf(wszNewLine);
  3024. wprintf(L"@del ");
  3025. DumpGetRecoverMergeCommandLine(
  3026. NULL, // strConfig
  3027. FALSE, // fRecoverKey
  3028. pksT,
  3029. NULL, // pwszPassword
  3030. wszP12SUFFIX,
  3031. NULL); // ppwszSimpleName
  3032. wprintf(wszNewLine);
  3033. }
  3034. }
  3035. if (CERT_V1 == dwVersion)
  3036. {
  3037. // generate certutil -ConvertEPF command:
  3038. wprintf(
  3039. L"%ws -p \"%ws,%ws\" -ConvertEPF \"%ws%ws%ws\" \"%ws%ws\"\n",
  3040. g_pwszProg,
  3041. wszBatchPassword(0, pwszPasswordIntermediate),
  3042. wszBatchPassword(1, pwszPasswordFinal),
  3043. pwszSimpleName,
  3044. wszV1SUFFIX,
  3045. wszP12SUFFIX,
  3046. pwszSimpleName,
  3047. wszEPFSUFFIX);
  3048. wszBatchPassword(0, NULL); // password data
  3049. wszBatchPassword(1, NULL); // password data
  3050. // generate V1 intermediate PFX file delete command:
  3051. wprintf(L"@del ");
  3052. wprintf(
  3053. L"@delete \"%ws%ws%ws\"\n",
  3054. pwszSimpleName,
  3055. wszV1SUFFIX,
  3056. wszP12SUFFIX);
  3057. }
  3058. //error:
  3059. if (NULL != pwszSimpleName)
  3060. {
  3061. LocalFree(pwszSimpleName);
  3062. }
  3063. }
  3064. HRESULT
  3065. cuGenerateOutFilePassword(
  3066. OUT WCHAR **ppwszPassword)
  3067. {
  3068. HRESULT hr;
  3069. WCHAR wszPassword[MAX_PATH];
  3070. *ppwszPassword = NULL;
  3071. hr = cuGeneratePassword(
  3072. 1, // cwcMax (use default length)
  3073. wszPassword,
  3074. ARRAYSIZE(wszPassword));
  3075. hr = myDupString(wszPassword, ppwszPassword);
  3076. _JumpIfError(hr, error, "myDupString");
  3077. error:
  3078. SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
  3079. return(hr);
  3080. }
  3081. HRESULT
  3082. verbGetKey(
  3083. IN WCHAR const *pwszOption,
  3084. IN WCHAR const *pwszUserNameOrSerialNumber,
  3085. OPTIONAL IN WCHAR const *pwszfnRecoveryBlob,
  3086. IN WCHAR const *pwszArg3,
  3087. IN WCHAR const *pwszArg4)
  3088. {
  3089. HRESULT hr;
  3090. DISPATCHINTERFACE diConfig;
  3091. BOOL fMustRelease = FALSE;
  3092. WCHAR *pwszCommonName = NULL;
  3093. WCHAR const *pwszRequesterName = NULL;
  3094. WCHAR const *pwszUPN = NULL;
  3095. BSTR strConfig = NULL;
  3096. BSTR strSerialNumber = NULL;
  3097. BYTE *pbHash = NULL;
  3098. DWORD cbHash;
  3099. BSTR strHash = NULL;
  3100. GETKEYSERIAL *pksList = NULL;
  3101. GETKEYSERIAL *pksT;
  3102. DWORD cCandidate;
  3103. DWORD cCandidateV1;
  3104. DWORD cCandidateV3;
  3105. WCHAR *pwszPasswordIntermediate = NULL;
  3106. WCHAR *pwszPasswordFinal = NULL;
  3107. if (NULL == pwszfnRecoveryBlob)
  3108. {
  3109. wprintf(L"\n@goto start\n");
  3110. }
  3111. hr = myMakeSerialBstr(pwszUserNameOrSerialNumber, &strSerialNumber);
  3112. CSASSERT((S_OK != hr) ^ (NULL != strSerialNumber));
  3113. hr = WszToMultiByteInteger(
  3114. TRUE,
  3115. pwszUserNameOrSerialNumber,
  3116. &cbHash,
  3117. &pbHash);
  3118. _PrintIfError2(hr, "WszToMultiByteInteger", hr);
  3119. if (S_OK == hr)
  3120. {
  3121. hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
  3122. _JumpIfError(hr, error, "MultiByteIntegerToBstr");
  3123. }
  3124. hr = myDupString(pwszUserNameOrSerialNumber, &pwszCommonName);
  3125. _JumpIfError(hr, error, "myDupString");
  3126. cuConvertEscapeSequences(pwszCommonName);
  3127. if (NULL != wcschr(pwszUserNameOrSerialNumber, L'\\'))
  3128. {
  3129. pwszRequesterName = pwszUserNameOrSerialNumber;
  3130. }
  3131. if (NULL != wcschr(pwszUserNameOrSerialNumber, L'@'))
  3132. {
  3133. pwszUPN = pwszUserNameOrSerialNumber;
  3134. }
  3135. if (NULL == g_pwszConfig)
  3136. {
  3137. LONG i;
  3138. LONG count;
  3139. LONG Index;
  3140. hr = Config_Init(g_DispatchFlags, &diConfig);
  3141. _JumpIfError(hr, error, "Config_Init");
  3142. fMustRelease = TRUE;
  3143. hr = Config_Reset(&diConfig, 0, &count);
  3144. _JumpIfError(hr, error, "Config_Reset");
  3145. Index = 0;
  3146. for (i = 0; i < count; i++)
  3147. {
  3148. hr = Config_Next(&diConfig, &Index);
  3149. if (S_OK != hr && S_FALSE != hr)
  3150. {
  3151. _JumpError(hr, error, "Config_Next");
  3152. }
  3153. hr = S_OK;
  3154. if (-1 == Index)
  3155. {
  3156. break;
  3157. }
  3158. hr = Config_GetField(&diConfig, wszCONFIG_CONFIG, &strConfig);
  3159. _JumpIfError(hr, error, "Config_GetField");
  3160. hr = GetKey(
  3161. strConfig,
  3162. pwszCommonName,
  3163. pwszRequesterName,
  3164. pwszUPN,
  3165. strSerialNumber,
  3166. strHash,
  3167. &pksList);
  3168. _PrintIfError(hr, "GetKey"); // Ignore connection failures
  3169. }
  3170. }
  3171. else
  3172. {
  3173. hr = GetKey(
  3174. g_pwszConfig,
  3175. pwszCommonName,
  3176. pwszRequesterName,
  3177. pwszUPN,
  3178. strSerialNumber,
  3179. strHash,
  3180. &pksList);
  3181. _JumpIfError(hr, error, "GetKey");
  3182. }
  3183. cCandidateV1 = 0;
  3184. cCandidateV3 = 0;
  3185. for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
  3186. {
  3187. if (NULL != pksT->strConfig)
  3188. {
  3189. wprintf(L"\n\"%ws\"\n", pksT->strConfig);
  3190. }
  3191. hr = DumpRecoveryCandidate(pksT);
  3192. _JumpIfError(hr, error, "DumpRecoveryCandidate");
  3193. if (CERT_V1 == pksT->dwVersion)
  3194. {
  3195. cCandidateV1++;
  3196. }
  3197. else
  3198. {
  3199. cCandidateV3++;
  3200. }
  3201. }
  3202. cCandidate = cCandidateV1 + cCandidateV3;
  3203. if (NULL == pwszfnRecoveryBlob && 0 != cCandidate)
  3204. {
  3205. hr = cuGenerateOutFilePassword(&pwszPasswordIntermediate);
  3206. _JumpIfError(hr, error, "cuGenerateOutFilePassword");
  3207. hr = cuGenerateOutFilePassword(&pwszPasswordFinal);
  3208. _JumpIfError(hr, error, "cuGenerateOutFilePassword");
  3209. wprintf(L"\n:start\n");
  3210. if (0 != cCandidateV1)
  3211. {
  3212. DumpRecoveryCommandLines(
  3213. pksList,
  3214. CERT_V1,
  3215. cCandidateV1,
  3216. pwszPasswordIntermediate,
  3217. pwszPasswordFinal);
  3218. }
  3219. if (0 != cCandidateV3)
  3220. {
  3221. DumpRecoveryCommandLines(
  3222. pksList,
  3223. CERT_V3,
  3224. cCandidateV3,
  3225. pwszPasswordIntermediate,
  3226. pwszPasswordFinal);
  3227. }
  3228. wprintf(L"@echo PASSWORD: \"%ws\"\n", wszBatchPassword(0, pwszPasswordFinal));
  3229. wszBatchPassword(0, NULL); // password data
  3230. wprintf(L"\n@goto exit\n");
  3231. }
  3232. if (1 != cCandidate)
  3233. {
  3234. hr = 0 == cCandidate? CRYPT_E_NOT_FOUND : TYPE_E_AMBIGUOUSNAME;
  3235. _JumpError(hr, error, "GetKey");
  3236. }
  3237. hr = GetArchivedKey(
  3238. pksList->strConfig,
  3239. pksList->RequestId,
  3240. pwszfnRecoveryBlob);
  3241. _JumpIfError(hr, error, "GetArchivedKey");
  3242. error:
  3243. while (NULL != pksList)
  3244. {
  3245. pksT = pksList;
  3246. pksList = pksList->Next;
  3247. FreeKeySerialEntry(pksT);
  3248. }
  3249. if (fMustRelease)
  3250. {
  3251. Config_Release(&diConfig);
  3252. }
  3253. if (NULL != strConfig)
  3254. {
  3255. SysFreeString(strConfig);
  3256. }
  3257. if (NULL != pwszPasswordIntermediate)
  3258. {
  3259. myZeroDataString(pwszPasswordIntermediate); // password data
  3260. LocalFree(pwszPasswordIntermediate);
  3261. }
  3262. if (NULL != pwszPasswordFinal)
  3263. {
  3264. myZeroDataString(pwszPasswordFinal); // password data
  3265. LocalFree(pwszPasswordFinal);
  3266. }
  3267. if (NULL != pwszCommonName)
  3268. {
  3269. LocalFree(pwszCommonName);
  3270. }
  3271. if (NULL != pbHash)
  3272. {
  3273. LocalFree(pbHash);
  3274. }
  3275. if (NULL != strHash)
  3276. {
  3277. SysFreeString(strHash);
  3278. }
  3279. if (NULL != strSerialNumber)
  3280. {
  3281. SysFreeString(strSerialNumber);
  3282. }
  3283. return(hr);
  3284. }
  3285. VOID
  3286. DeleteKey(
  3287. IN CRYPT_KEY_PROV_INFO const *pkpi)
  3288. {
  3289. HCRYPTPROV hProv;
  3290. CryptAcquireContext(
  3291. &hProv,
  3292. pkpi->pwszContainerName,
  3293. pkpi->pwszProvName,
  3294. pkpi->dwProvType,
  3295. CRYPT_DELETEKEYSET | pkpi->dwFlags);
  3296. }
  3297. HRESULT
  3298. SaveRecoveredKey(
  3299. IN CERT_CONTEXT const *pccUser,
  3300. IN BYTE const *pbKey,
  3301. IN DWORD cbKey,
  3302. OPTIONAL IN WCHAR const *pwszfnPFX,
  3303. OPTIONAL IN WCHAR const *pwszPassword)
  3304. {
  3305. HRESULT hr;
  3306. HCERTSTORE hStoreMemory = NULL;
  3307. BOOL fMatchingKey;
  3308. WCHAR wszPassword[MAX_PATH];
  3309. CRYPT_KEY_PROV_INFO kpi;
  3310. CRYPT_DATA_BLOB pfx;
  3311. BOOL fSigningKey;
  3312. pfx.pbData = NULL;
  3313. ZeroMemory(&kpi, sizeof(kpi));
  3314. hr = myValidateKeyBlob(
  3315. pbKey,
  3316. cbKey,
  3317. &pccUser->pCertInfo->SubjectPublicKeyInfo,
  3318. CERT_V1 == pccUser->pCertInfo->dwVersion,
  3319. &fSigningKey,
  3320. &kpi);
  3321. _JumpIfError(hr, error, "myValidateKeyBlob");
  3322. if (!CertSetCertificateContextProperty(
  3323. pccUser,
  3324. CERT_KEY_PROV_INFO_PROP_ID,
  3325. 0,
  3326. &kpi))
  3327. {
  3328. hr = myHLastError();
  3329. _JumpError(hr, error, "CertSetCertificateContextProperty");
  3330. }
  3331. hStoreMemory = CertOpenStore(
  3332. CERT_STORE_PROV_MEMORY,
  3333. X509_ASN_ENCODING,
  3334. NULL,
  3335. 0,
  3336. NULL);
  3337. if (NULL == hStoreMemory)
  3338. {
  3339. hr = myHLastError();
  3340. _JumpError(hr, error, "CertOpenStore");
  3341. }
  3342. // Begin Chain Building
  3343. hr = myAddChainToMemoryStore(hStoreMemory, pccUser, g_dwmsTimeout);
  3344. _JumpIfError(hr, error, "myAddChainToMemoryStore");
  3345. // End Chain Building
  3346. if (NULL != pwszfnPFX)
  3347. {
  3348. hr = cuGetPassword(
  3349. 0, // idsPrompt
  3350. NULL, // pwszfn
  3351. pwszPassword,
  3352. TRUE, // fVerify
  3353. wszPassword,
  3354. ARRAYSIZE(wszPassword),
  3355. &pwszPassword);
  3356. _JumpIfError(hr, error, "cuGetPassword");
  3357. }
  3358. hr = myPFXExportCertStore(
  3359. hStoreMemory,
  3360. &pfx,
  3361. pwszPassword,
  3362. !g_fWeakPFX,
  3363. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY);
  3364. _JumpIfError(hr, error, "myPFXExportCertStore");
  3365. if (NULL != pwszfnPFX)
  3366. {
  3367. hr = EncodeToFileW(
  3368. pwszfnPFX,
  3369. pfx.pbData,
  3370. pfx.cbData,
  3371. CRYPT_STRING_BINARY | (g_fForce? DECF_FORCEOVERWRITE : 0));
  3372. _JumpIfError(hr, error, "EncodeToFileW");
  3373. }
  3374. error:
  3375. SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data
  3376. if (NULL != hStoreMemory)
  3377. {
  3378. CertCloseStore(hStoreMemory, CERT_CLOSE_STORE_CHECK_FLAG);
  3379. }
  3380. if (NULL != kpi.pwszContainerName)
  3381. {
  3382. DeleteKey(&kpi);
  3383. LocalFree(kpi.pwszContainerName);
  3384. }
  3385. if (NULL != pfx.pbData)
  3386. {
  3387. LocalFree(pfx.pbData);
  3388. }
  3389. return(hr);
  3390. }
  3391. #if DBG_CERTSRV
  3392. #define CDWMS 6
  3393. VOID
  3394. DumpRecoverTime(
  3395. IN char const *pszPrefix,
  3396. IN DWORD *rgdwms,
  3397. IN DWORD idwms)
  3398. {
  3399. CSASSERT(0 < idwms);
  3400. CSASSERT(CDWMS > idwms);
  3401. rgdwms[idwms] = GetTickCount();
  3402. DBGPRINT((
  3403. g_fVerbose? DBG_SS_CERTUTIL : DBG_SS_CERTUTILI,
  3404. "RecoverKey[%u]: %hs: %ums/%ums\n",
  3405. idwms,
  3406. pszPrefix,
  3407. rgdwms[idwms] - rgdwms[idwms - 1],
  3408. rgdwms[idwms] - rgdwms[0]));
  3409. }
  3410. #endif
  3411. HRESULT
  3412. verbRecoverKey(
  3413. IN WCHAR const *pwszOption,
  3414. IN WCHAR const *pwszfnRecoveryBlob,
  3415. OPTIONAL IN WCHAR const *pwszfnPFX,
  3416. OPTIONAL IN WCHAR const *pwszRecipientIndex,
  3417. IN WCHAR const *pwszArg4)
  3418. {
  3419. HRESULT hr;
  3420. BYTE *pbIn = NULL;
  3421. DWORD cbIn;
  3422. BYTE *pbEncryptedPKCS7 = NULL;
  3423. DWORD cbEncryptedPKCS7;
  3424. DWORD cSigner;
  3425. DWORD cRecipient;
  3426. DWORD dwMsgType;
  3427. char *pszInnerContentObjId = NULL;
  3428. HCERTSTORE hStore = NULL;
  3429. HCRYPTMSG hMsg = NULL;
  3430. CERT_CONTEXT const *pccUser = NULL;
  3431. BYTE abHashUserCert[CBMAX_CRYPT_HASH_LEN];
  3432. CRYPT_HASH_BLOB BlobHash;
  3433. BYTE *pbKey = NULL;
  3434. DWORD cbKey;
  3435. DWORD RecipientIndex = MAXDWORD;
  3436. DBGCODE(DWORD adwms[CDWMS]);
  3437. DBGCODE(adwms[0] = GetTickCount());
  3438. if (NULL != pwszRecipientIndex)
  3439. {
  3440. hr = myGetLong(pwszRecipientIndex, (LONG *) &RecipientIndex);
  3441. _JumpIfError(hr, error, "RecipientIndex must be a number");
  3442. }
  3443. hr = DecodeFileW(pwszfnRecoveryBlob, &pbIn, &cbIn, CRYPT_STRING_ANY);
  3444. if (S_OK != hr)
  3445. {
  3446. cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr);
  3447. goto error;
  3448. }
  3449. // Decode outer PKCS 7 signed message, which contains all of the certs.
  3450. hr = myDecodePKCS7(
  3451. pbIn,
  3452. cbIn,
  3453. &pbEncryptedPKCS7,
  3454. &cbEncryptedPKCS7,
  3455. &dwMsgType,
  3456. &pszInnerContentObjId,
  3457. &cSigner,
  3458. &cRecipient,
  3459. &hStore,
  3460. &hMsg);
  3461. _JumpIfError(hr, error, "myDecodePKCS7(outer)");
  3462. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3463. if (CMSG_SIGNED != dwMsgType)
  3464. {
  3465. _JumpError(hr, error, "dwMsgType(outer)");
  3466. }
  3467. if (0 == cSigner)
  3468. {
  3469. _JumpError(hr, error, "cSigner(outer)");
  3470. }
  3471. if (0 != cRecipient)
  3472. {
  3473. _JumpError(hr, error, "cRecipient(outer)");
  3474. }
  3475. if (NULL == pszInnerContentObjId ||
  3476. 0 != strcmp(szOID_RSA_data, pszInnerContentObjId))
  3477. {
  3478. _JumpError(hr, error, "pszInnerContentObjId(outer)");
  3479. }
  3480. CSASSERT(NULL != hMsg);
  3481. ZeroMemory(abHashUserCert, sizeof(abHashUserCert));
  3482. BlobHash.cbData = sizeof(abHashUserCert);
  3483. BlobHash.pbData = abHashUserCert;
  3484. hr = cuDumpSigners(
  3485. hMsg,
  3486. pszInnerContentObjId,
  3487. hStore,
  3488. cSigner,
  3489. NULL == pbEncryptedPKCS7, // fContentEmpty
  3490. TRUE, // fVerifyOnly
  3491. BlobHash.pbData,
  3492. &BlobHash.cbData);
  3493. _JumpIfError(hr, error, "cuDumpSigners(outer)");
  3494. pccUser = CertFindCertificateInStore(
  3495. hStore,
  3496. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  3497. 0, // dwFindFlags
  3498. CERT_FIND_HASH,
  3499. &BlobHash,
  3500. NULL);
  3501. if (NULL == pccUser)
  3502. {
  3503. hr = myHLastError();
  3504. _JumpError(hr, error, "CertFindCertificateInStore");
  3505. }
  3506. LocalFree(pszInnerContentObjId);
  3507. pszInnerContentObjId = NULL;
  3508. CryptMsgClose(hMsg);
  3509. hMsg = NULL;
  3510. // Decode inner PKCS 7 encrypted message, which contains the private key.
  3511. DBGCODE(DumpRecoverTime("Outer PKCS 7", adwms, 1));
  3512. hr = myDecodePKCS7(
  3513. pbEncryptedPKCS7,
  3514. cbEncryptedPKCS7,
  3515. NULL, // ppbContents
  3516. NULL, // pcbContents
  3517. &dwMsgType,
  3518. &pszInnerContentObjId,
  3519. &cSigner,
  3520. &cRecipient,
  3521. NULL, // phStore
  3522. &hMsg);
  3523. _JumpIfError(hr, error, "myDecodePKCS7(inner)");
  3524. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3525. if (CMSG_ENVELOPED != dwMsgType)
  3526. {
  3527. _JumpError(hr, error, "dwMsgType(inner)");
  3528. }
  3529. if (0 != cSigner)
  3530. {
  3531. _JumpError(hr, error, "cSigner(inner)");
  3532. }
  3533. if (0 == cRecipient)
  3534. {
  3535. _JumpError(hr, error, "cRecipient(inner)");
  3536. }
  3537. if (NULL == pszInnerContentObjId ||
  3538. 0 != strcmp(szOID_RSA_data, pszInnerContentObjId))
  3539. {
  3540. _JumpError(hr, error, "pszInnerContentObjId(inner)");
  3541. }
  3542. CSASSERT(NULL != hMsg);
  3543. if (MAXDWORD != RecipientIndex && cRecipient <= RecipientIndex)
  3544. {
  3545. hr = E_INVALIDARG;
  3546. _JumpError(hr, error, "RecipientIndex too large");
  3547. }
  3548. DBGCODE(DumpRecoverTime("Inner PKCS 7", adwms, 2));
  3549. hr = cuDumpEncryptedAsnBinary(
  3550. hMsg,
  3551. cRecipient,
  3552. RecipientIndex,
  3553. hStore,
  3554. NULL,
  3555. pbEncryptedPKCS7,
  3556. cbEncryptedPKCS7,
  3557. TRUE,
  3558. &pbKey,
  3559. &cbKey);
  3560. {
  3561. HRESULT hr2;
  3562. wprintf(wszNewLine);
  3563. wprintf(myLoadResourceString(IDS_USER_CERT)); // "User Certificate:"
  3564. wprintf(wszNewLine);
  3565. hr2 = cuDumpIssuerSerialAndSubject(
  3566. &pccUser->pCertInfo->Issuer,
  3567. &pccUser->pCertInfo->SerialNumber,
  3568. &pccUser->pCertInfo->Subject,
  3569. NULL); // hStore
  3570. _PrintIfError(hr2, "cuDumpIssuerSerialAndSubject(user)");
  3571. hr2 = cuDisplayHash(
  3572. g_wszPad4,
  3573. pccUser,
  3574. NULL,
  3575. CERT_SHA1_HASH_PROP_ID,
  3576. L"sha1");
  3577. _PrintIfError(hr2, "cuDisplayHash");
  3578. }
  3579. DBGCODE(DumpRecoverTime("Decrypt key", adwms, 3));
  3580. if (CRYPT_E_NO_DECRYPT_CERT != hr)
  3581. {
  3582. _JumpIfError(hr, error, "cuDumpEncryptedAsnBinary");
  3583. if (g_fVerbose)
  3584. {
  3585. wprintf(wszNewLine);
  3586. hr = cuDumpPrivateKeyBlob(pbKey, cbKey, FALSE);
  3587. _JumpIfError(hr, error, "cuDumpPrivateKeyBlob");
  3588. }
  3589. // Verify the key matches the cert, then save in a PFX
  3590. hr = SaveRecoveredKey(
  3591. pccUser,
  3592. pbKey,
  3593. cbKey,
  3594. pwszfnPFX,
  3595. g_pwszPassword);
  3596. _JumpIfError(hr, error, "SaveRecoveredKey");
  3597. DBGCODE(DumpRecoverTime("Save key", adwms, 4));
  3598. }
  3599. else
  3600. {
  3601. // Can't decrypt the private key, list Recipient cert info.
  3602. wprintf(myLoadResourceString(IDS_CANT_DECRYPT)); // "Cannot decrypt message content."
  3603. wprintf(wszNewLine);
  3604. DBGCODE(DumpRecoverTime("nop", adwms, 4));
  3605. }
  3606. if (CRYPT_E_NO_DECRYPT_CERT == hr || NULL == pwszfnPFX)
  3607. {
  3608. HRESULT hrDecrypt = hr;
  3609. wprintf(wszNewLine);
  3610. wprintf(myLoadResourceString(IDS_NEED_RECOVERY_CERT)); // "Key recovery requires one of the following certificates and its private key:"
  3611. wprintf(wszNewLine);
  3612. hr = cuDumpRecipients(hMsg, hStore, cRecipient, TRUE);
  3613. _JumpIfError(hr, error, "cuDumpRecipients");
  3614. hr = hrDecrypt;
  3615. _JumpIfError(hr, error, "Cannot decrypt");
  3616. }
  3617. DBGCODE(DumpRecoverTime("Done", adwms, 5));
  3618. hr = S_OK;
  3619. error:
  3620. if (NULL != pccUser)
  3621. {
  3622. CertFreeCertificateContext(pccUser);
  3623. }
  3624. if (NULL != pbKey)
  3625. {
  3626. LocalFree(pbKey);
  3627. }
  3628. if (NULL != pbIn)
  3629. {
  3630. LocalFree(pbIn);
  3631. }
  3632. if (NULL != pbEncryptedPKCS7)
  3633. {
  3634. LocalFree(pbEncryptedPKCS7);
  3635. }
  3636. if (NULL != pszInnerContentObjId)
  3637. {
  3638. LocalFree(pszInnerContentObjId);
  3639. }
  3640. if (NULL != hStore)
  3641. {
  3642. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  3643. }
  3644. if (NULL != hMsg)
  3645. {
  3646. CryptMsgClose(hMsg);
  3647. }
  3648. return(hr);
  3649. }