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.

2354 lines
61 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: request.cpp
  7. //
  8. // Contents: Cert Server client implementation
  9. //
  10. // History: 24-Aug-96 vich created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include "pch.cpp"
  14. #pragma hdrstop
  15. #include <objbase.h>
  16. #include "certsrvd.h"
  17. #include "csdisp.h"
  18. #include "certrpc.h"
  19. #include <certca.h>
  20. #include "request.h"
  21. #define __dwFILE__ __dwFILE_CERTCLI_REQUEST_CPP__
  22. #define CR_RPC_CANCEL_TIMEOUT 5
  23. #define CR_RPC_REQUEST_TIMEOUT 60000 /* 60 seconds for the request timeout */
  24. typedef struct _RPC_TIMEOUT_CONTEXT
  25. {
  26. HANDLE hWait;
  27. HANDLE hEvent;
  28. HANDLE hThread;
  29. HRESULT hrRpcError;
  30. } RPC_TIMEOUT_CONTEXT, *PRPC_TIMEOUT_CONTEXT;
  31. typedef struct _WZR_RPC_BINDING_LIST
  32. {
  33. LPWSTR pszProtSeq;
  34. LPWSTR pszEndpoint;
  35. } WZR_RPC_BINDING_LIST;
  36. WZR_RPC_BINDING_LIST g_awzrBindingList[] =
  37. {
  38. { L"ncacn_ip_tcp", NULL },
  39. { L"ncacn_np", L"\\pipe\\cert" }
  40. };
  41. INT g_cwzrBindingList = sizeof(g_awzrBindingList)/sizeof(g_awzrBindingList[0]);
  42. typedef struct _WZR_RPC_ATHN_LIST
  43. {
  44. DWORD dwAuthnLevel;
  45. DWORD dwAuthnService;
  46. } WZR_RPC_ATHN_LIST;
  47. WZR_RPC_ATHN_LIST g_awzrAthnList[] =
  48. {
  49. { RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE},
  50. { RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_GSS_NEGOTIATE},
  51. { RPC_C_AUTHN_LEVEL_NONE, RPC_C_AUTHN_NONE }
  52. };
  53. INT g_cwzrAthnList = sizeof(g_awzrAthnList)/sizeof(g_awzrAthnList[0]);
  54. HRESULT
  55. crRegisterRPCCallTimeout(
  56. IN DWORD dwMilliseconds,
  57. OUT PRPC_TIMEOUT_CONTEXT pTimeout);
  58. HRESULT
  59. crCloseRPCCallTimeout(
  60. IN PRPC_TIMEOUT_CONTEXT pTimeout);
  61. HRESULT
  62. crSetRPCSecurity(
  63. IN handle_t hRPCCertServer,
  64. IN OUT INT *prpcAuthProtocol)
  65. {
  66. HRESULT hr = S_OK;
  67. LPWSTR pwszCAPrinceName = NULL;
  68. INT rpcAuthProtocol = *prpcAuthProtocol;
  69. // Set the RPC connect as the SNEGO connect, which can authenticate
  70. // a machine if supported by the system.
  71. // Don't need to check the return value since not supported by NT4/Win9x.
  72. if (rpcAuthProtocol >= g_cwzrAthnList)
  73. {
  74. hr = RPC_S_UNKNOWN_AUTHN_SERVICE;
  75. goto error;
  76. }
  77. for ( ; rpcAuthProtocol < g_cwzrAthnList; rpcAuthProtocol++)
  78. {
  79. pwszCAPrinceName = NULL;
  80. if (RPC_C_AUTHN_NONE != g_awzrAthnList[rpcAuthProtocol].dwAuthnService)
  81. {
  82. hr = RpcMgmtInqServerPrincName(
  83. hRPCCertServer,
  84. g_awzrAthnList[rpcAuthProtocol].dwAuthnService,
  85. &pwszCAPrinceName);
  86. if (hr == RPC_S_UNKNOWN_AUTHN_SERVICE)
  87. {
  88. continue;
  89. }
  90. }
  91. hr = RpcBindingSetAuthInfo(
  92. hRPCCertServer,
  93. pwszCAPrinceName,
  94. g_awzrAthnList[rpcAuthProtocol].dwAuthnLevel,
  95. g_awzrAthnList[rpcAuthProtocol].dwAuthnService,
  96. NULL,
  97. RPC_C_AUTHZ_NONE);
  98. if (NULL != pwszCAPrinceName)
  99. {
  100. RpcStringFree(&pwszCAPrinceName);
  101. }
  102. if (hr != RPC_S_UNKNOWN_AUTHN_SERVICE)
  103. {
  104. break;
  105. }
  106. }
  107. error:
  108. *prpcAuthProtocol = rpcAuthProtocol;
  109. return(hr);
  110. }
  111. HRESULT
  112. crOpenRPCConnection(
  113. IN WCHAR const *pwszServerName,
  114. IN OUT INT *prpcAuthProtocol,
  115. OUT handle_t *phRPCCertServer)
  116. {
  117. HRESULT hr = S_OK;
  118. INT i;
  119. WCHAR *pwszStringBinding = NULL;
  120. for (i = 0; i < g_cwzrBindingList; i++)
  121. {
  122. if (RPC_S_OK != RpcNetworkIsProtseqValid(
  123. g_awzrBindingList[i].pszProtSeq))
  124. {
  125. continue;
  126. }
  127. hr = RpcStringBindingCompose(
  128. NULL,
  129. g_awzrBindingList[i].pszProtSeq,
  130. const_cast<WCHAR *>(pwszServerName),
  131. g_awzrBindingList[i].pszEndpoint,
  132. NULL,
  133. &pwszStringBinding);
  134. if (S_OK != hr)
  135. {
  136. continue;
  137. }
  138. hr = RpcBindingFromStringBinding(
  139. pwszStringBinding,
  140. phRPCCertServer);
  141. if (NULL != pwszStringBinding)
  142. {
  143. RpcStringFree(&pwszStringBinding);
  144. }
  145. if (S_OK != hr)
  146. {
  147. continue;
  148. }
  149. hr = RpcEpResolveBinding(
  150. *phRPCCertServer,
  151. ICertPassage_v0_0_c_ifspec);
  152. if (S_OK == hr)
  153. {
  154. break;
  155. }
  156. }
  157. _JumpIfError(hr, error, "RPC Resolve Binding Loop");
  158. hr = crSetRPCSecurity(*phRPCCertServer, prpcAuthProtocol);
  159. _JumpIfError(hr, error, "_SetRPCSecurity");
  160. error:
  161. if (NULL != pwszStringBinding)
  162. {
  163. RpcStringFree(&pwszStringBinding);
  164. }
  165. return(hr);
  166. }
  167. VOID
  168. crCloseRPCConnection(
  169. IN OUT handle_t *phRPCCertServer)
  170. {
  171. if (NULL != *phRPCCertServer)
  172. {
  173. RpcBindingFree(phRPCCertServer);
  174. *phRPCCertServer = NULL;
  175. }
  176. }
  177. HRESULT
  178. crCertServerRequest(
  179. IN handle_t hRPCCertServer,
  180. IN OUT INT *prpcAuthProtocol,
  181. IN DWORD Flags,
  182. IN WCHAR const *pwszAuthority,
  183. IN OUT DWORD *pRequestId,
  184. OUT DWORD *pDisposition,
  185. IN CERTTRANSBLOB const *pctbAttrib,
  186. IN CERTTRANSBLOB const *pctbSerial,
  187. IN CERTTRANSBLOB const *pctbRequest,
  188. OUT CERTTRANSBLOB *pctbCertChain,
  189. OUT CERTTRANSBLOB *pctbCert,
  190. OUT CERTTRANSBLOB *pctbDispositionMessage)
  191. {
  192. HRESULT hr;
  193. RPC_TIMEOUT_CONTEXT Timeout = {NULL, NULL, NULL, S_OK};
  194. do
  195. {
  196. // Midl_user_allocate registers memory in RPC case
  197. hr = crRegisterRPCCallTimeout(CR_RPC_REQUEST_TIMEOUT, &Timeout);
  198. _JumpIfError(hr, error, "crRegisterRPCCallTimeout");
  199. // for pending requests, pass the serial number in pctbAttrib
  200. if (NULL == pctbAttrib ||
  201. NULL == pctbAttrib->pb ||
  202. 0 == pctbAttrib->cb)
  203. {
  204. pctbAttrib = pctbSerial;
  205. }
  206. __try
  207. {
  208. hr = CertServerRequest(
  209. hRPCCertServer,
  210. Flags,
  211. pwszAuthority,
  212. pRequestId,
  213. pDisposition,
  214. pctbAttrib, // or SerialNumber
  215. pctbRequest,
  216. pctbCertChain,
  217. pctbCert,
  218. pctbDispositionMessage);
  219. }
  220. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  221. {
  222. }
  223. if (HRESULT_FROM_WIN32(RPC_S_CALL_CANCELLED) == hr)
  224. {
  225. hr = Timeout.hrRpcError;
  226. crCloseRPCCallTimeout(&Timeout);
  227. }
  228. _PrintIfError(hr, "CertServerRequest");
  229. if (hr == RPC_S_UNKNOWN_AUTHN_SERVICE)
  230. {
  231. (*prpcAuthProtocol)++;
  232. hr = crSetRPCSecurity(hRPCCertServer, prpcAuthProtocol);
  233. if (hr == RPC_S_UNKNOWN_AUTHN_SERVICE)
  234. {
  235. break;
  236. }
  237. if (hr == S_OK)
  238. {
  239. continue;
  240. }
  241. }
  242. } while (hr == RPC_S_UNKNOWN_AUTHN_SERVICE);
  243. error:
  244. return(hr);
  245. }
  246. HRESULT
  247. crRequestCertificate(
  248. IN DWORD Flags,
  249. OPTIONAL IN BYTE const *pbRequest,
  250. IN DWORD cbRequest,
  251. IN DWORD RequestId,
  252. OPTIONAL IN WCHAR const *pwszRequestAttributes,
  253. OPTIONAL IN WCHAR const *pwszSerialNumber,
  254. IN WCHAR const *pwszServerName,
  255. IN WCHAR const *pwszAuthority,
  256. OUT CERTSERVERENROLL **ppcsEnroll) // free via CertServerFreeMemory
  257. {
  258. HRESULT hr;
  259. handle_t hRPCCertServer = NULL;
  260. INT rpcAuthProtocol = 0;
  261. CERTTRANSBLOB ctbRequest;
  262. CERTTRANSBLOB ctbAttrib;
  263. CERTTRANSBLOB ctbSerial;
  264. CERTTRANSBLOB ctbCert = { 0, NULL };
  265. CERTTRANSBLOB ctbCertChain = { 0, NULL };
  266. CERTTRANSBLOB ctbDispositionMessage = { 0, NULL };
  267. CERTSERVERENROLL csEnroll;
  268. CERTSERVERENROLL *pcsEnroll = NULL;
  269. BYTE *pbOut;
  270. DWORD cbAlloc;
  271. if (NULL == pwszServerName || NULL == pwszAuthority || NULL == ppcsEnroll)
  272. {
  273. hr = E_POINTER;
  274. _JumpError(hr, error, "NULL parm");
  275. }
  276. *ppcsEnroll = NULL;
  277. ZeroMemory(&csEnroll, sizeof(csEnroll));
  278. csEnroll.hrLastStatus = E_FAIL;
  279. csEnroll.Disposition = CR_DISP_ERROR;
  280. csEnroll.RequestId = RequestId;
  281. ctbRequest.pb = const_cast<BYTE *>(pbRequest);
  282. ctbRequest.cb = cbRequest;
  283. ctbAttrib.pb = (BYTE *) pwszRequestAttributes;
  284. ctbAttrib.cb = 0;
  285. if (NULL != pwszRequestAttributes)
  286. {
  287. ctbAttrib.cb = (wcslen(pwszRequestAttributes) + 1) * sizeof(WCHAR);
  288. }
  289. ctbSerial.pb = (BYTE *) pwszSerialNumber;
  290. ctbSerial.cb = 0;
  291. if (NULL != pwszSerialNumber)
  292. {
  293. ctbSerial.cb = (wcslen(pwszSerialNumber) + 1) * sizeof(WCHAR);
  294. }
  295. hr = crOpenRPCConnection(pwszServerName, &rpcAuthProtocol, &hRPCCertServer);
  296. _JumpIfError(hr, error, "crOpenRPCConnection");
  297. hr = crCertServerRequest(
  298. hRPCCertServer,
  299. &rpcAuthProtocol,
  300. Flags,
  301. pwszAuthority,
  302. &csEnroll.RequestId,
  303. &csEnroll.Disposition,
  304. &ctbAttrib,
  305. &ctbSerial,
  306. &ctbRequest,
  307. &ctbCertChain,
  308. &ctbCert,
  309. &ctbDispositionMessage);
  310. _JumpIfError(hr, error, "crCertServerRequest");
  311. csEnroll.hrLastStatus = hr;
  312. if (FAILED(csEnroll.Disposition))
  313. {
  314. csEnroll.hrLastStatus = csEnroll.Disposition;
  315. csEnroll.Disposition = CR_DISP_DENIED;
  316. }
  317. cbAlloc = sizeof(*pcsEnroll) +
  318. DWORDROUND(ctbCert.cb) +
  319. DWORDROUND(ctbCertChain.cb) +
  320. DWORDROUND(ctbDispositionMessage.cb);
  321. pcsEnroll = (CERTSERVERENROLL *) LocalAlloc(LMEM_FIXED, cbAlloc);
  322. if (NULL == pcsEnroll)
  323. {
  324. hr = E_OUTOFMEMORY;
  325. _JumpError(hr, error, "LocalAlloc");
  326. }
  327. *pcsEnroll = csEnroll; // structure copy
  328. pbOut = (BYTE *) &pcsEnroll[1];
  329. if (0 != ctbCert.cb)
  330. {
  331. CSASSERT(NULL != ctbCert.pb);
  332. pcsEnroll->pbCert = pbOut;
  333. pcsEnroll->cbCert = ctbCert.cb;
  334. CopyMemory(pbOut, ctbCert.pb, ctbCert.cb);
  335. pbOut += DWORDROUND(ctbCert.cb);
  336. }
  337. if (0 != ctbCertChain.cb)
  338. {
  339. CSASSERT(NULL != ctbCertChain.pb);
  340. pcsEnroll->pbCertChain = pbOut;
  341. pcsEnroll->cbCertChain = ctbCertChain.cb;
  342. CopyMemory(pbOut, ctbCertChain.pb, ctbCertChain.cb);
  343. pbOut += DWORDROUND(ctbCertChain.cb);
  344. }
  345. if (0 != ctbDispositionMessage.cb)
  346. {
  347. CSASSERT(NULL != ctbDispositionMessage.pb);
  348. pcsEnroll->pwszDispositionMessage = (WCHAR *) pbOut;
  349. CopyMemory(pbOut, ctbDispositionMessage.pb, ctbDispositionMessage.cb);
  350. pbOut += DWORDROUND(ctbDispositionMessage.cb);
  351. }
  352. CSASSERT(pbOut == &((BYTE *) pcsEnroll)[cbAlloc]);
  353. *ppcsEnroll = pcsEnroll;
  354. error:
  355. if (NULL != ctbCert.pb)
  356. {
  357. MIDL_user_free(ctbCert.pb);
  358. }
  359. if (NULL != ctbCertChain.pb)
  360. {
  361. MIDL_user_free(ctbCertChain.pb);
  362. }
  363. if (NULL != ctbDispositionMessage.pb)
  364. {
  365. MIDL_user_free(ctbDispositionMessage.pb);
  366. }
  367. crCloseRPCConnection(&hRPCCertServer);
  368. return(hr);
  369. }
  370. HRESULT
  371. CertServerSubmitRequest(
  372. IN DWORD Flags,
  373. IN BYTE const *pbRequest,
  374. IN DWORD cbRequest,
  375. OPTIONAL IN WCHAR const *pwszRequestAttributes,
  376. IN WCHAR const *pwszServerName,
  377. IN WCHAR const *pwszAuthority,
  378. OUT CERTSERVERENROLL **ppcsEnroll) // free via CertServerFreeMemory
  379. {
  380. HRESULT hr;
  381. if (NULL == pbRequest)
  382. {
  383. hr = E_POINTER;
  384. _JumpError(hr, error, "NULL parm");
  385. }
  386. if (CR_IN_BINARY != (CR_IN_ENCODEMASK & Flags))
  387. {
  388. hr = E_INVALIDARG;
  389. _JumpError(hr, error, "not CR_IN_BINARY");
  390. }
  391. hr = crRequestCertificate(
  392. Flags,
  393. pbRequest,
  394. cbRequest,
  395. 0, // RequestId
  396. pwszRequestAttributes,
  397. NULL, // pwszSerialNumber
  398. pwszServerName,
  399. pwszAuthority,
  400. ppcsEnroll);
  401. _JumpIfError(hr, error, "crRequestCertificate");
  402. error:
  403. return(hr);
  404. }
  405. HRESULT
  406. CertServerRetrievePending(
  407. IN DWORD RequestId,
  408. OPTIONAL IN WCHAR const *pwszSerialNumber,
  409. IN WCHAR const *pwszServerName,
  410. IN WCHAR const *pwszAuthority,
  411. OUT CERTSERVERENROLL **ppcsEnroll) // free via CertServerFreeMemory
  412. {
  413. HRESULT hr;
  414. if ((0 == RequestId) ^ (NULL != pwszSerialNumber))
  415. {
  416. hr = E_INVALIDARG;
  417. _JumpError(hr, error, "use RequestId OR pwszSerialNumber");
  418. }
  419. hr = crRequestCertificate(
  420. 0, // Flags
  421. NULL, // pbRequest
  422. 0, // cbRequest
  423. RequestId,
  424. NULL, // pwszRequestAttributes
  425. pwszSerialNumber,
  426. pwszServerName,
  427. pwszAuthority,
  428. ppcsEnroll);
  429. _JumpIfError(hr, error, "crRequestCertificate");
  430. error:
  431. return(hr);
  432. }
  433. VOID
  434. CertServerFreeMemory(
  435. IN VOID *pv)
  436. {
  437. LocalFree(pv);
  438. }
  439. //+--------------------------------------------------------------------------
  440. // CCertRequest::~CCertRequest -- destructor
  441. //
  442. // free memory associated with this instance
  443. //+--------------------------------------------------------------------------
  444. CCertRequest::~CCertRequest()
  445. {
  446. _Cleanup();
  447. }
  448. //+--------------------------------------------------------------------------
  449. // CCertRequest::_CleanupOldConnection -- free memory
  450. //
  451. // free memory associated with this instance
  452. //+--------------------------------------------------------------------------
  453. VOID
  454. CCertRequest::_CleanupOldConnection()
  455. {
  456. // bytes returned from interfaces are MIDL_user_allocate
  457. _CleanupCAPropInfo();
  458. if (NULL != m_pwszDispositionMessage)
  459. {
  460. MIDL_user_free(m_pwszDispositionMessage);
  461. m_pwszDispositionMessage = NULL;
  462. }
  463. if (NULL != m_pbCert)
  464. {
  465. MIDL_user_free(m_pbCert);
  466. m_pbCert = NULL;
  467. }
  468. if (NULL != m_pbCertificateChain)
  469. {
  470. MIDL_user_free(m_pbCertificateChain);
  471. m_pbCertificateChain = NULL;
  472. }
  473. if (NULL != m_pbFullResponse)
  474. {
  475. MIDL_user_free(m_pbFullResponse);
  476. m_pbFullResponse = NULL;
  477. }
  478. if (NULL != m_pbRequest)
  479. {
  480. LocalFree(m_pbRequest);
  481. m_pbRequest = NULL;
  482. }
  483. if (NULL != m_rgResponse)
  484. {
  485. FreeCMCResponse(m_rgResponse, m_cResponse);
  486. m_rgResponse = NULL;
  487. }
  488. if (NULL != m_hStoreResponse)
  489. {
  490. CertCloseStore(m_hStoreResponse, CERT_CLOSE_STORE_CHECK_FLAG);
  491. m_hStoreResponse = NULL;
  492. }
  493. m_cResponse = 0;
  494. m_LastStatus = S_OK;
  495. m_RequestId = 0;
  496. m_Disposition = 0;
  497. _CleanupCAPropInfo();
  498. }
  499. //+--------------------------------------------------------------------------
  500. // CCertRequest::_Cleanup -- free memory
  501. //
  502. // free memory associated with this instance
  503. //+--------------------------------------------------------------------------
  504. VOID
  505. CCertRequest::_Cleanup()
  506. {
  507. _CloseConnection();
  508. _CleanupOldConnection();
  509. }
  510. //+--------------------------------------------------------------------------
  511. // CCertRequest::_OpenRPCConnection -- establish RPC connection
  512. //
  513. // establish RPC connection
  514. //+--------------------------------------------------------------------------
  515. HRESULT
  516. CCertRequest::_OpenRPCConnection(
  517. IN WCHAR const *pwszConfig,
  518. OUT BOOL *pfNewConnection,
  519. OUT WCHAR const **ppwszAuthority)
  520. {
  521. HRESULT hr;
  522. WCHAR *pwszServerName = NULL;
  523. WCHAR *pwsz;
  524. DWORD cwc;
  525. CSASSERT(NULL != pwszConfig && NULL != pfNewConnection);
  526. *pfNewConnection = FALSE;
  527. pwsz = wcschr(pwszConfig, L'\\');
  528. if (NULL == pwsz)
  529. {
  530. cwc = wcslen(pwszConfig);
  531. *ppwszAuthority = &pwszConfig[cwc];
  532. }
  533. else
  534. {
  535. cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszConfig);
  536. *ppwszAuthority = &pwsz[1];
  537. }
  538. pwszServerName = (WCHAR *) LocalAlloc(
  539. LMEM_FIXED,
  540. (cwc + 1) * sizeof(WCHAR));
  541. if (NULL == pwszServerName)
  542. {
  543. hr = E_OUTOFMEMORY;
  544. _JumpError(hr, error, "LocalAlloc");
  545. }
  546. CopyMemory(pwszServerName, pwszConfig, cwc * sizeof(WCHAR));
  547. pwszServerName[cwc] = L'\0';
  548. if (NULL == m_hRPCCertServer ||
  549. NULL == m_pwszServerName ||
  550. 0 != mylstrcmpiL(pwszServerName, m_pwszServerName))
  551. {
  552. _CloseConnection();
  553. CSASSERT(NULL == m_pwszServerName);
  554. m_pwszServerName = pwszServerName;
  555. pwszServerName = NULL;
  556. hr = crOpenRPCConnection(
  557. m_pwszServerName,
  558. &m_rpcAuthProtocol,
  559. &m_hRPCCertServer);
  560. _JumpIfError(hr, error, "crOpenRPCConnection");
  561. *pfNewConnection = TRUE;
  562. }
  563. hr = S_OK;
  564. error:
  565. if (S_OK != hr)
  566. {
  567. _CloseConnection();
  568. hr = myHError(hr);
  569. }
  570. if (NULL != pwszServerName)
  571. {
  572. LocalFree(pwszServerName);
  573. }
  574. return(hr);
  575. }
  576. //+--------------------------------------------------------------------------
  577. // CCertRequest::_OpenConnection -- establish RPC connection
  578. //
  579. //+--------------------------------------------------------------------------
  580. HRESULT
  581. CCertRequest::_OpenConnection(
  582. IN BOOL fRPC,
  583. IN WCHAR const *pwszConfig,
  584. IN DWORD RequiredVersion,
  585. OUT WCHAR const **ppwszAuthority)
  586. {
  587. HRESULT hr;
  588. BOOL fNewConnection = FALSE;
  589. if (NULL == pwszConfig)
  590. {
  591. hr = E_POINTER;
  592. _JumpError(hr, error, "pwszConfig");
  593. }
  594. if (fRPC)
  595. {
  596. if (NULL != m_pICertRequestD)
  597. {
  598. _CloseConnection(); // switching to RPC
  599. }
  600. hr = _OpenRPCConnection(pwszConfig, &fNewConnection, ppwszAuthority);
  601. _JumpIfError(hr, error, "_OpenRPCConnection");
  602. CSASSERT(NULL != m_hRPCCertServer);
  603. CSASSERT(0 == m_dwServerVersion);
  604. }
  605. else
  606. {
  607. if (NULL != m_hRPCCertServer)
  608. {
  609. _CloseConnection(); // switching to DCOM
  610. }
  611. hr = myOpenRequestDComConnection(
  612. pwszConfig,
  613. ppwszAuthority,
  614. &m_pwszServerName,
  615. &fNewConnection,
  616. &m_dwServerVersion,
  617. &m_pICertRequestD);
  618. _JumpIfError(hr, error, "myOpenRequestDComConnection");
  619. CSASSERT(NULL != m_pICertRequestD);
  620. CSASSERT(0 != m_dwServerVersion);
  621. }
  622. if (m_dwServerVersion < RequiredVersion)
  623. {
  624. hr = RPC_E_VERSION_MISMATCH;
  625. _JumpError(hr, error, "old server");
  626. }
  627. if (fNewConnection)
  628. {
  629. _CleanupOldConnection();
  630. }
  631. error:
  632. return(hr);
  633. }
  634. //+--------------------------------------------------------------------------
  635. // CCertRequest::_CloseConnection -- release DCOM object
  636. //
  637. //+--------------------------------------------------------------------------
  638. VOID
  639. CCertRequest::_CloseConnection()
  640. {
  641. crCloseRPCConnection(&m_hRPCCertServer);
  642. myCloseDComConnection((IUnknown **) &m_pICertRequestD, &m_pwszServerName);
  643. m_dwServerVersion = 0;
  644. }
  645. //+--------------------------------------------------------------------------
  646. // CCertRequest::Submit -- Submit a cert request and return the disposition.
  647. //
  648. // Submit the passed certificate request to the Certificate Server and retrieve
  649. // the certificate from the server, if it is immediately available. If the
  650. // returned disposition so indicates, other CCertRequest methods may be called
  651. // to return the certificate or certificate chain to the caller.
  652. //
  653. // All state from previous method calls is cleared.
  654. //
  655. // After the Submit method completes execution, the GetDispositionMessage and
  656. // GetLastStatus methods may be called to retrieve informational disposition
  657. // text and a more specific error code.
  658. //
  659. // Flags contains flags that describe the input data format as defined above.
  660. //
  661. // strRequest points to the input request data, in base64-encoded form.
  662. //
  663. // strAttributes is optional. When non-NULL, it points to a string containing
  664. // attribute value pairs, one pair per line. The attribute name and value
  665. // strings may contain any text of the caller's choosing. Only the syntax of a
  666. // colon-separated attribute name and value string followed by a newline is
  667. // enforced. Attribute names that are not understood by the Certificate Server
  668. // will be available to Policy Modules, but are otherwise ignored by the
  669. // Certificate Server.
  670. // Example:
  671. // "Phone: 0424-12-3456\r\nServer: Microsoft Key Manager for IIS 2.0\r\n"
  672. // "Version: 3\r\nRequestType: Client\r\n"
  673. //
  674. // strConfig points to a string that contains the server name and Certificate
  675. // Authority name. See the ICertConfig interface.
  676. //
  677. // pDisposition points to the returned disposition of the request as defined
  678. // above. When the request cannot be immediately granted or denied (some off-
  679. // line processing may be required), *pDisposition is set to
  680. // CR_DISP_UNDER_SUBMISSION. After CR_DISP_UNDER_SUBMISSION is returned for
  681. // the initial request's disposition, the RetrievePending method may be called
  682. // to interrogate the disposition again and to retrieve the certificate if it
  683. // has been issued. If the returned disposition so indicates, RetrievePending
  684. // will retrieve the certificate and allow the other methods defined here to
  685. // return the certificate to the caller. If denied, the appropriate
  686. // disposition code will be returned. If the request has still not been
  687. // processed, CR_DISP_UNDER_SUBMISSION will again be returned by the
  688. // RetrievePending method.
  689. //
  690. // Returns S_OK if the method completed execution. Errors are indicated by
  691. // the returned disposition.
  692. //+--------------------------------------------------------------------------
  693. STDMETHODIMP
  694. CCertRequest::Submit(
  695. /* [in] */ LONG Flags,
  696. /* [in] */ BSTR const strRequest,
  697. /* [in] */ BSTR const strAttributes,
  698. /* [in] */ BSTR const strConfig,
  699. /* [out, retval] */ LONG __RPC_FAR *pDisposition)
  700. {
  701. HRESULT hr;
  702. if ((NULL == strRequest) || (NULL == pDisposition))
  703. {
  704. hr = E_POINTER;
  705. _JumpError(hr, error, "strRequest or pDisposition");
  706. }
  707. hr = _RequestCertificate(
  708. Flags,
  709. 0, // RequestId
  710. strRequest,
  711. strAttributes,
  712. NULL, // pwszSerialNumber
  713. strConfig,
  714. (CR_IN_RPC & Flags)? 0 : 1, // RequiredVersion
  715. pDisposition);
  716. _JumpIfError2(
  717. hr,
  718. error,
  719. "_RequestCertificate",
  720. HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  721. error:
  722. return(_SetErrorInfo(hr, L"CCertRequest::Submit"));
  723. }
  724. //+--------------------------------------------------------------------------
  725. // CCertRequest::RetrievePending -- Retrieve pending request disposition.
  726. //
  727. // Interrogate the Certificate Server and retrieve the certificate identified
  728. // by the passed RequestId, if it is now available. If the returned
  729. // disposition so indicates, other CCertRequest methods may be called to return
  730. // the certificate or certificate chain to the caller.
  731. //
  732. // All state from previous method calls is cleared.
  733. //
  734. // After the RetrievePending method completes execution, the
  735. // GetDispositionMessage and GetLastStatus methods may be called to retrieve
  736. // informational disposition text and a more specific error code.
  737. //
  738. // RequestId identifies a previously submitted request.
  739. //
  740. // strConfig points to a string that contains the server name and Certificate
  741. // Authority name.
  742. //
  743. // pDisposition points to the returned disposition of the pending request.
  744. //
  745. // Returns S_OK if the method completed execution. Errors are indicated by
  746. // the returned disposition.
  747. //+--------------------------------------------------------------------------
  748. STDMETHODIMP
  749. CCertRequest::RetrievePending(
  750. /* [in] */ LONG RequestId,
  751. /* [in] */ BSTR const strConfig,
  752. /* [out, retval] */ LONG __RPC_FAR *pDisposition)
  753. {
  754. HRESULT hr;
  755. BSTR strConfigT = strConfig;
  756. WCHAR *pwszSerialNumber = NULL;
  757. if (NULL == pDisposition || NULL == strConfig)
  758. {
  759. hr = E_POINTER;
  760. _JumpError(hr, error, "NULL param");
  761. }
  762. if (0 == RequestId)
  763. {
  764. DWORD cwc;
  765. pwszSerialNumber = wcschr(strConfigT, L'\\');
  766. if (NULL != pwszSerialNumber)
  767. {
  768. pwszSerialNumber = wcschr(&pwszSerialNumber[1], L'\\');
  769. }
  770. if (NULL == pwszSerialNumber)
  771. {
  772. hr = E_INVALIDARG;
  773. _JumpError(hr, error, "Missing SerialNumber");
  774. }
  775. cwc = SAFE_SUBTRACT_POINTERS(pwszSerialNumber, strConfigT);
  776. pwszSerialNumber++;
  777. strConfigT = SysAllocStringLen(strConfigT, cwc);
  778. if (NULL == strConfigT)
  779. {
  780. hr = E_OUTOFMEMORY;
  781. _JumpError(hr, error, "SysAllocStringLen");
  782. }
  783. }
  784. hr = _RequestCertificate(
  785. 0, // Flags
  786. RequestId,
  787. NULL, // strRequest
  788. NULL, // strAttributes
  789. pwszSerialNumber,
  790. strConfigT,
  791. 1, // RequiredVersion
  792. pDisposition);
  793. _JumpIfError(hr, error, "_RequestCertificate");
  794. error:
  795. if (NULL != strConfigT && strConfig != strConfigT)
  796. {
  797. SysFreeString(strConfigT);
  798. }
  799. return(_SetErrorInfo(hr, L"CCertRequest::RetrievePending"));
  800. }
  801. //+--------------------------------------------------------------------------
  802. // CCertRequest::GetIssuedCertificate -- Get an issued Certificate
  803. //
  804. // Returns S_OK on success.
  805. //+--------------------------------------------------------------------------
  806. STDMETHODIMP
  807. CCertRequest::GetIssuedCertificate(
  808. /* [in] */ const BSTR strConfig,
  809. /* [in] */ LONG RequestId,
  810. /* [in] */ const BSTR strSerialNumber, // OPTIONAL
  811. /* [out, retval] */ LONG __RPC_FAR *pDisposition)
  812. {
  813. HRESULT hr;
  814. WCHAR const *pwszSerialNumber = NULL;
  815. if (NULL == pDisposition || NULL == strConfig)
  816. {
  817. hr = E_POINTER;
  818. _JumpError(hr, error, "NULL param");
  819. }
  820. // VB callers pass "" instead of NULL, so treat them identically.
  821. if (NULL != strSerialNumber && L'\0' != *strSerialNumber)
  822. {
  823. pwszSerialNumber = strSerialNumber;
  824. }
  825. hr = _RequestCertificate(
  826. 0, // Flags
  827. RequestId,
  828. NULL, // strRequest
  829. NULL, // strAttributes
  830. pwszSerialNumber, // pwszSerialNumber
  831. strConfig,
  832. 2, // RequiredVersion
  833. pDisposition);
  834. _JumpIfError(hr, error, "_RequestCertificate");
  835. error:
  836. return(_SetErrorInfo(hr, L"CCertRequest::GetIssuedCertificate"));
  837. }
  838. //+--------------------------------------------------------------------------
  839. // CCertRequest::_RequestCertificate -- Submit the request
  840. //
  841. // Returns S_OK on success.
  842. //+--------------------------------------------------------------------------
  843. HRESULT
  844. CCertRequest::_RequestCertificate(
  845. IN LONG Flags,
  846. IN LONG RequestId,
  847. OPTIONAL IN BSTR const strRequest,
  848. OPTIONAL IN BSTR const strAttributes,
  849. OPTIONAL IN WCHAR const *pwszSerialNumber,
  850. IN BSTR const strConfig,
  851. IN DWORD RequiredVersion,
  852. OUT LONG *pDisposition)
  853. {
  854. HRESULT hr;
  855. WCHAR const *pwszAuthority;
  856. WCHAR *pwszAttrib = strAttributes;
  857. WCHAR *pwszAttribAlloc = NULL;
  858. BYTE *pbT = NULL;
  859. CERTTRANSBLOB ctbRequest = { 0, NULL };
  860. CERTTRANSBLOB ctbCert = { 0, NULL };
  861. CERTTRANSBLOB ctbCertChain = { 0, NULL };
  862. CERTTRANSBLOB ctbFullResponse = { 0, NULL };
  863. CERTTRANSBLOB ctbDispositionMessage = { 0, NULL };
  864. DWORD adwEncode[] = { CR_IN_BASE64HEADER, CR_IN_BASE64, CR_IN_BINARY };
  865. DWORD dwEncode;
  866. DWORD *pdwEncode;
  867. DWORD cEncode;
  868. WCHAR *pwszDnsName = NULL;
  869. if (NULL == pDisposition)
  870. {
  871. hr = E_POINTER;
  872. _JumpError(hr, error, "NULL parm");
  873. }
  874. _Cleanup();
  875. *pDisposition = CR_DISP_INCOMPLETE;
  876. hr = _OpenConnection(
  877. (CR_IN_RPC & Flags)? TRUE : FALSE,
  878. strConfig,
  879. RequiredVersion,
  880. &pwszAuthority);
  881. _JumpIfError(hr, error, "_OpenConnection");
  882. // If a new request, point at the attributes & decode the Base64 request.
  883. if (NULL != strRequest)
  884. {
  885. DWORD cchHeader;
  886. DWORD cwc;
  887. WCHAR *pch;
  888. CSASSERT(CR_IN_BASE64HEADER == CRYPT_STRING_BASE64HEADER);
  889. CSASSERT(CR_IN_BASE64 == CRYPT_STRING_BASE64);
  890. CSASSERT(CR_IN_BINARY == CRYPT_STRING_BINARY);
  891. hr = myGetMachineDnsName(&pwszDnsName);
  892. _JumpIfError(hr, error, "myGetMachineDnsName");
  893. dwEncode = CR_IN_ENCODEMASK & Flags;
  894. switch (dwEncode)
  895. {
  896. case CR_IN_BASE64HEADER:
  897. case CR_IN_BASE64:
  898. case CR_IN_BINARY:
  899. cEncode = 1;
  900. pdwEncode = &dwEncode;
  901. break;
  902. case CR_IN_ENCODEANY:
  903. cEncode = ARRAYSIZE(adwEncode);
  904. pdwEncode = adwEncode;
  905. break;
  906. default:
  907. hr = E_INVALIDARG;
  908. _JumpError(hr, error, "Flags");
  909. }
  910. while (TRUE)
  911. {
  912. hr = DecodeCertString(
  913. strRequest,
  914. *pdwEncode,
  915. &m_pbRequest,
  916. (DWORD *) &m_cbRequest);
  917. if (S_OK == hr)
  918. {
  919. Flags = (~CR_IN_ENCODEMASK & Flags) | *pdwEncode;
  920. break;
  921. }
  922. if (1 == cEncode || HRESULT_FROM_WIN32(ERROR_INVALID_DATA) != hr)
  923. {
  924. _JumpError(hr, error, "DecodeCertString");
  925. }
  926. _PrintErrorStr2(
  927. hr,
  928. "DecodeCertString",
  929. L"CR_IN_ENCODEANY",
  930. HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  931. cEncode--;
  932. pdwEncode++;
  933. }
  934. CSASSERT(0 < cEncode);
  935. CSASSERT(S_OK == hr);
  936. ctbRequest.pb = m_pbRequest;
  937. ctbRequest.cb = m_cbRequest;
  938. cchHeader = 0;
  939. if (CR_IN_BASE64HEADER == *pdwEncode)
  940. {
  941. DWORD cb;
  942. hr = myCryptStringToBinary(
  943. strRequest,
  944. wcslen(strRequest),
  945. CRYPT_STRING_BASE64HEADER,
  946. &pbT,
  947. &cb,
  948. &cchHeader,
  949. NULL);
  950. if (S_OK != hr)
  951. {
  952. cchHeader = 0;
  953. }
  954. }
  955. cwc = cchHeader;
  956. if (NULL != pwszAttrib)
  957. {
  958. cwc += 1 + wcslen(pwszAttrib);
  959. }
  960. cwc += 1 + WSZARRAYSIZE(wszPROPCERTCLIENTMACHINE) + 1 + wcslen(pwszDnsName);
  961. pwszAttribAlloc = (WCHAR *) LocalAlloc(
  962. LMEM_FIXED,
  963. (cwc + 1) * sizeof(WCHAR));
  964. if (NULL == pwszAttribAlloc)
  965. {
  966. hr = E_OUTOFMEMORY;
  967. _JumpError(hr, error, "alloc attributes");
  968. }
  969. pch = pwszAttribAlloc;
  970. if (0 != cchHeader)
  971. {
  972. CopyMemory(pch, strRequest, cchHeader * sizeof(WCHAR));
  973. pch += cchHeader;
  974. }
  975. *pch = L'\0';
  976. if (NULL != pwszAttrib)
  977. {
  978. *pch++ = L'\n';
  979. wcscpy(pch, (WCHAR const *) pwszAttrib);
  980. }
  981. wcscat(pch, L"\n" wszPROPCERTCLIENTMACHINE L":");
  982. wcscat(pch, pwszDnsName);
  983. CSASSERT(wcslen(pwszAttribAlloc) == cwc);
  984. pwszAttrib = pwszAttribAlloc;
  985. }
  986. m_RequestId = RequestId;
  987. __try
  988. {
  989. Flags |= CR_IN_FULLRESPONSE;
  990. if (NULL != m_hRPCCertServer)
  991. {
  992. CERTTRANSBLOB ctbAttrib;
  993. CERTTRANSBLOB ctbSerial;
  994. ctbAttrib.cb = 0;
  995. ctbAttrib.pb = (BYTE *) pwszAttrib;
  996. if (NULL != pwszAttrib)
  997. {
  998. ctbAttrib.cb = (wcslen(pwszAttrib) + 1) * sizeof(WCHAR);
  999. }
  1000. ctbSerial.cb = 0;
  1001. ctbSerial.pb = (BYTE *) pwszSerialNumber;
  1002. if (NULL != pwszSerialNumber)
  1003. {
  1004. ctbAttrib.cb = (wcslen(pwszSerialNumber) + 1) * sizeof(WCHAR);
  1005. }
  1006. hr = crCertServerRequest(
  1007. m_hRPCCertServer,
  1008. &m_rpcAuthProtocol,
  1009. Flags,
  1010. pwszAuthority,
  1011. (DWORD *) &m_RequestId,
  1012. (DWORD *) &m_Disposition,
  1013. &ctbAttrib,
  1014. &ctbSerial,
  1015. &ctbRequest,
  1016. &ctbCertChain,
  1017. &ctbCert,
  1018. &ctbDispositionMessage);
  1019. _PrintIfError(hr, "crCertServerRequest");
  1020. }
  1021. else
  1022. {
  1023. if (2 <= m_dwServerVersion)
  1024. {
  1025. hr = m_pICertRequestD->Request2(
  1026. pwszAuthority,
  1027. Flags,
  1028. pwszSerialNumber,
  1029. (DWORD *) &m_RequestId,
  1030. (DWORD *) &m_Disposition,
  1031. pwszAttrib,
  1032. &ctbRequest,
  1033. &ctbFullResponse,
  1034. &ctbCert,
  1035. &ctbDispositionMessage);
  1036. _PrintIfError(hr, "m_pICertRequestD->Request2");
  1037. }
  1038. else
  1039. {
  1040. Flags &= ~CR_IN_FULLRESPONSE;
  1041. hr = m_pICertRequestD->Request(
  1042. Flags,
  1043. pwszAuthority,
  1044. (DWORD *) &m_RequestId,
  1045. (DWORD *) &m_Disposition,
  1046. pwszAttrib,
  1047. &ctbRequest,
  1048. &ctbCertChain,
  1049. &ctbCert,
  1050. &ctbDispositionMessage);
  1051. _PrintIfError(hr, "m_pICertRequestD->Request");
  1052. }
  1053. // Midl_user_allocate registers memory in RPC case
  1054. if (NULL != ctbCertChain.pb)
  1055. {
  1056. myRegisterMemAlloc(
  1057. ctbCertChain.pb,
  1058. ctbCertChain.cb,
  1059. CSM_COTASKALLOC);
  1060. }
  1061. if (NULL != ctbFullResponse.pb)
  1062. {
  1063. myRegisterMemAlloc(
  1064. ctbFullResponse.pb,
  1065. ctbFullResponse.cb,
  1066. CSM_COTASKALLOC);
  1067. }
  1068. if (NULL != ctbCert.pb)
  1069. {
  1070. myRegisterMemAlloc(ctbCert.pb, ctbCert.cb, CSM_COTASKALLOC);
  1071. }
  1072. if (NULL != ctbDispositionMessage.pb)
  1073. {
  1074. myRegisterMemAlloc(
  1075. ctbDispositionMessage.pb,
  1076. ctbDispositionMessage.cb,
  1077. CSM_COTASKALLOC);
  1078. }
  1079. }
  1080. }
  1081. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  1082. {
  1083. }
  1084. if (HRESULT_FROM_WIN32(RPC_X_WRONG_STUB_VERSION) == hr)
  1085. {
  1086. _PrintError(hr, "Compile with MIDL_NO_ROBUST=1 to run on NT 4");
  1087. }
  1088. m_LastStatus = hr;
  1089. _JumpIfError(hr, error, "Request");
  1090. if (FAILED(m_Disposition))
  1091. {
  1092. m_LastStatus = m_Disposition;
  1093. m_Disposition = CR_DISP_DENIED;
  1094. }
  1095. *pDisposition = m_Disposition;
  1096. m_pbCertificateChain = ctbCertChain.pb; // CoTaskMem*
  1097. m_cbCertificateChain = ctbCertChain.cb;
  1098. m_pbFullResponse = ctbFullResponse.pb; // CoTaskMem*
  1099. m_cbFullResponse = ctbFullResponse.cb;
  1100. m_pbCert = ctbCert.pb; // CoTaskMem*
  1101. m_cbCert = ctbCert.cb;
  1102. m_pwszDispositionMessage = (WCHAR *) ctbDispositionMessage.pb; // CoTaskMem*
  1103. CSASSERT(0 == (ctbDispositionMessage.cb & (sizeof(WCHAR) - 1)));
  1104. CSASSERT(
  1105. NULL == m_pwszDispositionMessage ||
  1106. L'\0' ==
  1107. m_pwszDispositionMessage[ctbDispositionMessage.cb/sizeof(WCHAR) - 1]);
  1108. if (S_OK == hr && NULL != ctbFullResponse.pb)
  1109. {
  1110. hr = ParseCMCResponse(
  1111. m_pbFullResponse,
  1112. m_cbFullResponse,
  1113. &m_hStoreResponse,
  1114. &m_rgResponse,
  1115. &m_cResponse);
  1116. #if 0 // When all Whistler servers are upgraded to return full responses...
  1117. if (S_OK != hr && NULL != m_hRPCCertServer)
  1118. #else
  1119. if (S_OK != hr)
  1120. #endif
  1121. {
  1122. // Must be an old RPC cert server that ignored CR_IN_FULLRESPONSE,
  1123. // and returned a PKCS7 chain instead.
  1124. CSASSERT(NULL == m_pbCertificateChain);
  1125. m_pbCertificateChain = m_pbFullResponse;
  1126. m_cbCertificateChain = m_cbFullResponse;
  1127. m_pbFullResponse = NULL;
  1128. m_cbFullResponse = 0;
  1129. hr = S_OK;
  1130. }
  1131. _JumpIfError(hr, error, "ParseCMCResponse");
  1132. }
  1133. error:
  1134. if (NULL != pwszDnsName)
  1135. {
  1136. LocalFree(pwszDnsName);
  1137. }
  1138. if (NULL != pwszAttribAlloc)
  1139. {
  1140. LocalFree(pwszAttribAlloc);
  1141. }
  1142. if (NULL != pbT)
  1143. {
  1144. LocalFree(pbT);
  1145. }
  1146. return(myHError(hr));
  1147. }
  1148. //+--------------------------------------------------------------------------
  1149. // CCertRequest::GetLastStatus -- Get the status of the last request
  1150. //
  1151. // One of the Submit, RetrievePending or GetCACertificate methods must
  1152. // have been previously called for the returned status to be meaningful.
  1153. //
  1154. // Returns S_OK on success.
  1155. //+--------------------------------------------------------------------------
  1156. STDMETHODIMP
  1157. CCertRequest::GetLastStatus(
  1158. /* [out, retval] */ LONG __RPC_FAR *pLastStatus)
  1159. {
  1160. HRESULT hr;
  1161. if (NULL == pLastStatus)
  1162. {
  1163. hr = E_POINTER;
  1164. _JumpError(hr, error, "pLastStatus");
  1165. }
  1166. *pLastStatus = m_LastStatus;
  1167. hr = S_OK;
  1168. error:
  1169. return(_SetErrorInfo(hr, L"CCertRequest::GetLastStatus"));
  1170. }
  1171. //+--------------------------------------------------------------------------
  1172. // CCertRequest::GetRequestId -- Get the RequestId of the last request
  1173. //
  1174. // The Submit or RetrievePending method must have been previously called for
  1175. // the returned RequestId to be meaningful.
  1176. //
  1177. // Returns S_OK on success.
  1178. //+--------------------------------------------------------------------------
  1179. STDMETHODIMP
  1180. CCertRequest::GetRequestId(
  1181. /* [out, retval] */ LONG __RPC_FAR *pRequestId)
  1182. {
  1183. HRESULT hr;
  1184. if (NULL == pRequestId)
  1185. {
  1186. hr = E_POINTER;
  1187. _JumpError(hr, error, "pRequestId");
  1188. }
  1189. *pRequestId = m_RequestId;
  1190. hr = S_OK;
  1191. error:
  1192. return(_SetErrorInfo(hr, L"CCertRequest::GetRequestId"));
  1193. }
  1194. //+--------------------------------------------------------------------------
  1195. // CCertRequest::GetDispositionMessage -- Get the Disposition Message
  1196. //
  1197. // The Submit or RetrievePending method must have been previously called for
  1198. // the returned disposition message text to be meaningful.
  1199. //
  1200. // Returns S_OK on success.
  1201. //+--------------------------------------------------------------------------
  1202. STDMETHODIMP
  1203. CCertRequest::GetDispositionMessage(
  1204. /* [out, retval] */ BSTR __RPC_FAR *pstrDispositionMessage)
  1205. {
  1206. HRESULT hr = S_OK;
  1207. if (NULL == pstrDispositionMessage)
  1208. {
  1209. hr = E_POINTER;
  1210. _JumpError(hr, error, "pstrDispositionMessage");
  1211. }
  1212. if (NULL != *pstrDispositionMessage)
  1213. {
  1214. SysFreeString(*pstrDispositionMessage);
  1215. *pstrDispositionMessage = NULL;
  1216. }
  1217. if (NULL != m_pwszDispositionMessage)
  1218. {
  1219. if (!ConvertWszToBstr(
  1220. pstrDispositionMessage,
  1221. m_pwszDispositionMessage,
  1222. -1))
  1223. {
  1224. hr = E_OUTOFMEMORY;
  1225. _JumpError(hr, error, "ConvertWszToBstr");
  1226. }
  1227. }
  1228. error:
  1229. return(_SetErrorInfo(hr, L"CCertRequest::GetDispositionMessage"));
  1230. }
  1231. //+--------------------------------------------------------------------------
  1232. // CCertRequest::_BuildIssuedCertificateChain -- Build issued cert chain
  1233. //
  1234. // Returns S_OK on success.
  1235. //+--------------------------------------------------------------------------
  1236. HRESULT
  1237. CCertRequest::_BuildIssuedCertificateChain(
  1238. OPTIONAL IN BYTE const *pbCertHash,
  1239. IN DWORD cbCertHash,
  1240. IN BOOL fIncludeCRLs,
  1241. OUT BYTE **ppbCertChain,
  1242. OUT DWORD *pcbCertChain)
  1243. {
  1244. HRESULT hr;
  1245. CERT_CONTEXT const *pccIssued = NULL;
  1246. CERT_CHAIN_PARA CertChainPara;
  1247. CERT_CHAIN_CONTEXT const *pCertChainContext = NULL;
  1248. CERT_SIMPLE_CHAIN *pSimpleChain;
  1249. CRYPT_SIGN_MESSAGE_PARA csmp;
  1250. CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm = { szOID_OIWSEC_sha1, 0, 0 };
  1251. CERT_CONTEXT const **ppcc;
  1252. DWORD i;
  1253. *ppbCertChain = NULL;
  1254. // init csmp for empty signature
  1255. ZeroMemory(&csmp, sizeof(csmp));
  1256. csmp.cbSize = sizeof(csmp);
  1257. csmp.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
  1258. //csmp.pSigningCert = NULL;
  1259. csmp.HashAlgorithm = DigestAlgorithm;
  1260. //csmp.cMsgCert = 0;
  1261. //csmp.rgpMsgCert = NULL;
  1262. //csmp.cMsgCrl = 0;
  1263. //csmp.rgpMsgCrl = NULL;
  1264. hr = _FindIssuedCertificate(pbCertHash, cbCertHash, &pccIssued);
  1265. _JumpIfError(hr, error, "_FindIssuedCertificate");
  1266. // build the user cert chain
  1267. ZeroMemory(&CertChainPara, sizeof(CertChainPara));
  1268. CertChainPara.cbSize = sizeof(CertChainPara);
  1269. if (!CertGetCertificateChain(
  1270. HCCE_LOCAL_MACHINE,
  1271. pccIssued,
  1272. NULL, // pTime
  1273. m_hStoreResponse,
  1274. &CertChainPara,
  1275. fIncludeCRLs?
  1276. CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT :
  1277. 0,
  1278. NULL, // pvReserved
  1279. &pCertChainContext))
  1280. {
  1281. hr = myHLastError();
  1282. _JumpError(hr, error, "CertGetCertificateChain");
  1283. }
  1284. // make sure there is at least 1 simple chain
  1285. if (0 == pCertChainContext->cChain)
  1286. {
  1287. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1288. _JumpError(hr, error, "No user chain");
  1289. }
  1290. pSimpleChain = pCertChainContext->rgpChain[0];
  1291. csmp.cMsgCert = pSimpleChain->cElement;
  1292. if (0 == csmp.cMsgCert)
  1293. {
  1294. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1295. _JumpError(hr, error, "no certs");
  1296. }
  1297. csmp.rgpMsgCert = (CERT_CONTEXT const **) LocalAlloc(
  1298. LMEM_FIXED,
  1299. csmp.cMsgCert * sizeof(csmp.rgpMsgCert[0]));
  1300. if (NULL == csmp.rgpMsgCert)
  1301. {
  1302. hr = E_OUTOFMEMORY;
  1303. _JumpError(hr, error, "LocalAlloc");
  1304. }
  1305. if (fIncludeCRLs)
  1306. {
  1307. csmp.rgpMsgCrl = (CRL_CONTEXT const **) LocalAlloc(
  1308. LMEM_FIXED,
  1309. 2 * csmp.cMsgCert * sizeof(csmp.rgpMsgCrl[0]));
  1310. if (NULL == csmp.rgpMsgCrl)
  1311. {
  1312. hr = E_OUTOFMEMORY;
  1313. _JumpError(hr, error, "LocalAlloc");
  1314. }
  1315. }
  1316. ppcc = csmp.rgpMsgCert;
  1317. for (i = 0; i < csmp.cMsgCert; i++)
  1318. {
  1319. *ppcc++ = pSimpleChain->rgpElement[i]->pCertContext;
  1320. if (fIncludeCRLs)
  1321. {
  1322. CERT_REVOCATION_INFO *pRevocationInfo;
  1323. pRevocationInfo = pSimpleChain->rgpElement[i]->pRevocationInfo;
  1324. if (NULL != pRevocationInfo &&
  1325. CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
  1326. pRevocationInfo->cbSize &&
  1327. NULL != pRevocationInfo->pCrlInfo)
  1328. {
  1329. CERT_REVOCATION_CRL_INFO *pCrlInfo;
  1330. pCrlInfo = pRevocationInfo->pCrlInfo;
  1331. if (NULL != pCrlInfo)
  1332. {
  1333. if (NULL != pCrlInfo->pBaseCrlContext)
  1334. {
  1335. csmp.rgpMsgCrl[csmp.cMsgCrl++] = pCrlInfo->pBaseCrlContext;
  1336. }
  1337. if (NULL != pCrlInfo->pDeltaCrlContext)
  1338. {
  1339. csmp.rgpMsgCrl[csmp.cMsgCrl++] = pCrlInfo->pDeltaCrlContext;
  1340. }
  1341. }
  1342. }
  1343. }
  1344. }
  1345. CSASSERT(csmp.cMsgCrl <= 2 * csmp.cMsgCert);
  1346. if (!myCryptSignMessage(
  1347. &csmp,
  1348. pccIssued->pbCertEncoded,
  1349. pccIssued->cbCertEncoded,
  1350. CERTLIB_USE_LOCALALLOC,
  1351. ppbCertChain,
  1352. pcbCertChain))
  1353. {
  1354. hr = myHLastError();
  1355. _JumpError(hr, error, "myCryptSignMessage");
  1356. }
  1357. hr = S_OK;
  1358. error:
  1359. if (NULL != csmp.rgpMsgCert)
  1360. {
  1361. LocalFree(csmp.rgpMsgCert);
  1362. }
  1363. if (NULL != csmp.rgpMsgCrl)
  1364. {
  1365. LocalFree(csmp.rgpMsgCrl);
  1366. }
  1367. if (NULL != pccIssued)
  1368. {
  1369. CertFreeCertificateContext(pccIssued);
  1370. }
  1371. if (NULL != pCertChainContext)
  1372. {
  1373. CertFreeCertificateChain(pCertChainContext);
  1374. }
  1375. return(hr);
  1376. }
  1377. //+--------------------------------------------------------------------------
  1378. // CCertRequest::_FindIssuedCertificate -- Find Issued cert in store.
  1379. //
  1380. // Returns S_OK on success.
  1381. //+--------------------------------------------------------------------------
  1382. HRESULT
  1383. CCertRequest::_FindIssuedCertificate(
  1384. OPTIONAL IN BYTE const *pbCertHash,
  1385. IN DWORD cbCertHash,
  1386. OUT CERT_CONTEXT const **ppccIssued)
  1387. {
  1388. HRESULT hr;
  1389. CRYPT_HASH_BLOB BlobHash;
  1390. *ppccIssued = NULL;
  1391. if (NULL == pbCertHash)
  1392. {
  1393. if (1 < m_cResponse || NULL == m_pbCert)
  1394. {
  1395. hr = CERTSRV_E_PROPERTY_EMPTY;
  1396. _JumpError(hr, error, "no cert");
  1397. }
  1398. *ppccIssued = CertCreateCertificateContext(
  1399. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1400. m_pbCert,
  1401. m_cbCert);
  1402. if (NULL == *ppccIssued)
  1403. {
  1404. hr = myHLastError();
  1405. _JumpError(hr, error, "CertCreateCertificateContext");
  1406. }
  1407. }
  1408. else
  1409. {
  1410. BlobHash.pbData = const_cast<BYTE *>(pbCertHash);
  1411. BlobHash.cbData = cbCertHash;
  1412. *ppccIssued = CertFindCertificateInStore(
  1413. m_hStoreResponse,
  1414. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  1415. 0, // dwFindFlags
  1416. CERT_FIND_HASH,
  1417. &BlobHash, // pvFindPara
  1418. NULL); // pPrevCertContext
  1419. if (NULL == *ppccIssued)
  1420. {
  1421. hr = myHLastError();
  1422. _JumpError(hr, error, "CertFindCertificateInStore");
  1423. }
  1424. }
  1425. hr = S_OK;
  1426. error:
  1427. return(hr);
  1428. }
  1429. //+--------------------------------------------------------------------------
  1430. // CCertRequest::GetCertificate -- Get the Certificate encoding as requested
  1431. //
  1432. // The Submit or RetrievePending method must have previously returned
  1433. // CR_DISP_ISSUED, or this method will fail.
  1434. //
  1435. // Returns S_OK on success.
  1436. //+--------------------------------------------------------------------------
  1437. STDMETHODIMP
  1438. CCertRequest::GetCertificate(
  1439. /* [in] */ LONG Flags,
  1440. /* [out, retval] */ BSTR __RPC_FAR *pstrCertificate)
  1441. {
  1442. HRESULT hr;
  1443. BYTE *pbChain = NULL;
  1444. DWORD cbChain;
  1445. BYTE *pbCert;
  1446. DWORD cbCert;
  1447. if (NULL == pstrCertificate)
  1448. {
  1449. hr = E_POINTER;
  1450. _JumpError(hr, error, "pstrCertificate");
  1451. }
  1452. pbCert = m_pbCert;
  1453. cbCert = m_cbCert;
  1454. if (CR_OUT_CHAIN & Flags)
  1455. {
  1456. pbCert = m_pbCertificateChain;
  1457. cbCert = m_cbCertificateChain;
  1458. if (NULL == m_pbCertificateChain)
  1459. {
  1460. hr = _BuildIssuedCertificateChain(
  1461. NULL, // pbCertHash
  1462. 0, // cbCertHash
  1463. 0 != (CR_OUT_CRLS & Flags),
  1464. &pbChain,
  1465. &cbChain);
  1466. _JumpIfError(hr, error, "_BuildIssuedCertificateChain");
  1467. pbCert = pbChain;
  1468. cbCert = cbChain;
  1469. }
  1470. }
  1471. CSASSERT(CR_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER);
  1472. CSASSERT(CR_OUT_BASE64 == CRYPT_STRING_BASE64);
  1473. CSASSERT(CR_OUT_BINARY == CRYPT_STRING_BINARY);
  1474. hr = EncodeCertString(
  1475. pbCert,
  1476. cbCert,
  1477. ~(CR_OUT_CHAIN | CR_OUT_CRLS) & Flags,
  1478. pstrCertificate);
  1479. _JumpIfError(hr, error, "EncodeCertString");
  1480. error:
  1481. if (NULL != pbChain)
  1482. {
  1483. LocalFree(pbChain);
  1484. }
  1485. hr = myHError(hr);
  1486. return(_SetErrorInfo(hr, L"CCertRequest::GetCertificate"));
  1487. }
  1488. //+--------------------------------------------------------------------------
  1489. // CCertRequest::GetCACertificate -- Get the specified CA Certificate
  1490. //
  1491. // Interrogate the Certificate Server and retrieve the base64-encoded exchange
  1492. // or signature site certificate as indicated by fExchangeCertificate.
  1493. //
  1494. // All state from previous method calls is cleared.
  1495. //
  1496. // After the GetCACertificate method completes execution, the GetLastStatus
  1497. // method may be called to retrieve a more specific error code.
  1498. //
  1499. // fExchangeCertificate is TRUE to retrieve the Certificate Server's Exchange
  1500. // certificate. fExchangeCertificate is FALSE to retrieve the Certificate
  1501. // Server's Signature site certificate.
  1502. //
  1503. // Returns S_OK on success.
  1504. //+--------------------------------------------------------------------------
  1505. STDMETHODIMP
  1506. CCertRequest::GetCACertificate(
  1507. /* [in] */ LONG fExchangeCertificate,
  1508. /* [in] */ BSTR const strConfig,
  1509. /* [in] */ LONG Flags,
  1510. /* [out, retval] */ BSTR __RPC_FAR *pstrCACertificate)
  1511. {
  1512. HRESULT hr;
  1513. CERTTRANSBLOB ctbSite = { 0, NULL };
  1514. WCHAR const *pwszAuthority;
  1515. WCHAR const *pwszOut = NULL;
  1516. CAINFO const *pCAInfo;
  1517. BYTE *pbOut;
  1518. BOOL fCallServer;
  1519. DWORD Index;
  1520. WCHAR wszBuf[5 * (10 + 1)]; // enough for 5 numbers
  1521. if (NULL == pstrCACertificate)
  1522. {
  1523. hr = E_POINTER;
  1524. _JumpError(hr, error, "pstrCACertificate");
  1525. }
  1526. fCallServer = TRUE;
  1527. pbOut = NULL;
  1528. switch (fExchangeCertificate)
  1529. {
  1530. case GETCERT_ERRORTEXT1:
  1531. case GETCERT_ERRORTEXT2:
  1532. pwszOut = myGetErrorMessageText(
  1533. Flags, // error code passed in Flags parm
  1534. GETCERT_ERRORTEXT2 == fExchangeCertificate);
  1535. if (NULL == pwszOut)
  1536. {
  1537. hr = E_OUTOFMEMORY;
  1538. _JumpError(hr, error, "LocalAlloc");
  1539. }
  1540. Flags = CR_OUT_BINARY;
  1541. pbOut = (BYTE *) pwszOut;
  1542. fCallServer = FALSE;
  1543. break;
  1544. }
  1545. Index = MAXDWORD;
  1546. switch (GETCERT_BYINDEXMASK & fExchangeCertificate)
  1547. {
  1548. case GETCERT_CACERTSTATEBYINDEX:
  1549. case GETCERT_CRLSTATEBYINDEX:
  1550. if (CR_OUT_CHAIN & Flags)
  1551. {
  1552. hr = E_INVALIDARG;
  1553. _JumpError(hr, error, "Flags");
  1554. }
  1555. Index = GETCERT_INDEXVALUEMASK & fExchangeCertificate;
  1556. fExchangeCertificate &= ~GETCERT_INDEXVALUEMASK;
  1557. fCallServer =
  1558. NULL == ((GETCERT_CACERTSTATEBYINDEX == fExchangeCertificate)?
  1559. m_pbCACertState : m_pbCRLState);
  1560. break;
  1561. }
  1562. if (fCallServer)
  1563. {
  1564. hr = _OpenConnection(FALSE, strConfig, 1, &pwszAuthority);
  1565. _JumpIfError(hr, error, "_OpenConnection");
  1566. if (CR_OUT_CHAIN & Flags)
  1567. {
  1568. fExchangeCertificate |= GETCERT_CHAIN;
  1569. if (CR_OUT_CRLS & Flags)
  1570. {
  1571. fExchangeCertificate |= GETCERT_CRLS;
  1572. }
  1573. }
  1574. __try
  1575. {
  1576. hr = m_pICertRequestD->GetCACert(
  1577. fExchangeCertificate,
  1578. pwszAuthority,
  1579. &ctbSite);
  1580. }
  1581. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  1582. {
  1583. }
  1584. _JumpIfError2(
  1585. hr,
  1586. error,
  1587. "GetCACert",
  1588. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  1589. // must register this memory
  1590. myRegisterMemAlloc(ctbSite.pb, ctbSite.cb, CSM_COTASKALLOC);
  1591. pbOut = ctbSite.pb;
  1592. }
  1593. CSASSERT(CR_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER);
  1594. CSASSERT(CR_OUT_BASE64 == CRYPT_STRING_BASE64);
  1595. CSASSERT(CR_OUT_BINARY == CRYPT_STRING_BINARY);
  1596. switch (fExchangeCertificate)
  1597. {
  1598. // Serialize CAType into a string:
  1599. case GETCERT_CATYPE:
  1600. wsprintf(wszBuf, L"%u", *(ENUM_CATYPES const *) pbOut);
  1601. pwszOut = wszBuf;
  1602. pbOut = (BYTE *) pwszOut;
  1603. break;
  1604. // Serialize CAInfo into a string:
  1605. case GETCERT_CAINFO:
  1606. pCAInfo = (CAINFO const *) pbOut;
  1607. if (CCSIZEOF_STRUCT(CAINFO, cCASignatureCerts) > pCAInfo->cbSize)
  1608. {
  1609. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1610. _JumpError(hr, error, "CAINFO size");
  1611. }
  1612. wsprintf(
  1613. wszBuf,
  1614. L"%u,%u",
  1615. pCAInfo->CAType,
  1616. pCAInfo->cCASignatureCerts);
  1617. pwszOut = wszBuf;
  1618. pbOut = (BYTE *) pwszOut;
  1619. break;
  1620. case GETCERT_CACERTSTATEBYINDEX:
  1621. case GETCERT_CRLSTATEBYINDEX:
  1622. {
  1623. BYTE **ppb;
  1624. DWORD *pcb;
  1625. if (GETCERT_CACERTSTATEBYINDEX == fExchangeCertificate)
  1626. {
  1627. ppb = &m_pbCACertState;
  1628. pcb = &m_cbCACertState;
  1629. }
  1630. else
  1631. {
  1632. ppb = &m_pbCRLState;
  1633. pcb = &m_cbCRLState;
  1634. }
  1635. if (fCallServer)
  1636. {
  1637. CSASSERT(NULL == *ppb);
  1638. CSASSERT(NULL != ctbSite.pb);
  1639. *pcb = ctbSite.cb;
  1640. *ppb = ctbSite.pb;
  1641. ctbSite.pb = NULL;
  1642. }
  1643. if (Index >= *pcb)
  1644. {
  1645. hr = E_INVALIDARG;
  1646. _JumpError(hr, error, "Index");
  1647. }
  1648. wsprintf(wszBuf, L"%u", (*ppb)[Index]);
  1649. pwszOut = wszBuf;
  1650. pbOut = (BYTE *) pwszOut;
  1651. break;
  1652. }
  1653. // If retrieving a CRL in Base64, use "-----BEGIN X509 CRL..."
  1654. default:
  1655. if (GETCERT_CRLBYINDEX !=
  1656. (GETCERT_BYINDEXMASK & fExchangeCertificate))
  1657. {
  1658. break;
  1659. }
  1660. // FALLTHROUGH
  1661. case GETCERT_CURRENTCRL:
  1662. if (CR_OUT_BASE64HEADER == (~CR_OUT_CHAIN & Flags))
  1663. {
  1664. Flags = CRYPT_STRING_BASE64X509CRLHEADER;
  1665. }
  1666. break;
  1667. }
  1668. hr = EncodeCertString(
  1669. pbOut,
  1670. pbOut == (BYTE *) pwszOut?
  1671. wcslen(pwszOut) * sizeof(WCHAR) : ctbSite.cb,
  1672. ~CR_OUT_CHAIN & Flags,
  1673. pstrCACertificate);
  1674. _JumpIfError(hr, error, "EncodeCertString");
  1675. error:
  1676. m_LastStatus = hr;
  1677. if (NULL != pwszOut && wszBuf != pwszOut)
  1678. {
  1679. LocalFree(const_cast<WCHAR *>(pwszOut));
  1680. }
  1681. if (NULL != ctbSite.pb)
  1682. {
  1683. CoTaskMemFree(ctbSite.pb);
  1684. }
  1685. return(_SetErrorInfo(hr, L"CCertRequest::GetCACertificate"));
  1686. }
  1687. //+--------------------------------------------------------------------------
  1688. // CCertRequest::GetErrorMessageText -- Get error message text
  1689. //
  1690. // Returns S_OK on success.
  1691. //+--------------------------------------------------------------------------
  1692. STDMETHODIMP
  1693. CCertRequest::GetErrorMessageText(
  1694. /* [in] */ LONG hrMessage,
  1695. /* [in] */ LONG Flags,
  1696. /* [out, retval] */ BSTR __RPC_FAR *pstrErrorMessageText)
  1697. {
  1698. HRESULT hr;
  1699. WCHAR const *pwszError = NULL;
  1700. if (~CR_GEMT_HRESULT_STRING & Flags)
  1701. {
  1702. hr = E_INVALIDARG;
  1703. _JumpError(hr, error, "not CR_IN_BINARY");
  1704. }
  1705. pwszError = myGetErrorMessageText(
  1706. hrMessage,
  1707. 0 != (CR_GEMT_HRESULT_STRING & Flags));
  1708. if (NULL == pwszError)
  1709. {
  1710. hr = E_OUTOFMEMORY;
  1711. _JumpError(hr, error, "LocalAlloc");
  1712. }
  1713. if (!ConvertWszToBstr(
  1714. pstrErrorMessageText,
  1715. pwszError,
  1716. -1))
  1717. {
  1718. hr = E_OUTOFMEMORY;
  1719. _JumpError(hr, error, "ConvertWszToBstr");
  1720. }
  1721. hr = S_OK;
  1722. error:
  1723. if (NULL != pwszError)
  1724. {
  1725. LocalFree(const_cast<WCHAR *>(pwszError));
  1726. }
  1727. return(_SetErrorInfo(hr, L"CCertRequest::GetErrorMessageText"));
  1728. }
  1729. // for ICertRequest2::GetFullResponseProperty
  1730. CAPROP s_aFRProp[] = {
  1731. { FR_PROP_FULLRESPONSE, PROPTYPE_BINARY, },
  1732. { FR_PROP_FULLRESPONSENOPKCS7, PROPTYPE_BINARY, },
  1733. { FR_PROP_STATUSINFOCOUNT, PROPTYPE_LONG, },
  1734. { FR_PROP_BODYPARTSTRING, PROPTYPE_STRING | PROPFLAGS_INDEXED, },
  1735. { FR_PROP_STATUS, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
  1736. { FR_PROP_STATUSSTRING, PROPTYPE_STRING | PROPFLAGS_INDEXED, },
  1737. { FR_PROP_OTHERINFOCHOICE, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
  1738. { FR_PROP_FAILINFO, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
  1739. { FR_PROP_PENDINFOTOKEN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
  1740. { FR_PROP_PENDINFOTIME, PROPTYPE_DATE | PROPFLAGS_INDEXED, },
  1741. { FR_PROP_ISSUEDCERTIFICATEHASH, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
  1742. { FR_PROP_ISSUEDCERTIFICATE, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
  1743. { FR_PROP_ISSUEDCERTIFICATECHAIN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
  1744. { FR_PROP_ISSUEDCERTIFICATECRLCHAIN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
  1745. { FR_PROP_ENCRYPTEDKEYHASH, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
  1746. };
  1747. //+--------------------------------------------------------------------------
  1748. // CCertRequest::GetFullResponseProperty -- Get CMC Response property
  1749. //
  1750. // Returns S_OK on success.
  1751. //+--------------------------------------------------------------------------
  1752. STDMETHODIMP
  1753. CCertRequest::GetFullResponseProperty(
  1754. /* [in] */ LONG PropId, // FR_PROP_*
  1755. /* [in] */ LONG PropIndex,
  1756. /* [in] */ LONG PropType, // PROPTYPE_*
  1757. /* [in] */ LONG Flags, // CR_OUT_*
  1758. /* [out, retval] */ VARIANT *pvarPropertyValue)
  1759. {
  1760. HRESULT hr;
  1761. DWORD i;
  1762. BYTE const *pbOut;
  1763. WCHAR const *pwszOut;
  1764. DWORD cbOut;
  1765. DWORD dw;
  1766. XCMCRESPONSE *pResponse = NULL;
  1767. CERT_CONTEXT const *pccIssued = NULL;
  1768. BYTE *pbChain = NULL;
  1769. DWORD cbChain;
  1770. if (NULL == pvarPropertyValue)
  1771. {
  1772. hr = E_POINTER;
  1773. _JumpError(hr, error, "NULL parm");
  1774. }
  1775. VariantInit(pvarPropertyValue);
  1776. hr = E_INVALIDARG;
  1777. for (i = 0; PropId != s_aFRProp[i].lPropId; i++)
  1778. {
  1779. if (i >= ARRAYSIZE(s_aFRProp))
  1780. {
  1781. _JumpError(hr, error, "PropId");
  1782. }
  1783. }
  1784. if ((PROPTYPE_MASK & s_aFRProp[i].lPropFlags) != PropType)
  1785. {
  1786. _JumpError(hr, error, "PropType");
  1787. }
  1788. if (PROPFLAGS_INDEXED & s_aFRProp[i].lPropFlags)
  1789. {
  1790. if ((DWORD) PropIndex >= m_cResponse)
  1791. {
  1792. _JumpError(hr, error, "PropIndex");
  1793. }
  1794. pResponse = &m_rgResponse[PropIndex];
  1795. }
  1796. else if (0 != PropIndex)
  1797. {
  1798. _JumpError(hr, error, "non-zero PropIndex");
  1799. }
  1800. pbOut = NULL;
  1801. cbOut = 0;
  1802. pwszOut = NULL;
  1803. switch (PropId)
  1804. {
  1805. case FR_PROP_FULLRESPONSE:
  1806. case FR_PROP_FULLRESPONSENOPKCS7:
  1807. pbOut = m_pbFullResponse;
  1808. cbOut = m_cbFullResponse;
  1809. if (NULL == pbOut && FR_PROP_FULLRESPONSE == PropId)
  1810. {
  1811. pbOut = m_pbCertificateChain;
  1812. cbOut = m_cbCertificateChain;
  1813. }
  1814. break;
  1815. case FR_PROP_STATUSINFOCOUNT:
  1816. pbOut = (BYTE const *) &m_cResponse;
  1817. cbOut = sizeof(m_cResponse);
  1818. break;
  1819. case FR_PROP_BODYPARTSTRING:
  1820. if (pResponse == NULL)
  1821. {
  1822. hr = E_POINTER;
  1823. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1824. }
  1825. pwszOut = pResponse->pwszBodyPart;
  1826. break;
  1827. case FR_PROP_STATUS:
  1828. if (pResponse == NULL)
  1829. {
  1830. hr = E_POINTER;
  1831. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1832. }
  1833. pbOut = (BYTE const *) &pResponse->StatusInfo.dwStatus;
  1834. cbOut = sizeof(pResponse->StatusInfo.dwStatus);
  1835. break;
  1836. case FR_PROP_STATUSSTRING:
  1837. if (pResponse == NULL)
  1838. {
  1839. hr = E_POINTER;
  1840. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1841. }
  1842. pwszOut = pResponse->StatusInfo.pwszStatusString;
  1843. break;
  1844. case FR_PROP_OTHERINFOCHOICE:
  1845. if (pResponse == NULL)
  1846. {
  1847. hr = E_POINTER;
  1848. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1849. }
  1850. pbOut = (BYTE const *) &pResponse->StatusInfo.dwOtherInfoChoice;
  1851. cbOut = sizeof(pResponse->StatusInfo.dwOtherInfoChoice);
  1852. break;
  1853. case FR_PROP_FAILINFO:
  1854. if (pResponse == NULL)
  1855. {
  1856. hr = E_POINTER;
  1857. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1858. }
  1859. if (CMC_OTHER_INFO_FAIL_CHOICE ==
  1860. pResponse->StatusInfo.dwOtherInfoChoice)
  1861. {
  1862. pbOut = (BYTE const *) &pResponse->StatusInfo.dwFailInfo;
  1863. cbOut = sizeof(pResponse->StatusInfo.dwFailInfo);
  1864. }
  1865. break;
  1866. case FR_PROP_PENDINFOTOKEN:
  1867. if (pResponse == NULL)
  1868. {
  1869. hr = E_POINTER;
  1870. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1871. }
  1872. if (CMC_OTHER_INFO_PEND_CHOICE ==
  1873. pResponse->StatusInfo.dwOtherInfoChoice)
  1874. {
  1875. pbOut = (BYTE const *) &dw;
  1876. cbOut = sizeof(dw);
  1877. pbOut = pResponse->StatusInfo.pPendInfo->PendToken.pbData;
  1878. cbOut = pResponse->StatusInfo.pPendInfo->PendToken.cbData;
  1879. }
  1880. break;
  1881. case FR_PROP_PENDINFOTIME:
  1882. if (pResponse == NULL)
  1883. {
  1884. hr = E_POINTER;
  1885. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1886. }
  1887. if (CMC_OTHER_INFO_PEND_CHOICE ==
  1888. pResponse->StatusInfo.dwOtherInfoChoice)
  1889. {
  1890. pbOut = (BYTE const *) &pResponse->StatusInfo.pPendInfo->PendTime;
  1891. cbOut = sizeof(pResponse->StatusInfo.pPendInfo->PendTime);
  1892. }
  1893. break;
  1894. case FR_PROP_ISSUEDCERTIFICATEHASH:
  1895. if (pResponse == NULL)
  1896. {
  1897. hr = E_POINTER;
  1898. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1899. }
  1900. pbOut = pResponse->pbCertHash;
  1901. cbOut = pResponse->cbCertHash;
  1902. break;
  1903. case FR_PROP_ENCRYPTEDKEYHASH:
  1904. if (pResponse == NULL)
  1905. {
  1906. hr = E_POINTER;
  1907. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1908. }
  1909. pbOut = pResponse->pbEncryptedKeyHash;
  1910. cbOut = pResponse->cbEncryptedKeyHash;
  1911. break;
  1912. case FR_PROP_ISSUEDCERTIFICATE:
  1913. if (pResponse == NULL)
  1914. {
  1915. hr = E_POINTER;
  1916. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1917. }
  1918. hr = _FindIssuedCertificate(
  1919. pResponse->pbCertHash,
  1920. pResponse->cbCertHash,
  1921. &pccIssued);
  1922. _JumpIfError(hr, error, "_FindIssuedCertificate");
  1923. pbOut = pccIssued->pbCertEncoded;
  1924. cbOut = pccIssued->cbCertEncoded;
  1925. break;
  1926. case FR_PROP_ISSUEDCERTIFICATECHAIN:
  1927. case FR_PROP_ISSUEDCERTIFICATECRLCHAIN:
  1928. if (pResponse == NULL)
  1929. {
  1930. hr = E_POINTER;
  1931. _JumpError(hr, error, "Bad switch setup: NULL pResponse");
  1932. }
  1933. hr = _BuildIssuedCertificateChain(
  1934. pResponse->pbCertHash,
  1935. pResponse->cbCertHash,
  1936. FR_PROP_ISSUEDCERTIFICATECRLCHAIN == PropId ||
  1937. 0 != (CR_OUT_CRLS & Flags),
  1938. &pbChain,
  1939. &cbChain);
  1940. _JumpIfError(hr, error, "_BuildIssuedCertificateChain");
  1941. pbOut = pbChain;
  1942. cbOut = cbChain;
  1943. break;
  1944. }
  1945. if (NULL != pwszOut)
  1946. {
  1947. pbOut = (BYTE const *) pwszOut;
  1948. cbOut = (wcslen(pwszOut) + 1) * sizeof(WCHAR);
  1949. }
  1950. if (NULL == pbOut || 0 == cbOut)
  1951. {
  1952. hr = CERTSRV_E_PROPERTY_EMPTY;
  1953. _JumpError2(hr, error, "Empty", CERTSRV_E_PROPERTY_EMPTY);
  1954. }
  1955. __try
  1956. {
  1957. hr = myUnmarshalFormattedVariant(
  1958. Flags,
  1959. CR_PROP_CASIGCERT,
  1960. PropType,
  1961. cbOut,
  1962. pbOut,
  1963. pvarPropertyValue);
  1964. }
  1965. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  1966. {
  1967. }
  1968. _JumpIfError(hr, error, "myUnmarshalFormattedVariant");
  1969. error:
  1970. if (NULL != pccIssued)
  1971. {
  1972. CertFreeCertificateContext(pccIssued);
  1973. }
  1974. if (S_OK != hr && NULL != pvarPropertyValue)
  1975. {
  1976. VariantClear(pvarPropertyValue);
  1977. }
  1978. if (NULL != pbChain)
  1979. {
  1980. LocalFree(pbChain);
  1981. }
  1982. return(_SetErrorInfo(hr, L"CCertRequest::GetFullResponseProperty"));
  1983. }
  1984. HRESULT
  1985. CCertRequest::_SetErrorInfo(
  1986. IN HRESULT hrError,
  1987. IN WCHAR const *pwszDescription)
  1988. {
  1989. CSASSERT(FAILED(hrError) || S_OK == hrError || S_FALSE == hrError);
  1990. if (FAILED(hrError))
  1991. {
  1992. HRESULT hr;
  1993. hr = DispatchSetErrorInfo(
  1994. hrError,
  1995. pwszDescription,
  1996. wszCLASS_CERTREQUEST,
  1997. &IID_ICertRequest);
  1998. CSASSERT(hr == hrError);
  1999. }
  2000. return(hrError);
  2001. }
  2002. VOID
  2003. crRPCTimeoutCallback(
  2004. IN OUT VOID *pVoid,
  2005. IN BOOLEAN fTimeout)
  2006. {
  2007. PRPC_TIMEOUT_CONTEXT pTimeout = (RPC_TIMEOUT_CONTEXT *) pVoid;
  2008. if(fTimeout)
  2009. {
  2010. RpcCancelThreadEx(pTimeout->hThread, CR_RPC_CANCEL_TIMEOUT);
  2011. pTimeout->hrRpcError = RPC_E_TIMEOUT;
  2012. }
  2013. }
  2014. HRESULT
  2015. crRegisterRPCCallTimeout(
  2016. IN DWORD dwMilliseconds,
  2017. OUT PRPC_TIMEOUT_CONTEXT pTimeout)
  2018. {
  2019. HRESULT hr = S_OK;
  2020. pTimeout->hrRpcError = RPC_S_CALL_CANCELLED;
  2021. if (!DuplicateHandle(
  2022. GetCurrentProcess(), // hSourceProcessHandle
  2023. GetCurrentThread(), // hSourceHandle
  2024. GetCurrentProcess(), // hTargetProcessHandle
  2025. &pTimeout->hThread, // lpTargetHandle
  2026. 0, // dwDesiredAccess
  2027. FALSE, // bInheritHandle
  2028. DUPLICATE_SAME_ACCESS)) // dwOptions
  2029. {
  2030. hr = myHLastError();
  2031. _JumpError(hr, error, "DuplicateHandle");
  2032. }
  2033. pTimeout->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2034. if(pTimeout->hEvent == NULL)
  2035. {
  2036. hr = myHLastError();
  2037. _JumpError(hr, error, "CreateEvent");
  2038. }
  2039. if (!RegisterWaitForSingleObject(&pTimeout->hWait,
  2040. pTimeout->hEvent,
  2041. crRPCTimeoutCallback,
  2042. (PVOID)pTimeout ,
  2043. dwMilliseconds,
  2044. WT_EXECUTEONLYONCE))
  2045. {
  2046. hr = myHLastError();
  2047. _JumpError(hr, error, "RegisterWaitForSingleObject");
  2048. }
  2049. error:
  2050. if (S_OK != hr)
  2051. {
  2052. crCloseRPCCallTimeout(pTimeout);
  2053. }
  2054. return hr;
  2055. }
  2056. HRESULT
  2057. crCloseRPCCallTimeout(
  2058. IN PRPC_TIMEOUT_CONTEXT pTimeout)
  2059. {
  2060. if(pTimeout->hWait)
  2061. {
  2062. UnregisterWait(pTimeout->hWait);
  2063. pTimeout->hWait = NULL;
  2064. }
  2065. if(pTimeout->hEvent)
  2066. {
  2067. CloseHandle(pTimeout->hEvent);
  2068. pTimeout->hEvent = NULL;
  2069. }
  2070. if(pTimeout->hThread)
  2071. {
  2072. CloseHandle(pTimeout->hThread);
  2073. pTimeout->hThread = NULL;
  2074. }
  2075. return S_OK;
  2076. }
  2077. #undef __DIR__
  2078. #undef __dwFILE__
  2079. #define CCERTREQUEST
  2080. #include "csprop2.cpp"