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.
482 lines
14 KiB
482 lines
14 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
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:
|
|
SecureZeroMemory(wszPassword, wcslen(wszPassword)*sizeof(WCHAR));
|
|
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;
|
|
}
|