2429 lines
60 KiB
C++
2429 lines
60 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: certhier.cpp
|
|
//
|
|
// Contents: Install cert server hierarchical
|
|
//
|
|
// History: 09-26-96
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
// C Run-Time Includes
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
|
|
|
|
// Windows System Includes
|
|
#include <winsvc.h>
|
|
#include <rpc.h>
|
|
#include <tchar.h>
|
|
#include <csdisp.h>
|
|
#include <certca.h>
|
|
|
|
// Application Includes
|
|
#include "cscsp.h"
|
|
#include "certmsg.h"
|
|
#include "certhier.h"
|
|
#include "setupids.h"
|
|
|
|
#include "tfc.h"
|
|
|
|
#define __dwFILE__ __dwFILE_INITLIB_CERTHIER_CPP__
|
|
|
|
// following veriables are extern in initlib, bad.
|
|
LPSTR pszObjIdSignatureAlgorithm = szOID_OIWSEC_sha1RSASign;
|
|
|
|
|
|
HRESULT
|
|
csiFillKeyProvInfo(
|
|
IN WCHAR const *pwszContainerName,
|
|
IN WCHAR const *pwszProvName,
|
|
IN DWORD dwProvType,
|
|
IN BOOL fMachineKeyset,
|
|
OUT CRYPT_KEY_PROV_INFO *pKeyProvInfo) // call csiFreeKeyProvInfo to free
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszContainerNameT = NULL;
|
|
WCHAR *pwszProvNameT = NULL;
|
|
|
|
ZeroMemory(pKeyProvInfo, sizeof(*pKeyProvInfo));
|
|
|
|
hr = myDupString(pwszContainerName, &pwszContainerNameT);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
hr = myDupString(pwszProvName, &pwszProvNameT);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pKeyProvInfo->pwszContainerName = pwszContainerNameT;
|
|
pKeyProvInfo->pwszProvName = pwszProvNameT;
|
|
pKeyProvInfo->dwProvType = dwProvType;
|
|
if (fMachineKeyset)
|
|
{
|
|
pKeyProvInfo->dwFlags = CRYPT_MACHINE_KEYSET;
|
|
}
|
|
pKeyProvInfo->dwKeySpec = AT_SIGNATURE;
|
|
pwszContainerNameT = NULL;
|
|
pwszProvNameT = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszContainerNameT)
|
|
{
|
|
LocalFree(pwszContainerNameT);
|
|
}
|
|
if (NULL != pwszProvNameT)
|
|
{
|
|
LocalFree(pwszProvNameT);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
csiFreeKeyProvInfo(
|
|
IN OUT CRYPT_KEY_PROV_INFO *pKeyProvInfo)
|
|
{
|
|
if (NULL != pKeyProvInfo->pwszProvName)
|
|
{
|
|
LocalFree(pKeyProvInfo->pwszProvName);
|
|
pKeyProvInfo->pwszProvName = NULL;
|
|
}
|
|
if (NULL != pKeyProvInfo->pwszContainerName)
|
|
{
|
|
LocalFree(pKeyProvInfo->pwszContainerName);
|
|
pKeyProvInfo->pwszContainerName = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetCertServerKeyProviderInfo(
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN WCHAR const *pwszKeyContainerName,
|
|
OUT ALG_ID *pidAlg,
|
|
OUT BOOL *pfMachineKeyset,
|
|
OUT CRYPT_KEY_PROV_INFO *pKeyProvInfo) // call csiFreeKeyProvInfo to free
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszProvName = NULL;
|
|
DWORD dwProvType;
|
|
|
|
ZeroMemory(pKeyProvInfo, sizeof(*pKeyProvInfo));
|
|
|
|
// get CSP info
|
|
|
|
hr = myGetCertSrvCSP(
|
|
FALSE, // fEncryptionCSP
|
|
pwszSanitizedCAName,
|
|
&dwProvType,
|
|
&pwszProvName,
|
|
pidAlg,
|
|
pfMachineKeyset,
|
|
NULL); // pdwKeySize
|
|
_JumpIfError(hr, error, "myGetCertSrvCSP");
|
|
|
|
hr = csiFillKeyProvInfo(
|
|
pwszKeyContainerName,
|
|
pwszProvName,
|
|
dwProvType,
|
|
*pfMachineKeyset,
|
|
pKeyProvInfo);
|
|
_JumpIfError(hr, error, "csiFillKeyProvInfo");
|
|
|
|
error:
|
|
if (NULL != pwszProvName)
|
|
{
|
|
LocalFree(pwszProvName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
mySetCertRegKeyIndexAndContainer(
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN DWORD iKey,
|
|
IN WCHAR const *pwszKeyContainer)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = mySetCertRegDWValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGREQUESTKEYINDEX,
|
|
iKey);
|
|
_JumpIfErrorStr(hr, error, "mySetCertRegDWValue", wszREGREQUESTKEYINDEX);
|
|
|
|
hr = mySetCertRegStrValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGREQUESTKEYCONTAINER,
|
|
pwszKeyContainer);
|
|
_JumpIfErrorStr(hr, error, "mySetCertRegStrValue", wszREGREQUESTKEYCONTAINER);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myGetCertRegKeyIndexAndContainer(
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
OUT DWORD *piKey,
|
|
OUT WCHAR **ppwszKeyContainer)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppwszKeyContainer = NULL;
|
|
|
|
hr = myGetCertRegDWValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGREQUESTKEYINDEX,
|
|
piKey);
|
|
if (S_OK != hr)
|
|
{
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
|
|
{
|
|
_JumpErrorStr(hr, error, "myGetCertRegDWValue", wszREGREQUESTKEYINDEX);
|
|
}
|
|
*piKey = 0;
|
|
}
|
|
|
|
hr = myGetCertRegStrValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGREQUESTKEYCONTAINER,
|
|
ppwszKeyContainer);
|
|
if (S_OK != hr)
|
|
{
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
|
|
{
|
|
_JumpErrorStr(hr, error, "myGetCertRegStrValue", wszREGREQUESTKEYCONTAINER);
|
|
}
|
|
hr = myDupString(pwszSanitizedCAName, ppwszKeyContainer);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
FinishSuspendedSetupFromPKCS7(
|
|
IN HINSTANCE hInstance,
|
|
IN BOOL fUnattended,
|
|
IN HWND hwnd,
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN OPTIONAL WCHAR const *pwszKeyContainer,
|
|
IN DWORD iKey,
|
|
IN BOOL fRenew,
|
|
IN BYTE const *pbChain,
|
|
IN DWORD cbChain)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_KEY_PROV_INFO KeyProvInfo;
|
|
WCHAR *pwszCommonName = NULL;
|
|
WCHAR *pwszServerName = NULL;
|
|
WCHAR *pwszCertFile = NULL;
|
|
WCHAR *pwszKeyContainerReg = NULL;
|
|
ENUM_CATYPES CAType;
|
|
DWORD iCertNew;
|
|
BOOL fUseDS;
|
|
ALG_ID idAlg;
|
|
BOOL fMachineKeyset;
|
|
|
|
ZeroMemory(&KeyProvInfo, sizeof(KeyProvInfo));
|
|
|
|
hr = myGetCARegHashCount(pwszSanitizedCAName, CSRH_CASIGCERT, &iCertNew);
|
|
_JumpIfError(hr, error, "myGetCARegHashCount");
|
|
|
|
if (NULL == pwszKeyContainer)
|
|
{
|
|
// get Key Index and Container name from registry
|
|
|
|
hr = myGetCertRegKeyIndexAndContainer(
|
|
pwszSanitizedCAName,
|
|
&iKey,
|
|
&pwszKeyContainerReg);
|
|
_JumpIfError(hr, error, "myGetCertRegKeyIndexAndContainer");
|
|
|
|
pwszKeyContainer = pwszKeyContainerReg;
|
|
}
|
|
|
|
// get CSP info
|
|
hr = GetCertServerKeyProviderInfo(
|
|
pwszSanitizedCAName,
|
|
pwszKeyContainer,
|
|
&idAlg,
|
|
&fMachineKeyset,
|
|
&KeyProvInfo);
|
|
_JumpIfError(hr, error, "GetCertServerKeyProviderInfo");
|
|
|
|
// get common name
|
|
hr = myGetCertRegStrValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCOMMONNAME,
|
|
&pwszCommonName);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegStrValue", wszREGCOMMONNAME);
|
|
|
|
// get ca type
|
|
|
|
hr = myGetCertRegDWValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCATYPE,
|
|
(DWORD *) &CAType);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegDWValue", wszREGCATYPE);
|
|
|
|
// use DS or not
|
|
|
|
hr = myGetCertRegDWValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCAUSEDS,
|
|
(DWORD *) &fUseDS);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegDWValue", wszREGCAUSEDS);
|
|
|
|
// server name
|
|
|
|
hr = myGetCertRegStrValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCASERVERNAME,
|
|
&pwszServerName);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegStrValue", wszREGCASERVERNAME);
|
|
|
|
hr = myGetCARegFileNameTemplate(
|
|
wszREGCACERTFILENAME,
|
|
pwszServerName,
|
|
pwszSanitizedCAName,
|
|
iCertNew,
|
|
iKey,
|
|
&pwszCertFile);
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
|
|
{
|
|
_JumpIfError(hr, error, "myGetCARegFileNameTemplate");
|
|
}
|
|
|
|
hr = csiFinishInstallationFromPKCS7(
|
|
hInstance,
|
|
fUnattended,
|
|
hwnd,
|
|
pwszSanitizedCAName,
|
|
pwszCommonName,
|
|
&KeyProvInfo,
|
|
CAType,
|
|
iCertNew,
|
|
iKey,
|
|
fUseDS,
|
|
fRenew,
|
|
pwszServerName,
|
|
pbChain,
|
|
cbChain,
|
|
pwszCertFile);
|
|
_JumpIfError(hr, error, "csiFinishInstallationFromPKCS7");
|
|
|
|
error:
|
|
if (NULL != pwszKeyContainerReg)
|
|
{
|
|
LocalFree(pwszKeyContainerReg);
|
|
}
|
|
if (NULL != pwszCommonName)
|
|
{
|
|
LocalFree(pwszCommonName);
|
|
}
|
|
if (NULL != pwszCertFile)
|
|
{
|
|
LocalFree(pwszCertFile);
|
|
}
|
|
if (NULL != pwszServerName)
|
|
{
|
|
LocalFree(pwszServerName);
|
|
}
|
|
csiFreeKeyProvInfo(&KeyProvInfo);
|
|
CSILOG(hr, IDS_ILOG_FINISHSUSPENDEDSETUP, NULL, NULL, NULL);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
typedef struct _CERTHIERINFO
|
|
{
|
|
HINSTANCE hInstance;
|
|
BOOL fUnattended;
|
|
WCHAR *pwszSanitizedCAName;
|
|
WCHAR *pwszParentMachine;
|
|
WCHAR *pwszParentCA;
|
|
WCHAR *pwszParentMachineDefault;
|
|
WCHAR *pwszParentCADefault;
|
|
DWORD iCertNew;
|
|
DWORD iKey;
|
|
} CERTHIERINFO;
|
|
|
|
|
|
VOID
|
|
FreeCertHierInfo(
|
|
IN OUT CERTHIERINFO *pCertHierInfo)
|
|
{
|
|
if (NULL != pCertHierInfo->pwszSanitizedCAName)
|
|
{
|
|
LocalFree(pCertHierInfo->pwszSanitizedCAName);
|
|
}
|
|
if (NULL != pCertHierInfo->pwszParentMachine)
|
|
{
|
|
LocalFree(pCertHierInfo->pwszParentMachine);
|
|
}
|
|
if (NULL != pCertHierInfo->pwszParentCA)
|
|
{
|
|
LocalFree(pCertHierInfo->pwszParentCA);
|
|
}
|
|
if (NULL != pCertHierInfo->pwszParentMachineDefault)
|
|
{
|
|
LocalFree(pCertHierInfo->pwszParentMachineDefault);
|
|
}
|
|
if (NULL != pCertHierInfo->pwszParentCADefault)
|
|
{
|
|
LocalFree(pCertHierInfo->pwszParentCADefault);
|
|
}
|
|
}
|
|
|
|
|
|
CERTSRVUICASELECTION g_CertHierCARequestUICASelection =
|
|
{NULL, NULL, NULL, NULL, NULL, ENUM_UNKNOWN_CA, false};
|
|
|
|
HRESULT
|
|
csiGetCARequestFileName(
|
|
IN HINSTANCE hInstance,
|
|
IN HWND hwnd,
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN DWORD iCertNew,
|
|
IN DWORD iKey,
|
|
OUT WCHAR **ppwszRequestFile)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszServerName = NULL;
|
|
WCHAR *pwszRequestFile = NULL;
|
|
WCHAR *pwszSharedFolder = NULL;
|
|
|
|
// init
|
|
*ppwszRequestFile = NULL;
|
|
|
|
// get server name
|
|
hr = myGetCertRegStrValue(
|
|
pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCASERVERNAME,
|
|
&pwszServerName);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegStrValue", wszREGCASERVERNAME);
|
|
|
|
hr = myGetCARegFileNameTemplate(
|
|
wszREGREQUESTFILENAME,
|
|
pwszServerName,
|
|
pwszSanitizedCAName,
|
|
iCertNew,
|
|
iKey,
|
|
&pwszRequestFile);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myGetCertRegStrValue(
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
wszREGDIRECTORY,
|
|
&pwszSharedFolder);
|
|
if (S_OK != hr)
|
|
{
|
|
CSASSERT(NULL == pwszSharedFolder);
|
|
}
|
|
|
|
hr = csiBuildCACertFileName(
|
|
hInstance,
|
|
hwnd,
|
|
TRUE, // fUnattended
|
|
pwszSharedFolder,
|
|
pwszSanitizedCAName,
|
|
L".req",
|
|
0, // iCertNew == 0!
|
|
&pwszRequestFile);
|
|
_JumpIfError(hr, error, "csiBuildCACertFileName");
|
|
|
|
hr = mySetCARegFileNameTemplate(
|
|
wszREGREQUESTFILENAME,
|
|
pwszServerName,
|
|
pwszSanitizedCAName,
|
|
pwszRequestFile);
|
|
_JumpIfError(hr, error, "mySetCARegFileNameTemplate");
|
|
|
|
LocalFree(pwszRequestFile);
|
|
pwszRequestFile = NULL;
|
|
|
|
hr = csiBuildCACertFileName(
|
|
hInstance,
|
|
hwnd,
|
|
TRUE, // fUnattended
|
|
pwszSharedFolder,
|
|
pwszSanitizedCAName,
|
|
L".req",
|
|
iCertNew,
|
|
&pwszRequestFile);
|
|
_JumpIfError(hr, error, "csiBuildCACertFileName");
|
|
}
|
|
|
|
*ppwszRequestFile = pwszRequestFile;
|
|
pwszRequestFile = NULL;
|
|
|
|
hr = S_OK;
|
|
error:
|
|
if (NULL != pwszRequestFile)
|
|
{
|
|
LocalFree(pwszRequestFile);
|
|
}
|
|
if (NULL != pwszServerName)
|
|
{
|
|
LocalFree(pwszServerName);
|
|
}
|
|
if (NULL != pwszSharedFolder)
|
|
{
|
|
LocalFree(pwszSharedFolder);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
InitCertHierControls(
|
|
HWND hDlg,
|
|
CERTHIERINFO *pCertHierInfo)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fCAsExist;
|
|
WCHAR *pwszHelpText = NULL;
|
|
WCHAR *pwszRequestFile = NULL;
|
|
WCHAR *pwszExpandedHelpText = NULL;
|
|
|
|
if (NULL != pCertHierInfo->pwszParentMachineDefault)
|
|
{
|
|
SetWindowText(
|
|
GetDlgItem(hDlg, IDC_PARENT_COMPUTER_NAME),
|
|
pCertHierInfo->pwszParentMachineDefault);
|
|
|
|
if (NULL != pCertHierInfo->pwszParentCADefault)
|
|
{
|
|
SetWindowText(
|
|
GetDlgItem(hDlg, IDC_PARENT_CA_NAME),
|
|
pCertHierInfo->pwszParentCADefault);
|
|
}
|
|
}
|
|
|
|
// load formatted help string
|
|
hr = myLoadRCString(
|
|
pCertHierInfo->hInstance,
|
|
IDS_REQUEST_HELPTEXT,
|
|
&pwszHelpText);
|
|
_JumpIfError(hr, error, "myLoadRCString");
|
|
|
|
// get request file name
|
|
hr = csiGetCARequestFileName(
|
|
pCertHierInfo->hInstance,
|
|
hDlg,
|
|
pCertHierInfo->pwszSanitizedCAName,
|
|
pCertHierInfo->iCertNew,
|
|
pCertHierInfo->iKey,
|
|
&pwszRequestFile);
|
|
_JumpIfError(hr, error, "csiGetCARequestFileName");
|
|
|
|
// replace %1
|
|
if (!FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pwszHelpText,
|
|
0,
|
|
0,
|
|
reinterpret_cast<WCHAR *>(&pwszExpandedHelpText),
|
|
0,
|
|
reinterpret_cast<va_list *>
|
|
(const_cast<WCHAR **>(&pwszRequestFile))) )
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "FormatMessage");
|
|
}
|
|
|
|
// set help text
|
|
SetWindowText(GetDlgItem(hDlg, IDC_REQUEST_HELPTEXT), pwszExpandedHelpText);
|
|
|
|
hr = myInitUICASelectionControls(
|
|
&g_CertHierCARequestUICASelection,
|
|
pCertHierInfo->hInstance,
|
|
hDlg,
|
|
GetDlgItem(hDlg, IDC_BROWSE_CA),
|
|
GetDlgItem(hDlg, IDC_PARENT_COMPUTER_NAME),
|
|
GetDlgItem(hDlg, IDC_PARENT_CA_NAME),
|
|
csiIsAnyDSCAAvailable(),
|
|
&fCAsExist);
|
|
_JumpIfError(hr, error, "myInitUICASelectionControls");
|
|
|
|
error:
|
|
if (NULL != pwszHelpText)
|
|
{
|
|
LocalFree(pwszHelpText);
|
|
}
|
|
if (NULL != pwszRequestFile)
|
|
{
|
|
LocalFree(pwszRequestFile);
|
|
}
|
|
if (NULL != pwszExpandedHelpText)
|
|
{
|
|
LocalFree(pwszExpandedHelpText);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
HandleOKButton(
|
|
HWND hDlg,
|
|
CERTHIERINFO *pCertHierInfo,
|
|
BOOL *pfLeave)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszParentMachine = NULL;
|
|
WCHAR *pwszParentCA = NULL;
|
|
|
|
hr = myUICASelectionValidation(&g_CertHierCARequestUICASelection, pfLeave);
|
|
_JumpIfError(hr, error, "myUICASelectionValidation");
|
|
if (!*pfLeave)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// get parent ca info
|
|
hr = myUIGetWindowText(GetDlgItem(hDlg, IDC_PARENT_COMPUTER_NAME),
|
|
&pwszParentMachine);
|
|
_JumpIfError(hr, error, "myUIGetWindowText");
|
|
|
|
hr = myUIGetWindowText(GetDlgItem(hDlg, IDC_PARENT_CA_NAME),
|
|
&pwszParentCA);
|
|
_JumpIfError(hr, error, "myUIGetWindowText");
|
|
|
|
pCertHierInfo->pwszParentMachine = pwszParentMachine;
|
|
pwszParentMachine = NULL;
|
|
pCertHierInfo->pwszParentCA = pwszParentCA;
|
|
pwszParentCA = NULL;
|
|
|
|
hr = S_OK;
|
|
error:
|
|
if (NULL != pwszParentMachine)
|
|
{
|
|
LocalFree(pwszParentMachine);
|
|
}
|
|
if (NULL != pwszParentCA)
|
|
{
|
|
LocalFree(pwszParentCA);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
INT_PTR CALLBACK
|
|
CertHierProc(
|
|
HWND hDlg,
|
|
UINT iMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
HRESULT hr;
|
|
BOOL ret = FALSE;
|
|
BOOL fLeave;
|
|
static CERTHIERINFO *s_pCertHierInfo = NULL;
|
|
static BOOL s_fComputerChange = FALSE;
|
|
|
|
switch (iMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
s_pCertHierInfo = (CERTHIERINFO *) lParam;
|
|
|
|
hr = InitCertHierControls(hDlg, s_pCertHierInfo);
|
|
_JumpIfError(hr, error, "InitCertHierControls");
|
|
|
|
ret = TRUE;
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_BROWSE_CA:
|
|
ret = TRUE;
|
|
hr = myUICAHandleCABrowseButton(
|
|
&g_CertHierCARequestUICASelection,
|
|
csiIsAnyDSCAAvailable(),
|
|
IDS_CA_PICKER_TITLE,
|
|
IDS_CA_PICKER_PROMPT,
|
|
NULL);
|
|
_JumpIfError(hr, error, "myUICAHandleCABrowseButton");
|
|
break;
|
|
|
|
case IDC_PARENT_CA_NAME:
|
|
hr = myUICAHandleCAListDropdown(
|
|
(int)HIWORD(wParam),
|
|
&g_CertHierCARequestUICASelection,
|
|
&s_fComputerChange);
|
|
_PrintIfError(hr, "myUICAHandleCAListDropdown");
|
|
break;
|
|
|
|
case IDC_PARENT_COMPUTER_NAME:
|
|
switch ((int)HIWORD(wParam))
|
|
{
|
|
case EN_CHANGE: // edit change
|
|
s_fComputerChange = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
ret = TRUE;
|
|
hr = HandleOKButton(hDlg, s_pCertHierInfo, &fLeave);
|
|
_PrintIfError(hr, "HandleOKButton");
|
|
if (fLeave)
|
|
{
|
|
// update return status
|
|
ret = EndDialog(hDlg, IDOK);
|
|
goto error; //done;
|
|
}
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
ret = EndDialog(hDlg, IDCANCEL);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
error:
|
|
return(ret);
|
|
}
|
|
|
|
|
|
VOID
|
|
MarkSetupComplete(
|
|
IN WCHAR const *pwszSanitizedCAName)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Clear pending/denied flags:
|
|
|
|
hr = SetSetupStatus(
|
|
pwszSanitizedCAName,
|
|
SETUP_SUSPEND_FLAG |
|
|
SETUP_ONLINE_FLAG |
|
|
SETUP_REQUEST_FLAG |
|
|
SETUP_DENIED_FLAG,
|
|
FALSE);
|
|
_PrintIfError(hr, "SetSetupStatus");
|
|
|
|
// Force new CRL generation on startup:
|
|
|
|
hr = SetSetupStatus(pwszSanitizedCAName, SETUP_FORCECRL_FLAG, TRUE);
|
|
_PrintIfError(hr, "SetSetupStatus");
|
|
|
|
CSILOG(hr, IDS_ILOG_SETUPCOMPLETE, NULL, NULL, NULL);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
FindKeyIndex(
|
|
IN HCERTSTORE hMyStore,
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN BOOL fUnattended,
|
|
IN BOOL fMachineKeyset,
|
|
IN DWORD cCert,
|
|
CRYPT_KEY_PROV_INFO *pKeyMatch,
|
|
OUT DWORD *piKey)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
CERT_CONTEXT const *pccCert = NULL;
|
|
CRYPT_KEY_PROV_INFO *pKey = NULL;
|
|
HCRYPTPROV hProv = NULL;
|
|
CERT_PUBLIC_KEY_INFO *pPubKeyMatch = NULL;
|
|
CERT_PUBLIC_KEY_INFO *pPubKey = NULL;
|
|
DWORD cb;
|
|
DWORD NameId;
|
|
|
|
*piKey = MAXDWORD;
|
|
|
|
// get CSP handle
|
|
|
|
if (!myCertSrvCryptAcquireContext(
|
|
&hProv,
|
|
pKeyMatch->pwszContainerName,
|
|
pKeyMatch->pwszProvName,
|
|
pKeyMatch->dwProvType,
|
|
fUnattended? CRYPT_SILENT : 0,
|
|
fMachineKeyset))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
|
|
}
|
|
if (hProv == NULL)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
|
|
}
|
|
|
|
if (!myCryptExportPublicKeyInfo(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pPubKeyMatch,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myCryptExportPublicKeyInfo");
|
|
}
|
|
CryptReleaseContext(hProv, 0);
|
|
hProv = NULL;
|
|
|
|
for (i = 0; ; i++)
|
|
{
|
|
if (i >= cCert)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "old key not found");
|
|
}
|
|
hr = myFindCACertByHashIndex(
|
|
hMyStore,
|
|
pwszSanitizedCAName,
|
|
CSRH_CASIGCERT,
|
|
i,
|
|
&NameId,
|
|
&pccCert);
|
|
if (S_FALSE == hr)
|
|
{
|
|
continue;
|
|
}
|
|
_JumpIfError(hr, error, "myFindCACertByHashIndex");
|
|
|
|
// get the key provider info
|
|
|
|
if (!myCertGetCertificateContextProperty(
|
|
pccCert,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pKey,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertGetCertificateContextProperty");
|
|
}
|
|
|
|
// get CSP handle
|
|
|
|
if (!myCertSrvCryptAcquireContext(
|
|
&hProv,
|
|
pKey->pwszContainerName,
|
|
pKey->pwszProvName,
|
|
pKey->dwProvType,
|
|
fUnattended? CRYPT_SILENT : 0,
|
|
fMachineKeyset))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
|
|
}
|
|
if (hProv == NULL)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
|
|
}
|
|
|
|
if (!myCryptExportPublicKeyInfo(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pPubKey,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myCryptExportPublicKeyInfo");
|
|
}
|
|
|
|
// by design, CertComparePublicKeyInfo doesn't set last error!
|
|
|
|
if (CertComparePublicKeyInfo(X509_ASN_ENCODING, pPubKey, pPubKeyMatch))
|
|
{
|
|
hr = myGetNameId(pccCert, &NameId);
|
|
if (S_OK != hr)
|
|
{
|
|
*piKey = i;
|
|
}
|
|
else
|
|
{
|
|
*piKey = CANAMEIDTOIKEY(NameId);
|
|
}
|
|
break;
|
|
}
|
|
|
|
LocalFree(pPubKey);
|
|
pPubKey = NULL;
|
|
|
|
CryptReleaseContext(hProv, 0);
|
|
hProv = NULL;
|
|
|
|
LocalFree(pKey);
|
|
pKey = NULL;
|
|
|
|
CertFreeCertificateContext(pccCert);
|
|
pccCert = NULL;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pPubKeyMatch)
|
|
{
|
|
LocalFree(pPubKeyMatch);
|
|
}
|
|
if (NULL != pPubKey)
|
|
{
|
|
LocalFree(pPubKey);
|
|
}
|
|
if (NULL != hProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
if (NULL != pKey)
|
|
{
|
|
LocalFree(pKey);
|
|
}
|
|
if (NULL != pccCert)
|
|
{
|
|
CertFreeCertificateContext(pccCert);
|
|
}
|
|
CSILOG(hr, IDS_ILOG_KEYINDEX, NULL, NULL, piKey);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
LoadCurrentCACertAndKeyInfo(
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN BOOL fNewKey,
|
|
IN BOOL fUnattended,
|
|
IN BOOL fMachineKeyset,
|
|
IN DWORD iCertNew,
|
|
OUT DWORD *piKey,
|
|
OUT WCHAR **ppwszKeyContainer,
|
|
OUT CERT_CONTEXT const **ppccCertOld)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hMyStore = NULL;
|
|
DWORD cbKey;
|
|
CRYPT_KEY_PROV_INFO *pKey = NULL;
|
|
WCHAR *pwszKeyContainer = NULL;
|
|
DWORD NameId;
|
|
|
|
*ppwszKeyContainer = NULL;
|
|
*ppccCertOld = NULL;
|
|
*piKey = MAXDWORD;
|
|
|
|
// open MY store
|
|
hMyStore = CertOpenStore(
|
|
CERT_STORE_PROV_SYSTEM_W,
|
|
X509_ASN_ENCODING,
|
|
NULL, // hProv
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE |
|
|
CERT_STORE_MAXIMUM_ALLOWED_FLAG,
|
|
wszMY_CERTSTORE);
|
|
if (NULL == hMyStore)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertOpenStore");
|
|
}
|
|
hr = myFindCACertByHashIndex(
|
|
hMyStore,
|
|
pwszSanitizedCAName,
|
|
CSRH_CASIGCERT,
|
|
iCertNew - 1,
|
|
&NameId,
|
|
ppccCertOld);
|
|
_JumpIfError(hr, error, "myFindCACertByHashIndex");
|
|
|
|
if (fNewKey)
|
|
{
|
|
*piKey = iCertNew; // New key: iKey set to iCert
|
|
|
|
hr = myAllocIndexedName(
|
|
pwszSanitizedCAName,
|
|
*piKey,
|
|
&pwszKeyContainer);
|
|
_JumpIfError(hr, error, "myAllocIndexedName");
|
|
}
|
|
else
|
|
{
|
|
// get the key provider info
|
|
if (!myCertGetCertificateContextProperty(
|
|
*ppccCertOld,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pKey,
|
|
&cbKey))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertGetCertificateContextProperty");
|
|
}
|
|
hr = myDupString(pKey->pwszContainerName, &pwszKeyContainer);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
// Reuse key: iKey set to match oldest iCert using this key:
|
|
|
|
hr = FindKeyIndex(
|
|
hMyStore,
|
|
pwszSanitizedCAName,
|
|
fUnattended,
|
|
fMachineKeyset,
|
|
iCertNew,
|
|
pKey,
|
|
piKey);
|
|
_JumpIfError(hr, error, "FindKeyIndex");
|
|
|
|
CSASSERT(MAXDWORD != *piKey);
|
|
}
|
|
*ppwszKeyContainer = pwszKeyContainer;
|
|
pwszKeyContainer = NULL;
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
if (NULL != pwszKeyContainer)
|
|
{
|
|
LocalFree(pwszKeyContainer);
|
|
}
|
|
if (NULL != pKey)
|
|
{
|
|
LocalFree(pKey);
|
|
}
|
|
if (NULL != hMyStore)
|
|
{
|
|
CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
CSILOG(hr, IDS_ILOG_LOADOLDCERT, *ppwszKeyContainer, NULL, piKey);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ReplaceExtension(
|
|
IN CERT_EXTENSION const *pExtension,
|
|
IN OUT DWORD *pcExtension,
|
|
IN OUT CERT_EXTENSION *rgExtension)
|
|
{
|
|
DWORD i;
|
|
|
|
CSASSERT(NULL != pExtension->pszObjId);
|
|
for (i = 0; ; i++)
|
|
{
|
|
if (i == *pcExtension)
|
|
{
|
|
if (NULL != pExtension->Value.pbData)
|
|
{
|
|
(*pcExtension)++; // not found: append to array
|
|
}
|
|
break;
|
|
}
|
|
CSASSERT(i < *pcExtension);
|
|
if (0 == strcmp(pExtension->pszObjId, rgExtension[i].pszObjId))
|
|
{
|
|
if (NULL == pExtension->Value.pbData)
|
|
{
|
|
// remove extension: copy last extension on top of this one
|
|
// and decrement extension count
|
|
|
|
(*pcExtension)--;
|
|
pExtension = &rgExtension[*pcExtension];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
rgExtension[i] = *pExtension; // append or overwrite extension
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetMinimumCertValidityPeriod(
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN DWORD cCert,
|
|
OUT LONGLONG *pTimeDelta)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hMyStore = NULL;
|
|
DWORD NameId;
|
|
CERT_CONTEXT const *pcc = NULL;
|
|
BOOL fFirst = TRUE;
|
|
DWORD i;
|
|
|
|
// open MY store
|
|
hMyStore = CertOpenStore(
|
|
CERT_STORE_PROV_SYSTEM_W,
|
|
X509_ASN_ENCODING,
|
|
NULL, // hProv
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE |
|
|
CERT_STORE_MAXIMUM_ALLOWED_FLAG,
|
|
wszMY_CERTSTORE);
|
|
if (NULL == hMyStore)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertOpenStore");
|
|
}
|
|
for (i = 0; i < cCert; i++)
|
|
{
|
|
LONGLONG TimeDelta;
|
|
|
|
hr = myFindCACertByHashIndex(
|
|
hMyStore,
|
|
pwszSanitizedCAName,
|
|
CSRH_CASIGCERT,
|
|
i,
|
|
&NameId,
|
|
&pcc);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "myFindCACertByHashIndex");
|
|
continue;
|
|
}
|
|
|
|
TimeDelta = mySubtractFileTimes(
|
|
&pcc->pCertInfo->NotAfter,
|
|
&pcc->pCertInfo->NotBefore);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"iCert=%u TimeDelta=%x:%x\n",
|
|
i,
|
|
(DWORD) (TimeDelta >> 32),
|
|
(DWORD) TimeDelta));
|
|
|
|
if (fFirst || *pTimeDelta > TimeDelta)
|
|
{
|
|
*pTimeDelta = TimeDelta;
|
|
DBGPRINT((
|
|
DBG_SS_CERTLIBI,
|
|
"iCert=%u *pTimeDelta=%x:%x\n",
|
|
i,
|
|
(DWORD) (*pTimeDelta >> 32),
|
|
(DWORD) *pTimeDelta));
|
|
fFirst = FALSE;
|
|
}
|
|
|
|
CertFreeCertificateContext(pcc);
|
|
pcc = NULL;
|
|
}
|
|
if (fFirst)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "no old Certs");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pcc)
|
|
{
|
|
CertFreeCertificateContext(pcc);
|
|
}
|
|
if (NULL != hMyStore)
|
|
{
|
|
CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetCertHashExtension(
|
|
IN CERT_CONTEXT const *pCert,
|
|
OUT BYTE **ppbData,
|
|
OUT DWORD *pcbData)
|
|
{
|
|
HRESULT hr;
|
|
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
|
|
CRYPT_DATA_BLOB Blob;
|
|
DWORD cbHash;
|
|
|
|
cbHash = sizeof(abHash);
|
|
if (!CertGetCertificateContextProperty(
|
|
pCert,
|
|
CERT_HASH_PROP_ID,
|
|
abHash,
|
|
&cbHash))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertGetCertificateContextProperty");
|
|
}
|
|
Blob.cbData = cbHash;
|
|
Blob.pbData = abHash;
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_OCTET_STRING,
|
|
&Blob,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
ppbData,
|
|
pcbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CloneRootCert(
|
|
IN HINF hInf,
|
|
IN CERT_CONTEXT const *pccCertOld,
|
|
IN CRYPT_KEY_PROV_INFO const *pKeyProvInfo,
|
|
IN HCRYPTPROV hProv,
|
|
IN WCHAR const *pwszSanitizedCAName,
|
|
IN DWORD iCert,
|
|
IN DWORD iKey,
|
|
IN BOOL fUseDS,
|
|
IN BOOL fNewKey,
|
|
IN DWORD dwRevocationFlags,
|
|
IN HINSTANCE hInstance,
|
|
IN BOOL fUnattended,
|
|
IN HWND hwnd,
|
|
OUT BYTE **ppbCert,
|
|
OUT DWORD *pcbCert)
|
|
{
|
|
HRESULT hr;
|
|
CERT_INFO Cert;
|
|
GUID guidSerialNumber;
|
|
LONGLONG TimeDelta;
|
|
CERT_PUBLIC_KEY_INFO *pPubKey = NULL;
|
|
DWORD cbPubKey;
|
|
DWORD NameId;
|
|
CERT_EXTENSION *paext = NULL;
|
|
FILETIME ftNotAfterMin;
|
|
DWORD dwValidityPeriodCount;
|
|
ENUM_PERIOD enumValidityPeriod;
|
|
CERT_EXTENSION *pext;
|
|
|
|
#define CEXT_REPLACED 9
|
|
|
|
CERT_EXTENSION extBasicConstraints =
|
|
{ NULL, FALSE, 0, NULL};
|
|
CERT_EXTENSION extSKI =
|
|
{ szOID_SUBJECT_KEY_IDENTIFIER, FALSE, 0, NULL };
|
|
CERT_EXTENSION extCDP =
|
|
{ szOID_CRL_DIST_POINTS, FALSE, 0, NULL };
|
|
CERT_EXTENSION extVersion =
|
|
{ szOID_CERTSRV_CA_VERSION, FALSE, 0, NULL };
|
|
CERT_EXTENSION extPreviousHash =
|
|
{ szOID_CERTSRV_PREVIOUS_CERT_HASH, FALSE, 0, NULL };
|
|
CERT_EXTENSION extPolicy =
|
|
{ szOID_CERT_POLICIES, FALSE, 0, NULL };
|
|
CERT_EXTENSION extCross =
|
|
{ szOID_CROSS_CERT_DIST_POINTS, FALSE, 0, NULL };
|
|
CERT_EXTENSION extAIA =
|
|
{ szOID_AUTHORITY_INFO_ACCESS, FALSE, 0, NULL };
|
|
CERT_EXTENSION extEKU =
|
|
{ NULL, FALSE, 0, NULL};
|
|
|
|
*ppbCert = NULL;
|
|
|
|
CopyMemory(&Cert, pccCertOld->pCertInfo, sizeof(Cert));
|
|
Cert.dwVersion = CERT_V3;
|
|
myGenerateGuidSerialNumber(&guidSerialNumber);
|
|
|
|
Cert.SerialNumber.pbData = (BYTE *) &guidSerialNumber;
|
|
Cert.SerialNumber.cbData = sizeof(guidSerialNumber);
|
|
if (!myAreBlobsSame(
|
|
Cert.Issuer.pbData,
|
|
Cert.Issuer.cbData,
|
|
Cert.Subject.pbData,
|
|
Cert.Subject.cbData))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "non-Root Cert");
|
|
}
|
|
|
|
if (!myCryptExportPublicKeyInfo(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pPubKey,
|
|
&cbPubKey))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myCryptExportPublicKeyInfo");
|
|
}
|
|
|
|
Cert.SubjectPublicKeyInfo = *pPubKey; // Structure assignment
|
|
|
|
// make new cert expire at least 1 minute after old cert.
|
|
|
|
ftNotAfterMin = Cert.NotAfter;
|
|
myMakeExprDateTime(&ftNotAfterMin, 1, ENUM_PERIOD_MINUTES);
|
|
|
|
GetSystemTimeAsFileTime(&Cert.NotBefore);
|
|
|
|
hr = myInfGetValidityPeriod(
|
|
hInf,
|
|
NULL, // pwszValidityPeriodCount
|
|
NULL, // pwszValidityPeriodString
|
|
&dwValidityPeriodCount,
|
|
&enumValidityPeriod,
|
|
NULL); // pfSwap
|
|
if (S_OK == hr)
|
|
{
|
|
Cert.NotAfter = Cert.NotBefore;
|
|
myMakeExprDateTime(
|
|
&Cert.NotAfter,
|
|
dwValidityPeriodCount,
|
|
enumValidityPeriod);
|
|
TimeDelta = 0;
|
|
}
|
|
else
|
|
{
|
|
hr = GetMinimumCertValidityPeriod(
|
|
pwszSanitizedCAName,
|
|
iCert,
|
|
&TimeDelta);
|
|
_JumpIfError(hr, error, "GetMinimumCertValidityPeriod");
|
|
|
|
CSASSERT(0 != TimeDelta);
|
|
}
|
|
myMakeExprDateTime(
|
|
&Cert.NotBefore,
|
|
-CCLOCKSKEWMINUTESDEFAULT,
|
|
ENUM_PERIOD_MINUTES);
|
|
if (0 != TimeDelta)
|
|
{
|
|
Cert.NotAfter = Cert.NotBefore;
|
|
myAddToFileTime(&Cert.NotAfter, TimeDelta);
|
|
}
|
|
|
|
// make new cert expire at least 1 minute after old cert.
|
|
|
|
if (0 > CompareFileTime(&Cert.NotAfter, &ftNotAfterMin))
|
|
{
|
|
Cert.NotAfter = ftNotAfterMin;
|
|
}
|
|
|
|
if (!fNewKey)
|
|
{
|
|
Cert.NotBefore = pccCertOld->pCertInfo->NotBefore;
|
|
}
|
|
|
|
paext = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(Cert.cExtension + CEXT_REPLACED) * sizeof(paext[0]));
|
|
if (NULL == paext)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(paext, Cert.rgExtension, Cert.cExtension * sizeof(paext[0]));
|
|
Cert.rgExtension = paext;
|
|
|
|
// Basic constraints extension:
|
|
|
|
hr = myInfGetBasicConstraints2CAExtensionOrDefault(hInf, &extBasicConstraints);
|
|
_JumpIfError(hr, error, "myInfGetBasicConstraints2CAExtensionOrDefault");
|
|
|
|
ReplaceExtension(&extBasicConstraints, &Cert.cExtension, Cert.rgExtension);
|
|
|
|
// Subject Key Identifier extension:
|
|
// If we're reusing the old key, reuse the old SKI -- even if it's "wrong".
|
|
|
|
pext = NULL;
|
|
if (!fNewKey)
|
|
{
|
|
pext = CertFindExtension(
|
|
szOID_SUBJECT_KEY_IDENTIFIER,
|
|
Cert.cExtension,
|
|
Cert.rgExtension);
|
|
}
|
|
if (NULL == pext)
|
|
{
|
|
hr = myCreateSubjectKeyIdentifierExtension(
|
|
pPubKey,
|
|
&extSKI.Value.pbData,
|
|
&extSKI.Value.cbData);
|
|
_JumpIfError(hr, error, "myCreateSubjectKeyIdentifierExtension");
|
|
|
|
ReplaceExtension(&extSKI, &Cert.cExtension, Cert.rgExtension);
|
|
}
|
|
|
|
hr = CreateRevocationExtension(
|
|
hInf,
|
|
pwszSanitizedCAName,
|
|
iCert,
|
|
iKey,
|
|
fUseDS,
|
|
dwRevocationFlags,
|
|
&extCDP.fCritical,
|
|
&extCDP.Value.pbData,
|
|
&extCDP.Value.cbData);
|
|
_PrintIfError2(hr, "CreateRevocationExtension", S_FALSE);
|
|
if (S_OK == hr || S_FALSE == hr)
|
|
{
|
|
ReplaceExtension(&extCDP, &Cert.cExtension, Cert.rgExtension);
|
|
}
|
|
|
|
// Build the CA Version extension
|
|
|
|
NameId = MAKECANAMEID(iCert, iKey);
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_INTEGER,
|
|
&NameId,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&extVersion.Value.pbData,
|
|
&extVersion.Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
ReplaceExtension(&extVersion, &Cert.cExtension, Cert.rgExtension);
|
|
|
|
|
|
// Build the previous CA cert hash extension
|
|
|
|
hr = GetCertHashExtension(
|
|
pccCertOld,
|
|
&extPreviousHash.Value.pbData,
|
|
&extPreviousHash.Value.cbData);
|
|
_JumpIfError(hr, error, "GetCertHashExtension");
|
|
|
|
ReplaceExtension(&extPreviousHash, &Cert.cExtension, Cert.rgExtension);
|
|
|
|
|
|
// Build the Policy Statement extension
|
|
|
|
hr = myInfGetPolicyStatementExtension(hInf, &extPolicy);
|
|
if (S_OK == hr || S_FALSE == hr)
|
|
{
|
|
ReplaceExtension(&extPolicy, &Cert.cExtension, Cert.rgExtension);
|
|
}
|
|
|
|
|
|
// Build the Cross Cert Dist Points extension
|
|
|
|
hr = myInfGetCrossCertDistributionPointsExtension(hInf, &extCross);
|
|
if (S_OK == hr || S_FALSE == hr)
|
|
{
|
|
ReplaceExtension(&extCross, &Cert.cExtension, Cert.rgExtension);
|
|
}
|
|
|
|
|
|
// Build the Authority Information Access extension
|
|
|
|
hr = CreateAuthorityInformationAccessExtension(
|
|
hInf,
|
|
pwszSanitizedCAName,
|
|
iCert,
|
|
iKey,
|
|
fUseDS,
|
|
&extAIA.fCritical,
|
|
&extAIA.Value.pbData,
|
|
&extAIA.Value.cbData);
|
|
_PrintIfError3(
|
|
hr,
|
|
"CreateAuthorityInformationAccessExtension",
|
|
E_HANDLE,
|
|
S_FALSE);
|
|
if (S_OK == hr || S_FALSE == hr)
|
|
{
|
|
ReplaceExtension(&extAIA, &Cert.cExtension, Cert.rgExtension);
|
|
}
|
|
|
|
|
|
// Build the Enhanced Key Usage extension
|
|
|
|
hr = myInfGetEnhancedKeyUsageExtension(hInf, &extEKU);
|
|
if (S_OK == hr || S_FALSE == hr)
|
|
{
|
|
ReplaceExtension(&extEKU, &Cert.cExtension, Cert.rgExtension);
|
|
}
|
|
|
|
hr = EncodeCertAndSign(
|
|
hProv,
|
|
&Cert,
|
|
Cert.SignatureAlgorithm.pszObjId,
|
|
ppbCert,
|
|
pcbCert,
|
|
hInstance,
|
|
fUnattended,
|
|
hwnd);
|
|
_JumpIfError(hr, error, "EncodeCertAndSign");
|
|
|
|
error:
|
|
if (NULL != extBasicConstraints.Value.pbData)
|
|
{
|
|
LocalFree(extBasicConstraints.Value.pbData);
|
|
}
|
|
if (NULL != extSKI.Value.pbData)
|
|
{
|
|
LocalFree(extSKI.Value.pbData);
|
|
}
|
|
if (NULL != extCDP.Value.pbData)
|
|
{
|
|
LocalFree(extCDP.Value.pbData);
|
|
}
|
|
if (NULL != extVersion.Value.pbData)
|
|
{
|
|
LocalFree(extVersion.Value.pbData);
|
|
}
|
|
if (NULL != extPreviousHash.Value.pbData)
|
|
{
|
|
LocalFree(extPreviousHash.Value.pbData);
|
|
}
|
|
if (NULL != extPolicy.Value.pbData)
|
|
{
|
|
LocalFree(extPolicy.Value.pbData);
|
|
}
|
|
if (NULL != extCross.Value.pbData)
|
|
{
|
|
LocalFree(extCross.Value.pbData);
|
|
}
|
|
if (NULL != extAIA.Value.pbData)
|
|
{
|
|
LocalFree(extAIA.Value.pbData);
|
|
}
|
|
if (NULL != extEKU.Value.pbData)
|
|
{
|
|
LocalFree(extEKU.Value.pbData);
|
|
}
|
|
if (NULL != paext)
|
|
{
|
|
LocalFree(paext);
|
|
}
|
|
if (NULL != pPubKey)
|
|
{
|
|
LocalFree(pPubKey);
|
|
}
|
|
CSILOG(hr, IDS_ILOG_CLONECERT, NULL, NULL, NULL);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
csiBuildRequest(
|
|
OPTIONAL IN HINF hInf,
|
|
OPTIONAL IN CERT_CONTEXT const *pccPrevious,
|
|
IN BYTE const *pbSubjectEncoded,
|
|
IN DWORD cbSubjectEncoded,
|
|
IN char const *pszAlgId,
|
|
IN BOOL fNewKey,
|
|
IN DWORD iCert,
|
|
IN DWORD iKey,
|
|
IN HCRYPTPROV hProv,
|
|
IN HWND hwnd,
|
|
IN HINSTANCE hInstance,
|
|
IN BOOL fUnattended,
|
|
OUT BYTE **ppbEncode,
|
|
OUT DWORD *pcbEncode)
|
|
{
|
|
HRESULT hr;
|
|
CERT_PUBLIC_KEY_INFO *pInfo = NULL;
|
|
DWORD cbInfo = 0;
|
|
BYTE *pbEncode = NULL;
|
|
DWORD cbEncode;
|
|
CERT_REQUEST_INFO CertRequestInfo;
|
|
CRYPT_ALGORITHM_IDENTIFIER AlgId;
|
|
HCERTTYPE hCertType = NULL;
|
|
CRYPT_ATTR_BLOB ExtBlob;
|
|
CRYPT_ATTR_BLOB VersionBlob;
|
|
CRYPT_ATTRIBUTE aAttrib[2];
|
|
CERT_EXTENSIONS *pExtensions = NULL;
|
|
CERT_EXTENSIONS Extensions;
|
|
CERT_EXTENSION aext[8];
|
|
CERT_EXTENSION *paext = NULL;
|
|
DWORD i;
|
|
DWORD NameId = MAKECANAMEID(iCert, iKey);
|
|
DWORD cExtCommon = 0;
|
|
CERT_EXTENSION *pext;
|
|
DWORD cAttribute = 0;
|
|
CRYPT_ATTR_BLOB *paAttribute = NULL;
|
|
WCHAR *pwszTemplateName;
|
|
WCHAR *pwszTemplateNameInf = NULL;
|
|
|
|
ExtBlob.pbData = NULL;
|
|
VersionBlob.pbData = NULL;
|
|
|
|
if (!CryptExportPublicKeyInfo(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
NULL,
|
|
&cbInfo))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptExportPublicKeyInfo");
|
|
}
|
|
|
|
pInfo = (CERT_PUBLIC_KEY_INFO *) LocalAlloc(LMEM_FIXED, cbInfo);
|
|
if (NULL == pInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
if (!CryptExportPublicKeyInfo(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
pInfo,
|
|
&cbInfo))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptExportPublicKeyInfo");
|
|
}
|
|
|
|
CertRequestInfo.dwVersion = CERT_REQUEST_V1;
|
|
CertRequestInfo.Subject.pbData = const_cast<BYTE *>(pbSubjectEncoded);
|
|
CertRequestInfo.Subject.cbData = cbSubjectEncoded;
|
|
CertRequestInfo.SubjectPublicKeyInfo = *pInfo;
|
|
|
|
// Build the CA Version extension
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_INTEGER,
|
|
&NameId,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&aext[cExtCommon].Value.pbData,
|
|
&aext[cExtCommon].Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
aext[cExtCommon].pszObjId = szOID_CERTSRV_CA_VERSION;
|
|
aext[cExtCommon].fCritical = FALSE;
|
|
cExtCommon++;
|
|
|
|
// Build the previous CA cert hash extension
|
|
|
|
if (0 != iCert && NULL != pccPrevious)
|
|
{
|
|
hr = GetCertHashExtension(
|
|
pccPrevious,
|
|
&aext[cExtCommon].Value.pbData,
|
|
&aext[cExtCommon].Value.cbData);
|
|
_JumpIfError(hr, error, "GetCertHashExtension");
|
|
|
|
aext[cExtCommon].pszObjId = szOID_CERTSRV_PREVIOUS_CERT_HASH;
|
|
aext[cExtCommon].fCritical = FALSE;
|
|
cExtCommon++;
|
|
}
|
|
|
|
// Subject Key Identifier extension:
|
|
// If we're reusing the old key, reuse the old SKI -- even if it's "wrong".
|
|
|
|
pext = NULL;
|
|
if (0 != iCert && NULL != pccPrevious && !fNewKey)
|
|
{
|
|
pext = CertFindExtension(
|
|
szOID_SUBJECT_KEY_IDENTIFIER,
|
|
pccPrevious->pCertInfo->cExtension,
|
|
pccPrevious->pCertInfo->rgExtension);
|
|
}
|
|
if (NULL != pext)
|
|
{
|
|
aext[cExtCommon].Value.cbData = pext->Value.cbData;
|
|
aext[cExtCommon].Value.pbData = (BYTE *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
pext->Value.cbData);
|
|
if (NULL == aext[cExtCommon].Value.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(
|
|
aext[cExtCommon].Value.pbData,
|
|
pext->Value.pbData,
|
|
pext->Value.cbData);
|
|
}
|
|
else
|
|
{
|
|
hr = myCreateSubjectKeyIdentifierExtension(
|
|
&CertRequestInfo.SubjectPublicKeyInfo,
|
|
&aext[cExtCommon].Value.pbData,
|
|
&aext[cExtCommon].Value.cbData);
|
|
_JumpIfError(hr, error, "myCreateSubjectKeyIdentifierExtension");
|
|
}
|
|
|
|
aext[cExtCommon].pszObjId = szOID_SUBJECT_KEY_IDENTIFIER;
|
|
aext[cExtCommon].fCritical = FALSE;
|
|
cExtCommon++;
|
|
|
|
hr = myInfGetPolicyStatementExtension(hInf, &aext[cExtCommon]);
|
|
_PrintIfError(hr, "myInfGetPolicyStatementExtension");
|
|
if (S_OK == hr)
|
|
{
|
|
aext[cExtCommon].pszObjId = szOID_CERT_POLICIES;
|
|
cExtCommon++;
|
|
}
|
|
|
|
hr = myInfGetCrossCertDistributionPointsExtension(hInf, &aext[cExtCommon]);
|
|
_PrintIfError(hr, "myInfGetCrossCertDistributionPointsExtension");
|
|
if (S_OK == hr)
|
|
{
|
|
aext[cExtCommon].pszObjId = szOID_CROSS_CERT_DIST_POINTS;
|
|
cExtCommon++;
|
|
}
|
|
|
|
hr = myInfGetRequestAttributes(
|
|
hInf,
|
|
&cAttribute,
|
|
&paAttribute,
|
|
&pwszTemplateNameInf);
|
|
_PrintIfError(hr, "myInfGetRequestAttributes");
|
|
|
|
pwszTemplateName = pwszTemplateNameInf;
|
|
if (NULL == pwszTemplateName)
|
|
{
|
|
pwszTemplateName = wszCERTTYPE_SUBORDINATE_CA;
|
|
}
|
|
|
|
// Build the attribute containing the appropriate cert type info
|
|
|
|
hr = CAFindCertTypeByName(
|
|
pwszTemplateName,
|
|
NULL,
|
|
CT_FIND_LOCAL_SYSTEM |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES,
|
|
&hCertType);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = CAGetCertTypeExtensions(hCertType, &pExtensions);
|
|
_JumpIfError(hr, error, "CAGetCertTypeExtensions");
|
|
|
|
paext = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(pExtensions->cExtension + cExtCommon) * sizeof(paext[0]));
|
|
if (NULL == paext)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(&paext[0], &aext[0], cExtCommon * sizeof(paext[0]));
|
|
CopyMemory(
|
|
&paext[cExtCommon],
|
|
pExtensions->rgExtension,
|
|
pExtensions->cExtension * sizeof(paext[0]));
|
|
|
|
Extensions.cExtension = cExtCommon + pExtensions->cExtension;
|
|
Extensions.rgExtension = paext;
|
|
}
|
|
else
|
|
{
|
|
DBGERRORPRINTLINE("CAFindCertTypeByName", hr);
|
|
|
|
// standard extensions are not available from CAGetCertTypeExtensions;
|
|
// construct them manually.
|
|
|
|
// Build the Cert Template extension
|
|
|
|
hr = myBuildCertTypeExtension(pwszTemplateName, &aext[cExtCommon]);
|
|
_JumpIfError(hr, error, "myBuildCertTypeExtension");
|
|
|
|
cExtCommon++;
|
|
|
|
if (!CreateKeyUsageExtension(
|
|
myCASIGN_KEY_USAGE,
|
|
&aext[cExtCommon].Value.pbData,
|
|
&aext[cExtCommon].Value.cbData,
|
|
hInstance,
|
|
fUnattended,
|
|
hwnd))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CreateKeyUsageExtension");
|
|
}
|
|
aext[cExtCommon].pszObjId = szOID_KEY_USAGE;
|
|
aext[cExtCommon].fCritical = FALSE;
|
|
cExtCommon++;
|
|
|
|
hr = myInfGetBasicConstraints2CAExtensionOrDefault(
|
|
hInf,
|
|
&aext[cExtCommon]);
|
|
_JumpIfError(hr, error, "myInfGetBasicConstraints2CAExtensionOrDefault");
|
|
|
|
cExtCommon++;
|
|
|
|
CSASSERT(ARRAYSIZE(aext) >= cExtCommon);
|
|
|
|
Extensions.cExtension = cExtCommon;
|
|
Extensions.rgExtension = aext;
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_EXTENSIONS,
|
|
&Extensions,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&ExtBlob.pbData,
|
|
&ExtBlob.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
// get the OS Version
|
|
|
|
hr = myBuildOSVersionAttribute(&VersionBlob.pbData, &VersionBlob.cbData);
|
|
_JumpIfError(hr, error, "myBuildOSVersionAttribute");
|
|
|
|
aAttrib[0].pszObjId = szOID_RSA_certExtensions;
|
|
aAttrib[0].cValue = 1;
|
|
aAttrib[0].rgValue = &ExtBlob;
|
|
|
|
aAttrib[1].pszObjId = szOID_OS_VERSION;
|
|
aAttrib[1].cValue = 1;
|
|
aAttrib[1].rgValue = &VersionBlob;
|
|
|
|
CertRequestInfo.cAttribute = ARRAYSIZE(aAttrib);
|
|
CertRequestInfo.rgAttribute = aAttrib;
|
|
|
|
AlgId.pszObjId = const_cast<char *>(pszAlgId);
|
|
AlgId.Parameters.cbData = 0;
|
|
AlgId.Parameters.pbData = NULL;
|
|
|
|
if (!CryptSignAndEncodeCertificate(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&CertRequestInfo,
|
|
&AlgId,
|
|
NULL,
|
|
NULL,
|
|
&cbEncode))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptSignAndEncodeCertificate");
|
|
}
|
|
|
|
pbEncode = (BYTE *) LocalAlloc(LMEM_FIXED, cbEncode);
|
|
if (NULL == pbEncode)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
if (!CryptSignAndEncodeCertificate(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&CertRequestInfo,
|
|
&AlgId,
|
|
NULL,
|
|
pbEncode,
|
|
&cbEncode))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptSignAndEncodeCertificate");
|
|
}
|
|
|
|
// return value
|
|
*ppbEncode = pbEncode;
|
|
*pcbEncode = cbEncode;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszTemplateNameInf)
|
|
{
|
|
LocalFree(pwszTemplateNameInf);
|
|
}
|
|
if (NULL != paAttribute)
|
|
{
|
|
myInfFreeRequestAttributes(cAttribute, paAttribute);
|
|
}
|
|
for (i = 0; i < cExtCommon; i++)
|
|
{
|
|
if (NULL != aext[i].Value.pbData)
|
|
{
|
|
LocalFree(aext[i].Value.pbData);
|
|
}
|
|
}
|
|
if (NULL != paext)
|
|
{
|
|
LocalFree(paext);
|
|
}
|
|
if (NULL != ExtBlob.pbData)
|
|
{
|
|
LocalFree(ExtBlob.pbData);
|
|
}
|
|
if (NULL != VersionBlob.pbData)
|
|
{
|
|
LocalFree(VersionBlob.pbData);
|
|
}
|
|
if (NULL != pInfo)
|
|
{
|
|
LocalFree(pInfo);
|
|
}
|
|
if (NULL != hCertType)
|
|
{
|
|
if (NULL != pExtensions && &Extensions != pExtensions)
|
|
{
|
|
CAFreeCertTypeExtensions(hCertType, pExtensions);
|
|
}
|
|
CACloseCertType(hCertType);
|
|
}
|
|
CSILOG(hr, IDS_ILOG_BUILDREQUEST, NULL, NULL, &NameId);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// CertServerRequestCACertificateAndComplete -- implements the following:
|
|
// MMC snapin's RenewCert and InstallCert verbs
|
|
// certutil -InstallCert & -RenewCert
|
|
//+-------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CertServerRequestCACertificateAndComplete(
|
|
IN HINSTANCE hInstance,
|
|
IN HWND hwnd,
|
|
IN DWORD Flags,
|
|
IN WCHAR const *pwszCAName,
|
|
OPTIONAL IN WCHAR const *pwszParentMachine,
|
|
OPTIONAL IN WCHAR const *pwszParentCA,
|
|
OPTIONAL IN WCHAR const *pwszCAChainFile,
|
|
OPTIONAL OUT WCHAR **ppwszRequestFile)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwSetupStatus;
|
|
WCHAR const *pwszFinalParentMachine = pwszParentMachine;
|
|
WCHAR const *pwszFinalParentCA = pwszParentCA;
|
|
WCHAR *pwszRequestFile = NULL;
|
|
WCHAR *pwszCertFile = NULL;
|
|
BYTE *pbRequest = NULL;
|
|
DWORD cbRequest;
|
|
BSTR strChain = NULL;
|
|
BYTE *pbChain = NULL;
|
|
DWORD cbChain;
|
|
WCHAR *pwszKeyContainer = NULL;
|
|
WCHAR *pwszServerName = NULL;
|
|
WCHAR *pwsz;
|
|
CERTHIERINFO CertHierInfo;
|
|
ENUM_CATYPES CAType;
|
|
BOOL fUseDS;
|
|
DWORD dwRevocationFlags;
|
|
DWORD iCertNew;
|
|
DWORD iKey;
|
|
CERT_CONTEXT const *pccCertOld = NULL;
|
|
HCRYPTPROV hProv = NULL;
|
|
CRYPT_KEY_PROV_INFO KeyProvInfo;
|
|
ALG_ID idAlg;
|
|
BOOL fMachineKeyset;
|
|
BOOL fKeyGenFailed;
|
|
CHAR *pszAlgId = NULL;
|
|
BOOL fUnattended = (CSRF_UNATTENDED & Flags)? TRUE : FALSE;
|
|
BOOL fRenew = (CSRF_RENEWCACERT & Flags)? TRUE : FALSE;
|
|
BOOL fNewKey = (CSRF_NEWKEYS & Flags)? TRUE : FALSE;
|
|
UINT idMsg;
|
|
WCHAR *pwszProvName = NULL;
|
|
DWORD dwProvType;
|
|
HINF hInf = INVALID_HANDLE_VALUE;
|
|
DWORD ErrorLine;
|
|
|
|
idMsg = IDS_ILOG_INSTALLCERT;
|
|
if (fRenew)
|
|
{
|
|
idMsg = fNewKey? IDS_ILOG_RENEWNEWKEY : IDS_ILOG_RENEWOLDKEY;
|
|
}
|
|
|
|
ZeroMemory(&CertHierInfo, sizeof(CertHierInfo));
|
|
ZeroMemory(&KeyProvInfo, sizeof(KeyProvInfo));
|
|
|
|
if (NULL != ppwszRequestFile)
|
|
{
|
|
*ppwszRequestFile = NULL;
|
|
}
|
|
|
|
if (NULL == pwszCAName)
|
|
{
|
|
hr = E_POINTER;
|
|
_JumpError(hr, error, "NULL CA Name");
|
|
}
|
|
|
|
hr = mySanitizeName(pwszCAName, &CertHierInfo.pwszSanitizedCAName);
|
|
_JumpIfError(hr, error, "mySanitizeName");
|
|
|
|
hr = GetSetupStatus(CertHierInfo.pwszSanitizedCAName, &dwSetupStatus);
|
|
_JumpIfError(hr, error, "GetSetupStatus");
|
|
|
|
hr = myGetCertRegDWValue(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCATYPE,
|
|
(DWORD *) &CAType);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegDWValue", wszREGCATYPE);
|
|
|
|
// use DS or not
|
|
hr = myGetCertRegDWValue(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCAUSEDS,
|
|
(DWORD *) &fUseDS);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegDWValue", wszREGCAUSEDS);
|
|
|
|
hr = myGetCertRegStrValue(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCASERVERNAME,
|
|
&pwszServerName);
|
|
_JumpIfErrorStr(hr, error, "myGetCertRegStrValue", wszREGCASERVERNAME);
|
|
|
|
hr = myGetCertRegDWValue(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
wszREGKEYPOLICYMODULES,
|
|
wszCLASS_CERTPOLICY,
|
|
wszREGREVOCATIONTYPE,
|
|
&dwRevocationFlags);
|
|
if (S_OK != hr)
|
|
{
|
|
dwRevocationFlags = fUseDS? REVEXT_DEFAULT_DS : REVEXT_DEFAULT_NODS;
|
|
}
|
|
|
|
// Current Hash count is the same as the next iCert
|
|
|
|
hr = myGetCARegHashCount(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
CSRH_CASIGCERT,
|
|
&iCertNew);
|
|
_JumpIfError(hr, error, "myGetCARegHashCount");
|
|
|
|
if (fRenew)
|
|
{
|
|
// We're renewing the CA cert, so the initial setup should be complete.
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
|
|
if (0 == iCertNew || (SETUP_SUSPEND_FLAG & dwSetupStatus))
|
|
{
|
|
_JumpError(hr, error, "not fully installed");
|
|
}
|
|
if (SETUP_REQUEST_FLAG & dwSetupStatus)
|
|
{
|
|
if (0 == (CSRF_OVERWRITE & Flags))
|
|
{
|
|
_JumpError(hr, error, "Renewal already in progress");
|
|
}
|
|
_PrintError(hr, "Ignoring renewal already in progress");
|
|
}
|
|
|
|
hr = myGetCertSrvCSP(
|
|
FALSE, // fEncryptionCSP
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
&dwProvType,
|
|
&pwszProvName,
|
|
&idAlg,
|
|
&fMachineKeyset,
|
|
NULL); // pdwKeySize
|
|
_JumpIfError(hr, error, "myGetCertSrvCSP");
|
|
|
|
hr = LoadCurrentCACertAndKeyInfo(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
fNewKey,
|
|
fUnattended,
|
|
fMachineKeyset,
|
|
iCertNew,
|
|
&iKey,
|
|
&pwszKeyContainer,
|
|
&pccCertOld);
|
|
_JumpIfError(hr, error, "LoadCurrentCACertAndKeyInfo");
|
|
|
|
CSASSERT(MAXDWORD != iKey);
|
|
|
|
hr = csiFillKeyProvInfo(
|
|
pwszKeyContainer,
|
|
pwszProvName,
|
|
dwProvType,
|
|
fMachineKeyset,
|
|
&KeyProvInfo);
|
|
_JumpIfError(hr, error, "csiFillKeyProvInfo");
|
|
|
|
hr = GetCertServerKeyProviderInfo(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
pwszKeyContainer,
|
|
&idAlg,
|
|
&fMachineKeyset,
|
|
&KeyProvInfo);
|
|
_JumpIfError(hr, error, "GetCertServerKeyProviderInfo");
|
|
|
|
hr = myInfOpenFile(NULL, &hInf, &ErrorLine);
|
|
_PrintIfError2(
|
|
hr,
|
|
"myInfOpenFile",
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
|
|
|
if (fNewKey)
|
|
{
|
|
CWaitCursor cwait;
|
|
DWORD cbitKey;
|
|
|
|
hr = myInfGetKeyLength(hInf, &cbitKey);
|
|
if (S_OK != hr)
|
|
{
|
|
cbitKey = CertGetPublicKeyLength(
|
|
X509_ASN_ENCODING,
|
|
&pccCertOld->pCertInfo->SubjectPublicKeyInfo);
|
|
if (0 == cbitKey || 512 == cbitKey)
|
|
{
|
|
if (0 == cbitKey)
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError(hr, "CertGetPublicKeyLength");
|
|
}
|
|
cbitKey = 1024;
|
|
}
|
|
}
|
|
hr = csiGenerateCAKeys(
|
|
KeyProvInfo.pwszContainerName,
|
|
KeyProvInfo.pwszProvName,
|
|
KeyProvInfo.dwProvType,
|
|
fMachineKeyset,
|
|
cbitKey, // dwKeyLength,
|
|
hInstance,
|
|
fUnattended,
|
|
hwnd,
|
|
&fKeyGenFailed);
|
|
_JumpIfError(hr, error, "csiGenerateCAKeys");
|
|
}
|
|
|
|
// get CSP handle
|
|
|
|
if (!myCertSrvCryptAcquireContext(
|
|
&hProv,
|
|
KeyProvInfo.pwszContainerName,
|
|
KeyProvInfo.pwszProvName,
|
|
KeyProvInfo.dwProvType,
|
|
fUnattended? CRYPT_SILENT : 0,
|
|
fMachineKeyset))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
|
|
}
|
|
if (hProv == NULL)
|
|
{
|
|
hr = E_HANDLE;
|
|
_JumpError(hr, error, "myCertSrvCryptAcquireContext");
|
|
}
|
|
|
|
if (IsRootCA(CAType))
|
|
{
|
|
hr = CloneRootCert(
|
|
hInf,
|
|
pccCertOld,
|
|
&KeyProvInfo,
|
|
hProv,
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
iCertNew,
|
|
iKey,
|
|
fUseDS,
|
|
fNewKey,
|
|
dwRevocationFlags,
|
|
hInstance,
|
|
fUnattended,
|
|
hwnd,
|
|
&pbChain,
|
|
&cbChain);
|
|
_JumpIfError(hr, error, "CloneRootCert");
|
|
}
|
|
else
|
|
{
|
|
// get request file name
|
|
hr = csiGetCARequestFileName(
|
|
hInstance,
|
|
hwnd,
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
iCertNew,
|
|
iKey,
|
|
&pwszRequestFile);
|
|
_JumpIfError(hr, error, "csiGetCARequestFileName");
|
|
|
|
|
|
hr = myGetSigningOID(
|
|
NULL, // hProv
|
|
KeyProvInfo.pwszProvName,
|
|
KeyProvInfo.dwProvType,
|
|
idAlg,
|
|
&pszAlgId);
|
|
_JumpIfError(hr, error, "myGetSigningOID");
|
|
|
|
hr = csiBuildRequest(
|
|
hInf,
|
|
pccCertOld,
|
|
pccCertOld->pCertInfo->Subject.pbData,
|
|
pccCertOld->pCertInfo->Subject.cbData,
|
|
pszAlgId,
|
|
fNewKey,
|
|
iCertNew,
|
|
iKey,
|
|
hProv,
|
|
hwnd,
|
|
hInstance,
|
|
fUnattended,
|
|
&pbRequest,
|
|
&cbRequest);
|
|
_JumpIfError(hr, error, "csiBuildRequest");
|
|
|
|
hr = EncodeToFileW(
|
|
pwszRequestFile,
|
|
pbRequest,
|
|
cbRequest,
|
|
DECF_FORCEOVERWRITE | CRYPT_STRING_BASE64REQUESTHEADER);
|
|
_JumpIfError(hr, error, "EncodeToFileW");
|
|
|
|
hr = mySetCertRegKeyIndexAndContainer(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
iKey,
|
|
pwszKeyContainer);
|
|
_JumpIfError(hr, error, "mySetCertRegKeyIndexAndContainer");
|
|
|
|
hr = SetSetupStatus(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
SETUP_REQUEST_FLAG,
|
|
TRUE);
|
|
_JumpIfError(hr, error, "SetSetupStatus");
|
|
|
|
if (NULL != ppwszRequestFile)
|
|
{
|
|
*ppwszRequestFile = pwszRequestFile;
|
|
pwszRequestFile = NULL;
|
|
CSASSERT(S_OK == hr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We're not renewing the CA cert, so this had better be an incomplete
|
|
// renewal or initial setup; we're waiting for the new cert or chain.
|
|
|
|
if (IsRootCA(CAType) || 0 == (SETUP_REQUEST_FLAG & dwSetupStatus))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
|
|
_JumpIfError(hr, error, "no outstanding request");
|
|
}
|
|
|
|
hr = myGetCertRegKeyIndexAndContainer(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
&iKey,
|
|
&pwszKeyContainer);
|
|
_JumpIfError(hr, error, "myGetCertRegKeyIndexAndContainer");
|
|
|
|
if (NULL == pwszCAChainFile)
|
|
{
|
|
// pop up open dlg
|
|
hr = myGetOpenFileName(
|
|
hwnd,
|
|
hInstance,
|
|
IDS_CAHIER_INSTALL_TITLE,
|
|
IDS_CAHIER_CERTFILE_FILTER,
|
|
0, // no def ext
|
|
OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
|
|
NULL, // no default file
|
|
&pwszCertFile);
|
|
if (S_OK == hr && NULL != pwszCertFile)
|
|
{
|
|
pwszCAChainFile = pwszCertFile;
|
|
}
|
|
}
|
|
if (NULL != pwszCAChainFile)
|
|
{
|
|
hr = DecodeFileW(pwszCAChainFile, &pbChain, &cbChain, CRYPT_STRING_ANY);
|
|
_JumpIfErrorStr(hr, error, "DecodeFileW", pwszCAChainFile);
|
|
}
|
|
}
|
|
|
|
if (!IsRootCA(CAType) && NULL == pbChain)
|
|
{
|
|
// if we haven't created the request, grab it from a file for resubmission
|
|
if (pbRequest == NULL)
|
|
{
|
|
hr = myGetCARegFileNameTemplate(
|
|
wszREGREQUESTFILENAME,
|
|
pwszServerName,
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
iCertNew,
|
|
iKey,
|
|
&pwszRequestFile);
|
|
_JumpIfError(hr, error, "myGetCARegFileNameTemplate");
|
|
|
|
hr = DecodeFileW(pwszRequestFile, &pbRequest, &cbRequest, CRYPT_STRING_ANY);
|
|
_JumpIfErrorStr(hr, error, "DecodeFileW", pwszRequestFile);
|
|
}
|
|
|
|
if (NULL == pwszParentMachine || NULL == pwszParentCA)
|
|
{
|
|
CertHierInfo.hInstance = hInstance;
|
|
CertHierInfo.fUnattended = fUnattended;
|
|
CertHierInfo.iCertNew = iCertNew;
|
|
CertHierInfo.iKey = iKey;
|
|
|
|
// get parent ca info
|
|
hr = myGetCertRegStrValue(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGPARENTCAMACHINE,
|
|
&CertHierInfo.pwszParentMachineDefault);
|
|
_PrintIfErrorStr(hr, "myGetCertRegStrValue", wszREGPARENTCAMACHINE);
|
|
|
|
hr = myGetCertRegStrValue(
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
NULL,
|
|
NULL,
|
|
wszREGPARENTCANAME,
|
|
&CertHierInfo.pwszParentCADefault);
|
|
_PrintIfErrorStr(hr, "myGetCertRegStrValue", wszREGPARENTCANAME);
|
|
|
|
// invoke parent ca dialog to select
|
|
if (IDOK != (int) DialogBoxParam(
|
|
hInstance,
|
|
MAKEINTRESOURCE(IDD_COMPLETE_DIALOG),
|
|
hwnd,
|
|
CertHierProc,
|
|
(LPARAM) &CertHierInfo))
|
|
{
|
|
// cancel
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
_JumpError(hr, error, "cancel");
|
|
}
|
|
pwszFinalParentMachine = CertHierInfo.pwszParentMachine;
|
|
pwszFinalParentCA = CertHierInfo.pwszParentCA;
|
|
}
|
|
|
|
BOOL fRetrievePending =
|
|
(SETUP_REQUEST_FLAG & dwSetupStatus) &&
|
|
(SETUP_ONLINE_FLAG & dwSetupStatus) &&
|
|
NULL != CertHierInfo.pwszParentMachineDefault &&
|
|
NULL != CertHierInfo.pwszParentCADefault &&
|
|
0 == lstrcmpi(
|
|
pwszFinalParentMachine,
|
|
CertHierInfo.pwszParentMachineDefault) &&
|
|
0 == lstrcmpi(
|
|
pwszFinalParentCA,
|
|
CertHierInfo.pwszParentCADefault);
|
|
|
|
// submit to parent ca
|
|
hr = csiSubmitCARequest(
|
|
hInstance,
|
|
fUnattended,
|
|
hwnd,
|
|
fRenew,
|
|
fRetrievePending,
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
pwszFinalParentMachine,
|
|
pwszFinalParentCA,
|
|
pbRequest,
|
|
cbRequest,
|
|
&strChain);
|
|
_JumpIfError(hr, error, "csiSubmitCARequest");
|
|
|
|
cbChain = SysStringByteLen(strChain);
|
|
}
|
|
|
|
hr = FinishSuspendedSetupFromPKCS7(
|
|
hInstance,
|
|
fUnattended,
|
|
hwnd,
|
|
CertHierInfo.pwszSanitizedCAName,
|
|
pwszKeyContainer,
|
|
iKey,
|
|
fRenew || 0 != iCertNew,
|
|
NULL != pbChain? pbChain : (BYTE *) strChain,
|
|
cbChain);
|
|
_JumpIfError(hr, error, "FinishSuspendedSetupFromPKCS7");
|
|
|
|
MarkSetupComplete(CertHierInfo.pwszSanitizedCAName);
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
if (INVALID_HANDLE_VALUE != hInf)
|
|
{
|
|
myInfCloseFile(hInf);
|
|
}
|
|
FreeCertHierInfo(&CertHierInfo);
|
|
csiFreeKeyProvInfo(&KeyProvInfo);
|
|
if (NULL != hProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
if (NULL != pszAlgId)
|
|
{
|
|
LocalFree(pszAlgId);
|
|
}
|
|
if (NULL != pwszKeyContainer)
|
|
{
|
|
LocalFree(pwszKeyContainer);
|
|
}
|
|
if (NULL != pccCertOld)
|
|
{
|
|
CertFreeCertificateContext(pccCertOld);
|
|
}
|
|
if (NULL != pwszRequestFile)
|
|
{
|
|
LocalFree(pwszRequestFile);
|
|
}
|
|
if (NULL != pwszCertFile)
|
|
{
|
|
LocalFree(pwszCertFile);
|
|
}
|
|
if (NULL != pwszServerName)
|
|
{
|
|
LocalFree(pwszServerName);
|
|
}
|
|
if (NULL != pbRequest)
|
|
{
|
|
LocalFree(pbRequest);
|
|
}
|
|
if (NULL != pbChain)
|
|
{
|
|
LocalFree(pbChain);
|
|
}
|
|
if (NULL != pwszProvName)
|
|
{
|
|
LocalFree(pwszProvName);
|
|
}
|
|
if (NULL != strChain)
|
|
{
|
|
SysFreeString(strChain);
|
|
}
|
|
CSILOG(hr, idMsg, pwszCAName, NULL, NULL);
|
|
return(hr);
|
|
}
|