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.

484 lines
14 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: pfximpt.cpp
  8. //
  9. // Contents: PFX import dialog
  10. //
  11. // History: 06/98 xtan
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "pch.cpp"
  15. #pragma hdrstop
  16. #include "cscsp.h"
  17. #include "certmsg.h"
  18. #include "initcert.h"
  19. #include "setuput.h"
  20. #include "cspenum.h"
  21. #include "wizpage.h"
  22. #include "usecert.h"
  23. #define __dwFILE__ __dwFILE_OCMSETUP_PFXIMPT_CPP__
  24. typedef struct _certpfximportinfo
  25. {
  26. HINSTANCE hInstance;
  27. BOOL fUnattended;
  28. WCHAR *pwszFileName;
  29. DWORD dwFileNameSize;
  30. WCHAR *pwszPassword;
  31. DWORD dwPasswordSize;
  32. } CERTPFXIMPORTINFO;
  33. HRESULT
  34. CertBrowsePFX(HINSTANCE hInstance, HWND hDlg)
  35. {
  36. HRESULT hr;
  37. WCHAR *pwszFileNameIn = NULL;
  38. WCHAR *pwszFileNameOut = NULL;
  39. HWND hCtrl = GetDlgItem(hDlg, IDC_PFX_FILENAME);
  40. hr = myUIGetWindowText(hCtrl, &pwszFileNameIn);
  41. _JumpIfError(hr, error, "myUIGetWindowText");
  42. hr = myGetOpenFileName(
  43. hDlg,
  44. hInstance,
  45. IDS_IMPORT_PFX_TITLE,
  46. IDS_PFX_FILE_FILTER,
  47. 0, // no def ext
  48. OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
  49. pwszFileNameIn,
  50. &pwszFileNameOut);
  51. _JumpIfError(hr, error, "myGetOpenFileName");
  52. if (NULL != pwszFileNameOut)
  53. {
  54. SetWindowText(hCtrl, pwszFileNameOut);
  55. }
  56. hr = S_OK;
  57. error:
  58. if (NULL != pwszFileNameOut)
  59. {
  60. LocalFree(pwszFileNameOut);
  61. }
  62. if (NULL != pwszFileNameIn)
  63. {
  64. LocalFree(pwszFileNameIn);
  65. }
  66. return hr;
  67. }
  68. HRESULT
  69. GetPFXInfo(
  70. HWND hDlg,
  71. CERTPFXIMPORTINFO* pCertPfxImportInfo)
  72. {
  73. HRESULT hr;
  74. GetWindowText(GetDlgItem(hDlg, IDC_PFX_FILENAME),
  75. pCertPfxImportInfo->pwszFileName,
  76. pCertPfxImportInfo->dwFileNameSize);
  77. if (0x0 == pCertPfxImportInfo->pwszFileName[0])
  78. {
  79. // file can't empty
  80. hr = E_INVALIDARG;
  81. CertWarningMessageBox(
  82. pCertPfxImportInfo->hInstance,
  83. pCertPfxImportInfo->fUnattended,
  84. hDlg,
  85. IDS_ERR_EMPTYPFXFILE,
  86. 0,
  87. NULL);
  88. SetFocus(GetDlgItem(hDlg, IDC_PFX_FILENAME));
  89. goto error;
  90. }
  91. GetWindowText(GetDlgItem(hDlg, IDC_PFX_PASSWORD),
  92. pCertPfxImportInfo->pwszPassword,
  93. pCertPfxImportInfo->dwPasswordSize);
  94. hr = S_OK;
  95. error:
  96. return hr;
  97. }
  98. INT_PTR CALLBACK
  99. CertPFXFilePasswordProc(
  100. HWND hDlg,
  101. UINT iMsg,
  102. WPARAM wParam,
  103. LPARAM lParam)
  104. {
  105. HRESULT hr;
  106. BOOL ret = FALSE;
  107. int id = IDCANCEL;
  108. static CERTPFXIMPORTINFO *pCertPfxImportInfo = NULL;
  109. switch (iMsg)
  110. {
  111. case WM_INITDIALOG:
  112. pCertPfxImportInfo = (CERTPFXIMPORTINFO*)lParam;
  113. ret = TRUE;
  114. break;
  115. case WM_COMMAND:
  116. switch (LOWORD(wParam))
  117. {
  118. case IDC_PFX_FILENAME:
  119. break;
  120. case IDC_PFX_PASSWORD:
  121. break;
  122. case IDC_PFX_BROWSE:
  123. CertBrowsePFX(pCertPfxImportInfo->hInstance, hDlg);
  124. ret = TRUE;
  125. break;
  126. case IDOK:
  127. hr = GetPFXInfo(hDlg, pCertPfxImportInfo);
  128. if (S_OK != hr)
  129. {
  130. break;
  131. }
  132. id = IDOK;
  133. case IDCANCEL:
  134. ret = EndDialog(hDlg, id);
  135. break;
  136. }
  137. break;
  138. default:
  139. ret = FALSE;
  140. }
  141. return ret;
  142. }
  143. int
  144. CertGetPFXFileAndPassword(
  145. IN HWND hwnd,
  146. IN HINSTANCE hInstance,
  147. IN BOOL fUnattended,
  148. IN OUT WCHAR *pwszFileName,
  149. IN DWORD dwFileNameSize,
  150. IN OUT WCHAR *pwszPassword,
  151. IN DWORD dwPasswordSize)
  152. {
  153. CERTPFXIMPORTINFO CertPfxImportInfo =
  154. {hInstance, fUnattended,
  155. pwszFileName, dwFileNameSize,
  156. pwszPassword, dwPasswordSize};
  157. return (int) DialogBoxParam(hInstance,
  158. MAKEINTRESOURCE(IDD_PFXIMPORT),
  159. hwnd,
  160. CertPFXFilePasswordProc,
  161. (LPARAM)&CertPfxImportInfo);
  162. }
  163. //--------------------------------------------------------------------
  164. HRESULT
  165. ImportPFXAndUpdateCSPInfo(
  166. IN const HWND hDlg,
  167. IN OUT PER_COMPONENT_DATA *pComp)
  168. {
  169. HRESULT hr;
  170. int nDlgRet;
  171. BOOL bRetVal;
  172. DWORD dwVerificationFlags;
  173. BOOL bSelfSigned;
  174. CSP_HASH * pHash;
  175. WCHAR wszName[MAX_PATH];
  176. WCHAR wszPassword[MAX_PATH];
  177. CSP_INFO * pCSPInfo;
  178. DWORD dwCSPInfoSize;
  179. CASERVERSETUPINFO * pServer=pComp->CA.pServer;
  180. // variables that must be cleaned up
  181. CRYPT_KEY_PROV_INFO *pCertKeyProvInfo = NULL;
  182. CERT_CONTEXT const *pSavedLeafCert = NULL;
  183. wszName[0] = L'\0';
  184. // get file name & password
  185. if(pComp->fUnattended)
  186. {
  187. CSASSERT(NULL!=pServer->pwszPFXFile);
  188. if(MAX_PATH<=wcslen(pServer->pwszPFXFile)||
  189. NULL!=pServer->pwszPFXPassword &&
  190. MAX_PATH<=wcslen(pServer->pwszPFXPassword))
  191. {
  192. hr = ERROR_BAD_PATHNAME;
  193. CertWarningMessageBox(
  194. pComp->hInstance,
  195. pComp->fUnattended,
  196. hDlg,
  197. IDS_PFX_FILE_OR_PASSWORD_TOO_LONG,
  198. 0,
  199. NULL);
  200. _JumpError(hr, error, "PFX file name or password is too long");
  201. }
  202. wcscpy(wszName, pServer->pwszPFXFile);
  203. wcscpy(wszPassword,
  204. pServer->pwszPFXPassword?pServer->pwszPFXPassword:L"");
  205. if (NULL == pServer->pCSPInfoList)
  206. {
  207. hr = GetCSPInfoList(&pServer->pCSPInfoList);
  208. _JumpIfError(hr, error, "GetCSPInfoList");
  209. }
  210. }
  211. else{
  212. nDlgRet = CertGetPFXFileAndPassword(
  213. hDlg,
  214. pComp->hInstance,
  215. pComp->fUnattended,
  216. wszName,
  217. sizeof(wszName)/sizeof(WCHAR),
  218. wszPassword,
  219. sizeof(wszPassword)/sizeof(WCHAR));
  220. if (IDOK != nDlgRet)
  221. {
  222. // cancel
  223. hr=HRESULT_FROM_WIN32(ERROR_CANCELLED);
  224. _JumpError(hr, error, "CertGetPFXFileAndPassword canceled");
  225. }
  226. }
  227. // import pkcs12
  228. hr=myCertServerImportPFX(
  229. wszName,
  230. wszPassword,
  231. FALSE,
  232. NULL,
  233. NULL,
  234. &pSavedLeafCert);
  235. if (S_OK != hr)
  236. {
  237. if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD)==hr)
  238. {
  239. // tell the user that their password was invalid
  240. CertWarningMessageBox(
  241. pComp->hInstance,
  242. pComp->fUnattended,
  243. hDlg,
  244. IDS_PFX_INVALID_PASSWORD,
  245. 0,
  246. NULL);
  247. _JumpError(hr, error, "myCertServerImportPFX");
  248. }
  249. else if (HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr)
  250. {
  251. if(pComp->fUnattended)
  252. {
  253. nDlgRet=IDYES;
  254. }
  255. else
  256. {
  257. // confirm from user that they want to overwrite
  258. // the existing key and cert
  259. nDlgRet=CertMessageBox(
  260. pComp->hInstance,
  261. pComp->fUnattended,
  262. hDlg,
  263. IDS_PFX_KEYANDCERTEXIST,
  264. 0,
  265. MB_YESNO | MB_ICONWARNING | CMB_NOERRFROMSYS,
  266. NULL);
  267. }
  268. if (IDYES==nDlgRet)
  269. {
  270. hr=myCertServerImportPFX(
  271. wszName,
  272. wszPassword,
  273. TRUE,
  274. NULL,
  275. NULL,
  276. &pSavedLeafCert);
  277. _JumpIfError(hr, errorMsg, "myCertServerImportPFX");
  278. }
  279. else
  280. {
  281. // cancel
  282. hr=HRESULT_FROM_WIN32(ERROR_CANCELLED);
  283. _JumpError(hr, error, "myCertServerImportPFX canceled");
  284. }
  285. }
  286. else if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
  287. {
  288. CertWarningMessageBox(
  289. pComp->hInstance,
  290. pComp->fUnattended,
  291. hDlg,
  292. IDS_PFX_PATH_INVALID,
  293. 0,
  294. wszName);
  295. _JumpError(hr, error, "myCertServerImportPFX");
  296. }
  297. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  298. {
  299. CertWarningMessageBox(
  300. pComp->hInstance,
  301. pComp->fUnattended,
  302. hDlg,
  303. IDS_PFX_FILE_NOT_FOUND,
  304. 0,
  305. wszName);
  306. _JumpError(hr, error, "myCertServerImportPFX");
  307. }
  308. else if (HRESULT_FROM_WIN32(CRYPT_E_SELF_SIGNED) == hr)
  309. {
  310. // this cert is not appropriate for this CA type (no CA certs found at all)
  311. CertWarningMessageBox(
  312. pComp->hInstance,
  313. pComp->fUnattended,
  314. hDlg,
  315. IDS_PFX_WRONG_SELFSIGN_TYPE,
  316. S_OK, // don't show an error number
  317. NULL);
  318. _JumpError(hr, error, "This cert is not appropriate for this CA type");
  319. }
  320. else
  321. {
  322. // import failed for some other reason
  323. _JumpError(hr, errorMsg, "myCertServerImportPFX");
  324. }
  325. }
  326. // PFX import was successful. The cert is in the machine's MY store.
  327. CSASSERT(NULL!=pSavedLeafCert);
  328. // The following things have been verified by myCertServerImportPFX
  329. // * The cert has an AT_SIGNATURE key
  330. // * The key in the store matches the one on the cer
  331. // * The cert is not expired
  332. //
  333. // We still need to check:
  334. // * self-signed or not
  335. // * verify chain
  336. // Note: IT IS VERY IMPORTANT that pfx import maintains all the
  337. // invariants about CSP, key container, hash, cert validity, etc.
  338. // that the rest of the UI maintains.
  339. // get key prov info from cert
  340. bRetVal=myCertGetCertificateContextProperty(
  341. pSavedLeafCert,
  342. CERT_KEY_PROV_INFO_PROP_ID,
  343. CERTLIB_USE_LOCALALLOC,
  344. (void **)&pCertKeyProvInfo,
  345. &dwCSPInfoSize);
  346. if (FALSE==bRetVal) {
  347. hr=myHLastError();
  348. _JumpError(hr, errorMsg, "myCertGetCertificateContextProperty");
  349. }
  350. // find our description of the CSP
  351. pCSPInfo=findCSPInfoFromList(pServer->pCSPInfoList,
  352. pCertKeyProvInfo->pwszProvName,
  353. pCertKeyProvInfo->dwProvType);
  354. CSASSERT(NULL!=pCSPInfo);
  355. if (pCSPInfo == NULL) // we don't have this CSP enumerated in our UI
  356. {
  357. hr = CRYPT_E_NOT_FOUND;
  358. _JumpError(hr, errorMsg, "pCSPInfo NULL");
  359. }
  360. //
  361. // Looks like this key is good. Use it.
  362. //
  363. // Stop using the previous cert and key
  364. // delete previously created key container, if necessary.
  365. ClearKeyContainerName(pServer);
  366. // update the CSP
  367. // note: CSP, key container, and hash must all be consistent!
  368. pServer->pCSPInfo=pCSPInfo;
  369. hr = DetermineDefaultHash(pServer);
  370. _JumpIfError(hr, error, "DetermineDefaultHash");
  371. // save the name of the key container
  372. hr=SetKeyContainerName(pServer, pCertKeyProvInfo->pwszContainerName);
  373. _JumpIfError(hr, error, "SetKeyContainerName");
  374. // See if we can use the cert
  375. // verify to make sure no cert in chain is revoked, but don't kill yourself if offline
  376. hr=myVerifyCertContext(
  377. pSavedLeafCert,
  378. CA_VERIFY_FLAGS_IGNORE_OFFLINE,
  379. 0,
  380. NULL,
  381. HCCE_LOCAL_MACHINE,
  382. NULL,
  383. NULL);
  384. _JumpIfError(hr, errorMsg, "myVerifyCertContext");
  385. // See if this cert appropriately is self-signed or not.
  386. // A root CA cert must be self-signed, while
  387. // a subordinate CA cert must not be self-signed.
  388. hr=IsCertSelfSignedForCAType(pServer, pSavedLeafCert, &bRetVal);
  389. _JumpIfError(hr, errorMsg, "IsCertSelfSignedForCAType");
  390. if (FALSE==bRetVal) {
  391. // this cert is not appropriate for this CA type
  392. CertWarningMessageBox(
  393. pComp->hInstance,
  394. pComp->fUnattended,
  395. hDlg,
  396. IDS_PFX_WRONG_SELFSIGN_TYPE,
  397. S_OK, // don't show an error number
  398. NULL);
  399. hr=CRYPT_E_SELF_SIGNED;
  400. _JumpError(hr, error, "This cert is not appropriate for this CA type");
  401. }
  402. //
  403. // Looks like this cert is good. Use it.
  404. //
  405. // save the cert and update the hash algorithm
  406. hr=SetExistingCertToUse(pServer, pSavedLeafCert);
  407. _JumpIfError(hr, error, "SetExistingCertToUse");
  408. pSavedLeafCert=NULL;
  409. hr=S_OK;
  410. errorMsg:
  411. if (FAILED(hr)) {
  412. // an error occurred while trying to import the PFX file
  413. CertWarningMessageBox(
  414. pComp->hInstance,
  415. pComp->fUnattended,
  416. hDlg,
  417. IDS_ERR_IMPORTPFX,
  418. hr,
  419. NULL);
  420. }
  421. error:
  422. CSILOG(
  423. hr,
  424. IDS_LOG_IMPORTPFX,
  425. L'\0' == wszName[0]? NULL : wszName,
  426. NULL,
  427. NULL);
  428. if (NULL != pSavedLeafCert)
  429. {
  430. CertFreeCertificateContext(pSavedLeafCert);
  431. }
  432. if (NULL != pCertKeyProvInfo)
  433. {
  434. LocalFree(pCertKeyProvInfo);
  435. }
  436. return hr;
  437. }