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.

1603 lines
54 KiB

  1. #include "wzrdpvk.h"
  2. #include "certca.h"
  3. #include "cautil.h"
  4. #include "CertRequesterContext.h"
  5. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  6. //
  7. //
  8. // LocalContext Implementation.
  9. // See CertRequestContext.h for method-level documentation.
  10. //
  11. //
  12. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  13. HRESULT LocalContext::BuildCSPList()
  14. {
  15. DWORD dwIndex = 0;
  16. DWORD dwProviderType = 0;
  17. DWORD cbSize = 0;
  18. HRESULT hr = E_FAIL;
  19. LPWSTR pwszProviderName = 0;
  20. if (NULL == m_pCertWizardInfo)
  21. return E_POINTER;
  22. //free the old memory
  23. FreeProviders(m_pCertWizardInfo->dwCSPCount,
  24. m_pCertWizardInfo->rgdwProviderType,
  25. m_pCertWizardInfo->rgwszProvider);
  26. m_pCertWizardInfo->dwCSPCount = 0;
  27. m_pCertWizardInfo->rgdwProviderType = NULL;
  28. m_pCertWizardInfo->rgwszProvider = NULL;
  29. for (dwIndex = 0;
  30. CryptEnumProvidersU(dwIndex, 0, 0, &dwProviderType, NULL, &cbSize);
  31. dwIndex++)
  32. {
  33. pwszProviderName = (LPWSTR)WizardAlloc(cbSize);
  34. if(NULL == pwszProviderName)
  35. goto MemoryErr;
  36. //get the provider name and type
  37. if(!CryptEnumProvidersU
  38. (dwIndex,
  39. 0,
  40. 0,
  41. &dwProviderType,
  42. pwszProviderName,
  43. &cbSize))
  44. goto CryptEnumProvidersUError;
  45. m_pCertWizardInfo->dwCSPCount = dwIndex + 1;
  46. m_pCertWizardInfo->rgdwProviderType = (DWORD *)WizardRealloc
  47. (m_pCertWizardInfo->rgdwProviderType, sizeof(DWORD) * m_pCertWizardInfo->dwCSPCount);
  48. if(NULL == m_pCertWizardInfo->rgdwProviderType)
  49. goto MemoryErr;
  50. m_pCertWizardInfo->rgwszProvider = (LPWSTR *)WizardRealloc
  51. (m_pCertWizardInfo->rgwszProvider, sizeof(LPWSTR) * m_pCertWizardInfo->dwCSPCount);
  52. if(NULL == m_pCertWizardInfo->rgwszProvider)
  53. goto MemoryErr;
  54. (m_pCertWizardInfo->rgdwProviderType)[dwIndex] = dwProviderType;
  55. (m_pCertWizardInfo->rgwszProvider)[dwIndex] = pwszProviderName;
  56. // Our only reference to this data should now be m_pCertWizardInfo->rgwszProvider.
  57. pwszProviderName = NULL;
  58. }
  59. //we should have some CSPs
  60. if(0 == m_pCertWizardInfo->dwCSPCount)
  61. goto FailErr;
  62. hr = S_OK;
  63. CommonReturn:
  64. return hr;
  65. ErrorReturn:
  66. if (NULL != pwszProviderName) { WizardFree(pwszProviderName); }
  67. //free the old memory
  68. FreeProviders(m_pCertWizardInfo->dwCSPCount,
  69. m_pCertWizardInfo->rgdwProviderType,
  70. m_pCertWizardInfo->rgwszProvider);
  71. m_pCertWizardInfo->dwCSPCount = 0;
  72. m_pCertWizardInfo->rgdwProviderType = NULL;
  73. m_pCertWizardInfo->rgwszProvider = NULL;
  74. goto CommonReturn;
  75. SET_HRESULT(CryptEnumProvidersUError, HRESULT_FROM_WIN32(GetLastError()));
  76. SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
  77. SET_HRESULT(FailErr, E_FAIL);
  78. }
  79. BOOL LocalContext::CheckAccessPermission(IN HCERTTYPE hCertType)
  80. {
  81. BOOL fResult = FALSE;
  82. HANDLE hClientToken = NULL;
  83. HRESULT hr = E_FAIL;
  84. // First attempts to get the thread token. If this fails, acquires the
  85. // process token. Finally, if that fails, returns NULL.
  86. if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_TEMPLATES)) {
  87. fResult = TRUE;
  88. } else {
  89. hClientToken = this->GetClientIdentity();
  90. if (NULL == hClientToken)
  91. goto GetClientIdentityError;
  92. __try {
  93. fResult = S_OK == CACertTypeAccessCheck(hCertType, hClientToken);
  94. } __except(EXCEPTION_EXECUTE_HANDLER) {
  95. goto CACertTypeAccessCheckError;
  96. }
  97. }
  98. CommonReturn:
  99. if (NULL != hClientToken) { CloseHandle(hClientToken); }
  100. return fResult;
  101. ErrorReturn:
  102. fResult = FALSE;
  103. goto CommonReturn;
  104. SET_HRESULT(CACertTypeAccessCheckError, HRESULT_FROM_WIN32(GetLastError()));
  105. SET_HRESULT(GetClientIdentityError, HRESULT_FROM_WIN32(GetLastError()));
  106. }
  107. BOOL LocalContext::CheckCAPermission(IN HCAINFO hCAInfo)
  108. {
  109. BOOL fResult = FALSE;
  110. HANDLE hClientToken = NULL;
  111. HRESULT hr = E_FAIL;
  112. if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_CAS)) {
  113. fResult = TRUE;
  114. } else {
  115. hClientToken = this->GetClientIdentity();
  116. if (NULL == hClientToken)
  117. goto GetClientIdentityError;
  118. __try {
  119. fResult = S_OK == CAAccessCheck(hCAInfo, hClientToken);
  120. } __except(EXCEPTION_EXECUTE_HANDLER) {
  121. goto CAAccessCheckError;
  122. }
  123. }
  124. CommonReturn:
  125. if (NULL != hClientToken) { CloseHandle(hClientToken); }
  126. return fResult;
  127. ErrorReturn:
  128. fResult = FALSE;
  129. goto CommonReturn;
  130. SET_HRESULT(CAAccessCheckError, HRESULT_FROM_WIN32(GetLastError()));
  131. SET_HRESULT(GetClientIdentityError, HRESULT_FROM_WIN32(GetLastError()));
  132. }
  133. HRESULT LocalContext::GetDefaultCSP(OUT BOOL *pfAllocateCSP)
  134. {
  135. DWORD cbData = 0;
  136. HCRYPTPROV hProv = NULL;
  137. HRESULT hr = E_FAIL;
  138. LPSTR pszName = NULL;
  139. LPWSTR pwszName = NULL;
  140. if (NULL == m_pCertWizardInfo)
  141. return E_POINTER;
  142. if (NULL == pfAllocateCSP)
  143. return E_INVALIDARG;
  144. *pfAllocateCSP = FALSE;
  145. //no provider has been selected
  146. if(0 == m_pCertWizardInfo->dwProviderType)
  147. return S_OK;
  148. //return if user has selected both the dwProviderType
  149. //or the provider name
  150. if(NULL != m_pCertWizardInfo->pwszProvider)
  151. return S_OK;
  152. //get the default provider
  153. if(!CryptAcquireContext(&hProv,
  154. NULL,
  155. NULL,
  156. m_pCertWizardInfo->dwProviderType,
  157. CRYPT_VERIFYCONTEXT))
  158. goto Win32Err;
  159. //get the provider name
  160. if(!CryptGetProvParam(hProv,
  161. PP_NAME,
  162. NULL,
  163. &cbData,
  164. 0) || (0==cbData))
  165. goto Win32Err;
  166. if(NULL == (pszName = (LPSTR)WizardAlloc(cbData)))
  167. goto MemoryErr;
  168. if(!CryptGetProvParam(hProv,
  169. PP_NAME,
  170. (BYTE *)pszName,
  171. &cbData,
  172. 0))
  173. goto Win32Err;
  174. pwszName = MkWStr(pszName);
  175. if(NULL == pwszName)
  176. goto MemoryErr;
  177. m_pCertWizardInfo->pwszProvider=(LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszName)+1));
  178. if(NULL == m_pCertWizardInfo->pwszProvider)
  179. goto MemoryErr;
  180. *pfAllocateCSP = TRUE;
  181. wcscpy(m_pCertWizardInfo->pwszProvider,pwszName);
  182. hr = S_OK;
  183. CommonReturn:
  184. if(NULL != hProv) { CryptReleaseContext(hProv, 0); }
  185. if(NULL != pszName) { WizardFree(pszName); }
  186. if(NULL != pwszName) { FreeWStr(pwszName); }
  187. return hr;
  188. ErrorReturn:
  189. m_idsText = IDS_INVALID_CSP;
  190. goto CommonReturn;
  191. SET_HRESULT(Win32Err, HRESULT_FROM_WIN32(GetLastError()));
  192. SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
  193. }
  194. HRESULT LocalContext::Enroll(OUT DWORD *pdwStatus,
  195. OUT HANDLE *pResult)
  196. {
  197. BOOL fHasNextCSP = TRUE;
  198. BOOL fHasNextCA = TRUE;
  199. BOOL fRequestIsCached;
  200. BOOL fCreateRequest;
  201. BOOL fFreeRequest;
  202. BOOL fSubmitRequest;
  203. CERT_BLOB renewCert;
  204. CERT_ENROLL_INFO RequestInfo;
  205. CERT_REQUEST_PVK_NEW CertRequestPvkNew;
  206. CERT_REQUEST_PVK_NEW CertRenewPvk;
  207. CRYPTUI_WIZ_CERT_CA CertCA;
  208. DWORD dwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNKNOWN;
  209. DWORD dwCSPIndex;
  210. DWORD dwSavedGenKeyFlags;
  211. HANDLE hRequest = NULL;
  212. HRESULT hr = E_FAIL;
  213. LPWSTR pwszHashAlg = NULL;
  214. //init 1st for error jump
  215. ZeroMemory(&CertRenewPvk, sizeof(CertRenewPvk));
  216. if (NULL == pResult)
  217. return E_INVALIDARG;
  218. if (NULL == m_pCertWizardInfo)
  219. return E_POINTER;
  220. memset(&CertCA, 0, sizeof(CertCA));
  221. memset(&RequestInfo, 0, sizeof(RequestInfo));
  222. dwSavedGenKeyFlags = m_pCertWizardInfo->dwGenKeyFlags;
  223. fCreateRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY));
  224. fFreeRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY));
  225. fSubmitRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY));
  226. // An invalid combination of flags was specified.
  227. if (FALSE == (fCreateRequest || fFreeRequest || fSubmitRequest))
  228. return E_INVALIDARG;
  229. // For FREE_ONLY and SUBMIT_ONLY, copy the request from the IN parameter.
  230. if (0 != ((CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY) & m_pCertWizardInfo->dwFlags))
  231. {
  232. if (NULL == *pResult)
  233. return E_INVALIDARG;
  234. hRequest = *pResult;
  235. }
  236. // Initialize to false ... we need the marshalled parameters to know whether we can cache the request.
  237. fRequestIsCached = FALSE;
  238. // Iterate over each CA, performing a create and submit operation for each.
  239. // Note that we can cache requests for certs if key archival is not needed.
  240. //
  241. if (fCreateRequest || fSubmitRequest)
  242. {
  243. for (IEnumCA CAEnumerator(m_pCertWizardInfo); TRUE; )
  244. {
  245. if (S_OK != (CAEnumerator.Next(&CertCA)))
  246. {
  247. if (!FAILED(hr))
  248. hr=E_FAIL;
  249. if (E_FAIL == hr)
  250. m_pCertWizardInfo->idsText = IDS_NO_CA_FOR_ENROLL_REQUEST_FAILED;
  251. goto ErrorReturn;
  252. }
  253. // Create a certificate request only if
  254. // 1) This is not a submit-only or a free-only operation.
  255. // 2) We don't already have a cached request.
  256. // (We can cache requests which don't require key archival on the CA).
  257. //
  258. // The request is created by looping over available CSPs until one successfully generates
  259. // the request.
  260. //
  261. if (TRUE == fCreateRequest && FALSE == fRequestIsCached)
  262. {
  263. BOOL fHasNextCSP = TRUE;
  264. for (IEnumCSP CSPEnumerator(m_pCertWizardInfo); fHasNextCSP; )
  265. {
  266. _JumpCondition(S_OK != (hr = CSPEnumerator.Next(&dwCSPIndex)), ErrorReturn);
  267. _JumpCondition(S_OK != (hr = CSPEnumerator.HasNext(&fHasNextCSP)), ErrorReturn);
  268. // Each call to MarshallRequestParameters can change the dwGenKeyFlags of pCertWizardInfo
  269. // if the CSP does not support the min key size contained in this field.
  270. // As a result, we must reset the dwGenKeyFlags field to the desired value
  271. // before every call to MarshallRequestParameters.
  272. m_pCertWizardInfo->dwGenKeyFlags = dwSavedGenKeyFlags;
  273. if (S_OK != (hr = ::MarshallRequestParameters
  274. (dwCSPIndex,
  275. m_pCertWizardInfo,
  276. &renewCert,
  277. &CertRequestPvkNew,
  278. &CertRenewPvk,
  279. &pwszHashAlg,
  280. &RequestInfo)))
  281. goto NextCSP;
  282. if (NULL != hRequest)
  283. {
  284. ::FreeRequest(hRequest);
  285. hRequest = NULL;
  286. }
  287. hr = ::CreateRequest
  288. (m_pCertWizardInfo->dwFlags,
  289. m_pCertWizardInfo->dwPurpose,
  290. CertCA.pwszCAName,
  291. CertCA.pwszCALocation,
  292. ((CRYPTUI_WIZ_CERT_RENEW & m_pCertWizardInfo->dwPurpose) ? &renewCert : NULL),
  293. ((CRYPTUI_WIZ_CERT_RENEW & m_pCertWizardInfo->dwPurpose) ? &CertRenewPvk : NULL),
  294. m_pCertWizardInfo->fNewKey,
  295. &CertRequestPvkNew,
  296. pwszHashAlg,
  297. (LPWSTR)m_pCertWizardInfo->pwszDesStore,
  298. m_pCertWizardInfo->dwStoreFlags,
  299. &RequestInfo,
  300. &hRequest);
  301. // Process the return value:
  302. if (S_OK == hr)
  303. {
  304. // Success, get rid of whatever error text we have from past creations:
  305. m_pCertWizardInfo->idsText = 0;
  306. // We're done if we don't need to submit the request.
  307. _JumpCondition(!fSubmitRequest, CommonReturn);
  308. // Cache the request if we don't need support for key archival.
  309. fRequestIsCached = 0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL);
  310. break;
  311. }
  312. else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
  313. {
  314. // E_ACCESSDENIED could indicate one of several different error conditions. Map this
  315. // to an resource identifier which details the possible causes of failure, and try again...
  316. m_pCertWizardInfo->idsText = IDS_NO_ACCESS_TO_ICERTREQUEST2;
  317. }
  318. else if (NTE_BAD_ALGID == HRESULT_FROM_WIN32(hr))
  319. {
  320. // NTE_BAD_ALGID indicates that the CSP didn't support the algorithm type required
  321. // by the template. Map this to a resource identifier that details the possible causes
  322. // of failure, and try again...
  323. m_pCertWizardInfo->idsText = IDS_CSP_BAD_ALGTYPE;
  324. }
  325. else if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == HRESULT_FROM_WIN32(hr))
  326. {
  327. // The user cancelled the operation. Don't try to enroll any longer.
  328. goto ErrorReturn;
  329. }
  330. else
  331. {
  332. // It's an error, but we don't need to map it to special text. Just keep processing...
  333. }
  334. // We're out of CSPs, and we haven't yet created the request!
  335. if (!fHasNextCSP)
  336. {
  337. // If the template doesn't require key archival, we're done. Otherwise, we've got to
  338. // try the other CAs. Note that if we had a mechanism for knowing whether it was the
  339. // key archival step
  340. if (0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL))
  341. goto ErrorReturn;
  342. else
  343. {
  344. ::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
  345. goto NextCA;
  346. }
  347. }
  348. NextCSP:
  349. ::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
  350. }
  351. }
  352. // Submit the request only if this is not a create-only or a free-only operation:
  353. //
  354. if (TRUE == fSubmitRequest)
  355. {
  356. hr = ::SubmitRequest
  357. (hRequest,
  358. FALSE,
  359. m_pCertWizardInfo->dwPurpose,
  360. m_pCertWizardInfo->fConfirmation,
  361. m_pCertWizardInfo->hwndParent,
  362. (LPWSTR)m_pCertWizardInfo->pwszConfirmationTitle,
  363. m_pCertWizardInfo->idsConfirmTitle,
  364. CertCA.pwszCALocation,
  365. CertCA.pwszCAName,
  366. NULL,
  367. NULL,
  368. NULL,
  369. &dwStatus,
  370. (PCCERT_CONTEXT *)pResult);
  371. if (S_OK == hr)
  372. {
  373. // Success, get rid of whatever error text we have from past submits:
  374. m_pCertWizardInfo->idsText = 0;
  375. // If we've successfully submitted or pended
  376. goto CommonReturn;
  377. }
  378. else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
  379. {
  380. // E_ACCESSDENIED could indicate one of several different error conditions. Map this
  381. // to an resource identifier which details the possible causes of failure, and try again...
  382. m_pCertWizardInfo->idsText = IDS_SUBMIT_NO_ACCESS_TO_ICERTREQUEST2;
  383. }
  384. // Some error has occured.
  385. // If it's a non-CA related error, give up...
  386. _JumpCondition(dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR &&
  387. dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_DENIED &&
  388. dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_CONNECTION_FAILED,
  389. ErrorReturn);
  390. // Otherwise, try another CA...
  391. }
  392. NextCA:;
  393. }
  394. }
  395. CommonReturn:
  396. // Write the request to pResult for a create only operation:
  397. if (hr == S_OK && 0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_CREATE_ONLY))
  398. {
  399. *pResult = hRequest;
  400. }
  401. // Write the status code, if requested.
  402. if (NULL != pdwStatus) { *pdwStatus = dwStatus; }
  403. // Free resources.
  404. if (NULL != hRequest && fFreeRequest) { ::FreeRequest(hRequest); }
  405. ::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
  406. if (NULL != CertRenewPvk.pwszKeyContainer)
  407. {
  408. WizardFree((LPVOID)CertRenewPvk.pwszKeyContainer);
  409. }
  410. if (NULL != CertRenewPvk.pwszProvider)
  411. {
  412. WizardFree((LPVOID)CertRenewPvk.pwszProvider);
  413. }
  414. return hr;
  415. ErrorReturn:
  416. goto CommonReturn;
  417. }
  418. HRESULT LocalContext::QueryRequestStatus(IN HANDLE hRequest, OUT CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO *pQueryInfo)
  419. {
  420. HRESULT hr;
  421. if (!QueryRequest(hRequest, pQueryInfo))
  422. goto QueryRequestError;
  423. hr = S_OK;
  424. ErrorReturn:
  425. return hr;
  426. SET_HRESULT(QueryRequestError, GetLastError());
  427. }
  428. HRESULT KeySvcContext::QueryRequestStatus(IN HANDLE hRequest, OUT CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO *pQueryInfo)
  429. {
  430. DWORD dwErr = 0;
  431. DWORD dwIndex = 0;
  432. HRESULT hr = E_FAIL;
  433. KEYSVCC_HANDLE hKeyService = NULL;
  434. KEYSVC_TYPE dwServiceType = KeySvcMachine;
  435. LPSTR pszMachineName = NULL;
  436. PKEYSVC_PROVIDER_INFO pProviderInfo = NULL;
  437. ULONG cProvider = 0;
  438. if (NULL == m_pCertWizardInfo)
  439. return E_POINTER;
  440. if (0 != (hr = ::KeyOpenKeyService(pszMachineName,
  441. dwServiceType,
  442. (LPWSTR)(m_pCertWizardInfo->pwszAccountName), // Service name if necessary
  443. NULL, // no authentication string right now
  444. NULL,
  445. &hKeyService)))
  446. goto KeyOpenKeyServiceError;
  447. if (0 != (hr = ::KeyQueryRequestStatus(hKeyService, hRequest, pQueryInfo)))
  448. goto KeyQueryRequestStatusError;
  449. hr = S_OK;
  450. ErrorReturn:
  451. if (NULL != hKeyService) { KeyCloseKeyService(hKeyService, NULL); }
  452. if (NULL != pszMachineName) { FreeMBStr(NULL,pszMachineName); }
  453. return hr;
  454. TRACE_ERROR(KeyOpenKeyServiceError);
  455. TRACE_ERROR(KeyQueryRequestStatusError);
  456. }
  457. HRESULT LocalContext::Initialize()
  458. {
  459. return S_OK;
  460. }
  461. HANDLE LocalContext::GetClientIdentity()
  462. {
  463. HANDLE hHandle = NULL;
  464. HANDLE hClientToken = NULL;
  465. HANDLE hProcessToken = NULL;
  466. HRESULT hr;
  467. // Step 1: attempt to acquire the thread token.
  468. hHandle = GetCurrentThread();
  469. if (NULL == hHandle)
  470. goto GetThreadTokenError;
  471. if (!OpenThreadToken(hHandle,
  472. TOKEN_QUERY,
  473. TRUE, // open as self
  474. &hClientToken))
  475. goto GetThreadTokenError;
  476. // We got the thread token:
  477. goto GetThreadTokenSuccess;
  478. // Step 2: we've failed to acquire the thread token,
  479. // try to get the process token.
  480. GetThreadTokenError:
  481. if (hHandle != NULL) { CloseHandle(hHandle); }
  482. // We failed to get the thread token, now try to acquire the process token:
  483. hHandle = GetCurrentProcess();
  484. if (NULL == hHandle)
  485. goto GetProcessHandleError;
  486. if (!OpenProcessToken(hHandle,
  487. TOKEN_DUPLICATE,
  488. &hProcessToken))
  489. goto OpenProcessTokenError;
  490. if(!DuplicateToken(hProcessToken,
  491. SecurityImpersonation,
  492. &hClientToken))
  493. goto DuplicateTokenError;
  494. GetThreadTokenSuccess:
  495. CommonReturn:
  496. if (NULL != hHandle) { CloseHandle(hHandle); }
  497. if (NULL != hProcessToken) { CloseHandle(hProcessToken); }
  498. return hClientToken;
  499. ErrorReturn:
  500. goto CommonReturn;
  501. SET_HRESULT(DuplicateTokenError, HRESULT_FROM_WIN32(GetLastError()));
  502. SET_HRESULT(GetProcessHandleError, HRESULT_FROM_WIN32(GetLastError()));
  503. SET_HRESULT(OpenProcessTokenError, HRESULT_FROM_WIN32(GetLastError()));
  504. }
  505. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  506. //
  507. //
  508. // KeySvcContext Implementation.
  509. // See requesters.h for method-level documentation.
  510. //
  511. //
  512. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  513. HRESULT KeySvcContext::BuildCSPList()
  514. {
  515. DWORD dwErr = 0;
  516. DWORD dwIndex = 0;
  517. HRESULT hr = E_FAIL;
  518. KEYSVCC_HANDLE hKeyService = NULL;
  519. KEYSVC_TYPE dwServiceType = KeySvcMachine;
  520. LPSTR pszMachineName = NULL;
  521. PKEYSVC_PROVIDER_INFO pProviderInfo = NULL;
  522. ULONG cProvider = 0;
  523. if (NULL == m_pCertWizardInfo)
  524. return E_POINTER;
  525. // Free the memory currently associated with the CSP fields:
  526. FreeProviders(m_pCertWizardInfo->dwCSPCount,
  527. m_pCertWizardInfo->rgdwProviderType,
  528. m_pCertWizardInfo->rgwszProvider);
  529. m_pCertWizardInfo->dwCSPCount = 0;
  530. m_pCertWizardInfo->rgdwProviderType = NULL;
  531. m_pCertWizardInfo->rgwszProvider = NULL;
  532. //get the psz machine name
  533. if(NULL == m_pCertWizardInfo->pwszMachineName)
  534. goto FailErr;
  535. if(!MkMBStr(NULL, 0, m_pCertWizardInfo->pwszMachineName, &pszMachineName))
  536. goto MkMBStrError;
  537. //connect to the key service
  538. dwServiceType = NULL != m_pCertWizardInfo->pwszAccountName ? KeySvcService : KeySvcMachine;
  539. if (0 != (hr = ::KeyOpenKeyService(pszMachineName,
  540. dwServiceType,
  541. (LPWSTR)(m_pCertWizardInfo->pwszAccountName), // Service name if necessary
  542. NULL, // no authentication string right now
  543. NULL,
  544. &hKeyService)))
  545. goto KeyOpenKeyServiceError;
  546. //get the providers
  547. if(0 != (hr = KeyEnumerateProviders
  548. (hKeyService,
  549. NULL,
  550. &cProvider,
  551. &pProviderInfo)))
  552. goto KeyEnumerateProvidersError;
  553. //copy the provider information
  554. m_pCertWizardInfo->dwCSPCount = cProvider;
  555. m_pCertWizardInfo->rgdwProviderType = (DWORD *)WizardAlloc(sizeof(DWORD) * cProvider);
  556. if (NULL == m_pCertWizardInfo->rgdwProviderType)
  557. goto MemoryErr;
  558. memset(m_pCertWizardInfo->rgdwProviderType, 0, sizeof(DWORD) * cProvider);
  559. m_pCertWizardInfo->rgwszProvider = (LPWSTR *)WizardAlloc(sizeof(LPWSTR) * cProvider);
  560. if (NULL == m_pCertWizardInfo->rgwszProvider)
  561. goto MemoryErr;
  562. memset(m_pCertWizardInfo->rgwszProvider, 0, sizeof(LPWSTR) * cProvider);
  563. for(dwIndex=0; dwIndex < cProvider; dwIndex++)
  564. {
  565. (m_pCertWizardInfo->rgdwProviderType)[dwIndex] = pProviderInfo[dwIndex].ProviderType;
  566. (m_pCertWizardInfo->rgwszProvider)[dwIndex] = WizardAllocAndCopyWStr((LPWSTR)(pProviderInfo[dwIndex].Name.Buffer));
  567. if (NULL == (m_pCertWizardInfo->rgwszProvider)[dwIndex])
  568. goto MemoryErr;
  569. }
  570. //we should have some CSPs
  571. if(0 == m_pCertWizardInfo->dwCSPCount)
  572. goto FailErr;
  573. hr = S_OK;
  574. CommonReturn:
  575. if (NULL != hKeyService) { KeyCloseKeyService(hKeyService, NULL); }
  576. if (NULL != pszMachineName) { FreeMBStr(NULL,pszMachineName); }
  577. if (NULL != pProviderInfo) { WizardFree(pProviderInfo); }
  578. return hr;
  579. ErrorReturn:
  580. // Free and invalidate our provider lists:
  581. FreeProviders(m_pCertWizardInfo->dwCSPCount,
  582. m_pCertWizardInfo->rgdwProviderType,
  583. m_pCertWizardInfo->rgwszProvider);
  584. m_pCertWizardInfo->dwCSPCount = 0;
  585. m_pCertWizardInfo->rgdwProviderType = NULL;
  586. m_pCertWizardInfo->rgwszProvider = NULL;
  587. goto CommonReturn;
  588. SET_HRESULT(FailErr, E_FAIL);
  589. SET_HRESULT(KeyEnumerateProvidersError, HRESULT_FROM_WIN32(hr));
  590. SET_HRESULT(KeyOpenKeyServiceError, HRESULT_FROM_WIN32(hr));
  591. SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
  592. SET_HRESULT(MkMBStrError, HRESULT_FROM_WIN32(GetLastError()));
  593. }
  594. BOOL KeySvcContext::CheckAccessPermission(IN HCERTTYPE hCertType)
  595. {
  596. BOOL fResult = FALSE;
  597. LPWSTR *awszCurrentType = NULL;
  598. LPWSTR *awszTypeName = NULL;
  599. if (NULL == m_pCertWizardInfo)
  600. {
  601. SetLastError(E_POINTER);
  602. return FALSE;
  603. }
  604. if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_TEMPLATES)) {
  605. return TRUE;
  606. }
  607. if(NULL != m_pCertWizardInfo->awszAllowedCertTypes)
  608. {
  609. if(S_OK == CAGetCertTypeProperty(hCertType, CERTTYPE_PROP_DN, &awszTypeName))
  610. {
  611. if(NULL != awszTypeName)
  612. {
  613. if(NULL != awszTypeName[0])
  614. {
  615. awszCurrentType = m_pCertWizardInfo->awszAllowedCertTypes;
  616. while(NULL != *awszCurrentType)
  617. {
  618. if(wcscmp(*awszCurrentType, awszTypeName[0]) == 0)
  619. {
  620. return TRUE;
  621. }
  622. awszCurrentType++;
  623. }
  624. }
  625. CAFreeCertTypeProperty(hCertType, awszTypeName);
  626. }
  627. }
  628. }
  629. return FALSE;
  630. }
  631. BOOL KeySvcContext::CheckCAPermission(IN HCAINFO hCAInfo)
  632. {
  633. LPWSTR *wszCAName = NULL;
  634. LPWSTR *wszCurrentCA = NULL;
  635. if (NULL == m_pCertWizardInfo)
  636. {
  637. SetLastError(E_POINTER);
  638. return FALSE;
  639. }
  640. if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_CAS)) {
  641. return TRUE;
  642. }
  643. if (NULL != m_pCertWizardInfo->awszValidCA)
  644. {
  645. if(S_OK == CAGetCAProperty(hCAInfo, CA_PROP_NAME, &wszCAName))
  646. {
  647. if(NULL != wszCAName)
  648. {
  649. if(NULL != wszCAName[0])
  650. {
  651. wszCurrentCA = m_pCertWizardInfo->awszValidCA;
  652. while(*wszCurrentCA)
  653. {
  654. if(0 == wcscmp(*wszCurrentCA, wszCAName[0]))
  655. {
  656. return TRUE;
  657. }
  658. wszCurrentCA++;
  659. }
  660. }
  661. CAFreeCAProperty(hCAInfo, wszCAName);
  662. }
  663. }
  664. }
  665. return FALSE;
  666. }
  667. HRESULT KeySvcContext::GetDefaultCSP(OUT BOOL *pfAllocateCSP)
  668. {
  669. DWORD dwDefaultFlag = 0;
  670. HRESULT hr = E_FAIL;
  671. LPSTR pszMachineName = NULL;
  672. LPWSTR pwszName = NULL;
  673. KEYSVC_TYPE dwServiceType = KeySvcMachine;
  674. KEYSVCC_HANDLE hKeyService = NULL;
  675. PKEYSVC_PROVIDER_INFO pKeyProviderInfo = NULL;
  676. if (NULL == m_pCertWizardInfo)
  677. return E_POINTER;
  678. if (NULL == pfAllocateCSP)
  679. return E_INVALIDARG;
  680. *pfAllocateCSP = FALSE;
  681. //no provider has been selected
  682. if(0 == m_pCertWizardInfo->dwProviderType)
  683. return S_OK;
  684. //return if user has selected both the dwProviderType
  685. //or the provider name
  686. if(NULL != m_pCertWizardInfo->pwszProvider)
  687. return S_OK;
  688. //get the psz machine name
  689. if(NULL == m_pCertWizardInfo->pwszMachineName)
  690. goto InvalidArgErr;
  691. if(!MkMBStr(NULL, 0, m_pCertWizardInfo->pwszMachineName, &pszMachineName))
  692. goto Win32Err;
  693. dwServiceType = NULL != m_pCertWizardInfo->pwszAccountName ? KeySvcService : KeySvcMachine;
  694. //connect to the key service
  695. if (0 != (hr = KeyOpenKeyService
  696. (pszMachineName,
  697. dwServiceType,
  698. (LPWSTR)(m_pCertWizardInfo->pwszAccountName), // Service name if necessary
  699. NULL, // no authentication string right now
  700. NULL,
  701. &hKeyService)))
  702. {
  703. m_idsText = IDS_RPC_CALL_FAILED;
  704. goto Win32Err;
  705. }
  706. //get the default provider name
  707. if(0 != (hr = KeyGetDefaultProvider
  708. (hKeyService,
  709. m_pCertWizardInfo->dwProviderType,
  710. 0,
  711. NULL,
  712. &dwDefaultFlag,
  713. &pKeyProviderInfo)))
  714. {
  715. m_idsText = IDS_RPC_CALL_FAILED;
  716. goto Win32Err;
  717. }
  718. pwszName = (LPWSTR)(pKeyProviderInfo->Name.Buffer);
  719. if(NULL == pwszName)
  720. goto FailErr;
  721. m_pCertWizardInfo->pwszProvider = (LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszName)+1));
  722. if(NULL == m_pCertWizardInfo->pwszProvider)
  723. goto MemoryErr;
  724. *pfAllocateCSP = TRUE;
  725. wcscpy(m_pCertWizardInfo->pwszProvider, pwszName);
  726. hr = S_OK;
  727. CommonReturn:
  728. if (NULL != pKeyProviderInfo) { WizardFree(pKeyProviderInfo); }
  729. if (NULL != hKeyService) { KeyCloseKeyService(hKeyService, NULL); }
  730. if (NULL != pszMachineName) { FreeMBStr(NULL,pszMachineName); }
  731. return hr;
  732. ErrorReturn:
  733. goto CommonReturn;
  734. SET_HRESULT(InvalidArgErr, E_INVALIDARG);
  735. SET_HRESULT(Win32Err, HRESULT_FROM_WIN32(GetLastError()));
  736. SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
  737. SET_HRESULT(FailErr, E_FAIL);
  738. }
  739. HRESULT WhistlerMachineContext::Enroll(OUT DWORD *pdwStatus,
  740. IN OUT HANDLE *pResult)
  741. {
  742. BOOL fRequestIsCached;
  743. BOOL fCreateRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY));
  744. BOOL fFreeRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY));
  745. BOOL fSubmitRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY));
  746. CERT_BLOB renewCert;
  747. CERT_ENROLL_INFO RequestInfo;
  748. CERT_REQUEST_PVK_NEW CertRequestPvkNew;
  749. CERT_REQUEST_PVK_NEW CertRenewPvk;
  750. CRYPTUI_WIZ_CERT_CA CertCA;
  751. DWORD dwFlags;
  752. DWORD dwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNKNOWN;
  753. DWORD dwCSPIndex;
  754. DWORD dwSavedGenKeyFlags;
  755. HANDLE hRequest = NULL;
  756. HRESULT hr = E_FAIL;
  757. KEYSVCC_HANDLE hKeyService = NULL;
  758. KEYSVC_TYPE ktServiceType;
  759. LPSTR pszMachineName = NULL;
  760. LPWSTR pwszHashAlg = NULL;
  761. //init 1st for error jump
  762. ZeroMemory(&CertRenewPvk, sizeof(CertRenewPvk));
  763. if (NULL == pResult)
  764. return E_INVALIDARG;
  765. if (NULL == m_pCertWizardInfo)
  766. return E_POINTER;
  767. memset(&renewCert, 0, sizeof(renewCert));
  768. memset(&CertCA, 0, sizeof(CertCA));
  769. memset(&RequestInfo, 0, sizeof(RequestInfo));
  770. dwSavedGenKeyFlags = m_pCertWizardInfo->dwGenKeyFlags;
  771. // An invalid combination of flags was specified.
  772. if (FALSE == (fCreateRequest || fFreeRequest || fSubmitRequest))
  773. return E_INVALIDARG;
  774. // For FREE_ONLY and SUBMIT_ONLY, copy the request from the IN parameter.
  775. if (0 != ((CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY) & m_pCertWizardInfo->dwFlags))
  776. {
  777. if (NULL == *pResult)
  778. return E_INVALIDARG;
  779. hRequest = *pResult;
  780. }
  781. if(!MkMBStr(NULL, 0, m_pCertWizardInfo->pwszMachineName, &pszMachineName))
  782. goto MkMBStrError;
  783. ktServiceType = NULL != m_pCertWizardInfo->pwszAccountName ? KeySvcService : KeySvcMachine;
  784. hr = ::KeyOpenKeyService
  785. (pszMachineName,
  786. ktServiceType,
  787. (LPWSTR)(m_pCertWizardInfo->pwszAccountName),
  788. NULL,
  789. NULL,
  790. &hKeyService);
  791. _JumpConditionWithExpr(S_OK != hr, KeyOpenKeyServiceError, m_idsText = IDS_RPC_CALL_FAILED);
  792. // Initialize to false ... we need the marshalled parameters to know whether we can cache the request.
  793. fRequestIsCached = FALSE;
  794. // Iterate over each CA, performing a create and submit operation for each.
  795. // Note that we can cache requests for certs if key archival is not needed.
  796. //
  797. if (fCreateRequest || fSubmitRequest)
  798. {
  799. for (IEnumCA CAEnumerator(m_pCertWizardInfo); TRUE; )
  800. {
  801. if (S_OK != (CAEnumerator.Next(&CertCA)))
  802. {
  803. if(!FAILED(hr))
  804. hr=E_FAIL;
  805. if (E_FAIL == hr)
  806. m_pCertWizardInfo->idsText = IDS_NO_CA_FOR_ENROLL_REQUEST_FAILED;
  807. goto ErrorReturn;
  808. }
  809. // Create a certificate request only if
  810. // 1) This is not a submit-only or a free-only operation.
  811. // 2) We don't already have a cached request.
  812. // (We can cache requests which don't require key archival on the CA).
  813. //
  814. // The request is created by looping over available CSPs until one successfully generates
  815. // the request.
  816. //
  817. if (TRUE == fCreateRequest && FALSE == fRequestIsCached)
  818. {
  819. BOOL fHasNextCSP = TRUE;
  820. for (IEnumCSP CSPEnumerator(m_pCertWizardInfo); fHasNextCSP; )
  821. {
  822. _JumpCondition(S_OK != (hr = CSPEnumerator.Next(&dwCSPIndex)), ErrorReturn);
  823. _JumpCondition(S_OK != (hr = CSPEnumerator.HasNext(&fHasNextCSP)), ErrorReturn);
  824. // Each call to MarshallRequestParameters can change the dwGenKeyFlags of pCertWizardInfo
  825. // if the CSP does not support the min key size contained in this field.
  826. // As a result, we must reset the dwGenKeyFlags field to the desired value
  827. // before every call to MarshallRequestParameters.
  828. m_pCertWizardInfo->dwGenKeyFlags = dwSavedGenKeyFlags;
  829. if (S_OK != (hr = ::MarshallRequestParameters
  830. (dwCSPIndex,
  831. m_pCertWizardInfo,
  832. &renewCert,
  833. &CertRequestPvkNew,
  834. &CertRenewPvk,
  835. &pwszHashAlg,
  836. &RequestInfo)))
  837. goto NextCSP;
  838. if (NULL != hRequest)
  839. {
  840. this->FreeRequest(hKeyService, pszMachineName, &hRequest);
  841. hRequest = NULL;
  842. }
  843. hr = this->CreateRequest
  844. (hKeyService,
  845. pszMachineName,
  846. CertCA.pwszCALocation,
  847. CertCA.pwszCAName,
  848. &CertRequestPvkNew,
  849. &renewCert,
  850. &CertRenewPvk,
  851. pwszHashAlg,
  852. &RequestInfo,
  853. &hRequest);
  854. // Process the return value:
  855. if (S_OK == hr)
  856. {
  857. // Success, get rid of whatever error text we have from past creations:
  858. m_pCertWizardInfo->idsText = 0;
  859. // We're done if we don't need to submit the request.
  860. _JumpCondition(!fSubmitRequest, CommonReturn);
  861. // Cache the request if we don't need support for key archival.
  862. fRequestIsCached = 0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL);
  863. break;
  864. }
  865. else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
  866. {
  867. // E_ACCESSDENIED could indicate one of several different error conditions. Map this
  868. // to an resource identifier which details the possible causes of failure, and try again...
  869. m_pCertWizardInfo->idsText = IDS_NO_ACCESS_TO_ICERTREQUEST2;
  870. }
  871. else if (NTE_BAD_ALGID == HRESULT_FROM_WIN32(hr))
  872. {
  873. // NTE_BAD_ALGID indicates that the CSP didn't support the algorithm type required
  874. // by the template. Map this to a resource identifier that details the possible causes
  875. // of failure, and try again...
  876. m_pCertWizardInfo->idsText = IDS_CSP_BAD_ALGTYPE;
  877. }
  878. else if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == HRESULT_FROM_WIN32(hr))
  879. {
  880. // The user cancelled the operation. Don't try to enroll any longer.
  881. goto ErrorReturn;
  882. }
  883. else
  884. {
  885. // It's an error, but we don't need to map it to special text. Just keep processing...
  886. }
  887. // We're out of CSPs, and we haven't yet created the request!
  888. if (!fHasNextCSP)
  889. {
  890. // If the template doesn't require key archival, we're done. Otherwise, we've got to
  891. // try the other CAs. Note that if we had a mechanism for knowing whether it was the
  892. // key archival step
  893. if (0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL))
  894. goto ErrorReturn;
  895. else
  896. {
  897. ::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
  898. goto NextCA;
  899. }
  900. }
  901. NextCSP:
  902. ::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
  903. }
  904. }
  905. if (TRUE == fSubmitRequest)
  906. {
  907. hr = this->SubmitRequest
  908. (hKeyService,
  909. pszMachineName,
  910. CertCA.pwszCALocation,
  911. CertCA.pwszCAName,
  912. hRequest,
  913. (PCCERT_CONTEXT *)pResult,
  914. &dwStatus);
  915. if (S_OK == hr)
  916. {
  917. // Success, get rid of whatever error text we have from past submits:
  918. m_pCertWizardInfo->idsText = 0;
  919. // If we've successfully submitted or pended
  920. goto CommonReturn;
  921. }
  922. else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
  923. {
  924. // E_ACCESSDENIED could indicate one of several different error conditions. Map this
  925. // to an resource identifier which details the possible causes of failure, and try again...
  926. m_pCertWizardInfo->idsText = IDS_SUBMIT_NO_ACCESS_TO_ICERTREQUEST2;
  927. }
  928. // Some error has occured.
  929. // If it's a non-CA related error, give up...
  930. _JumpCondition(dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR &&
  931. dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_DENIED &&
  932. dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_CONNECTION_FAILED,
  933. ErrorReturn);
  934. // Otherwise, try another CA...
  935. }
  936. NextCA:;
  937. }
  938. }
  939. CommonReturn:
  940. // Write the request to pResult for a create only operation:
  941. if (hr == S_OK && 0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_CREATE_ONLY))
  942. {
  943. *pResult = hRequest;
  944. }
  945. // Write the status code, if requested.
  946. if (NULL != pdwStatus) { *pdwStatus = dwStatus; }
  947. // Free resources.
  948. if (NULL != hRequest && TRUE == fFreeRequest) { this->FreeRequest(hKeyService, pszMachineName, hRequest); }
  949. if (NULL != hKeyService) { ::KeyCloseKeyService(hKeyService, NULL); }
  950. if (NULL != pszMachineName) { ::FreeMBStr(NULL,pszMachineName); }
  951. if (NULL != CertRenewPvk.pwszKeyContainer)
  952. {
  953. WizardFree((LPVOID)CertRenewPvk.pwszKeyContainer);
  954. }
  955. if (NULL != CertRenewPvk.pwszProvider)
  956. {
  957. WizardFree((LPVOID)CertRenewPvk.pwszProvider);
  958. }
  959. ::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
  960. return hr;
  961. ErrorReturn:
  962. goto CommonReturn;
  963. SET_HRESULT(KeyOpenKeyServiceError, hr);
  964. SET_HRESULT(MkMBStrError, HRESULT_FROM_WIN32(GetLastError()));
  965. }
  966. HRESULT WhistlerMachineContext::CreateRequest
  967. (IN KEYSVCC_HANDLE hKeyService,
  968. IN LPSTR pszMachineName,
  969. IN LPWSTR pwszCALocation,
  970. IN LPWSTR pwszCAName,
  971. IN PCERT_REQUEST_PVK_NEW pKeyNew,
  972. IN CERT_BLOB *pCert,
  973. IN PCERT_REQUEST_PVK_NEW pRenewKey,
  974. IN LPWSTR pwszHashAlg,
  975. IN PCERT_ENROLL_INFO pRequestInfo,
  976. OUT HANDLE *phRequest)
  977. {
  978. CERT_BLOB PKCS7Blob;
  979. CERT_BLOB renewCert;
  980. DWORD dwFlags = m_pCertWizardInfo->dwFlags;
  981. dwFlags &= ~(CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY);
  982. dwFlags |= CRYPTUI_WIZ_CREATE_ONLY;
  983. // Create the certificate request...
  984. return ::KeyEnroll_V2
  985. (hKeyService,
  986. pszMachineName,
  987. TRUE,
  988. m_pCertWizardInfo->dwPurpose,
  989. dwFlags,
  990. (LPWSTR)(m_pCertWizardInfo->pwszAccountName),
  991. NULL,
  992. (CRYPTUI_WIZ_CERT_ENROLL & m_pCertWizardInfo->dwPurpose) ? TRUE : FALSE,
  993. pwszCALocation,
  994. pwszCAName,
  995. m_pCertWizardInfo->fNewKey,
  996. pKeyNew,
  997. pCert,
  998. pRenewKey,
  999. pwszHashAlg,
  1000. (LPWSTR)m_pCertWizardInfo->pwszDesStore,
  1001. m_pCertWizardInfo->dwStoreFlags,
  1002. pRequestInfo,
  1003. (LPWSTR)m_pCertWizardInfo->pwszRequestString,
  1004. 0,
  1005. NULL,
  1006. phRequest,
  1007. NULL,
  1008. NULL,
  1009. NULL);
  1010. }
  1011. HRESULT WhistlerMachineContext::SubmitRequest
  1012. (IN KEYSVCC_HANDLE hKeyService,
  1013. IN LPSTR pszMachineName,
  1014. IN LPWSTR pwszCALocation,
  1015. IN LPWSTR pwszCAName,
  1016. IN HANDLE hRequest,
  1017. OUT PCCERT_CONTEXT *ppCertContext,
  1018. OUT DWORD *pdwStatus)
  1019. {
  1020. CERT_BLOB HashBlob;
  1021. CERT_BLOB PKCS7Blob;
  1022. HRESULT hr = E_FAIL;
  1023. memset(&HashBlob, 0, sizeof(HashBlob));
  1024. memset(&PKCS7Blob, 0, sizeof(PKCS7Blob));
  1025. DWORD dwFlags = m_pCertWizardInfo->dwFlags;
  1026. dwFlags &= ~(CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY);
  1027. dwFlags |= CRYPTUI_WIZ_SUBMIT_ONLY;
  1028. // Submit the certificate request...
  1029. hr = ::KeyEnroll_V2
  1030. (hKeyService,
  1031. pszMachineName,
  1032. TRUE,
  1033. m_pCertWizardInfo->dwPurpose,
  1034. dwFlags,
  1035. (LPWSTR)(m_pCertWizardInfo->pwszAccountName),
  1036. NULL,
  1037. (CRYPTUI_WIZ_CERT_ENROLL & m_pCertWizardInfo->dwPurpose) ? TRUE : FALSE,
  1038. pwszCALocation,
  1039. pwszCAName,
  1040. m_pCertWizardInfo->fNewKey,
  1041. NULL,
  1042. NULL,
  1043. NULL,
  1044. NULL,
  1045. NULL,
  1046. 0,
  1047. NULL,
  1048. NULL,
  1049. 0,
  1050. NULL,
  1051. &hRequest,
  1052. &PKCS7Blob,
  1053. &HashBlob,
  1054. pdwStatus);
  1055. if (S_OK == hr && CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED == *pdwStatus)
  1056. {
  1057. hr = this->ToCertContext
  1058. (&PKCS7Blob,
  1059. &HashBlob,
  1060. pdwStatus,
  1061. ppCertContext);
  1062. }
  1063. if (NULL != HashBlob.pbData) { ::WizardFree(HashBlob.pbData); }
  1064. if (NULL != PKCS7Blob.pbData) { ::WizardFree(PKCS7Blob.pbData); }
  1065. return hr;
  1066. }
  1067. void WhistlerMachineContext::FreeRequest
  1068. (IN KEYSVCC_HANDLE hKeyService,
  1069. IN LPSTR pszMachineName,
  1070. IN HANDLE hRequest)
  1071. {
  1072. DWORD dwFlags = m_pCertWizardInfo->dwFlags;
  1073. dwFlags &= ~(CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY);
  1074. dwFlags |= CRYPTUI_WIZ_FREE_ONLY;
  1075. ::KeyEnroll_V2
  1076. (hKeyService,
  1077. pszMachineName,
  1078. TRUE,
  1079. 0,
  1080. dwFlags,
  1081. NULL,
  1082. NULL,
  1083. FALSE,
  1084. NULL,
  1085. NULL,
  1086. FALSE,
  1087. NULL,
  1088. NULL,
  1089. NULL,
  1090. NULL,
  1091. NULL,
  1092. 0,
  1093. NULL,
  1094. NULL,
  1095. 0,
  1096. NULL,
  1097. &hRequest,
  1098. NULL,
  1099. NULL,
  1100. NULL);
  1101. }
  1102. HRESULT KeySvcContext::ToCertContext(IN CERT_BLOB *pPKCS7Blob,
  1103. IN CERT_BLOB *pHashBlob,
  1104. OUT DWORD *pdwStatus,
  1105. OUT PCCERT_CONTEXT *ppCertContext)
  1106. {
  1107. HCERTSTORE hCertStore = NULL;
  1108. HRESULT hr = E_FAIL;
  1109. if (NULL == pPKCS7Blob || NULL == pHashBlob || NULL == ppCertContext)
  1110. return E_INVALIDARG;
  1111. //get the certificate store from the PKCS7 for the remote case
  1112. if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
  1113. pPKCS7Blob,
  1114. CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
  1115. CERT_QUERY_FORMAT_FLAG_ALL,
  1116. 0,
  1117. NULL,
  1118. NULL,
  1119. NULL,
  1120. &hCertStore,
  1121. NULL,
  1122. NULL))
  1123. {
  1124. if (NULL != pdwStatus) { *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; }
  1125. goto FailError;
  1126. }
  1127. //find the certificate based on the hash
  1128. if (NULL == (*ppCertContext = ::CertFindCertificateInStore
  1129. (hCertStore,
  1130. X509_ASN_ENCODING,
  1131. 0,
  1132. CERT_FIND_SHA1_HASH,
  1133. pHashBlob,
  1134. NULL)))
  1135. {
  1136. if (NULL != pdwStatus) { *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; }
  1137. goto FailError;
  1138. }
  1139. hr = S_OK;
  1140. CommonReturn:
  1141. if(NULL != hCertStore) { CertCloseStore(hCertStore, 0); }
  1142. return hr;
  1143. ErrorReturn:
  1144. if (NULL != pdwStatus && 0 == *pdwStatus) { *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_KEYSVC_FAILED; }
  1145. goto CommonReturn;
  1146. SET_HRESULT(FailError, E_FAIL);
  1147. }
  1148. HRESULT KeySvcContext::Initialize()
  1149. {
  1150. if (NULL == m_pCertWizardInfo)
  1151. return E_POINTER;
  1152. // We don't need to download the list of allowed templates if we're not going
  1153. // to be performing the access check anyway.
  1154. if (0 == (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_TEMPLATES))
  1155. {
  1156. //for the remote enrollment, we have to get the allowed cert type
  1157. //list from the key service.
  1158. if(!::GetCertTypeName(m_pCertWizardInfo))
  1159. {
  1160. m_idsText = IDS_NO_VALID_CERT_TEMPLATE;
  1161. return HRESULT_FROM_WIN32(GetLastError());
  1162. }
  1163. }
  1164. // We don't need to download the list of allowed CAs if we're not going
  1165. // to be performing the access check anyway
  1166. if (0 == (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_CAS))
  1167. {
  1168. if(!::GetCAName(m_pCertWizardInfo))
  1169. {
  1170. m_idsText = IDS_NO_CA_FOR_ENROLL;
  1171. return HRESULT_FROM_WIN32(GetLastError());
  1172. }
  1173. }
  1174. return S_OK;
  1175. }
  1176. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1177. //
  1178. //
  1179. // CertRequesterContext: implementation of abstract superclass.
  1180. // See requesters.h for method-level documentation.
  1181. //
  1182. //
  1183. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1184. HRESULT CertRequesterContext::MakeDefaultCertRequesterContext
  1185. (OUT CertRequesterContext **ppRequesterContext)
  1186. {
  1187. CERT_WIZARD_INFO *pCertWizardInfo = NULL;
  1188. HRESULT hr;
  1189. pCertWizardInfo = (CERT_WIZARD_INFO *)WizardAlloc(sizeof(CERT_WIZARD_INFO));
  1190. _JumpCondition(NULL == pCertWizardInfo, MemoryError);
  1191. hr = MakeCertRequesterContext
  1192. (NULL,
  1193. NULL,
  1194. 0,
  1195. pCertWizardInfo,
  1196. ppRequesterContext,
  1197. NULL);
  1198. _JumpCondition(S_OK != hr, MakeCertRequesterContextError);
  1199. hr = S_OK;
  1200. CommonReturn:
  1201. return hr;
  1202. ErrorReturn:
  1203. if (NULL != pCertWizardInfo) { WizardFree(pCertWizardInfo); }
  1204. goto CommonReturn;
  1205. SET_HRESULT(MakeCertRequesterContextError, hr);
  1206. SET_HRESULT(MemoryError, E_OUTOFMEMORY);
  1207. }
  1208. HRESULT CertRequesterContext::MakeCertRequesterContext
  1209. (IN LPCWSTR pwszAccountName,
  1210. IN LPCWSTR pwszMachineName,
  1211. IN DWORD dwCertOpenStoreFlags,
  1212. IN CERT_WIZARD_INFO *pCertWizardInfo,
  1213. OUT CertRequesterContext **ppRequesterContext,
  1214. OUT UINT *pIDSText)
  1215. {
  1216. BOOL fMachine = FALSE;
  1217. DWORD const dwLocalUserNameSize = UNLEN + 1;
  1218. DWORD const dwLocalMachineNameSize = MAX_COMPUTERNAME_LENGTH + 1;
  1219. HRESULT hr = E_FAIL;
  1220. UINT idsText = NULL == pIDSText ? 0 : *pIDSText;
  1221. WCHAR wszLocalUserName[dwLocalUserNameSize] = { 0 };
  1222. WCHAR wszLocalMachineName[dwLocalMachineNameSize] = { 0 };
  1223. // Input validation:
  1224. if (NULL == pCertWizardInfo || NULL == ppRequesterContext)
  1225. return E_INVALIDARG;
  1226. // Should not have assigned values to these fields yet:
  1227. if (NULL != pCertWizardInfo->pwszAccountName || NULL != pCertWizardInfo->pwszMachineName)
  1228. return E_INVALIDARG;
  1229. if(!GetUserNameU(wszLocalUserName, (DWORD *)&dwLocalUserNameSize))
  1230. {
  1231. idsText=IDS_FAIL_TO_GET_USER_NAME;
  1232. goto Win32Error;
  1233. }
  1234. if(!GetComputerNameU(wszLocalMachineName, (DWORD *)&dwLocalMachineNameSize))
  1235. {
  1236. idsText=IDS_FAIL_TO_GET_COMPUTER_NAME;
  1237. goto Win32Error;
  1238. }
  1239. // Map all unspecified values to defaults:
  1240. //
  1241. // Default #1: NULL pwszAccountName indicates current user _iff_ pwszMachineName is NULL.
  1242. if (NULL == pwszAccountName && NULL == pwszMachineName)
  1243. { pwszAccountName = wszLocalUserName; }
  1244. // Default #2: NULL pwszMachineName indicates local machine.
  1245. if (NULL == pwszMachineName)
  1246. { pwszMachineName = wszLocalMachineName; }
  1247. // Default #3: NULL pwszAccountName and non-NULL pwszMachineName indicates machine enrollment.
  1248. fMachine = (NULL == pwszAccountName ||
  1249. (0 != _wcsicmp(pwszAccountName, wszLocalUserName)) ||
  1250. (0 != _wcsicmp(pwszMachineName, wszLocalMachineName)));
  1251. // Default #4: dwCertOpenStoreFlags == 0 defaults to CERT_SYSTEM_STORE_LOCAL_MACHINE
  1252. // for machine enrollment, CERT_SYSTEM_STORE_CURRENT_USER for user enrollment.
  1253. if (0 == dwCertOpenStoreFlags)
  1254. { dwCertOpenStoreFlags = fMachine ? CERT_SYSTEM_STORE_LOCAL_MACHINE : CERT_SYSTEM_STORE_CURRENT_USER; }
  1255. // Now that we've mapped unspecified values to defaults, assign the wizard's fields
  1256. // with these values:
  1257. //
  1258. if (NULL != pwszAccountName)
  1259. {
  1260. pCertWizardInfo->pwszAccountName = (LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszAccountName) + 1));
  1261. _JumpConditionWithExpr(NULL == pCertWizardInfo->pwszAccountName, MemoryError, idsText = IDS_OUT_OF_MEMORY);
  1262. wcscpy((LPWSTR)pCertWizardInfo->pwszAccountName, pwszAccountName);
  1263. }
  1264. pCertWizardInfo->pwszMachineName = (LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszMachineName) + 1));
  1265. _JumpConditionWithExpr(NULL == pCertWizardInfo->pwszMachineName, MemoryError, idsText = IDS_OUT_OF_MEMORY);
  1266. wcscpy((LPWSTR)pCertWizardInfo->pwszMachineName, pwszMachineName);
  1267. pCertWizardInfo->fMachine = fMachine;
  1268. pCertWizardInfo->dwStoreFlags = dwCertOpenStoreFlags;
  1269. // We need keysvc if:
  1270. //
  1271. // 1) We're doing machine enrollment (we need to run under the local machine's context).
  1272. // 2) An account _other_ than the current user on the local machine is specified.
  1273. // (we need to run under another user's context).
  1274. //
  1275. if (TRUE == fMachine)
  1276. {
  1277. KEYSVC_TYPE ktServiceType;
  1278. KEYSVC_OPEN_KEYSVC_INFO OpenKeySvcInfo = { sizeof(KEYSVC_OPEN_KEYSVC_INFO), 0 };
  1279. KEYSVCC_HANDLE hKeyService = NULL;
  1280. LPSTR pszMachineName = NULL;
  1281. ktServiceType = NULL != pwszAccountName ? KeySvcService : KeySvcMachine;
  1282. _JumpConditionWithExpr(!MkMBStr(NULL, 0, pwszMachineName, &pszMachineName), MkMBStrError, idsText = IDS_OUT_OF_MEMORY);
  1283. // See if we're enrolling for a W2K or a Whistler machine:
  1284. hr = KeyOpenKeyService
  1285. (pszMachineName,
  1286. ktServiceType,
  1287. (LPWSTR)pwszAccountName,
  1288. NULL,
  1289. &OpenKeySvcInfo,
  1290. &hKeyService);
  1291. _JumpConditionWithExpr(S_OK != hr, KeyOpenKeyServiceError, idsText = IDS_RPC_CALL_FAILED);
  1292. switch (OpenKeySvcInfo.ulVersion)
  1293. {
  1294. case KEYSVC_VERSION_WHISTLER:
  1295. *ppRequesterContext = new WhistlerMachineContext(pCertWizardInfo);
  1296. break;
  1297. case KEYSVC_VERSION_W2K:
  1298. default:
  1299. hr = E_UNEXPECTED;
  1300. goto KeyOpenKeyServiceError;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. // We're requesting a cert for ourselves: we don't need keysvc.
  1306. *ppRequesterContext = new LocalContext(pCertWizardInfo);
  1307. }
  1308. if (NULL == *ppRequesterContext)
  1309. goto MemoryError;
  1310. hr = S_OK;
  1311. CommonReturn:
  1312. return hr;
  1313. ErrorReturn:
  1314. if (NULL != pCertWizardInfo->pwszMachineName) { WizardFree((LPVOID)pCertWizardInfo->pwszMachineName); }
  1315. if (NULL != pCertWizardInfo->pwszAccountName) { WizardFree((LPVOID)pCertWizardInfo->pwszAccountName); }
  1316. pCertWizardInfo->pwszMachineName = NULL;
  1317. pCertWizardInfo->pwszAccountName = NULL;
  1318. // Assign error text if specified:
  1319. if (NULL != pIDSText) { *pIDSText = idsText; }
  1320. goto CommonReturn;
  1321. SET_HRESULT(MemoryError, E_OUTOFMEMORY);
  1322. SET_HRESULT(KeyOpenKeyServiceError, hr);
  1323. SET_HRESULT(MkMBStrError, HRESULT_FROM_WIN32(GetLastError()));
  1324. SET_HRESULT(Win32Error, HRESULT_FROM_WIN32(GetLastError()));
  1325. }
  1326. CertRequesterContext::~CertRequesterContext()
  1327. {
  1328. if (NULL != m_pCertWizardInfo)
  1329. {
  1330. if (NULL != m_pCertWizardInfo->pwszMachineName) { WizardFree((LPVOID)m_pCertWizardInfo->pwszMachineName); }
  1331. if (NULL != m_pCertWizardInfo->pwszAccountName) { WizardFree((LPVOID)m_pCertWizardInfo->pwszAccountName); }
  1332. m_pCertWizardInfo->pwszMachineName = NULL;
  1333. m_pCertWizardInfo->pwszAccountName = NULL;
  1334. }
  1335. }