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.
1032 lines
33 KiB
1032 lines
33 KiB
//depot/Lab03_N/DS/security/cryptoapi/cryptsvc/keysvr.cpp#9 - edit change 6380 (text)
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <svcs.h> // SVCS_
|
|
#include <ntsecapi.h>
|
|
#include <wincrypt.h>
|
|
#include <wintrust.h>
|
|
#include <wintrustp.h>
|
|
#include <userenv.h>
|
|
#include <lmcons.h>
|
|
#include <certca.h>
|
|
#include "keysvc.h"
|
|
#include "keysvr.h"
|
|
#include "pfx.h"
|
|
#include "cryptui.h"
|
|
#include "lenroll.h"
|
|
#include "cryptmsg.h"
|
|
|
|
#include "unicode.h"
|
|
#include "unicode5.h"
|
|
#include <crypt.h>
|
|
|
|
|
|
#define KEYSVC_DEFAULT_ENDPOINT TEXT("\\pipe\\keysvc")
|
|
#define KEYSVC_DEFAULT_PROT_SEQ TEXT("ncacn_np")
|
|
#define MAXPROTSEQ 20
|
|
|
|
#define ARRAYSIZE(rg) (sizeof(rg) / sizeof((rg)[0]))
|
|
|
|
void *MyAlloc(size_t len)
|
|
{
|
|
return LocalAlloc(LMEM_ZEROINIT, len);
|
|
}
|
|
|
|
void MyFree(void *p)
|
|
{
|
|
LocalFree(p);
|
|
}
|
|
|
|
void MyRpcRevertToSelfEx(RPC_BINDING_HANDLE hRPCBinding)
|
|
{
|
|
RPC_STATUS rpcStatus;
|
|
|
|
rpcStatus = RpcRevertToSelfEx((RPC_BINDING_HANDLE)hRPCBinding);
|
|
if (RPC_S_OK != rpcStatus) {
|
|
MyLogErrorMessage(rpcStatus, MSG_KEYSVC_REVERT_TO_SELF_FAILED);
|
|
}
|
|
}
|
|
|
|
void MyRevertToSelf()
|
|
{
|
|
if (!RevertToSelf()) {
|
|
MyLogErrorMessage(GetLastError(), MSG_KEYSVC_REVERT_TO_SELF_FAILED);
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
StartKeyService(
|
|
VOID
|
|
)
|
|
{
|
|
return ERROR_SUCCESS; }
|
|
|
|
DWORD
|
|
StopKeyService(
|
|
VOID
|
|
)
|
|
{
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD AllocAndAssignString(
|
|
IN PKEYSVC_UNICODE_STRING pUnicodeString,
|
|
OUT LPWSTR *ppwsz
|
|
)
|
|
{
|
|
DWORD dwErr = 0;
|
|
|
|
if ((NULL != pUnicodeString->Buffer) && (0 != pUnicodeString->Length))
|
|
{
|
|
if ((pUnicodeString->Length > pUnicodeString->MaximumLength) ||
|
|
(pUnicodeString->Length & 1) || (pUnicodeString->MaximumLength & 1))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto Ret;
|
|
}
|
|
|
|
if (NULL == (*ppwsz = (LPWSTR)MyAlloc(pUnicodeString->MaximumLength +
|
|
sizeof(WCHAR))))
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
memcpy(*ppwsz, pUnicodeString->Buffer, pUnicodeString->Length);
|
|
}
|
|
Ret:
|
|
return dwErr;
|
|
}
|
|
|
|
// key service functions
|
|
ULONG s_KeyrOpenKeyService(
|
|
/* [in] */ handle_t /*hRPCBinding*/,
|
|
/* [in] */ KEYSVC_TYPE /*OwnerType*/,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING /*pOwnerName*/,
|
|
/* [in] */ ULONG /*ulDesiredAccess*/,
|
|
/* [in] */ PKEYSVC_BLOB /*pAuthentication*/,
|
|
/* [in, out] */ PKEYSVC_BLOB * /*ppReserved*/,
|
|
/* [out] */ KEYSVC_HANDLE * /*phKeySvc*/)
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
ULONG s_KeyrEnumerateProviders(
|
|
/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ KEYSVC_HANDLE /*hKeySvc*/,
|
|
/* [in, out] */ PKEYSVC_BLOB * /*ppReserved*/,
|
|
/* [in, out] */ ULONG *pcProviderCount,
|
|
/* [in, out][size_is(,*pcProviderCount)] */
|
|
PKEYSVC_PROVIDER_INFO *ppProviders)
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
ULONG s_KeyrCloseKeyService(
|
|
/* [in] */ handle_t /*hRPCBinding*/,
|
|
/* [in] */ KEYSVC_HANDLE /*hKeySvc*/,
|
|
/* [in, out] */ PKEYSVC_BLOB * /*ppReserved*/)
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
ULONG s_KeyrGetDefaultProvider(
|
|
/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ KEYSVC_HANDLE /*hKeySvc*/,
|
|
/* [in] */ ULONG ulProvType,
|
|
/* [in] */ ULONG /*ulFlags*/,
|
|
/* [in, out] */ PKEYSVC_BLOB * /*ppReserved*/,
|
|
/* [out] */ ULONG *pulDefType,
|
|
/* [out] */ PKEYSVC_PROVIDER_INFO *ppProvider)
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
ULONG s_KeyrEnroll(
|
|
/* [in] */ handle_t /*hRPCBinding*/,
|
|
/* [in] */ BOOL /*fKeyService*/,
|
|
/* [in] */ ULONG /*ulPurpose*/,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING /*pAcctName*/,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING /*pCALocation*/,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING /*pCAName*/,
|
|
/* [in] */ BOOL /*fNewKey*/,
|
|
/* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW /*pKeyNew*/,
|
|
/* [in] */ PKEYSVC_BLOB __RPC_FAR /*pCert*/,
|
|
/* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW /*pRenewKey*/,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING /*pHashAlg*/,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING /*pDesStore*/,
|
|
/* [in] */ ULONG /*ulStoreFlags*/,
|
|
/* [in] */ PKEYSVC_CERT_ENROLL_INFO /*pRequestInfo*/,
|
|
/* [in] */ ULONG /*ulFlags*/,
|
|
/* [out][in] */ PKEYSVC_BLOB __RPC_FAR * /*ppReserved*/,
|
|
/* [out] */ PKEYSVC_BLOB __RPC_FAR * /*ppPKCS7Blob*/,
|
|
/* [out] */ PKEYSVC_BLOB __RPC_FAR * /*ppHashBlob*/,
|
|
/* [out] */ ULONG __RPC_FAR * /*pulStatus*/)
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
ULONG s_KeyrEnumerateAvailableCertTypes(
|
|
|
|
/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ KEYSVC_HANDLE /*hKeySvc*/,
|
|
/* [in, out] */ PKEYSVC_BLOB * /*ppReserved*/,
|
|
/* [out][in] */ ULONG *pcCertTypeCount,
|
|
/* [in, out][size_is(,*pcCertTypeCount)] */
|
|
PKEYSVC_UNICODE_STRING *ppCertTypes)
|
|
|
|
{
|
|
DWORD dwErr = ERROR_INVALID_DATA;
|
|
HCERTTYPE hType = NULL;
|
|
DWORD cTypes = 0;
|
|
DWORD cTrustedTypes = 0;
|
|
DWORD i;
|
|
LPWSTR *awszTrustedTypes = NULL;
|
|
DWORD cbTrustedTypes = 0;
|
|
PKEYSVC_UNICODE_STRING awszResult = NULL;
|
|
LPWSTR wszCurrentName;
|
|
|
|
__try
|
|
{
|
|
*pcCertTypeCount = 0;
|
|
*ppCertTypes = NULL;
|
|
|
|
dwErr = CAEnumCertTypes(CT_FIND_LOCAL_SYSTEM | CT_ENUM_MACHINE_TYPES, &hType);
|
|
if(dwErr != S_OK)
|
|
{
|
|
goto Ret;
|
|
}
|
|
cTypes = CACountCertTypes(hType);
|
|
|
|
awszTrustedTypes = (LPWSTR *)MyAlloc(sizeof(LPWSTR)*cTypes);
|
|
if(awszTrustedTypes == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
while(hType)
|
|
{
|
|
HCERTTYPE hNextType = NULL;
|
|
LPWSTR *awszTypeName = NULL;
|
|
dwErr = CAGetCertTypeProperty(hType, CERTTYPE_PROP_DN, &awszTypeName);
|
|
if((dwErr == S_OK) && (awszTypeName))
|
|
{
|
|
if(awszTypeName[0])
|
|
{
|
|
dwErr = CACertTypeAccessCheck(hType, NULL);
|
|
if(dwErr == S_OK)
|
|
{
|
|
// SECURITY: can awszTypeName be very large (perhaps the hacker managed to get into the DS and muck with template names).
|
|
// Should we disable allocs over a certain value?
|
|
awszTrustedTypes[cTrustedTypes] = (LPWSTR)MyAlloc((wcslen(awszTypeName[0])+1)*sizeof(WCHAR));
|
|
if(awszTrustedTypes[cTrustedTypes])
|
|
{
|
|
wcscpy(awszTrustedTypes[cTrustedTypes], awszTypeName[0]);
|
|
cbTrustedTypes += (wcslen(awszTypeName[0])+1)*sizeof(WCHAR);
|
|
cTrustedTypes++;
|
|
}
|
|
}
|
|
|
|
}
|
|
CAFreeCertTypeProperty(hType, awszTypeName);
|
|
}
|
|
dwErr = CAEnumNextCertType(hType, &hNextType);
|
|
if(dwErr != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
CACloseCertType(hType);
|
|
hType = hNextType;
|
|
}
|
|
|
|
cbTrustedTypes += sizeof(KEYSVC_UNICODE_STRING)*cTrustedTypes;
|
|
awszResult = (PKEYSVC_UNICODE_STRING)MyAlloc(cbTrustedTypes);
|
|
if(awszResult == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
wszCurrentName = (LPWSTR)(&awszResult[cTrustedTypes]);
|
|
for(i=0; i < cTrustedTypes; i++)
|
|
{
|
|
wcscpy(wszCurrentName, awszTrustedTypes[i]);
|
|
// BUGBUG: we're truncating the template name here. Might be better to filter this out? Are there any security issues here?
|
|
awszResult[i].Length = (WORD)(((wcslen(awszTrustedTypes[i]) + 1)*sizeof(WCHAR)) & 0xFFFF);
|
|
awszResult[i].MaximumLength = awszResult[i].Length;
|
|
awszResult[i].Buffer = wszCurrentName;
|
|
wszCurrentName += wcslen(awszTrustedTypes[i]) + 1;
|
|
}
|
|
|
|
*pcCertTypeCount = cTrustedTypes;
|
|
*ppCertTypes = awszResult;
|
|
awszResult = NULL;
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwErr = _exception_code();
|
|
}
|
|
Ret:
|
|
__try
|
|
{
|
|
if(awszTrustedTypes)
|
|
{
|
|
for(i=0; i < cTrustedTypes; i++)
|
|
{
|
|
if(awszTrustedTypes[i])
|
|
{
|
|
MyFree(awszTrustedTypes[i]);
|
|
}
|
|
}
|
|
MyFree(awszTrustedTypes);
|
|
}
|
|
if(awszResult)
|
|
{
|
|
MyFree(awszResult);
|
|
}
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
|
|
|
|
ULONG s_KeyrEnumerateCAs(
|
|
|
|
/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ KEYSVC_HANDLE /*hKeySvc*/,
|
|
/* [in, out] */ PKEYSVC_BLOB * /*ppReserved*/,
|
|
/* [in] */ ULONG ulFlags,
|
|
/* [out][in] */ ULONG *pcCACount,
|
|
/* [in, out][size_is(,*pcCACount)] */
|
|
PKEYSVC_UNICODE_STRING *ppCAs)
|
|
|
|
{
|
|
DWORD dwErr = ERROR_INVALID_DATA;
|
|
HCAINFO hCA = NULL;
|
|
DWORD cCAs = 0;
|
|
DWORD cTrustedCAs = 0;
|
|
DWORD i;
|
|
LPWSTR *awszTrustedCAs = NULL;
|
|
DWORD cbTrustedCAs = 0;
|
|
PKEYSVC_UNICODE_STRING awszResult = NULL;
|
|
LPWSTR wszCurrentName;
|
|
|
|
__try
|
|
{
|
|
*pcCACount = 0;
|
|
*ppCAs = NULL;
|
|
|
|
dwErr = CAEnumFirstCA(NULL, ulFlags, &hCA);
|
|
|
|
if(dwErr != S_OK)
|
|
{
|
|
goto Ret;
|
|
}
|
|
cCAs = CACountCAs(hCA);
|
|
|
|
awszTrustedCAs = (LPWSTR *)MyAlloc(sizeof(LPWSTR)*cCAs);
|
|
if(awszTrustedCAs == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
while(hCA)
|
|
{
|
|
HCAINFO hNextCA = NULL;
|
|
LPWSTR *awszCAName = NULL;
|
|
dwErr = CAGetCAProperty(hCA, CA_PROP_NAME, &awszCAName);
|
|
if((dwErr == S_OK) && (awszCAName))
|
|
{
|
|
if(awszCAName[0])
|
|
{
|
|
dwErr = CAAccessCheck(hCA, NULL);
|
|
if(dwErr == S_OK)
|
|
{
|
|
awszTrustedCAs[cTrustedCAs] = (LPWSTR)MyAlloc((wcslen(awszCAName[0])+1)*sizeof(WCHAR));
|
|
if(awszTrustedCAs[cTrustedCAs])
|
|
{
|
|
wcscpy(awszTrustedCAs[cTrustedCAs], awszCAName[0]);
|
|
cbTrustedCAs += (wcslen(awszCAName[0])+1)*sizeof(WCHAR);
|
|
cTrustedCAs++;
|
|
}
|
|
}
|
|
|
|
}
|
|
CAFreeCAProperty(hCA, awszCAName);
|
|
}
|
|
dwErr = CAEnumNextCA(hCA, &hNextCA);
|
|
if(dwErr != S_OK)
|
|
{
|
|
break;
|
|
}
|
|
CACloseCA(hCA);
|
|
hCA = hNextCA;
|
|
}
|
|
|
|
cbTrustedCAs += sizeof(KEYSVC_UNICODE_STRING)*cTrustedCAs;
|
|
awszResult = (PKEYSVC_UNICODE_STRING)MyAlloc(cbTrustedCAs);
|
|
if(awszResult == NULL)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
wszCurrentName = (LPWSTR)(&awszResult[cTrustedCAs]);
|
|
for(i=0; i < cTrustedCAs; i++)
|
|
{
|
|
wcscpy(wszCurrentName, awszTrustedCAs[i]);
|
|
// BUGBUG: we're truncating the template name here. Might be better to filter this out? Are there any security issues here?
|
|
awszResult[i].Length = (WORD)(((wcslen(awszTrustedCAs[i]) + 1)*sizeof(WCHAR)) & 0xFFFF);
|
|
awszResult[i].MaximumLength = awszResult[i].Length;
|
|
awszResult[i].Buffer = wszCurrentName;
|
|
wszCurrentName += wcslen(awszTrustedCAs[i]) + 1;
|
|
}
|
|
|
|
|
|
*pcCACount = cTrustedCAs;
|
|
*ppCAs = awszResult;
|
|
awszResult = NULL;
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwErr = _exception_code();
|
|
}
|
|
Ret:
|
|
__try
|
|
{
|
|
if(awszTrustedCAs)
|
|
{
|
|
for(i=0; i < cTrustedCAs; i++)
|
|
{
|
|
if(awszTrustedCAs[i])
|
|
{
|
|
MyFree(awszTrustedCAs[i]);
|
|
}
|
|
}
|
|
MyFree(awszTrustedCAs);
|
|
}
|
|
if(awszResult)
|
|
{
|
|
MyFree(awszResult);
|
|
}
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
return dwErr;
|
|
}
|
|
|
|
ULONG s_KeyrEnroll_V2
|
|
(/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ BOOL fKeyService,
|
|
/* [in] */ ULONG ulPurpose,
|
|
/* [in] */ ULONG ulFlags,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING pAcctName,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING pCALocation,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING pCAName,
|
|
/* [in] */ BOOL fNewKey,
|
|
/* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW_V2 pKeyNew,
|
|
/* [in] */ PKEYSVC_BLOB __RPC_FAR pCert,
|
|
/* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW_V2 pRenewKey,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING pHashAlg,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING pDesStore,
|
|
/* [in] */ ULONG ulStoreFlags,
|
|
/* [in] */ PKEYSVC_CERT_ENROLL_INFO pRequestInfo,
|
|
/* [in] */ ULONG /*ulReservedFlags*/,
|
|
/* [out][in] */ PKEYSVC_BLOB __RPC_FAR * /*ppReserved*/,
|
|
/* [out][in] */ PKEYSVC_BLOB __RPC_FAR *ppRequest,
|
|
/* [out] */ PKEYSVC_BLOB __RPC_FAR *ppPKCS7Blob,
|
|
/* [out] */ PKEYSVC_BLOB __RPC_FAR *ppHashBlob,
|
|
/* [out] */ ULONG __RPC_FAR *pulStatus)
|
|
{
|
|
CERT_REQUEST_PVK_NEW KeyNew;
|
|
CERT_REQUEST_PVK_NEW RenewKey;
|
|
DWORD cbExtensions;
|
|
PBYTE pbExtensions = NULL;
|
|
PCERT_REQUEST_PVK_NEW pTmpRenewKey = NULL;
|
|
PCERT_REQUEST_PVK_NEW pTmpKeyNew = NULL;
|
|
LPWSTR pwszProv = NULL;
|
|
LPWSTR pwszCont = NULL;
|
|
LPWSTR pwszRenewProv = NULL;
|
|
LPWSTR pwszRenewCont = NULL;
|
|
LPWSTR pwszDesStore = NULL;
|
|
LPWSTR pwszAttributes = NULL;
|
|
LPWSTR pwszFriendly = NULL;
|
|
LPWSTR pwszDescription = NULL;
|
|
LPWSTR pwszUsage = NULL;
|
|
LPWSTR pwszCALocation = NULL;
|
|
LPWSTR pwszCertDNName = NULL;
|
|
LPWSTR pwszCAName = NULL;
|
|
LPWSTR pwszHashAlg = NULL;
|
|
CERT_BLOB CertBlob;
|
|
CERT_BLOB *pCertBlob = NULL;
|
|
CERT_BLOB PKCS7Blob;
|
|
CERT_BLOB HashBlob;
|
|
CERT_ENROLL_INFO EnrollInfo;
|
|
DWORD dwErr = 0;
|
|
HANDLE hRequest = *ppRequest;
|
|
KEYSVC_BLOB ReservedBlob;
|
|
BOOL fCreateRequest = 0 == (ulFlags & (CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY));
|
|
BOOL fFreeRequest = 0 == (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY));
|
|
BOOL fSubmitRequest = 0 == (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY));
|
|
|
|
__try
|
|
{
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// INITIALIZATION:
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
memset(&KeyNew, 0, sizeof(KeyNew));
|
|
memset(&RenewKey, 0, sizeof(RenewKey));
|
|
memset(&EnrollInfo, 0, sizeof(EnrollInfo));
|
|
memset(&PKCS7Blob, 0, sizeof(PKCS7Blob));
|
|
memset(&HashBlob, 0, sizeof(HashBlob));
|
|
memset(&CertBlob, 0, sizeof(CertBlob));
|
|
memset(&ReservedBlob, 0, sizeof(ReservedBlob));
|
|
|
|
*ppPKCS7Blob = NULL;
|
|
*ppHashBlob = NULL;
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// INPUT VALIDATION:
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
BOOL fValidInput = TRUE;
|
|
|
|
fValidInput &= fCreateRequest || fSubmitRequest || fFreeRequest;
|
|
|
|
switch (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY))
|
|
{
|
|
case CRYPTUI_WIZ_CREATE_ONLY:
|
|
fValidInput &= NULL == *ppRequest;
|
|
break;
|
|
|
|
case CRYPTUI_WIZ_SUBMIT_ONLY:
|
|
case CRYPTUI_WIZ_FREE_ONLY:
|
|
fValidInput &= NULL != *ppRequest;
|
|
break;
|
|
|
|
case 0:
|
|
default:
|
|
;
|
|
}
|
|
|
|
if (FALSE == fValidInput)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto Ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// PROCEDURE BODY:
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// if enrolling for a service account then need to logon and load profile
|
|
if (0 != pAcctName->Length)
|
|
{
|
|
dwErr = ERROR_NOT_SUPPORTED;
|
|
goto Ret;
|
|
}
|
|
|
|
// assign all the values in the passed in structure to the
|
|
// temporary structure
|
|
KeyNew.dwSize = sizeof(CERT_REQUEST_PVK_NEW);
|
|
KeyNew.dwProvType = pKeyNew->ulProvType;
|
|
if (0 != (dwErr = AllocAndAssignString(&pKeyNew->Provider,
|
|
&pwszProv)))
|
|
goto Ret;
|
|
KeyNew.pwszProvider = pwszProv;
|
|
KeyNew.dwProviderFlags = pKeyNew->ulProviderFlags;
|
|
if (0 != (dwErr = AllocAndAssignString(&pKeyNew->KeyContainer,
|
|
&pwszCont)))
|
|
goto Ret;
|
|
KeyNew.pwszKeyContainer = pwszCont;
|
|
KeyNew.dwKeySpec = pKeyNew->ulKeySpec;
|
|
KeyNew.dwGenKeyFlags = pKeyNew->ulGenKeyFlags;
|
|
KeyNew.dwEnrollmentFlags = pKeyNew->ulEnrollmentFlags;
|
|
KeyNew.dwSubjectNameFlags = pKeyNew->ulSubjectNameFlags;
|
|
KeyNew.dwPrivateKeyFlags = pKeyNew->ulPrivateKeyFlags;
|
|
KeyNew.dwGeneralFlags = pKeyNew->ulGeneralFlags;
|
|
|
|
pTmpKeyNew = &KeyNew;
|
|
|
|
if (pCert->cb)
|
|
{
|
|
// if necessary assign the cert to be renewed values
|
|
// temporary structure
|
|
CertBlob.cbData = pCert->cb;
|
|
CertBlob.pbData = pCert->pb;
|
|
|
|
pCertBlob = &CertBlob;
|
|
}
|
|
|
|
if (CRYPTUI_WIZ_CERT_RENEW == ulPurpose)
|
|
{
|
|
// assign all the values in the passed in structure to the
|
|
// temporary structure
|
|
RenewKey.dwSize = sizeof(CERT_REQUEST_PVK_NEW);
|
|
RenewKey.dwProvType = pRenewKey->ulProvType;
|
|
if (0 != (dwErr = AllocAndAssignString(&pRenewKey->Provider,
|
|
&pwszRenewProv)))
|
|
goto Ret;
|
|
RenewKey.pwszProvider = pwszRenewProv;
|
|
RenewKey.dwProviderFlags = pRenewKey->ulProviderFlags;
|
|
if (0 != (dwErr = AllocAndAssignString(&pRenewKey->KeyContainer,
|
|
&pwszRenewCont)))
|
|
goto Ret;
|
|
RenewKey.pwszKeyContainer = pwszRenewCont;
|
|
RenewKey.dwKeySpec = pRenewKey->ulKeySpec;
|
|
RenewKey.dwGenKeyFlags = pRenewKey->ulGenKeyFlags;
|
|
RenewKey.dwEnrollmentFlags = pRenewKey->ulEnrollmentFlags;
|
|
RenewKey.dwSubjectNameFlags = pRenewKey->ulSubjectNameFlags;
|
|
RenewKey.dwPrivateKeyFlags = pRenewKey->ulPrivateKeyFlags;
|
|
RenewKey.dwGeneralFlags = pRenewKey->ulGeneralFlags;
|
|
|
|
pTmpRenewKey = &RenewKey;
|
|
}
|
|
|
|
// For SUBMIT and FREE operations, hRequest is an IN parameter.
|
|
if (0 != ((CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY) & ulFlags))
|
|
{
|
|
memcpy(&hRequest, (*ppRequest)->pb, sizeof(hRequest));
|
|
}
|
|
|
|
// check if the destination cert store was passed in
|
|
if (0 != (dwErr = AllocAndAssignString(pDesStore, &pwszDesStore)))
|
|
goto Ret;
|
|
|
|
// copy over the request info
|
|
EnrollInfo.dwSize = sizeof(EnrollInfo);
|
|
if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->UsageOID,
|
|
&pwszUsage)))
|
|
goto Ret;
|
|
EnrollInfo.pwszUsageOID = pwszUsage;
|
|
|
|
if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->CertDNName,
|
|
&pwszCertDNName)))
|
|
goto Ret;
|
|
EnrollInfo.pwszCertDNName = pwszCertDNName;
|
|
|
|
// cast the cert extensions
|
|
EnrollInfo.dwExtensions = pRequestInfo->cExtensions;
|
|
cbExtensions = (sizeof(CERT_EXTENSIONS)+sizeof(PCERT_EXTENSIONS)) * pRequestInfo->cExtensions;
|
|
for (DWORD dwIndex = 0; dwIndex < pRequestInfo->cExtensions; dwIndex++)
|
|
{
|
|
cbExtensions += sizeof(CERT_EXTENSION) *
|
|
pRequestInfo->prgExtensions[dwIndex]->cExtension;
|
|
}
|
|
|
|
EnrollInfo.prgExtensions = (PCERT_EXTENSIONS *)MyAlloc(cbExtensions);
|
|
if (NULL == EnrollInfo.prgExtensions)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
pbExtensions = (PBYTE)(EnrollInfo.prgExtensions + EnrollInfo.dwExtensions);
|
|
for (DWORD dwIndex = 0; dwIndex < EnrollInfo.dwExtensions; dwIndex++)
|
|
{
|
|
EnrollInfo.prgExtensions[dwIndex] = (PCERT_EXTENSIONS)pbExtensions;
|
|
pbExtensions += sizeof(CERT_EXTENSIONS);
|
|
EnrollInfo.prgExtensions[dwIndex]->cExtension = pRequestInfo->prgExtensions[dwIndex]->cExtension;
|
|
EnrollInfo.prgExtensions[dwIndex]->rgExtension = (PCERT_EXTENSION)pbExtensions;
|
|
pbExtensions += sizeof(CERT_EXTENSION) * EnrollInfo.prgExtensions[dwIndex]->cExtension;
|
|
|
|
for (DWORD dwSubIndex = 0; dwSubIndex < EnrollInfo.prgExtensions[dwIndex]->cExtension; dwSubIndex++)
|
|
{
|
|
EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].pszObjId =
|
|
pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].pszObjId;
|
|
|
|
EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].fCritical =
|
|
pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].fCritical;
|
|
|
|
EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].Value.cbData =
|
|
pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].cbData;
|
|
|
|
EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].Value.pbData =
|
|
pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].pbData;
|
|
}
|
|
}
|
|
|
|
EnrollInfo.dwPostOption = pRequestInfo->ulPostOption;
|
|
if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->FriendlyName,
|
|
&pwszFriendly)))
|
|
goto Ret;
|
|
EnrollInfo.pwszFriendlyName = pwszFriendly;
|
|
if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->Description,
|
|
&pwszDescription)))
|
|
goto Ret;
|
|
EnrollInfo.pwszDescription = pwszDescription;
|
|
|
|
if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->Attributes,
|
|
&pwszAttributes)))
|
|
goto Ret;
|
|
|
|
if (0 != (dwErr = AllocAndAssignString(pHashAlg,
|
|
&pwszHashAlg)))
|
|
goto Ret;
|
|
if (0 != (dwErr = AllocAndAssignString(pCALocation,
|
|
&pwszCALocation)))
|
|
goto Ret;
|
|
if (0 != (dwErr = AllocAndAssignString(pCAName,
|
|
&pwszCAName)))
|
|
goto Ret;
|
|
|
|
// call the local enrollment API
|
|
|
|
__try {
|
|
dwErr = LocalEnrollNoDS(ulFlags, pwszAttributes, NULL, fKeyService,
|
|
ulPurpose, FALSE, 0, NULL, 0, pwszCALocation,
|
|
pwszCAName, pCertBlob, pTmpRenewKey, fNewKey,
|
|
pTmpKeyNew, pwszHashAlg, pwszDesStore, ulStoreFlags,
|
|
&EnrollInfo, &PKCS7Blob, &HashBlob, pulStatus, &hRequest);
|
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
// TODO: convert to Winerror
|
|
dwErr = GetExceptionCode();
|
|
}
|
|
|
|
if( dwErr != 0 )
|
|
goto Ret;
|
|
|
|
// Assign OUT parameters based on what kind of request we've just made.
|
|
// Possible requests are:
|
|
//
|
|
// 1) CREATE only // Assign "ppRequest" to contain a HANDLE to the cert request.
|
|
// 2) SUBMIT only // Assign "ppPKCS7Blob" and "ppHashBlob" to the values returned from LocalEnrollNoDS()
|
|
// 3) FREE only // No need to assign OUT params.
|
|
// 4) Complete (all 3).
|
|
switch (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY))
|
|
{
|
|
case CRYPTUI_WIZ_CREATE_ONLY:
|
|
// We've done the request creation portion of a 3-stage request,
|
|
// assign the "request" out parameter now:
|
|
if (NULL == (*ppRequest = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB)+
|
|
sizeof(hRequest))))
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
(*ppRequest)->cb = sizeof(hRequest);
|
|
(*ppRequest)->pb = (BYTE*)(*ppRequest) + sizeof(KEYSVC_BLOB);
|
|
memcpy((*ppRequest)->pb, &hRequest, sizeof(hRequest));
|
|
|
|
break;
|
|
|
|
case CRYPTUI_WIZ_SUBMIT_ONLY:
|
|
case 0:
|
|
// We've done the request submittal portion of a 3-stage request,
|
|
// or we've done a 1-stage request. Assign the "certificate" out parameters now:
|
|
|
|
// alloc and copy for the RPC out parameters
|
|
if (NULL == (*ppPKCS7Blob = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB) +
|
|
PKCS7Blob.cbData)))
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
(*ppPKCS7Blob)->cb = PKCS7Blob.cbData;
|
|
(*ppPKCS7Blob)->pb = (BYTE*)(*ppPKCS7Blob) + sizeof(KEYSVC_BLOB);
|
|
memcpy((*ppPKCS7Blob)->pb, PKCS7Blob.pbData, (*ppPKCS7Blob)->cb);
|
|
|
|
if (NULL == (*ppHashBlob = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB) +
|
|
HashBlob.cbData)))
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
(*ppHashBlob)->cb = HashBlob.cbData;
|
|
(*ppHashBlob)->pb = (BYTE*)(*ppHashBlob) + sizeof(KEYSVC_BLOB);
|
|
memcpy((*ppHashBlob)->pb, HashBlob.pbData, (*ppHashBlob)->cb);
|
|
|
|
break;
|
|
|
|
case CRYPTUI_WIZ_FREE_ONLY:
|
|
default:
|
|
*ppRequest = NULL;
|
|
break;
|
|
}
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto Ret;
|
|
}
|
|
Ret:
|
|
__try
|
|
{
|
|
if (pwszProv)
|
|
MyFree(pwszProv);
|
|
if (pwszCont)
|
|
MyFree(pwszCont);
|
|
if (pwszRenewProv)
|
|
MyFree(pwszRenewProv);
|
|
if (pwszRenewCont)
|
|
MyFree(pwszRenewCont);
|
|
if (pwszDesStore)
|
|
MyFree(pwszDesStore);
|
|
if (pwszAttributes)
|
|
MyFree(pwszAttributes);
|
|
if (pwszFriendly)
|
|
MyFree(pwszFriendly);
|
|
if (pwszDescription)
|
|
MyFree(pwszDescription);
|
|
if (pwszUsage)
|
|
MyFree(pwszUsage);
|
|
if (pwszCertDNName)
|
|
MyFree(pwszCertDNName);
|
|
if (pwszCAName)
|
|
MyFree(pwszCAName);
|
|
if (pwszCALocation)
|
|
MyFree(pwszCALocation);
|
|
if (pwszHashAlg)
|
|
MyFree(pwszHashAlg);
|
|
if (PKCS7Blob.pbData)
|
|
{
|
|
MyFree(PKCS7Blob.pbData);
|
|
}
|
|
if (HashBlob.pbData)
|
|
{
|
|
MyFree(HashBlob.pbData);
|
|
}
|
|
if (EnrollInfo.prgExtensions)
|
|
MyFree(EnrollInfo.prgExtensions);
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
}
|
|
return dwErr;
|
|
}
|
|
|
|
ULONG s_KeyrQueryRequestStatus
|
|
(/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ unsigned __int64 u64Request,
|
|
/* [out, ref] */ KEYSVC_QUERY_CERT_REQUEST_INFO *pQueryInfo)
|
|
|
|
{
|
|
CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO QueryInfo;
|
|
DWORD dwErr = 0;
|
|
HANDLE hRequest = (HANDLE)u64Request;
|
|
|
|
__try
|
|
{
|
|
// We have the permission necessary to query the request. Proceed.
|
|
ZeroMemory(&QueryInfo, sizeof(QueryInfo));
|
|
|
|
// Query the request.
|
|
dwErr = LocalEnrollNoDS(CRYPTUI_WIZ_QUERY_ONLY, NULL, &QueryInfo, FALSE, 0, FALSE, NULL, NULL,
|
|
0, NULL, NULL, NULL, NULL, FALSE, NULL, NULL, NULL,
|
|
0, NULL, NULL, NULL, NULL, &hRequest);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
goto Ret;
|
|
}
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto Ret;
|
|
}
|
|
|
|
pQueryInfo->ulSize = QueryInfo.dwSize;
|
|
pQueryInfo->ulStatus = QueryInfo.dwStatus;
|
|
Ret:
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
ULONG s_RKeyrPFXInstall
|
|
(/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ PKEYSVC_BLOB pPFX,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING pPassword,
|
|
/* [in] */ ULONG ulFlags)
|
|
|
|
{
|
|
BOOL fIsImpersonatingClient = FALSE;
|
|
CRYPT_DATA_BLOB PFXBlob;
|
|
DWORD dwCertOpenStoreFlags;
|
|
DWORD dwData;
|
|
DWORD dwResult;
|
|
HCERTSTORE hSrcStore = NULL;
|
|
HCERTSTORE hCAStore = NULL;
|
|
HCERTSTORE hMyStore = NULL;
|
|
HCERTSTORE hRootStore = NULL;
|
|
LPWSTR pwszPassword = NULL;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
|
|
struct Stores {
|
|
HANDLE *phStore;
|
|
LPCWSTR pwszStoreName;
|
|
} rgStores[] = {
|
|
{ &hMyStore, L"my" },
|
|
{ &hCAStore, L"ca" },
|
|
{ &hRootStore, L"root" }
|
|
};
|
|
|
|
__try
|
|
{
|
|
// Initialize locals:
|
|
PFXBlob.cbData = pPFX->cb;
|
|
PFXBlob.pbData = pPFX->pb;
|
|
|
|
switch (ulFlags & (CRYPT_MACHINE_KEYSET | CRYPT_USER_KEYSET))
|
|
{
|
|
case CRYPT_MACHINE_KEYSET:
|
|
dwCertOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
|
|
break;
|
|
|
|
case CRYPT_USER_KEYSET: // not supported
|
|
default:
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
goto error;
|
|
}
|
|
|
|
dwResult = RpcImpersonateClient(hRPCBinding);
|
|
if (RPC_S_OK != dwResult)
|
|
goto error;
|
|
fIsImpersonatingClient = TRUE;
|
|
|
|
if (ERROR_SUCCESS != (dwResult = AllocAndAssignString((PKEYSVC_UNICODE_STRING)pPassword, &pwszPassword)))
|
|
goto error;
|
|
|
|
// Get an in-memory store which contains all of the certs in the PFX
|
|
// blob.
|
|
if (NULL == (hSrcStore = PFXImportCertStore(&PFXBlob, pwszPassword, ulFlags)))
|
|
{
|
|
dwResult = GetLastError();
|
|
goto error;
|
|
}
|
|
|
|
// Open the stores we'll need:
|
|
for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStores); dwIndex++)
|
|
{
|
|
*(rgStores[dwIndex].phStore) = CertOpenStore
|
|
(CERT_STORE_PROV_SYSTEM_W, // store provider type
|
|
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, // cert encoding type
|
|
NULL, // hCryptProv
|
|
dwCertOpenStoreFlags, // open store flags
|
|
rgStores[dwIndex].pwszStoreName // store name
|
|
);
|
|
if (NULL == *(rgStores[dwIndex].phStore))
|
|
{
|
|
dwResult = GetLastError();
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
// Enumerate the certs in the in-memory store, and add them to the local machine's
|
|
// "my" store. NOTE: CertEnumCertificatesInStore frees the previous cert context
|
|
// before returning the new context.
|
|
while (NULL != (pCertContext = CertEnumCertificatesInStore(hSrcStore, pCertContext)))
|
|
{
|
|
HCERTSTORE hCertStore;
|
|
|
|
// check if the certificate has the property on it
|
|
// make sure the private key matches the certificate
|
|
// search for both machine key and user keys
|
|
if (CertGetCertificateContextProperty
|
|
(pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&dwData) &&
|
|
CryptFindCertificateKeyProvInfo
|
|
(pCertContext,
|
|
0,
|
|
NULL))
|
|
{
|
|
hCertStore = hMyStore;
|
|
}
|
|
else if (TrustIsCertificateSelfSigned
|
|
(pCertContext,
|
|
pCertContext->dwCertEncodingType,
|
|
0))
|
|
{
|
|
hCertStore = hRootStore;
|
|
}
|
|
else
|
|
{
|
|
hCertStore = hCAStore;
|
|
}
|
|
|
|
if (!CertAddCertificateContextToStore
|
|
(hCertStore,
|
|
pCertContext,
|
|
CERT_STORE_ADD_NEW,
|
|
NULL))
|
|
{
|
|
dwResult = GetLastError();
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwResult = GetExceptionCode();
|
|
goto error;
|
|
}
|
|
|
|
// We're done!
|
|
dwResult = ERROR_SUCCESS;
|
|
error:
|
|
if (fIsImpersonatingClient) { MyRpcRevertToSelfEx(hRPCBinding); }
|
|
if (NULL != hSrcStore) { CertCloseStore(hSrcStore, 0); }
|
|
|
|
// Close all of the destination stores we've opened.
|
|
for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStores); dwIndex++)
|
|
if (NULL != *(rgStores[dwIndex].phStore))
|
|
CertCloseStore(*(rgStores[dwIndex].phStore), 0);
|
|
|
|
if (NULL != pwszPassword) { MyFree(pwszPassword); }
|
|
if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); }
|
|
return dwResult;
|
|
}
|
|
|
|
ULONG s_RKeyrOpenKeyService(
|
|
/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ KEYSVC_TYPE OwnerType,
|
|
/* [in] */ PKEYSVC_UNICODE_STRING pOwnerName,
|
|
/* [in] */ ULONG ulDesiredAccess,
|
|
/* [in] */ PKEYSVC_BLOB pAuthentication,
|
|
/* [in, out] */ PKEYSVC_BLOB *ppReserved,
|
|
/* [out] */ KEYSVC_HANDLE *phKeySvc)
|
|
{
|
|
return s_KeyrOpenKeyService
|
|
(hRPCBinding,
|
|
OwnerType,
|
|
pOwnerName,
|
|
ulDesiredAccess,
|
|
pAuthentication,
|
|
ppReserved,
|
|
phKeySvc);
|
|
}
|
|
|
|
ULONG s_RKeyrCloseKeyService(
|
|
/* [in] */ handle_t hRPCBinding,
|
|
/* [in] */ KEYSVC_HANDLE hKeySvc,
|
|
/* [in, out] */ PKEYSVC_BLOB *ppReserved)
|
|
{
|
|
return s_KeyrCloseKeyService
|
|
(hRPCBinding,
|
|
hKeySvc,
|
|
ppReserved);
|
|
}
|