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

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