//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: pfximpt.cpp // // Contents: PFX import dialog // // History: 06/98 xtan // //---------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include "cscsp.h" #include "certmsg.h" #include "initcert.h" #include "setuput.h" #include "cspenum.h" #include "wizpage.h" #include "usecert.h" #define __dwFILE__ __dwFILE_OCMSETUP_PFXIMPT_CPP__ typedef struct _certpfximportinfo { HINSTANCE hInstance; BOOL fUnattended; WCHAR *pwszFileName; DWORD dwFileNameSize; WCHAR *pwszPassword; DWORD dwPasswordSize; } CERTPFXIMPORTINFO; HRESULT CertBrowsePFX(HINSTANCE hInstance, HWND hDlg) { HRESULT hr; WCHAR *pwszFileNameIn = NULL; WCHAR *pwszFileNameOut = NULL; HWND hCtrl = GetDlgItem(hDlg, IDC_PFX_FILENAME); hr = myUIGetWindowText(hCtrl, &pwszFileNameIn); _JumpIfError(hr, error, "myUIGetWindowText"); hr = myGetOpenFileName( hDlg, hInstance, IDS_IMPORT_PFX_TITLE, IDS_PFX_FILE_FILTER, 0, // no def ext OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, pwszFileNameIn, &pwszFileNameOut); _JumpIfError(hr, error, "myGetOpenFileName"); if (NULL != pwszFileNameOut) { SetWindowText(hCtrl, pwszFileNameOut); } hr = S_OK; error: if (NULL != pwszFileNameOut) { LocalFree(pwszFileNameOut); } if (NULL != pwszFileNameIn) { LocalFree(pwszFileNameIn); } return hr; } HRESULT GetPFXInfo( HWND hDlg, CERTPFXIMPORTINFO* pCertPfxImportInfo) { HRESULT hr; GetWindowText(GetDlgItem(hDlg, IDC_PFX_FILENAME), pCertPfxImportInfo->pwszFileName, pCertPfxImportInfo->dwFileNameSize); if (0x0 == pCertPfxImportInfo->pwszFileName[0]) { // file can't empty hr = E_INVALIDARG; CertWarningMessageBox( pCertPfxImportInfo->hInstance, pCertPfxImportInfo->fUnattended, hDlg, IDS_ERR_EMPTYPFXFILE, 0, NULL); SetFocus(GetDlgItem(hDlg, IDC_PFX_FILENAME)); goto error; } GetWindowText(GetDlgItem(hDlg, IDC_PFX_PASSWORD), pCertPfxImportInfo->pwszPassword, pCertPfxImportInfo->dwPasswordSize); hr = S_OK; error: return hr; } INT_PTR CALLBACK CertPFXFilePasswordProc( HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr; BOOL ret = FALSE; int id = IDCANCEL; static CERTPFXIMPORTINFO *pCertPfxImportInfo = NULL; switch (iMsg) { case WM_INITDIALOG: pCertPfxImportInfo = (CERTPFXIMPORTINFO*)lParam; ret = TRUE; break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_PFX_FILENAME: break; case IDC_PFX_PASSWORD: break; case IDC_PFX_BROWSE: CertBrowsePFX(pCertPfxImportInfo->hInstance, hDlg); ret = TRUE; break; case IDOK: hr = GetPFXInfo(hDlg, pCertPfxImportInfo); if (S_OK != hr) { break; } id = IDOK; case IDCANCEL: ret = EndDialog(hDlg, id); break; } break; default: ret = FALSE; } return ret; } int CertGetPFXFileAndPassword( IN HWND hwnd, IN HINSTANCE hInstance, IN BOOL fUnattended, IN OUT WCHAR *pwszFileName, IN DWORD dwFileNameSize, IN OUT WCHAR *pwszPassword, IN DWORD dwPasswordSize) { CERTPFXIMPORTINFO CertPfxImportInfo = {hInstance, fUnattended, pwszFileName, dwFileNameSize, pwszPassword, dwPasswordSize}; return (int) DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PFXIMPORT), hwnd, CertPFXFilePasswordProc, (LPARAM)&CertPfxImportInfo); } //-------------------------------------------------------------------- HRESULT ImportPFXAndUpdateCSPInfo( IN const HWND hDlg, IN OUT PER_COMPONENT_DATA *pComp) { HRESULT hr; int nDlgRet; BOOL bRetVal; DWORD dwVerificationFlags; BOOL bSelfSigned; CSP_HASH * pHash; WCHAR wszName[MAX_PATH]; WCHAR wszPassword[MAX_PATH]; CSP_INFO * pCSPInfo; DWORD dwCSPInfoSize; CASERVERSETUPINFO * pServer=pComp->CA.pServer; // variables that must be cleaned up CRYPT_KEY_PROV_INFO *pCertKeyProvInfo = NULL; CERT_CONTEXT const *pSavedLeafCert = NULL; wszName[0] = L'\0'; // get file name & password if(pComp->fUnattended) { CSASSERT(NULL!=pServer->pwszPFXFile); if(MAX_PATH<=wcslen(pServer->pwszPFXFile)|| NULL!=pServer->pwszPFXPassword && MAX_PATH<=wcslen(pServer->pwszPFXPassword)) { hr = ERROR_BAD_PATHNAME; CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PFX_FILE_OR_PASSWORD_TOO_LONG, 0, NULL); _JumpError(hr, error, "PFX file name or password is too long"); } wcscpy(wszName, pServer->pwszPFXFile); wcscpy(wszPassword, pServer->pwszPFXPassword?pServer->pwszPFXPassword:L""); if (NULL == pServer->pCSPInfoList) { hr = GetCSPInfoList(&pServer->pCSPInfoList); _JumpIfError(hr, error, "GetCSPInfoList"); } } else{ nDlgRet = CertGetPFXFileAndPassword( hDlg, pComp->hInstance, pComp->fUnattended, wszName, sizeof(wszName)/sizeof(WCHAR), wszPassword, sizeof(wszPassword)/sizeof(WCHAR)); if (IDOK != nDlgRet) { // cancel hr=HRESULT_FROM_WIN32(ERROR_CANCELLED); _JumpError(hr, error, "CertGetPFXFileAndPassword canceled"); } } // import pkcs12 hr=myCertServerImportPFX( wszName, wszPassword, FALSE, NULL, NULL, &pSavedLeafCert); if (S_OK != hr) { if (HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD)==hr) { // tell the user that their password was invalid CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PFX_INVALID_PASSWORD, 0, NULL); _JumpError(hr, error, "myCertServerImportPFX"); } else if (HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) == hr) { if(pComp->fUnattended) { nDlgRet=IDYES; } else { // confirm from user that they want to overwrite // the existing key and cert nDlgRet=CertMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PFX_KEYANDCERTEXIST, 0, MB_YESNO | MB_ICONWARNING | CMB_NOERRFROMSYS, NULL); } if (IDYES==nDlgRet) { hr=myCertServerImportPFX( wszName, wszPassword, TRUE, NULL, NULL, &pSavedLeafCert); _JumpIfError(hr, errorMsg, "myCertServerImportPFX"); } else { // cancel hr=HRESULT_FROM_WIN32(ERROR_CANCELLED); _JumpError(hr, error, "myCertServerImportPFX canceled"); } } else if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PFX_PATH_INVALID, 0, wszName); _JumpError(hr, error, "myCertServerImportPFX"); } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PFX_FILE_NOT_FOUND, 0, wszName); _JumpError(hr, error, "myCertServerImportPFX"); } else if (HRESULT_FROM_WIN32(CRYPT_E_SELF_SIGNED) == hr) { // this cert is not appropriate for this CA type (no CA certs found at all) CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PFX_WRONG_SELFSIGN_TYPE, S_OK, // don't show an error number NULL); _JumpError(hr, error, "This cert is not appropriate for this CA type"); } else { // import failed for some other reason _JumpError(hr, errorMsg, "myCertServerImportPFX"); } } // PFX import was successful. The cert is in the machine's MY store. CSASSERT(NULL!=pSavedLeafCert); // The following things have been verified by myCertServerImportPFX // * The cert has an AT_SIGNATURE key // * The key in the store matches the one on the cer // * The cert is not expired // // We still need to check: // * self-signed or not // * verify chain // Note: IT IS VERY IMPORTANT that pfx import maintains all the // invariants about CSP, key container, hash, cert validity, etc. // that the rest of the UI maintains. // get key prov info from cert bRetVal=myCertGetCertificateContextProperty( pSavedLeafCert, CERT_KEY_PROV_INFO_PROP_ID, CERTLIB_USE_LOCALALLOC, (void **)&pCertKeyProvInfo, &dwCSPInfoSize); if (FALSE==bRetVal) { hr=myHLastError(); _JumpError(hr, errorMsg, "myCertGetCertificateContextProperty"); } // find our description of the CSP pCSPInfo=findCSPInfoFromList(pServer->pCSPInfoList, pCertKeyProvInfo->pwszProvName, pCertKeyProvInfo->dwProvType); CSASSERT(NULL!=pCSPInfo); if (pCSPInfo == NULL) // we don't have this CSP enumerated in our UI { hr = CRYPT_E_NOT_FOUND; _JumpError(hr, errorMsg, "pCSPInfo NULL"); } // // Looks like this key is good. Use it. // // Stop using the previous cert and key // delete previously created key container, if necessary. ClearKeyContainerName(pServer); // update the CSP // note: CSP, key container, and hash must all be consistent! pServer->pCSPInfo=pCSPInfo; hr = DetermineDefaultHash(pServer); _JumpIfError(hr, error, "DetermineDefaultHash"); // save the name of the key container hr=SetKeyContainerName(pServer, pCertKeyProvInfo->pwszContainerName); _JumpIfError(hr, error, "SetKeyContainerName"); // See if we can use the cert // verify to make sure no cert in chain is revoked, but don't kill yourself if offline hr=myVerifyCertContext( pSavedLeafCert, CA_VERIFY_FLAGS_IGNORE_OFFLINE, 0, NULL, HCCE_LOCAL_MACHINE, NULL, NULL); _JumpIfError(hr, errorMsg, "myVerifyCertContext"); // See if this cert appropriately is self-signed or not. // A root CA cert must be self-signed, while // a subordinate CA cert must not be self-signed. hr=IsCertSelfSignedForCAType(pServer, pSavedLeafCert, &bRetVal); _JumpIfError(hr, errorMsg, "IsCertSelfSignedForCAType"); if (FALSE==bRetVal) { // this cert is not appropriate for this CA type CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_PFX_WRONG_SELFSIGN_TYPE, S_OK, // don't show an error number NULL); hr=CRYPT_E_SELF_SIGNED; _JumpError(hr, error, "This cert is not appropriate for this CA type"); } // // Looks like this cert is good. Use it. // // save the cert and update the hash algorithm hr=SetExistingCertToUse(pServer, pSavedLeafCert); _JumpIfError(hr, error, "SetExistingCertToUse"); pSavedLeafCert=NULL; hr=S_OK; errorMsg: if (FAILED(hr)) { // an error occurred while trying to import the PFX file CertWarningMessageBox( pComp->hInstance, pComp->fUnattended, hDlg, IDS_ERR_IMPORTPFX, hr, NULL); } error: CSILOG( hr, IDS_LOG_IMPORTPFX, L'\0' == wszName[0]? NULL : wszName, NULL, NULL); if (NULL != pSavedLeafCert) { CertFreeCertificateContext(pSavedLeafCert); } if (NULL != pCertKeyProvInfo) { LocalFree(pCertKeyProvInfo); } return hr; }