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.
12798 lines
368 KiB
12798 lines
368 KiB
//depot/Lab03_DEV/Ds/security/cryptoapi/pki/activex/xenroll/cenroll.cpp#4 - edit change 19979 (text)
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: cenroll.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
// CEnroll.cpp : Implementation of CCEnroll
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
#include <unicode.h>
|
|
#define SECURITY_WIN32
|
|
#include <security.h>
|
|
#include <aclapi.h>
|
|
#include <pvk.h>
|
|
#include <wintrust.h>
|
|
#include <xasn.h>
|
|
#include <autoenr.h>
|
|
#include <sddl.h>
|
|
|
|
#include "xenroll.h"
|
|
#include "cenroll.h"
|
|
#include "xelib.h"
|
|
#include "sfscript.h"
|
|
|
|
#define NO_OSS_DEBUG
|
|
#include <dbgdef.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
static LPVOID (* MyCoTaskMemAlloc)(ULONG) = NULL;
|
|
static LPVOID (* MyCoTaskMemRealloc)(LPVOID, ULONG) = NULL;
|
|
static void (* MyCoTaskMemFree)(LPVOID) = NULL;
|
|
|
|
#define MY_HRESULT_FROM_WIN32(a) ((a >= 0x80000000) ? a : HRESULT_FROM_WIN32(a))
|
|
|
|
#ifndef NTE_TOKEN_KEYSET_STORAGE_FULL
|
|
#define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L)
|
|
#endif
|
|
|
|
#define CEnrollLocalScope(ScopeName) struct ScopeName##TheLocalScope { public
|
|
#define CEnrollEndLocalScope } local
|
|
|
|
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
#pragma warning(disable:4213) // nonstandard extension used : cast on l-value
|
|
|
|
|
|
static LPSTR MBFromWide(LPCWSTR wsz) {
|
|
|
|
LPSTR sz = NULL;
|
|
DWORD cb = 0;
|
|
|
|
assert(wsz != NULL);
|
|
if(wsz == NULL) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(NULL);
|
|
}
|
|
|
|
if( (cb = WideCharToMultiByte(0, 0, wsz, -1, NULL, 0, NULL, NULL)) == 0 ||
|
|
(sz = (char *) MyCoTaskMemAlloc(cb)) == NULL ||
|
|
(cb = WideCharToMultiByte(0, 0, wsz, -1, sz, cb, NULL, NULL)) == 0 ) {
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
return(sz);
|
|
}
|
|
|
|
static LPWSTR WideFromMB(LPCSTR sz) {
|
|
|
|
DWORD cch = 0;
|
|
LPWSTR wsz = NULL;
|
|
|
|
assert(sz != NULL);
|
|
if(sz == NULL) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(NULL);
|
|
}
|
|
|
|
if( (cch = MultiByteToWideChar(0, 0, sz, -1, NULL, 0)) == 0 ||
|
|
(wsz = (WCHAR *) MyCoTaskMemAlloc(cch * sizeof(WCHAR))) == NULL ||
|
|
(cch = MultiByteToWideChar(0, 0, sz, -1, wsz, cch)) == 0) {
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
return(wsz);
|
|
}
|
|
|
|
static BSTR
|
|
BSTRFromMB(LPCSTR sz)
|
|
{
|
|
BSTR bstr = NULL;
|
|
DWORD cch = 0;
|
|
WCHAR *pwsz = NULL;
|
|
BOOL fFail = FALSE;
|
|
|
|
assert(sz != NULL);
|
|
if(sz == NULL) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(NULL);
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
if(0 == (cch = MultiByteToWideChar(0, 0, sz, -1, pwsz, cch)))
|
|
{
|
|
//error
|
|
fFail = TRUE;
|
|
break;
|
|
}
|
|
if (NULL != pwsz)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pwsz = (WCHAR *)LocalAlloc(LMEM_FIXED, cch * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
//error
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fFail && NULL != pwsz)
|
|
{
|
|
bstr = SysAllocString(pwsz);
|
|
if (NULL == bstr)
|
|
{
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
}
|
|
}
|
|
|
|
if (NULL != pwsz)
|
|
{
|
|
LocalFree(pwsz);
|
|
}
|
|
return(bstr);
|
|
}
|
|
|
|
static LPWSTR CopyWideString(LPCWSTR wsz) {
|
|
|
|
size_t cch = 0;
|
|
LPWSTR wszOut = NULL;
|
|
|
|
// shouldn't send in a NULL
|
|
assert(wsz != NULL);
|
|
if(wsz == NULL) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(NULL);
|
|
}
|
|
|
|
cch = wcslen(wsz) + 1;
|
|
if (cch*sizeof(WCHAR) > (ULONG)-1) {
|
|
// prevent errors caused by conversion from size_t --> ULONG
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
if( (wszOut = (LPWSTR) MyCoTaskMemAlloc((ULONG)(sizeof(WCHAR) * cch))) == NULL ) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(NULL);
|
|
}
|
|
|
|
wcscpy(wszOut, wsz);
|
|
|
|
return(wszOut);
|
|
}
|
|
|
|
static LPSTR CopyAsciiString(LPCSTR sz) {
|
|
|
|
size_t cch = 0;
|
|
LPSTR szOut = NULL;
|
|
|
|
// shouldn't send in a NULL
|
|
assert(sz != NULL);
|
|
if(sz == NULL) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(NULL);
|
|
}
|
|
|
|
cch = strlen(sz) + 1;
|
|
if (cch > (ULONG)-1) {
|
|
// prevent errors caused by conversion from size_t --> ULONG
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
if( (szOut = (LPSTR) MyCoTaskMemAlloc((ULONG)cch)) == NULL ) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(NULL);
|
|
}
|
|
|
|
strcpy(szOut, sz);
|
|
|
|
return(szOut);
|
|
}
|
|
|
|
static DWORD KeyLocationFromStoreLocation(DWORD dwStoreFlags) {
|
|
|
|
if(
|
|
((CERT_SYSTEM_STORE_LOCATION_MASK & dwStoreFlags) == CERT_SYSTEM_STORE_CURRENT_USER) ||
|
|
((CERT_SYSTEM_STORE_LOCATION_MASK & dwStoreFlags) == CERT_SYSTEM_STORE_USERS) ||
|
|
((CERT_SYSTEM_STORE_LOCATION_MASK & dwStoreFlags) == CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY)
|
|
) {
|
|
return(0);
|
|
}
|
|
|
|
// CERT_SYSTEM_STORE_LOCAL_MACHINE
|
|
// CERT_SYSTEM_STORE_DOMAIN_POLICY
|
|
// CERT_SYSTEM_STORE_CURRENT_SERVICE
|
|
// CERT_SYSTEM_STORE_SERVICES
|
|
// CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
|
|
|
|
return(CRYPT_MACHINE_KEYSET);
|
|
}
|
|
|
|
//modified from myLoadRCString from ca
|
|
HRESULT
|
|
xeLoadRCString(
|
|
IN HINSTANCE hInstance,
|
|
IN int iRCId,
|
|
OUT WCHAR **ppwsz)
|
|
{
|
|
#define REALLOCATEBLOCK 512
|
|
HRESULT hr;
|
|
WCHAR *pwszTemp = NULL;
|
|
int sizeTemp;
|
|
int size = 0;
|
|
int cBlocks = 1;
|
|
|
|
*ppwsz = NULL;
|
|
|
|
while (NULL == pwszTemp)
|
|
{
|
|
sizeTemp = cBlocks * REALLOCATEBLOCK;
|
|
pwszTemp = (WCHAR*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeTemp * sizeof(WCHAR));
|
|
if (NULL == pwszTemp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
|
|
size = LoadStringU(
|
|
hInstance,
|
|
iRCId,
|
|
pwszTemp,
|
|
sizeTemp);
|
|
if (0 == size)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto LoadStringError;
|
|
}
|
|
|
|
if (size < sizeTemp - 1)
|
|
{
|
|
// ok, size is big enough
|
|
break;
|
|
}
|
|
++cBlocks;
|
|
LocalFree(pwszTemp);
|
|
pwszTemp = NULL;
|
|
}
|
|
|
|
*ppwsz = (WCHAR*) LocalAlloc(LPTR, (size+1) * sizeof(WCHAR));
|
|
if (NULL == *ppwsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
// copy it
|
|
wcscpy(*ppwsz, pwszTemp);
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pwszTemp)
|
|
{
|
|
LocalFree(pwszTemp);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(LocalAllocError)
|
|
TRACE_ERROR(LoadStringError)
|
|
}
|
|
|
|
HANDLE CCEnroll::CreateOpenFileSafely2(
|
|
LPCWSTR pwszFileName,
|
|
DWORD idsCreate,
|
|
DWORD idsOverwrite)
|
|
{
|
|
HANDLE hFile = NULL;
|
|
WCHAR *pwszMsg = NULL;
|
|
WCHAR *pwszFormat = NULL;
|
|
WCHAR *pwszTitle = NULL;
|
|
WCHAR *pwszSafety = NULL;
|
|
DWORD dwAttribs = 0;
|
|
BOOL fNotProperFile;
|
|
|
|
LPCWSTR apwszInsertArray[2];
|
|
BOOL fNo;
|
|
BOOL fMsgBox;
|
|
int idPrefix = IDS_NOTSAFE_WRITE_PREFIX; //default to write prefix
|
|
BOOL fCreate = (0xFFFFFFFF != idsCreate) &&
|
|
(0xFFFFFFFF != idsOverwrite);
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
fMsgBox = (m_dwEnabledSafteyOptions != 0);
|
|
dwAttribs = GetFileAttributesU(pwszFileName);
|
|
|
|
if(0xFFFFFFFF == dwAttribs)
|
|
{
|
|
//file doesn't exist
|
|
if (!fCreate)
|
|
{
|
|
//try to read a non-existing file
|
|
//for safety reasons, don't return system error
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
goto InvalidFileError;
|
|
}
|
|
//if got here, write a new file
|
|
if (fMsgBox)
|
|
{
|
|
hr = xeLoadRCString(hInstanceXEnroll, idsCreate, &pwszFormat);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//file exists, check if a proper file to write or read
|
|
//in either write or read, the following file attrib not proper
|
|
fNotProperFile =
|
|
(dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ||
|
|
(dwAttribs & FILE_ATTRIBUTE_HIDDEN) ||
|
|
(dwAttribs & FILE_ATTRIBUTE_SYSTEM);
|
|
|
|
if (!fNotProperFile)
|
|
{
|
|
//so far so good
|
|
if (fCreate)
|
|
{
|
|
//write a file
|
|
if (0x0 != (dwAttribs & FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
//don't take read-only and archive
|
|
fNotProperFile = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//try to overwrite existing file
|
|
hr = xeLoadRCString(hInstanceXEnroll, idsOverwrite, &pwszFormat);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
//enforce popup if overwrite
|
|
fMsgBox = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//read an existing file always violate scripting safety
|
|
//it allows detecting file existence
|
|
//put out a warning
|
|
fMsgBox = TRUE;
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_OPEN, &pwszFormat);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
idPrefix = IDS_NOTSAFE_OPEN_PREFIX;
|
|
}
|
|
}
|
|
|
|
if (fNotProperFile)
|
|
{
|
|
//for safety reasons, don't return system error
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
goto InvalidFileError;
|
|
}
|
|
}
|
|
|
|
if (fMsgBox)
|
|
{
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
hr = xeLoadRCString(hInstanceXEnroll, idPrefix, &pwszSafety);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
|
|
apwszInsertArray[0] = pwszSafety;
|
|
apwszInsertArray[1] = pwszFileName;
|
|
|
|
if (!FormatMessageU(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pwszFormat,
|
|
0,
|
|
0,
|
|
(LPWSTR) &pwszMsg,
|
|
0,
|
|
(va_list *)apwszInsertArray))
|
|
{
|
|
goto FormatMessageError;
|
|
}
|
|
|
|
fNo = (MessageBoxU(
|
|
NULL,
|
|
pwszMsg,
|
|
pwszTitle,
|
|
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES);
|
|
|
|
if(fNo)
|
|
{
|
|
SetLastError(ERROR_CANCELLED);
|
|
goto CancelError;
|
|
}
|
|
}
|
|
|
|
hFile = CreateFileU(
|
|
pwszFileName,
|
|
fCreate ? GENERIC_WRITE : GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
fCreate ? CREATE_ALWAYS : OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE || hFile == NULL)
|
|
{
|
|
//don't return system error so keep xenroll relative safe for scripting
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
hFile = NULL;
|
|
goto CreateFileUError;
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
if(NULL != pwszMsg)
|
|
{
|
|
LocalFree(pwszMsg);
|
|
}
|
|
if(NULL != pwszFormat)
|
|
{
|
|
LocalFree(pwszFormat);
|
|
}
|
|
if(NULL != pwszTitle)
|
|
{
|
|
LocalFree(pwszTitle);
|
|
}
|
|
if(NULL != pwszSafety)
|
|
{
|
|
LocalFree(pwszSafety);
|
|
}
|
|
return(hFile);
|
|
|
|
TRACE_ERROR(CreateFileUError)
|
|
TRACE_ERROR(FormatMessageError);
|
|
TRACE_ERROR(CancelError)
|
|
TRACE_ERROR(InvalidFileError)
|
|
TRACE_ERROR(xeLoadRCStringError)
|
|
}
|
|
|
|
HANDLE CCEnroll::CreateOpenFileSafely(
|
|
LPCWSTR pwszFileName,
|
|
BOOL fCreate)
|
|
{
|
|
HANDLE hFile = NULL;
|
|
WCHAR *pwszMsg = NULL;
|
|
DWORD dwAttribs = 0;
|
|
BOOL fNotProperFile;
|
|
|
|
WCHAR *pwszFormat = NULL;
|
|
WCHAR *pwszTitle = NULL;
|
|
LPCWSTR apwszInsertArray[] = {pwszFileName};
|
|
BOOL fNo;
|
|
BOOL fMsgBox = 0 != m_dwEnabledSafteyOptions;
|
|
BOOL fOverWrite = FALSE;
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
dwAttribs = GetFileAttributesU(pwszFileName);
|
|
if(0xFFFFFFFF == dwAttribs)
|
|
{
|
|
//file doesn't exist
|
|
if (!fCreate)
|
|
{
|
|
//try to read a non-existing file
|
|
//for safety reasons, don't return system error
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
goto InvalidFileError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//file exists, check if a proper file to write or read
|
|
//in either write or read, the following file attrib not proper
|
|
fNotProperFile =
|
|
(dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ||
|
|
(dwAttribs & FILE_ATTRIBUTE_HIDDEN) ||
|
|
(dwAttribs & FILE_ATTRIBUTE_SYSTEM);
|
|
|
|
if (!fNotProperFile)
|
|
{
|
|
//so far so good
|
|
if (fCreate)
|
|
{
|
|
//write a file
|
|
if (0x0 != (dwAttribs & FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
//don't take read-only and archive
|
|
fNotProperFile = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//try to overwrite existing file
|
|
fOverWrite = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fNotProperFile)
|
|
{
|
|
//for safety reasons, don't return system error
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
goto InvalidFileError;
|
|
}
|
|
}
|
|
|
|
if (fMsgBox)
|
|
{
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_CERTENROLL, &pwszTitle);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
hr = xeLoadRCString(
|
|
hInstanceXEnroll,
|
|
fCreate ? IDS_NOTSAFE_WRITE_FORMAT : IDS_NOTSAFE_OPEN_FORMAT,
|
|
&pwszFormat);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
|
|
if (!FormatMessageU(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pwszFormat,
|
|
0,
|
|
0,
|
|
(LPWSTR) &pwszMsg,
|
|
0,
|
|
(va_list *)apwszInsertArray))
|
|
{
|
|
goto FormatMessageUError;
|
|
}
|
|
|
|
fNo = (MessageBoxU(
|
|
NULL,
|
|
pwszMsg,
|
|
pwszTitle,
|
|
MB_DEFBUTTON2 | MB_YESNO | MB_ICONWARNING) == IDNO);
|
|
if(fNo)
|
|
{
|
|
SetLastError(ERROR_CANCELLED);
|
|
goto CancelError;
|
|
}
|
|
}
|
|
|
|
if (fCreate && fOverWrite)
|
|
{
|
|
if (!fMsgBox)
|
|
{
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_CERTENROLL, &pwszTitle);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
}
|
|
|
|
//popup overwrite confirmation
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_OVERWRITE_FORMAT, &pwszFormat);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeLoadRCStringError;
|
|
}
|
|
|
|
//make sure free before alloc again
|
|
if (NULL != pwszMsg)
|
|
{
|
|
LocalFree(pwszMsg);
|
|
pwszMsg = NULL;
|
|
}
|
|
FormatMessageU(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
pwszFormat,
|
|
0,
|
|
0,
|
|
(LPWSTR) &pwszMsg,
|
|
0,
|
|
(va_list *)apwszInsertArray);
|
|
|
|
fNo = (MessageBoxU(
|
|
NULL,
|
|
pwszMsg,
|
|
pwszTitle,
|
|
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES);
|
|
if(fNo)
|
|
{
|
|
SetLastError(ERROR_CANCELLED);
|
|
goto CancelError;
|
|
}
|
|
}
|
|
|
|
hFile = CreateFileU(
|
|
pwszFileName,
|
|
fCreate ? GENERIC_WRITE : GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
fCreate ? CREATE_ALWAYS : OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE || hFile == NULL)
|
|
{
|
|
//don't return system error so keep xenroll relative safe for scripting
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
hFile = NULL;
|
|
goto CreateFileUError;
|
|
}
|
|
|
|
ErrorReturn:
|
|
if(NULL != pwszMsg)
|
|
{
|
|
LocalFree(pwszMsg);
|
|
}
|
|
if(NULL != pwszTitle)
|
|
{
|
|
LocalFree(pwszTitle);
|
|
}
|
|
if(NULL != pwszFormat)
|
|
{
|
|
LocalFree(pwszFormat);
|
|
}
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hFile);
|
|
|
|
TRACE_ERROR(CreateFileUError)
|
|
TRACE_ERROR(CancelError)
|
|
TRACE_ERROR(FormatMessageUError);
|
|
TRACE_ERROR(InvalidFileError)
|
|
TRACE_ERROR(xeLoadRCStringError)
|
|
}
|
|
|
|
HANDLE CCEnroll::CreateFileSafely(
|
|
LPCWSTR pwszFileName)
|
|
{
|
|
return CreateOpenFileSafely(pwszFileName, TRUE); //write
|
|
}
|
|
|
|
HANDLE CCEnroll::OpenFileSafely(
|
|
LPCWSTR pwszFileName)
|
|
{
|
|
return CreateOpenFileSafely(pwszFileName, FALSE); //open
|
|
}
|
|
|
|
void DwordToWide(DWORD dw, LPWSTR lpwstr) {
|
|
|
|
DWORD i = 0;
|
|
DWORD j;
|
|
WCHAR wch;
|
|
|
|
while(dw > 0) {
|
|
j = dw % 10;
|
|
dw /= 10;
|
|
lpwstr[i++] = (WCHAR) (j + L'\0');
|
|
}
|
|
|
|
if( i == 0 )
|
|
lpwstr[i++] = L'\0';
|
|
|
|
lpwstr[i] = 0;
|
|
|
|
for(j=0, i--; i > j; i--, j++) {
|
|
wch = lpwstr[i];
|
|
lpwstr[i] = lpwstr[j];
|
|
lpwstr[j] = wch;
|
|
}
|
|
}
|
|
|
|
//take a name value pair info and return encoded value
|
|
HRESULT
|
|
xeEncodeNameValuePair(
|
|
IN PCRYPT_ENROLLMENT_NAME_VALUE_PAIR pNameValuePair,
|
|
OUT BYTE **ppbData,
|
|
OUT DWORD *pcbData)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//init
|
|
*ppbData = NULL;
|
|
*pcbData = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
szOID_ENROLLMENT_NAME_VALUE_PAIR,
|
|
pNameValuePair,
|
|
*ppbData,
|
|
pcbData))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto error;
|
|
}
|
|
|
|
if (NULL != *ppbData)
|
|
{
|
|
break;
|
|
}
|
|
|
|
*ppbData = (BYTE*)MyCoTaskMemAlloc(*pcbData);
|
|
if (NULL == *ppbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (S_OK != hr && NULL != *ppbData)
|
|
{
|
|
MyCoTaskMemFree(*ppbData);
|
|
*ppbData = NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//convert wsz to sz and allocate mem
|
|
HRESULT
|
|
xeWSZToSZ(
|
|
IN LPCWSTR pwsz,
|
|
OUT LPSTR *ppsz)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG cc = 0;
|
|
|
|
//init
|
|
*ppsz = NULL;
|
|
|
|
while (TRUE)
|
|
{
|
|
cc = WideCharToMultiByte(
|
|
GetACP(),
|
|
0,
|
|
pwsz,
|
|
-1,
|
|
*ppsz,
|
|
cc,
|
|
NULL,
|
|
NULL);
|
|
if (0 >= cc)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto error;
|
|
}
|
|
|
|
if (NULL != *ppsz)
|
|
{
|
|
break;
|
|
}
|
|
*ppsz= (CHAR*)MyCoTaskMemAlloc(cc);
|
|
if (NULL == *ppsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto error;
|
|
}
|
|
}
|
|
error:
|
|
if (S_OK != hr && NULL != *ppsz)
|
|
{
|
|
MyCoTaskMemFree(*ppsz);
|
|
*ppsz = NULL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//modified from DecodeFile on certsrv
|
|
HRESULT
|
|
CCEnroll::xeStringToBinaryFromFile(
|
|
IN WCHAR const *pwszfn,
|
|
OUT BYTE **ppbOut,
|
|
OUT DWORD *pcbOut,
|
|
IN DWORD Flags)
|
|
{
|
|
HANDLE hFile;
|
|
HRESULT hr;
|
|
CHAR *pchFile = NULL;
|
|
BYTE *pbOut = NULL;
|
|
DWORD cchFile;
|
|
DWORD cbRead;
|
|
DWORD cbOut = 0;
|
|
|
|
hFile = OpenFileSafely(pwszfn);
|
|
if (NULL == hFile)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto OpenFileSafelyError;
|
|
}
|
|
|
|
cchFile = GetFileSize(hFile, NULL);
|
|
if ((DWORD) -1 == cchFile)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetFileSizeError;
|
|
}
|
|
|
|
pchFile = (CHAR *) LocalAlloc(LMEM_FIXED, cchFile);
|
|
if (NULL == pchFile)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
|
|
if (!ReadFile(hFile, pchFile, cchFile, &cbRead, NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ReadFileError;
|
|
}
|
|
|
|
assert(cbRead <= cchFile);
|
|
if (cbRead != cchFile)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
|
|
goto ReadFileError;
|
|
}
|
|
|
|
if (CRYPT_STRING_BINARY == Flags)
|
|
{
|
|
pbOut = (BYTE *) pchFile;
|
|
cbOut = cchFile;
|
|
pchFile = NULL;
|
|
}
|
|
else
|
|
{
|
|
// Decode file contents.
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryA(
|
|
pchFile,
|
|
cchFile,
|
|
Flags,
|
|
pbOut,
|
|
&cbOut,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CyrptStringToBinaryError;
|
|
}
|
|
if (NULL != pbOut)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pbOut = (BYTE*)LocalAlloc(LMEM_FIXED, cbOut);
|
|
if (NULL == pbOut)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
}
|
|
}
|
|
*pcbOut = cbOut;
|
|
*ppbOut = pbOut;
|
|
pbOut = NULL;
|
|
|
|
hr = S_OK;
|
|
error:
|
|
if (INVALID_HANDLE_VALUE != hFile)
|
|
{
|
|
CloseHandle(hFile);
|
|
}
|
|
if (NULL != pchFile)
|
|
{
|
|
LocalFree(pchFile);
|
|
}
|
|
if (NULL != pbOut)
|
|
{
|
|
LocalFree(pbOut);
|
|
}
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
goto error;
|
|
|
|
TRACE_ERROR(CyrptStringToBinaryError)
|
|
TRACE_ERROR(ReadFileError)
|
|
TRACE_ERROR(LocalAllocError)
|
|
TRACE_ERROR(GetFileSizeError)
|
|
TRACE_ERROR(OpenFileSafelyError)
|
|
}
|
|
|
|
//following two functions handle some APIs not available
|
|
//in downlevel client crypt32.dll
|
|
typedef VOID
|
|
(WINAPI * PFNCertFreeCertificateChain)
|
|
(IN PCCERT_CHAIN_CONTEXT pChainContext);
|
|
|
|
typedef BOOL
|
|
(WINAPI * PFNCertGetCertificateChain)
|
|
(IN OPTIONAL HCERTCHAINENGINE hChainEngine,
|
|
IN PCCERT_CONTEXT pCertContext,
|
|
IN OPTIONAL LPFILETIME pTime,
|
|
IN OPTIONAL HCERTSTORE hAdditionalStore,
|
|
IN PCERT_CHAIN_PARA pChainPara,
|
|
IN DWORD dwFlags,
|
|
IN LPVOID pvReserved,
|
|
OUT PCCERT_CHAIN_CONTEXT* ppChainContext);
|
|
|
|
typedef BOOL (WINAPI *PFNCertVerifyCertificateChainPolicy) (
|
|
LPCSTR pszPolicyOID,
|
|
PCCERT_CHAIN_CONTEXT pChainContext,
|
|
PCERT_CHAIN_POLICY_PARA pPolicyPara,
|
|
PCERT_CHAIN_POLICY_STATUS pPolicyStatus
|
|
);
|
|
|
|
typedef BOOL (*PFNCheckTokenMembership) (
|
|
HANDLE TokenHandle, // handle to access token
|
|
PSID SidToCheck, // SID
|
|
PBOOL IsMember // result
|
|
);
|
|
|
|
typedef BOOL (*PFNSetSecurityDescriptorControl) (
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor, // SD
|
|
SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, // control bits
|
|
SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet // new control bits
|
|
);
|
|
|
|
VOID
|
|
MyCertFreeCertificateChain (
|
|
IN PCCERT_CHAIN_CONTEXT pChainContext
|
|
)
|
|
{
|
|
PFNCertFreeCertificateChain pfnCertFreeCertificateChain = NULL;
|
|
HMODULE hModule = NULL;
|
|
|
|
hModule = GetModuleHandle("crypt32.dll");
|
|
if (NULL != hModule)
|
|
{
|
|
pfnCertFreeCertificateChain = (PFNCertFreeCertificateChain)
|
|
GetProcAddress(hModule,
|
|
"CertFreeCertificateChain");
|
|
if (NULL != pfnCertFreeCertificateChain)
|
|
{
|
|
pfnCertFreeCertificateChain(pChainContext);
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
MyCertGetCertificateChain (
|
|
IN OPTIONAL HCERTCHAINENGINE hChainEngine,
|
|
IN PCCERT_CONTEXT pCertContext,
|
|
IN OPTIONAL LPFILETIME pTime,
|
|
IN OPTIONAL HCERTSTORE hAdditionalStore,
|
|
IN PCERT_CHAIN_PARA pChainPara,
|
|
IN DWORD dwFlags,
|
|
IN LPVOID pvReserved,
|
|
OUT PCCERT_CHAIN_CONTEXT* ppChainContext
|
|
)
|
|
{
|
|
PFNCertGetCertificateChain pfnCertGetCertificateChain = NULL;
|
|
HMODULE hModule = NULL;
|
|
|
|
hModule = GetModuleHandle("crypt32.dll");
|
|
if (NULL != hModule)
|
|
{
|
|
pfnCertGetCertificateChain = (PFNCertGetCertificateChain)
|
|
GetProcAddress(hModule,
|
|
"CertGetCertificateChain");
|
|
if (NULL != pfnCertGetCertificateChain)
|
|
{
|
|
return pfnCertGetCertificateChain(
|
|
hChainEngine,
|
|
pCertContext,
|
|
pTime,
|
|
hAdditionalStore,
|
|
pChainPara,
|
|
dwFlags,
|
|
pvReserved,
|
|
ppChainContext);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
MyCertVerifyCertificateChainPolicy(
|
|
LPCSTR pszPolicyOID,
|
|
PCCERT_CHAIN_CONTEXT pChainContext,
|
|
PCERT_CHAIN_POLICY_PARA pPolicyPara,
|
|
PCERT_CHAIN_POLICY_STATUS pPolicyStatus
|
|
)
|
|
{
|
|
PFNCertVerifyCertificateChainPolicy pfnCertVerifyCertificateChainPolicy = NULL;
|
|
HMODULE hModule = NULL;
|
|
|
|
hModule = GetModuleHandle("crypt32.dll");
|
|
if (NULL != hModule)
|
|
{
|
|
pfnCertVerifyCertificateChainPolicy = (PFNCertVerifyCertificateChainPolicy)
|
|
GetProcAddress(hModule,
|
|
"CertVerifyCertificateChainPolicy");
|
|
if (NULL != pfnCertVerifyCertificateChainPolicy)
|
|
{
|
|
return pfnCertVerifyCertificateChainPolicy(
|
|
pszPolicyOID,
|
|
pChainContext,
|
|
pPolicyPara,
|
|
pPolicyStatus);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
MyCheckTokenMembership(
|
|
HANDLE TokenHandle, // handle to access token
|
|
PSID SidToCheck, // SID
|
|
PBOOL IsMember // result
|
|
)
|
|
{
|
|
PFNCheckTokenMembership pfnCheckTokenMembership = NULL;
|
|
HMODULE hModule = NULL;
|
|
|
|
hModule = GetModuleHandle("advapi32.dll");
|
|
if (NULL != hModule)
|
|
{
|
|
pfnCheckTokenMembership = (PFNCheckTokenMembership)
|
|
GetProcAddress(hModule,
|
|
"CheckTokenMembership");
|
|
if (NULL != pfnCheckTokenMembership)
|
|
{
|
|
return pfnCheckTokenMembership(
|
|
TokenHandle,
|
|
SidToCheck,
|
|
IsMember);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
MySetSecurityDescriptorControl(
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor, // SD
|
|
SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, // control bits
|
|
SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet // new control bits
|
|
)
|
|
{
|
|
PFNSetSecurityDescriptorControl pfnSetSecurityDescriptorControl = NULL;
|
|
HMODULE hModule = NULL;
|
|
|
|
hModule = GetModuleHandle("advapi32.dll");
|
|
if (NULL != hModule)
|
|
{
|
|
pfnSetSecurityDescriptorControl = (PFNSetSecurityDescriptorControl)
|
|
GetProcAddress(hModule,
|
|
"SetSecurityDescriptorControl");
|
|
if (NULL != pfnSetSecurityDescriptorControl)
|
|
{
|
|
return pfnSetSecurityDescriptorControl(
|
|
pSecurityDescriptor,
|
|
ControlBitsOfInterest,
|
|
ControlBitsToSet);
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT __stdcall CCEnroll::GetInterfaceSafetyOptions(
|
|
/* [in] */ REFIID riid,
|
|
/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
|
|
/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions) {
|
|
|
|
RPC_STATUS rpcStatus;
|
|
|
|
if(0 != UuidCompare((GUID *) &riid, (GUID *) &IID_IDispatch, &rpcStatus) )
|
|
return(E_NOINTERFACE);
|
|
|
|
*pdwEnabledOptions = m_dwEnabledSafteyOptions;
|
|
*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
|
|
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT __stdcall CCEnroll::SetInterfaceSafetyOptions(
|
|
/* [in] */ REFIID riid,
|
|
/* [in] */ DWORD dwOptionSetMask,
|
|
/* [in] */ DWORD dwEnabledOptions) {
|
|
|
|
RPC_STATUS rpcStatus;
|
|
DWORD dwSupport = 0;
|
|
|
|
if(0 != UuidCompare((GUID *) &riid, (GUID *) &IID_IDispatch, &rpcStatus) )
|
|
return(E_NOINTERFACE);
|
|
|
|
dwSupport = dwOptionSetMask & ~(INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA);
|
|
if(dwSupport != 0)
|
|
return(E_FAIL);
|
|
|
|
(DWORD)m_dwEnabledSafteyOptions &= ~dwOptionSetMask;
|
|
(DWORD)m_dwEnabledSafteyOptions |= dwEnabledOptions;
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CCEnroll::GetVerifyProv()
|
|
{
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (NULL == m_hVerifyProv)
|
|
{
|
|
if (!CryptAcquireContextU(
|
|
&m_hVerifyProv,
|
|
NULL,
|
|
m_keyProvInfo.pwszProvName,
|
|
m_keyProvInfo.dwProvType,
|
|
CRYPT_VERIFYCONTEXT))
|
|
{
|
|
#if DBG
|
|
assert(NULL == m_hVerifyProv);
|
|
#endif //DBG
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptAcquireContextUError;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return hr;
|
|
|
|
TRACE_ERROR(CryptAcquireContextUError)
|
|
}
|
|
|
|
BOOL CCEnroll::GetCapiHashAndSigAlgId(ALG_ID rgAlg[2]) {
|
|
|
|
|
|
DWORD iHashBest = 0;
|
|
ALG_ID arDefaultHash[] = {m_HashAlgId, CALG_SHA1, CALG_MD5};
|
|
DWORD cDefaultHash = sizeof(arDefaultHash) / sizeof(DWORD);
|
|
|
|
HCRYPTPROV hProvU = NULL;
|
|
|
|
DWORD dwFlags = CRYPT_FIRST;
|
|
|
|
DWORD i;
|
|
PROV_ENUMALGS enumAlgs;
|
|
DWORD cb = sizeof(enumAlgs);
|
|
|
|
BOOL fRet = TRUE;
|
|
|
|
rgAlg[0] = 0;
|
|
rgAlg[1] = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// only get a prov if one wasn't passed in.
|
|
if(m_hProv == NULL)
|
|
{
|
|
HRESULT hr;
|
|
hr = GetVerifyProv();
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetVerifyProvError;
|
|
}
|
|
hProvU = m_hVerifyProv;
|
|
}
|
|
else
|
|
{
|
|
// otherwise use the current m_hProv, SCard only likes on
|
|
// CryptAcquireContext to be used.
|
|
hProvU = m_hProv;
|
|
}
|
|
|
|
cb = sizeof(enumAlgs);
|
|
while( CryptGetProvParam(
|
|
hProvU,
|
|
PP_ENUMALGS,
|
|
(BYTE *) &enumAlgs,
|
|
&cb,
|
|
dwFlags
|
|
) ) {
|
|
|
|
cb = sizeof(enumAlgs);
|
|
|
|
// not first pass anymore
|
|
dwFlags = 0;
|
|
|
|
// see if this is a hash alg
|
|
if( ALG_CLASS_HASH == GET_ALG_CLASS(enumAlgs.aiAlgid) ) {
|
|
|
|
// get things init with the first hash alg
|
|
if(rgAlg[0] == 0) {
|
|
rgAlg[0] = enumAlgs.aiAlgid;
|
|
iHashBest = cDefaultHash;
|
|
}
|
|
|
|
// pick the best one
|
|
for(i=0; i<iHashBest; i++) {
|
|
|
|
if(arDefaultHash[i] == enumAlgs.aiAlgid) {
|
|
rgAlg[0] = enumAlgs.aiAlgid;
|
|
iHashBest = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// we will only pick up the first signature type
|
|
// in general there is only 1 per csp (Ref: JeffSpel)
|
|
else if( ALG_CLASS_SIGNATURE == GET_ALG_CLASS(enumAlgs.aiAlgid) ) {
|
|
|
|
if(rgAlg[1] == 0)
|
|
rgAlg[1] = enumAlgs.aiAlgid;
|
|
}
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
// some CSPs say they can't sign, but they really can
|
|
// so if we have not hashalg or sigalg we will put a default
|
|
// in and if the CSP really can't do it, it will error
|
|
// this is for backwards compatibility
|
|
|
|
// default hash to sha1
|
|
if(rgAlg[0] == 0)
|
|
rgAlg[0] = CALG_SHA1;
|
|
|
|
// default sig to RSA
|
|
if(rgAlg[1] == 0)
|
|
rgAlg[1] = CALG_RSA_SIGN;
|
|
|
|
#if 0
|
|
if(rgAlg[0] == 0 || rgAlg[1] == 0) {
|
|
SetLastError((DWORD)NTE_BAD_ALGID);
|
|
fRet = FALSE;
|
|
}
|
|
#endif
|
|
|
|
return(fRet);
|
|
|
|
TRACE_ERROR(GetVerifyProvError)
|
|
}
|
|
|
|
BOOL CreatePvkProperty(
|
|
CRYPT_KEY_PROV_INFO *pKeyProvInfo,
|
|
PCRYPT_DATA_BLOB pBlob)
|
|
{
|
|
WCHAR wszKeySpec[11];
|
|
WCHAR wszProvType[11];
|
|
DWORD cbContainer;
|
|
DWORD cbKeySpec;
|
|
DWORD cbProvType;
|
|
DWORD cbProvName;
|
|
|
|
assert(pBlob != NULL);
|
|
assert(pKeyProvInfo != NULL);
|
|
|
|
// convert dwords to strings
|
|
DwordToWide(pKeyProvInfo->dwKeySpec, wszKeySpec);
|
|
DwordToWide(pKeyProvInfo->dwProvType, wszProvType);
|
|
|
|
// get total length of string
|
|
cbContainer = (DWORD)(wcslen(pKeyProvInfo->pwszContainerName) + 1) * sizeof(WCHAR);
|
|
cbKeySpec = (DWORD)(wcslen(wszKeySpec) + 1) * sizeof(WCHAR);
|
|
cbProvType = (DWORD)(wcslen(wszProvType) + 1) * sizeof(WCHAR);
|
|
|
|
cbProvName = (DWORD)(wcslen(pKeyProvInfo->pwszProvName) + 1) * sizeof(WCHAR);
|
|
|
|
pBlob->cbData =
|
|
cbContainer +
|
|
cbKeySpec +
|
|
cbProvType +
|
|
cbProvName +
|
|
sizeof(WCHAR);
|
|
|
|
// allocate the string
|
|
if( (pBlob->pbData = (BYTE *) MyCoTaskMemAlloc(pBlob->cbData)) == NULL) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
// copy the strings
|
|
memset(pBlob->pbData, 0, pBlob->cbData);
|
|
memcpy(pBlob->pbData, pKeyProvInfo->pwszContainerName, cbContainer);
|
|
memcpy(&pBlob->pbData[cbContainer], wszKeySpec, cbKeySpec);
|
|
memcpy(&pBlob->pbData[cbContainer + cbKeySpec], wszProvType, cbProvType);
|
|
memcpy(&pBlob->pbData[cbContainer + cbKeySpec + cbProvType], pKeyProvInfo->pwszProvName, cbProvName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
static LPWSTR wszEmpty = L"";
|
|
static LPWSTR wszMY = L"MY";
|
|
static LPWSTR wszCA = L"CA";
|
|
static LPWSTR wszROOT = L"ROOT";
|
|
static LPWSTR wszREQUEST = L"REQUEST";
|
|
static LPSTR szSystemStore = sz_CERT_STORE_PROV_SYSTEM;
|
|
// static LPSTR szSystemStore = sz_CERT_STORE_PROV_SYSTEM_REGISTRY;
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CCEnroll
|
|
|
|
|
|
CCEnroll::~CCEnroll(void) {
|
|
Destruct();
|
|
DeleteCriticalSection(&m_csXEnroll);
|
|
}
|
|
|
|
void CCEnroll::Destruct(void) {
|
|
|
|
if(NULL != m_PrivateKeyArchiveCertificate)
|
|
{
|
|
CertFreeCertificateContext(m_PrivateKeyArchiveCertificate);
|
|
}
|
|
if(NULL != m_pCertContextSigner)
|
|
{
|
|
CertFreeCertificateContext(m_pCertContextSigner);
|
|
}
|
|
if(m_pCertContextRenewal != NULL)
|
|
CertFreeCertificateContext(m_pCertContextRenewal);
|
|
if(m_pCertContextStatic != NULL)
|
|
CertFreeCertificateContext(m_pCertContextStatic);
|
|
|
|
if(m_keyProvInfo.pwszContainerName != wszEmpty)
|
|
MyCoTaskMemFree(m_keyProvInfo.pwszContainerName);
|
|
|
|
if(m_keyProvInfo.pwszProvName != wszEmpty)
|
|
MyCoTaskMemFree(m_keyProvInfo.pwszProvName);
|
|
|
|
if(m_MyStore.wszName != wszMY)
|
|
MyCoTaskMemFree(m_MyStore.wszName);
|
|
|
|
if(m_CAStore.wszName != wszCA)
|
|
MyCoTaskMemFree(m_CAStore.wszName);
|
|
|
|
if(m_RootStore.wszName != wszROOT && m_RootStore.wszName != wszCA)
|
|
MyCoTaskMemFree(m_RootStore.wszName);
|
|
|
|
if(m_RequestStore.wszName != wszREQUEST)
|
|
MyCoTaskMemFree(m_RequestStore.wszName);
|
|
|
|
if(m_MyStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_MyStore.szType);
|
|
|
|
if(m_CAStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_CAStore.szType);
|
|
|
|
if(m_RootStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_RootStore.szType);
|
|
|
|
if(m_RequestStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_RequestStore.szType);
|
|
|
|
if(m_wszSPCFileName != wszEmpty)
|
|
MyCoTaskMemFree(m_wszSPCFileName);
|
|
|
|
if(m_wszPVKFileName != wszEmpty)
|
|
MyCoTaskMemFree(m_wszPVKFileName);
|
|
|
|
if (NULL != m_pCertContextPendingRequest)
|
|
CertFreeCertificateContext(m_pCertContextPendingRequest);
|
|
|
|
if (NULL != m_pPendingRequestTable)
|
|
delete m_pPendingRequestTable;
|
|
|
|
// store handles
|
|
if(m_RootStore.hStore != NULL)
|
|
CertCloseStore(m_RootStore.hStore, 0);
|
|
m_RootStore.hStore = NULL;
|
|
|
|
if(m_CAStore.hStore != NULL)
|
|
CertCloseStore(m_CAStore.hStore, 0);
|
|
m_CAStore.hStore = NULL;
|
|
|
|
if(m_MyStore.hStore != NULL)
|
|
CertCloseStore(m_MyStore.hStore, 0);
|
|
m_MyStore.hStore = NULL;
|
|
|
|
if(m_RequestStore.hStore != NULL)
|
|
CertCloseStore(m_RequestStore.hStore, 0);
|
|
m_RequestStore.hStore = NULL;
|
|
|
|
// remove provider handles
|
|
if(m_hProv != NULL)
|
|
CryptReleaseContext(m_hProv, 0);
|
|
m_hProv = NULL;
|
|
|
|
if(m_hVerifyProv != NULL)
|
|
CryptReleaseContext(m_hVerifyProv, 0);
|
|
m_hVerifyProv = NULL;
|
|
|
|
if (NULL != m_hCachedKey)
|
|
{
|
|
//this should be destroyed early but just in case
|
|
CryptDestroyKey(m_hCachedKey);
|
|
}
|
|
|
|
if (NULL != m_pPublicKeyInfo)
|
|
{
|
|
LocalFree(m_pPublicKeyInfo);
|
|
m_pPublicKeyInfo = NULL;
|
|
}
|
|
|
|
FreeAllStackExtension();
|
|
FreeAllStackAttribute();
|
|
resetBlobProperties();
|
|
}
|
|
|
|
static LPVOID CoTaskMemAllocTrap(ULONG cb) {
|
|
|
|
__try {
|
|
return(CoTaskMemAlloc(cb));
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError(ERROR_DLL_NOT_FOUND);
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
static LPVOID CoTaskMemReallocTrap(LPVOID ptr, ULONG cb) {
|
|
__try {
|
|
return(CoTaskMemRealloc(ptr, cb));
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError(ERROR_DLL_NOT_FOUND);
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
static void CoTaskMemFreeTrap(LPVOID ptr) {
|
|
__try {
|
|
CoTaskMemFree(ptr);
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
SetLastError(ERROR_DLL_NOT_FOUND);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
// Initialize the safety options in the constructor, so they won't
|
|
// be clobbered when we do a reset().
|
|
CCEnroll::CCEnroll(void) : m_dwEnabledSafteyOptions(0) {
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&m_csXEnroll);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
Init();
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::Init(void)
|
|
{
|
|
HRESULT hr;
|
|
GUID guidContainerName;
|
|
char * sz = NULL;
|
|
RPC_STATUS rpc_status;
|
|
|
|
// set default mem allocators
|
|
if(MyCoTaskMemAlloc == NULL)
|
|
{
|
|
|
|
MyCoTaskMemAlloc = CoTaskMemAllocTrap;
|
|
MyCoTaskMemRealloc = CoTaskMemReallocTrap;
|
|
MyCoTaskMemFree = CoTaskMemFreeTrap;
|
|
}
|
|
|
|
// get a container based on a guid
|
|
rpc_status = UuidCreate(&guidContainerName);
|
|
if (RPC_S_OK != rpc_status && RPC_S_UUID_LOCAL_ONLY != rpc_status)
|
|
{
|
|
hr = rpc_status;
|
|
goto UuidCreateError;
|
|
}
|
|
rpc_status = UuidToStringA(&guidContainerName, (unsigned char **) &sz);
|
|
if (RPC_S_OK != rpc_status)
|
|
{
|
|
hr = rpc_status;
|
|
goto UuidToStringAError;
|
|
}
|
|
assert(sz != NULL);
|
|
m_keyProvInfo.pwszContainerName = WideFromMB(sz);
|
|
RpcStringFree((unsigned char **) &sz);
|
|
|
|
m_keyProvInfo.pwszProvName = wszEmpty;
|
|
m_keyProvInfo.dwProvType = PROV_RSA_FULL;
|
|
m_keyProvInfo.dwFlags = 0;
|
|
m_keyProvInfo.cProvParam = 0;
|
|
m_keyProvInfo.rgProvParam = NULL;
|
|
m_keyProvInfo.dwKeySpec = AT_SIGNATURE;
|
|
m_fEnableSMIMECapabilities =
|
|
(m_keyProvInfo.dwKeySpec == AT_KEYEXCHANGE);
|
|
m_fSMIMESetByClient = FALSE;
|
|
m_fKeySpecSetByClient = FALSE;
|
|
m_hProv = NULL;
|
|
m_hVerifyProv = NULL;
|
|
|
|
m_fDeleteRequestCert = TRUE;
|
|
m_fUseExistingKey = FALSE;
|
|
m_fWriteCertToCSPModified = FALSE;
|
|
m_fWriteCertToCSP = TRUE; // always want to try
|
|
m_fWriteCertToUserDSModified = FALSE;
|
|
m_fWriteCertToUserDS = FALSE;
|
|
m_fReuseHardwareKeyIfUnableToGenNew = TRUE;
|
|
m_fLimitExchangeKeyToEncipherment = FALSE;
|
|
m_dwT61DNEncoding = 0; // or CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG
|
|
m_dwGenKeyFlags = 0;
|
|
m_wszSPCFileName = wszEmpty;
|
|
m_wszPVKFileName = wszEmpty;
|
|
m_HashAlgId = 0;
|
|
|
|
m_fMyStoreOpenFlagsModified = FALSE;
|
|
m_MyStore.wszName = wszMY;
|
|
m_MyStore.szType = szSystemStore;
|
|
m_MyStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER;
|
|
m_MyStore.hStore = NULL;
|
|
|
|
m_fCAStoreOpenFlagsModified = FALSE;
|
|
m_CAStore.wszName = wszCA;
|
|
m_CAStore.szType = szSystemStore;
|
|
m_CAStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER;
|
|
m_CAStore.hStore = NULL;
|
|
|
|
m_fRootStoreOpenFlagsModified = FALSE;
|
|
m_RootStore.wszName = wszROOT;
|
|
m_RootStore.szType = szSystemStore;
|
|
m_RootStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER;
|
|
m_RootStore.hStore = NULL;
|
|
|
|
m_fRequestStoreOpenFlagsModified = FALSE;
|
|
m_RequestStore.wszName = wszREQUEST ;
|
|
m_RequestStore.szType = szSystemStore;
|
|
m_RequestStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER;
|
|
m_RequestStore.hStore = NULL;
|
|
|
|
m_PrivateKeyArchiveCertificate= NULL;
|
|
m_pCertContextRenewal = NULL;
|
|
m_pCertContextSigner = NULL;
|
|
m_pCertContextStatic = NULL;
|
|
memset(m_arHashBytesNewCert, 0, sizeof(m_arHashBytesNewCert));
|
|
memset(m_arHashBytesOldCert, 0, sizeof(m_arHashBytesOldCert));
|
|
m_fArchiveOldCert = FALSE;
|
|
|
|
m_pExtStack = NULL;
|
|
m_cExtStack = 0;
|
|
|
|
m_pAttrStack = NULL;
|
|
m_cAttrStack = 0;
|
|
|
|
m_pExtStackNew = NULL;
|
|
m_cExtStackNew = 0;
|
|
|
|
m_pAttrStackNew = NULL;
|
|
m_cAttrStackNew = 0;
|
|
|
|
m_pPropStack = NULL;
|
|
m_cPropStack = 0;
|
|
|
|
m_fNewRequestMethod = FALSE;
|
|
m_fCMCFormat = FALSE;
|
|
m_fHonorRenew = TRUE; //critical, if passing XECR_PKCS10*
|
|
m_fOID_V2 = FALSE; //critical
|
|
m_hCachedKey = NULL;
|
|
m_fUseClientKeyUsage = FALSE;
|
|
m_lClientId = XECI_XENROLL;
|
|
m_dwLastAlgIndex = MAXDWORD;
|
|
m_fIncludeSubjectKeyID = TRUE;
|
|
m_fHonorIncludeSubjectKeyID = FALSE;
|
|
m_pPublicKeyInfo = NULL;
|
|
|
|
m_dwSigKeyLenMax = 0;
|
|
m_dwSigKeyLenMin = 0;
|
|
m_dwSigKeyLenDef = 0;
|
|
m_dwSigKeyLenInc = 0;
|
|
m_dwXhgKeyLenMax = 0;
|
|
m_dwXhgKeyLenMin = 0;
|
|
m_dwXhgKeyLenDef = 0;
|
|
m_dwXhgKeyLenInc = 0;
|
|
|
|
// Initialize pending info data:
|
|
m_pCertContextPendingRequest = NULL;
|
|
m_pCertContextLastEnumerated = NULL;
|
|
m_dwCurrentPendingRequestIndex = 0;
|
|
m_pPendingRequestTable = NULL;
|
|
memset(&m_hashBlobPendingRequest, 0, sizeof(CRYPT_DATA_BLOB));
|
|
ZeroMemory(&m_blobResponseKAHash, sizeof(m_blobResponseKAHash));
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
return hr;
|
|
TRACE_ERROR(UuidToStringAError)
|
|
TRACE_ERROR(UuidCreateError)
|
|
}
|
|
|
|
void CCEnroll::FlushStore(StoreType storeType) {
|
|
PSTOREINFO pStoreInfo = NULL;
|
|
|
|
// get store struct
|
|
switch(storeType) {
|
|
|
|
case StoreMY:
|
|
pStoreInfo = &m_MyStore;
|
|
break;
|
|
|
|
case StoreCA:
|
|
pStoreInfo = &m_CAStore;
|
|
break;
|
|
|
|
case StoreROOT:
|
|
pStoreInfo = &m_RootStore;
|
|
break;
|
|
|
|
case StoreREQUEST:
|
|
pStoreInfo = &m_RequestStore;
|
|
break;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// if store already open, return it
|
|
if(pStoreInfo->hStore != NULL) {
|
|
|
|
CertCloseStore(pStoreInfo->hStore, 0);
|
|
pStoreInfo->hStore = NULL;
|
|
}
|
|
|
|
// we may have something or not, but return it
|
|
// the errors will be correct.
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
}
|
|
|
|
HCERTSTORE CCEnroll::GetStore(StoreType storeType) {
|
|
|
|
PSTOREINFO pStoreInfo = NULL;
|
|
HCERTSTORE hStore = NULL;
|
|
|
|
// get store struct
|
|
switch(storeType) {
|
|
|
|
case StoreMY:
|
|
pStoreInfo = &m_MyStore;
|
|
break;
|
|
|
|
case StoreCA:
|
|
pStoreInfo = &m_CAStore;
|
|
break;
|
|
|
|
case StoreROOT:
|
|
pStoreInfo = &m_RootStore;
|
|
break;
|
|
|
|
case StoreREQUEST:
|
|
pStoreInfo = &m_RequestStore;
|
|
break;
|
|
|
|
default:
|
|
SetLastError(ERROR_BAD_ARGUMENTS);
|
|
return(NULL);
|
|
break;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// if store already open, return it
|
|
if(pStoreInfo->hStore == NULL) {
|
|
|
|
// otherwise attempt to open the store
|
|
pStoreInfo->hStore = CertOpenStore(
|
|
pStoreInfo->szType,
|
|
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
|
NULL,
|
|
pStoreInfo->dwFlags,
|
|
pStoreInfo->wszName);
|
|
}
|
|
|
|
// we may have something or not, but return it
|
|
// the errors will be correct.
|
|
hStore = pStoreInfo->hStore;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hStore);
|
|
}
|
|
|
|
HCRYPTPROV CCEnroll::GetProv(DWORD dwFlags) {
|
|
|
|
HCRYPTPROV hProvT = NULL;
|
|
DWORD cb = 0;
|
|
char * pszProvName = NULL;
|
|
char * pszContainerName = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
DWORD dwProvType = m_keyProvInfo.dwProvType;
|
|
|
|
switch(dwFlags) {
|
|
|
|
case CRYPT_NEWKEYSET:
|
|
dwFlags = dwFlags | m_keyProvInfo.dwFlags;
|
|
break;
|
|
|
|
case CRYPT_DELETEKEYSET:
|
|
if( m_hProv != NULL ) {
|
|
|
|
CryptReleaseContext(m_hProv, 0);
|
|
m_hProv = NULL;
|
|
|
|
CryptAcquireContextU(&m_hProv,
|
|
m_keyProvInfo.pwszContainerName,
|
|
m_keyProvInfo.pwszProvName,
|
|
m_keyProvInfo.dwProvType,
|
|
CRYPT_DELETEKEYSET);
|
|
}
|
|
m_hProv = NULL;
|
|
goto CommonReturn;
|
|
break;
|
|
|
|
default:
|
|
dwFlags = m_keyProvInfo.dwFlags;
|
|
break;
|
|
}
|
|
|
|
if(m_hProv == NULL) {
|
|
|
|
if( CryptAcquireContextU(&m_hProv,
|
|
m_keyProvInfo.pwszContainerName,
|
|
m_keyProvInfo.pwszProvName,
|
|
m_keyProvInfo.dwProvType,
|
|
dwFlags) ) {
|
|
|
|
// we have the m_hProv, now set the provider name
|
|
// Since this is secondary to the task, don't do error checking
|
|
// nothing here should really fail anyway
|
|
pszProvName = NULL;
|
|
while (TRUE)
|
|
{
|
|
if(!CryptGetProvParam( m_hProv,
|
|
PP_NAME,
|
|
(BYTE*)pszProvName,
|
|
&cb,
|
|
0))
|
|
{
|
|
break;
|
|
}
|
|
if (NULL != pszProvName)
|
|
{
|
|
if(m_keyProvInfo.pwszProvName != wszEmpty)
|
|
MyCoTaskMemFree(m_keyProvInfo.pwszProvName);
|
|
m_keyProvInfo.pwszProvName = WideFromMB(pszProvName);
|
|
break;
|
|
}
|
|
pszProvName = (char *)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pszProvName)
|
|
{
|
|
goto CommonReturn;
|
|
}
|
|
}
|
|
|
|
// Here we just try and get the unique container name
|
|
// If not, just go on
|
|
|
|
BOOL fTryAnother = FALSE;
|
|
cb = 0;
|
|
pszContainerName = NULL;
|
|
while (TRUE)
|
|
{
|
|
if(!CryptGetProvParam( m_hProv,
|
|
PP_UNIQUE_CONTAINER,
|
|
(BYTE*)pszContainerName,
|
|
&cb,
|
|
0))
|
|
{
|
|
if (NULL == pszContainerName)
|
|
{
|
|
fTryAnother = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pszContainerName);
|
|
pszContainerName = NULL;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (NULL != pszContainerName)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
}
|
|
pszContainerName = (char *)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pszContainerName)
|
|
{
|
|
goto CommonReturn;
|
|
}
|
|
}
|
|
|
|
if (fTryAnother)
|
|
{
|
|
// so we can't get the unique container name,
|
|
// lets just go for the container name (may not be unique).
|
|
cb = 0;
|
|
pszContainerName = NULL;
|
|
while (TRUE)
|
|
{
|
|
if(!CryptGetProvParam(m_hProv,
|
|
PP_CONTAINER,
|
|
(BYTE*)pszContainerName,
|
|
&cb,
|
|
0))
|
|
{
|
|
if (NULL != pszContainerName)
|
|
{
|
|
LocalFree(pszContainerName);
|
|
pszContainerName = NULL;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (NULL != pszContainerName)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
pszContainerName = (char *)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pszContainerName)
|
|
{
|
|
goto CommonReturn;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// set the container, otherwise use what was there
|
|
if(pszContainerName != NULL) {
|
|
if( m_keyProvInfo.pwszContainerName != wszEmpty )
|
|
MyCoTaskMemFree(m_keyProvInfo.pwszContainerName);
|
|
m_keyProvInfo.pwszContainerName = WideFromMB(pszContainerName);
|
|
}
|
|
|
|
// now because some providers double duty for provider types
|
|
// get what the the provider thinks its type is
|
|
cb = sizeof(DWORD);
|
|
if(CryptGetProvParam( m_hProv,
|
|
PP_PROVTYPE,
|
|
(BYTE *) &dwProvType,
|
|
&cb,
|
|
0) ) {
|
|
m_keyProvInfo.dwProvType = dwProvType;
|
|
}
|
|
|
|
} else {
|
|
m_hProv = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
CommonReturn:
|
|
hProvT = m_hProv;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
if (NULL != pszProvName)
|
|
{
|
|
LocalFree(pszProvName);
|
|
}
|
|
if (NULL != pszContainerName)
|
|
{
|
|
LocalFree(pszContainerName);
|
|
}
|
|
return(hProvT);
|
|
}
|
|
|
|
|
|
BOOL CCEnroll::SetKeyParams(
|
|
PCRYPT_KEY_PROV_INFO pKeyProvInfo
|
|
) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// remove provider handles
|
|
if(m_hProv != NULL)
|
|
CryptReleaseContext(m_hProv, 0);
|
|
m_hProv = NULL;
|
|
|
|
if(m_hVerifyProv != NULL)
|
|
CryptReleaseContext(m_hVerifyProv, 0);
|
|
m_hVerifyProv = NULL;
|
|
|
|
put_ContainerNameWStr(pKeyProvInfo->pwszContainerName);
|
|
put_ProviderNameWStr(pKeyProvInfo->pwszProvName);
|
|
put_ProviderFlags(pKeyProvInfo->dwFlags);
|
|
put_KeySpec(pKeyProvInfo->dwKeySpec);
|
|
put_ProviderType(pKeyProvInfo->dwProvType);
|
|
|
|
// someday we will have to pay attention to this too.
|
|
m_keyProvInfo.cProvParam = 0;
|
|
m_keyProvInfo.rgProvParam = NULL;
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::createPKCS10(
|
|
/* [in] */ BSTR DNName,
|
|
/* [in] */ BSTR wszPurpose,
|
|
/* [retval][out] */ BSTR __RPC_FAR *pPKCS10) {
|
|
|
|
return(createPKCS10WStrBStr(DNName, wszPurpose, pPKCS10));
|
|
}
|
|
|
|
HRESULT CCEnroll::createPKCS10WStrBStr(
|
|
LPCWSTR DNName,
|
|
LPCWSTR wszPurpose,
|
|
BSTR __RPC_FAR *pPKCS10) {
|
|
|
|
HRESULT hr = S_OK;
|
|
CRYPT_DATA_BLOB blobPKCS10;
|
|
|
|
memset(&blobPKCS10, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
hr = createPKCS10WStr(DNName, wszPurpose, &blobPKCS10);
|
|
if(S_OK != hr)
|
|
{
|
|
goto createPKCS10Error;
|
|
}
|
|
|
|
// BASE64 encode pkcs 10, no header for backward compatible
|
|
hr = BlobToBstring(&blobPKCS10, CRYPT_STRING_BASE64, pPKCS10);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BlobToBstringError;
|
|
}
|
|
|
|
CommonReturn:
|
|
|
|
if(NULL != blobPKCS10.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobPKCS10.pbData);
|
|
}
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
if(*pPKCS10 != NULL)
|
|
SysFreeString(*pPKCS10);
|
|
*pPKCS10 = NULL;
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(createPKCS10Error);
|
|
TRACE_ERROR(BlobToBstringError);
|
|
}
|
|
|
|
HRESULT CCEnroll::AddCertsToStores(
|
|
HCERTSTORE hStoreMsg,
|
|
LONG *plCertInstalled
|
|
) {
|
|
|
|
HCERTSTORE hStoreRoot = NULL;
|
|
HCERTSTORE hStoreCA = NULL;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
PCCERT_CONTEXT pCertContextLast = NULL;
|
|
LONG lCertInstalled = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
//init
|
|
if (NULL != plCertInstalled)
|
|
{
|
|
*plCertInstalled = 0;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if( (hStoreCA = GetStore(StoreCA)) == NULL )
|
|
goto ErrorCertOpenCAStore;
|
|
|
|
if( (hStoreRoot = GetStore(StoreROOT)) == NULL )
|
|
goto ErrorCertOpenRootStore;
|
|
|
|
// now just place the rest of the cert in either the ROOT or CA store
|
|
// we know we removed the end-entity cert from the msg store already
|
|
// put all certs that came in the message into the appropriate store
|
|
while( (pCertContext = CertEnumCertificatesInStore(
|
|
hStoreMsg,
|
|
pCertContextLast)) != NULL ) {
|
|
|
|
// if it is a self sign, it is a ROOT
|
|
if( CertCompareCertificateName(
|
|
CRYPT_ASN_ENCODING,
|
|
&pCertContext->pCertInfo->Subject,
|
|
&pCertContext->pCertInfo->Issuer) ) {
|
|
|
|
// to root store could invoke a pop up, check cancel button
|
|
// but don't error out from any fail
|
|
if (MySafeCertAddCertificateContextToStore(
|
|
hStoreRoot,
|
|
pCertContext,
|
|
CERT_STORE_ADD_USE_EXISTING,
|
|
NULL,
|
|
m_dwEnabledSafteyOptions))
|
|
{
|
|
++lCertInstalled;
|
|
}
|
|
else
|
|
{
|
|
if (S_OK == hr)
|
|
{
|
|
//save the 1st error as return
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr)
|
|
{
|
|
//map generic access deny to xenroll error
|
|
hr = XENROLL_E_CANNOT_ADD_ROOT_CERT;
|
|
}
|
|
}
|
|
//don't goto error here and finish the loop
|
|
}
|
|
}
|
|
|
|
// if it is not the MY cert, it must go in the CA store
|
|
// do nothing with the MY cert as we already handled it
|
|
else {
|
|
|
|
// likewise we don't care if these get added to the
|
|
// CA store
|
|
if (MySafeCertAddCertificateContextToStore(
|
|
hStoreCA,
|
|
pCertContext,
|
|
CERT_STORE_ADD_USE_EXISTING,
|
|
NULL,
|
|
m_dwEnabledSafteyOptions))
|
|
{
|
|
//no error code check
|
|
++lCertInstalled;
|
|
}
|
|
}
|
|
|
|
pCertContextLast = pCertContext;
|
|
}
|
|
pCertContextLast = NULL;
|
|
if (NULL != plCertInstalled)
|
|
{
|
|
*plCertInstalled = lCertInstalled;
|
|
}
|
|
|
|
CommonReturn:
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorCertOpenCAStore);
|
|
TRACE_ERROR(ErrorCertOpenRootStore);
|
|
}
|
|
|
|
BOOL
|
|
IsDesiredProperty(DWORD dwPropertyId)
|
|
{
|
|
DWORD DesiredIds[] = {
|
|
CERT_PVK_FILE_PROP_ID,
|
|
CERT_FRIENDLY_NAME_PROP_ID,
|
|
CERT_DESCRIPTION_PROP_ID,
|
|
CERT_RENEWAL_PROP_ID,
|
|
};
|
|
DWORD i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(DesiredIds); ++i)
|
|
{
|
|
if (dwPropertyId == DesiredIds[i])
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
IsFilteredOutProperty(DWORD dwPropertyId)
|
|
{
|
|
DWORD FilteredIds[] = {
|
|
XENROLL_RENEWAL_CERTIFICATE_PROP_ID,
|
|
XENROLL_PASS_THRU_PROP_ID,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
CERT_ENROLLMENT_PROP_ID, //pending property
|
|
};
|
|
DWORD i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(FilteredIds); ++i)
|
|
{
|
|
if (dwPropertyId == FilteredIds[i])
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT CCEnroll::GetEndEntityCert(
|
|
PCRYPT_DATA_BLOB pBlobPKCS7,
|
|
BOOL fSaveToStores,
|
|
PCCERT_CONTEXT *ppCert
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCERTSTORE hStoreMsg = NULL;
|
|
HCERTSTORE hStoreMy = NULL;
|
|
HCERTSTORE hStoreRequest = NULL;
|
|
|
|
PCCERT_CONTEXT pCertContextLast = NULL;
|
|
PCCERT_CONTEXT pCertContextRequest = NULL;
|
|
PCCERT_CONTEXT pCertContextMsg = NULL;
|
|
PCCERT_CONTEXT pCertContextArchive = NULL;
|
|
|
|
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;
|
|
DWORD cb = 0;
|
|
CRYPT_DATA_BLOB blobData;
|
|
|
|
CRYPT_HASH_BLOB blobHash = {sizeof(m_arHashBytesNewCert), m_arHashBytesNewCert};
|
|
CRYPT_HASH_BLOB blobHashRenew = {sizeof(m_arHashBytesOldCert), m_arHashBytesOldCert};
|
|
|
|
RequestFlags requestFlags;
|
|
CRYPT_HASH_BLOB requestFlagsBlob;
|
|
|
|
CRYPT_HASH_BLOB renewalCertBlob;
|
|
|
|
//Bug #202557 for IE3.02 upd clients (xiaohs)
|
|
HCRYPTPROV hProv=NULL;
|
|
BOOL fSetting;
|
|
DWORD dwPropertyId;
|
|
CRYPT_DATA_BLOB blobProp;
|
|
BYTE *pbArchivedKeyHash = NULL;
|
|
DWORD cbArchivedKeyHash = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
memset(&requestFlags, 0, sizeof(RequestFlags));
|
|
memset(&blobData, 0, sizeof(CRYPT_DATA_BLOB));
|
|
memset(&requestFlagsBlob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
memset(&renewalCertBlob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
ZeroMemory(&blobProp, sizeof(blobProp));
|
|
|
|
if (NULL == ppCert)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
goto InvalidParameterError;
|
|
}
|
|
|
|
//init return
|
|
*ppCert = NULL;
|
|
|
|
if(!MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
pBlobPKCS7,
|
|
(CERT_QUERY_CONTENT_FLAG_CERT |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
|
|
CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED) ,
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&hStoreMsg,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCryptQueryObject;
|
|
}
|
|
|
|
// check to see if this hash is in the message
|
|
if (m_pCertContextStatic == NULL ||
|
|
(NULL == (pCertContextMsg = CertFindCertificateInStore(
|
|
hStoreMsg,
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_HASH,
|
|
&blobHash,
|
|
NULL))))
|
|
{
|
|
// open the request store
|
|
if (NULL == (hStoreRequest = GetStore(StoreREQUEST)))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertOpenRequestStore;
|
|
}
|
|
// find cert in request store that matches cert
|
|
// in message, by public key
|
|
while (NULL != (pCertContextMsg = CertEnumCertificatesInStore(
|
|
hStoreMsg,
|
|
pCertContextLast)))
|
|
{
|
|
// check to see if this is in the request store
|
|
if (NULL != (pCertContextRequest = CertFindCertificateInStore(
|
|
hStoreRequest,
|
|
CRYPT_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_PUBLIC_KEY,
|
|
(void *) &pCertContextMsg->pCertInfo->SubjectPublicKeyInfo,
|
|
NULL)))
|
|
{
|
|
// found a match, get out
|
|
break;
|
|
}
|
|
|
|
pCertContextLast = pCertContextMsg;
|
|
}
|
|
pCertContextLast = NULL;
|
|
|
|
// if we didn't find one, then GetLastError was set either
|
|
// by CertEnumCerificatesInStore or CertEnumCerificatesInStore
|
|
if (NULL == pCertContextRequest)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorNoCertFound;
|
|
}
|
|
|
|
if (fSaveToStores)
|
|
{
|
|
// check archived key hash property first
|
|
// if the property exists, means key archival was in the request
|
|
cb = 0;
|
|
while (TRUE)
|
|
{
|
|
if(!CertGetCertificateContextProperty(
|
|
pCertContextRequest,
|
|
CERT_ARCHIVED_KEY_HASH_PROP_ID,
|
|
pbArchivedKeyHash,
|
|
&cbArchivedKeyHash))
|
|
{
|
|
if (NULL == pbArchivedKeyHash)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
if (MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND) == hr)
|
|
{
|
|
//no such property, so we are done
|
|
break;
|
|
}
|
|
// some other error
|
|
goto ErrorCertGetCertificateContextProperty;
|
|
}
|
|
else
|
|
{
|
|
//if pbArchivedKeyHash non-null, error
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertGetCertificateContextProperty;
|
|
}
|
|
}
|
|
if (NULL != pbArchivedKeyHash)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
pbArchivedKeyHash = (BYTE*)LocalAlloc(
|
|
LMEM_FIXED, cbArchivedKeyHash);
|
|
if (NULL == pbArchivedKeyHash)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
if (NULL != pbArchivedKeyHash && NULL == m_blobResponseKAHash.pbData)
|
|
{
|
|
//request cert has archived key hash but response
|
|
//doesn't contain key hash for verification. maybe
|
|
//a spoofing response?
|
|
hr = XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND;
|
|
goto ResponseKAHashNotFoundError;
|
|
}
|
|
if (NULL == pbArchivedKeyHash && NULL != m_blobResponseKAHash.pbData)
|
|
{
|
|
//request cert doesn't have archived key hash but
|
|
//response does. confliciting. seems no security harm
|
|
hr = XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH;
|
|
goto ResponseUnexpectedKAHashError;
|
|
}
|
|
if (NULL != pbArchivedKeyHash && NULL != m_blobResponseKAHash.pbData)
|
|
{
|
|
//now we should check if they match
|
|
//compare size and hash
|
|
if (cbArchivedKeyHash != m_blobResponseKAHash.cbData ||
|
|
0 != memcmp(pbArchivedKeyHash,
|
|
m_blobResponseKAHash.pbData,
|
|
cbArchivedKeyHash))
|
|
{
|
|
//oh, potential attack
|
|
hr = XENROLL_E_RESPONSE_KA_HASH_MISMATCH;
|
|
//should remove the request cert?
|
|
goto ResponseKAMismatchError;
|
|
}
|
|
}
|
|
}
|
|
|
|
// get those request cert properties that are,
|
|
// either the property not blob property
|
|
// or blob property needs special handling
|
|
// Important: remember to add these Ids in IsFilteredOutProperty
|
|
fSetting = TRUE;
|
|
cb = 0;
|
|
while (TRUE)
|
|
{
|
|
if(!CertGetCertificateContextProperty(
|
|
pCertContextRequest,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
pKeyProvInfo,
|
|
&cb))
|
|
{
|
|
if (NULL == pKeyProvInfo)
|
|
{
|
|
//skip setting
|
|
fSetting = FALSE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertGetCertificateContextProperty;
|
|
}
|
|
}
|
|
if (NULL != pKeyProvInfo)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
pKeyProvInfo = (PCRYPT_KEY_PROV_INFO)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pKeyProvInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
if (fSetting)
|
|
{
|
|
// put the property on the returned cert
|
|
if( !CertSetCertificateContextProperty(
|
|
pCertContextMsg,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
0,
|
|
pKeyProvInfo) )
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorSetMyCertPropError;
|
|
}
|
|
|
|
// Set the provider info
|
|
SetKeyParams(pKeyProvInfo);
|
|
}
|
|
|
|
fSetting = TRUE;
|
|
while (TRUE)
|
|
{
|
|
if(!CertGetCertificateContextProperty(
|
|
pCertContextRequest,
|
|
XENROLL_PASS_THRU_PROP_ID,
|
|
requestFlagsBlob.pbData,
|
|
&requestFlagsBlob.cbData) )
|
|
{
|
|
if (NULL == requestFlagsBlob.pbData)
|
|
{
|
|
//do nothing
|
|
fSetting = FALSE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorDecodeRequestFlags;
|
|
}
|
|
}
|
|
if (NULL != requestFlagsBlob.pbData)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
requestFlagsBlob.pbData = (BYTE *)LocalAlloc(LMEM_FIXED,
|
|
requestFlagsBlob.cbData);
|
|
if (NULL == requestFlagsBlob.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
if (fSetting)
|
|
{
|
|
// get the encoded blob
|
|
cb = sizeof(requestFlags);
|
|
// since this is a private data structure, its size should be
|
|
// known and this should aways pass
|
|
if (!CryptDecodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
XENROLL_REQUEST_INFO,
|
|
requestFlagsBlob.pbData,
|
|
requestFlagsBlob.cbData,
|
|
0,
|
|
&requestFlags,
|
|
&cb))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorDecodeRequestFlags;
|
|
}
|
|
// now set the flags
|
|
if(!m_fWriteCertToCSPModified)
|
|
m_fWriteCertToCSP = requestFlags.fWriteToCSP;
|
|
if(!m_fWriteCertToUserDSModified)
|
|
m_fWriteCertToUserDS = requestFlags.fWriteToDS;
|
|
if(!m_fRequestStoreOpenFlagsModified)
|
|
m_RequestStore.dwFlags = requestFlags.openFlags;
|
|
if(!m_fMyStoreOpenFlagsModified)
|
|
m_MyStore.dwFlags = (m_MyStore.dwFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) |
|
|
(requestFlags.openFlags & CERT_SYSTEM_STORE_LOCATION_MASK);
|
|
if(!m_fCAStoreOpenFlagsModified)
|
|
m_CAStore.dwFlags = (m_CAStore.dwFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) |
|
|
(requestFlags.openFlags & CERT_SYSTEM_STORE_LOCATION_MASK);
|
|
if(!m_fRootStoreOpenFlagsModified) {
|
|
//
|
|
// POTENTIAL SCRIPTING VIOLATION: we're mapping request store flags directly to root store flags.
|
|
// If they have set request store flags to local machine, propagate this setting to the root store flags,
|
|
// but set the root store name to "CA".
|
|
//
|
|
if (0 != m_dwEnabledSafteyOptions) {
|
|
if (requestFlags.openFlags & CERT_SYSTEM_STORE_LOCAL_MACHINE) {
|
|
m_RootStore.wszName = wszCA;
|
|
}
|
|
}
|
|
m_RootStore.dwFlags = (m_RootStore.dwFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) |
|
|
(requestFlags.openFlags & CERT_SYSTEM_STORE_LOCATION_MASK);
|
|
}
|
|
}
|
|
|
|
// see if this is a renewal request
|
|
m_fArchiveOldCert = FALSE;
|
|
fSetting = TRUE;
|
|
while (TRUE)
|
|
{
|
|
// get the encoded blob
|
|
if (!CertGetCertificateContextProperty(
|
|
pCertContextRequest,
|
|
XENROLL_RENEWAL_CERTIFICATE_PROP_ID,
|
|
renewalCertBlob.pbData,
|
|
&renewalCertBlob.cbData))
|
|
{
|
|
if (NULL == renewalCertBlob.pbData)
|
|
{
|
|
fSetting = FALSE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertGetCertificateContextProperty;
|
|
}
|
|
}
|
|
if (NULL != renewalCertBlob.pbData)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
renewalCertBlob.pbData = (BYTE *)LocalAlloc(LMEM_FIXED,
|
|
renewalCertBlob.cbData);
|
|
if (NULL == renewalCertBlob.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
if (fSetting)
|
|
{
|
|
//Bug #202557 for IE3.02 upd clients (xiaohs)
|
|
if (NULL==hProv)
|
|
{
|
|
if(!CryptAcquireContext(
|
|
&hProv,
|
|
NULL,
|
|
MS_DEF_PROV,
|
|
PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorAcquireContext;
|
|
}
|
|
}
|
|
|
|
if (!CryptHashCertificate(
|
|
hProv, //NULL, Bug #202557 for IE3.02 upd clients (xiaohs)
|
|
0, //alg
|
|
X509_ASN_ENCODING, //0 dwFlags
|
|
renewalCertBlob.pbData,
|
|
renewalCertBlob.cbData,
|
|
blobHashRenew.pbData,
|
|
&blobHashRenew.cbData))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCryptHashCertificate;
|
|
}
|
|
m_fArchiveOldCert = TRUE;
|
|
}
|
|
|
|
//get rest of blob properties from request store and set to the cert
|
|
dwPropertyId = CertEnumCertificateContextProperties(
|
|
pCertContextRequest, 0); //enum from 1st
|
|
while (0 != dwPropertyId)
|
|
{
|
|
// if (!IsFilteredOutProperty(dwPropertyId))
|
|
//because iis cert install doesn't like to copy all properties from
|
|
//request cert to install cert we just copy selected properties for now
|
|
if (IsDesiredProperty(dwPropertyId))
|
|
{
|
|
fSetting = TRUE;
|
|
while (TRUE)
|
|
{
|
|
if (!CertGetCertificateContextProperty(
|
|
pCertContextRequest,
|
|
dwPropertyId,
|
|
blobProp.pbData,
|
|
&blobProp.cbData))
|
|
{
|
|
//no get, no set, go on
|
|
fSetting = FALSE;
|
|
break;
|
|
}
|
|
if (NULL != blobProp.pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
blobProp.pbData = (BYTE*)LocalAlloc(LMEM_FIXED,
|
|
blobProp.cbData);
|
|
if (NULL == blobProp.pbData)
|
|
{
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
if (fSetting)
|
|
{
|
|
//should get the property from the request cert
|
|
if (!CertSetCertificateContextProperty(
|
|
pCertContextMsg,
|
|
dwPropertyId,
|
|
0,
|
|
&blobProp))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorSetMyCertPropError;
|
|
}
|
|
}
|
|
if (NULL != blobProp.pbData)
|
|
{
|
|
//set for the next enum
|
|
LocalFree(blobProp.pbData);
|
|
blobProp.pbData = NULL;
|
|
}
|
|
}
|
|
dwPropertyId = CertEnumCertificateContextProperties(
|
|
pCertContextRequest,
|
|
dwPropertyId);
|
|
}
|
|
|
|
// save this away in the cache
|
|
if(m_pCertContextStatic != NULL)
|
|
CertFreeCertificateContext(m_pCertContextStatic);
|
|
|
|
m_pCertContextStatic = CertDuplicateCertificateContext(pCertContextMsg);
|
|
|
|
//Bug #202557 for IE3.02 upd clients (xiaohs)
|
|
if(NULL==hProv)
|
|
{
|
|
if(!CryptAcquireContext(
|
|
&hProv,
|
|
NULL,
|
|
MS_DEF_PROV,
|
|
PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorAcquireContext;
|
|
}
|
|
}
|
|
|
|
if( !CryptHashCertificate(
|
|
hProv, //NULL Bug #202557 for IE3.02 upd clients (xiaohs)
|
|
0,
|
|
X509_ASN_ENCODING,
|
|
pCertContextMsg->pbCertEncoded,
|
|
pCertContextMsg->cbCertEncoded,
|
|
blobHash.pbData,
|
|
&blobHash.cbData) )
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCryptHashCertificate;
|
|
}
|
|
}
|
|
|
|
// at this point we have 2 context m_pCertContextStatic which we want to return to the user
|
|
// and pCertContextMsg which we want to delete from the Msg store
|
|
assert(pCertContextMsg != NULL);
|
|
CertDeleteCertificateFromStore(pCertContextMsg);
|
|
pCertContextMsg = NULL; // freed by the delete
|
|
|
|
// we want to return our static, so make a dup and this is what we will return
|
|
assert(m_pCertContextStatic != NULL);
|
|
pCertContextMsg = CertDuplicateCertificateContext(m_pCertContextStatic);
|
|
|
|
// put these in the stores if asked
|
|
if(fSaveToStores) {
|
|
|
|
// open the stores
|
|
if( (hStoreMy = GetStore(StoreMY)) == NULL)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertOpenMYStore;
|
|
}
|
|
|
|
// we know that the pCertContextMsg is a dup of the end-entity cert in m_pCertContextStatic
|
|
// and we want to put this in the MY store
|
|
assert(pCertContextMsg != NULL);
|
|
if( !MySafeCertAddCertificateContextToStore(
|
|
hStoreMy,
|
|
pCertContextMsg,
|
|
CERT_STORE_ADD_USE_EXISTING,
|
|
NULL,
|
|
m_dwEnabledSafteyOptions) )
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertAddToMyStore;
|
|
}
|
|
|
|
// If we have renewal, then mark the old cert as an archive
|
|
if(m_fArchiveOldCert &&
|
|
((pCertContextArchive = CertFindCertificateInStore(
|
|
hStoreMy,
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_HASH,
|
|
&blobHashRenew,
|
|
NULL)) != NULL) ) {
|
|
|
|
// Set the Archive property on the cert.
|
|
// crypt32 in IE3.02upd does not support this prop, so don't fail on error
|
|
CertSetCertificateContextProperty(
|
|
pCertContextArchive,
|
|
CERT_ARCHIVED_PROP_ID,
|
|
0,
|
|
&blobData);
|
|
|
|
//set new cert hash on old archived cert
|
|
//ignore error if it fails
|
|
CertSetCertificateContextProperty(
|
|
pCertContextArchive,
|
|
CERT_RENEWAL_PROP_ID,
|
|
0,
|
|
&blobHash);
|
|
}
|
|
|
|
// add the rest of the certs to the stores
|
|
hr = AddCertsToStores(hStoreMsg, NULL);
|
|
//ignore cancel error since it from root cert install
|
|
//ignore XENROLL_E_CANNOT_ADD_ROOT_CERT also
|
|
if (S_OK != hr &&
|
|
MY_HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr &&
|
|
XENROLL_E_CANNOT_ADD_ROOT_CERT != hr)
|
|
{
|
|
goto ErrorAddCertsToStores;
|
|
}
|
|
}
|
|
|
|
*ppCert = pCertContextMsg;
|
|
|
|
CommonReturn:
|
|
|
|
//Bug #202557 for IE3.02 upd clients (xiaohs)
|
|
if(hProv)
|
|
CryptReleaseContext(hProv, 0);
|
|
|
|
if(pCertContextRequest != NULL)
|
|
CertFreeCertificateContext(pCertContextRequest);
|
|
|
|
if(pCertContextArchive != NULL)
|
|
CertFreeCertificateContext(pCertContextArchive);
|
|
|
|
// it really should be NULL
|
|
assert(pCertContextLast == NULL);
|
|
|
|
if(hStoreMsg != NULL)
|
|
CertCloseStore(hStoreMsg, 0);
|
|
|
|
// we need to do this because the store that may be opened is the systemstore, but
|
|
// the store we may need is the local machine store, but we don't know that until the
|
|
// system store finds the request cert in the local machine physical store.
|
|
// Later when we do the delete, we want the local machine store open.
|
|
FlushStore(StoreREQUEST);
|
|
|
|
if (NULL != requestFlagsBlob.pbData)
|
|
{
|
|
LocalFree(requestFlagsBlob.pbData);
|
|
}
|
|
if (NULL != renewalCertBlob.pbData)
|
|
{
|
|
LocalFree(renewalCertBlob.pbData);
|
|
}
|
|
if (NULL != blobProp.pbData)
|
|
{
|
|
LocalFree(blobProp.pbData);
|
|
}
|
|
if (NULL != pKeyProvInfo)
|
|
{
|
|
LocalFree(pKeyProvInfo);
|
|
}
|
|
if (NULL != pbArchivedKeyHash)
|
|
{
|
|
LocalFree(pbArchivedKeyHash);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return (hr);
|
|
|
|
ErrorReturn:
|
|
if(NULL != pCertContextMsg)
|
|
{
|
|
CertFreeCertificateContext(pCertContextMsg);
|
|
}
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorCryptHashCertificate);
|
|
TRACE_ERROR(ErrorCertOpenMYStore);
|
|
TRACE_ERROR(ErrorCertAddToMyStore);
|
|
TRACE_ERROR(ErrorCryptQueryObject);
|
|
TRACE_ERROR(ErrorCertOpenRequestStore);
|
|
TRACE_ERROR(ErrorNoCertFound);
|
|
TRACE_ERROR(ErrorCertGetCertificateContextProperty);
|
|
TRACE_ERROR(ErrorSetMyCertPropError);
|
|
TRACE_ERROR(ErrorDecodeRequestFlags);
|
|
TRACE_ERROR(ErrorAcquireContext); //Bug #202557 for IE3.02 upd clients (xiaohs)
|
|
TRACE_ERROR(ErrorAddCertsToStores);
|
|
TRACE_ERROR(OutOfMemoryError);
|
|
TRACE_ERROR(InvalidParameterError);
|
|
TRACE_ERROR(ResponseKAMismatchError)
|
|
TRACE_ERROR(ResponseUnexpectedKAHashError)
|
|
TRACE_ERROR(ResponseKAHashNotFoundError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::getCertFromPKCS7(
|
|
/* [in] */ BSTR wszPKCS7,
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrCert
|
|
) {
|
|
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobPKCS7;
|
|
CRYPT_DATA_BLOB blobX509;
|
|
PCCERT_CONTEXT pCertContextMy = NULL;
|
|
|
|
assert(wszPKCS7 != NULL && pbstrCert != NULL);
|
|
if (NULL == wszPKCS7 || NULL == pbstrCert)
|
|
goto PointerError;
|
|
|
|
// just put into a blob
|
|
memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB));
|
|
blobPKCS7.cbData = SysStringByteLen(wszPKCS7);
|
|
blobPKCS7.pbData = (PBYTE) wszPKCS7;
|
|
|
|
// Get a Cert Context for the end-entity
|
|
if( (pCertContextMy = getCertContextFromPKCS7(&blobPKCS7)) == NULL)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto getCertContextFromPKCS7Error;
|
|
}
|
|
|
|
blobX509.pbData = pCertContextMy->pbCertEncoded;
|
|
blobX509.cbData = pCertContextMy->cbCertEncoded;
|
|
//base64 with no header for backward compatible
|
|
hr = BlobToBstring(&blobX509, CRYPT_STRING_BASE64, pbstrCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BlobToBstringError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(pCertContextMy != NULL)
|
|
CertFreeCertificateContext(pCertContextMy);
|
|
|
|
return(hr);
|
|
|
|
SET_HRESULT(PointerError, E_POINTER);
|
|
TRACE_ERROR(getCertContextFromPKCS7Error);
|
|
TRACE_ERROR(BlobToBstringError);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::acceptPKCS7(
|
|
/* [in] */ BSTR wszPKCS7) {
|
|
|
|
CRYPT_DATA_BLOB blobPKCS7;
|
|
HRESULT hr;
|
|
|
|
assert(wszPKCS7 != NULL);
|
|
if (NULL == wszPKCS7)
|
|
goto PointerError;
|
|
|
|
// just put into a blob
|
|
memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB));
|
|
blobPKCS7.cbData = SysStringByteLen(wszPKCS7);
|
|
blobPKCS7.pbData = (PBYTE) wszPKCS7;
|
|
|
|
// accept the blob
|
|
hr = acceptPKCS7Blob(&blobPKCS7);
|
|
ErrorReturn:
|
|
return hr;
|
|
|
|
SET_HRESULT(PointerError, E_POINTER);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::createFilePKCS10(
|
|
/* [in] */ BSTR DNName,
|
|
/* [in] */ BSTR Usage,
|
|
/* [in] */ BSTR wszPKCS10FileName) {
|
|
return(createFilePKCS10WStr(DNName, Usage, wszPKCS10FileName));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::addCertTypeToRequest(
|
|
/* [in] */ BSTR CertType) {
|
|
return(AddCertTypeToRequestWStr(CertType));
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::addCertTypeToRequestEx(
|
|
IN LONG lType,
|
|
IN BSTR bstrOIDOrName,
|
|
IN LONG lMajorVersion,
|
|
IN BOOL fMinorVersion,
|
|
IN LONG lMinorVersion)
|
|
{
|
|
return AddCertTypeToRequestWStrEx(
|
|
lType,
|
|
bstrOIDOrName,
|
|
lMajorVersion,
|
|
fMinorVersion,
|
|
lMinorVersion);
|
|
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::getProviderType(
|
|
IN BSTR strProvName,
|
|
OUT LONG *plProvType)
|
|
{
|
|
return getProviderTypeWStr(strProvName, plProvType);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::addNameValuePairToSignature(
|
|
/* [in] */ BSTR Name,
|
|
/* [in] */ BSTR Value) {
|
|
return(AddNameValuePairToSignatureWStr(Name, Value));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::acceptFilePKCS7(
|
|
/* [in] */ BSTR wszPKCS7FileName) {
|
|
return(acceptFilePKCS7WStr(wszPKCS7FileName));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::freeRequestInfo(
|
|
/* [in] */ BSTR bstrPKCS7OrPKCS10)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blob;
|
|
BYTE *pbData = NULL;
|
|
DWORD cbData = 0;
|
|
|
|
// could be base64
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryW(
|
|
(WCHAR*)bstrPKCS7OrPKCS10,
|
|
SysStringLen(bstrPKCS7OrPKCS10),
|
|
CRYPT_STRING_ANY,
|
|
pbData,
|
|
&cbData,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptStringToBinaryWError;
|
|
}
|
|
if (NULL != pbData)
|
|
{
|
|
break; //done
|
|
}
|
|
pbData = (BYTE*)LocalAlloc(LMEM_FIXED, cbData);
|
|
if (NULL == pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
blob.cbData = cbData;
|
|
blob.pbData = pbData;
|
|
|
|
hr = freeRequestInfoBlob(blob);
|
|
if (S_OK != hr)
|
|
{
|
|
goto freeRequestInfoBlobError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pbData)
|
|
{
|
|
LocalFree(pbData);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(MyCryptStringToBinaryWError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
TRACE_ERROR(freeRequestInfoBlobError)
|
|
}
|
|
|
|
|
|
//
|
|
// MY STORE
|
|
//
|
|
HCERTSTORE STDMETHODCALLTYPE CCEnroll::getMyStore( void)
|
|
{
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_MyStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*pbstrName = SysAllocString(m_MyStore.wszName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreName(
|
|
/* [in] */ BSTR bstrName) {
|
|
return(put_MyStoreNameWStr(bstrName));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreType(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstrType = BSTRFromMB(m_MyStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreType(
|
|
/* [in] */ BSTR bstrType) {
|
|
return(put_MyStoreTypeWStr(bstrType));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreFlags(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdwFlags) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdwFlags = m_MyStore.dwFlags;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// This method is only safe for scripting if it's parameter is safe.
|
|
// See VerifyStoreFlagsSafeForScripting().
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreFlags(
|
|
/* [in] */ LONG dwFlags) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// If we're marked as safe for scripting, see if the flags passed in are safe:
|
|
if (0 != m_dwEnabledSafteyOptions && !VerifyStoreFlagsSafeForScripting(dwFlags))
|
|
goto AccessDeniedError;
|
|
|
|
if(m_MyStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
|
|
// set the my store flags
|
|
m_MyStore.dwFlags = dwFlags;
|
|
m_fMyStoreOpenFlagsModified = TRUE;
|
|
m_keyProvInfo.dwFlags |= KeyLocationFromStoreLocation(dwFlags);
|
|
|
|
// track the request store location to the my store, only if the request store has not been modified
|
|
// do NOT set the modify bit for the request store, this is a default
|
|
if(!m_fRequestStoreOpenFlagsModified) {
|
|
m_RequestStore.dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
|
|
m_RequestStore.dwFlags |= (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK);
|
|
}
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_MyStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*szwName = CopyWideString(m_MyStore.wszName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreNameWStr(
|
|
/* [in] */ LPWSTR szwName) {
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_MyStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_MyStore.wszName != wszMY)
|
|
MyCoTaskMemFree(m_MyStore.wszName);
|
|
if( (m_MyStore.wszName = CopyWideString(szwName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreTypeWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*szwType = WideFromMB(m_MyStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreTypeWStr(
|
|
/* [in] */ LPWSTR szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_MyStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_MyStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_MyStore.szType);
|
|
if( (m_MyStore.szType = MBFromWide(szwType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
//
|
|
// CA STORE
|
|
//
|
|
HCERTSTORE STDMETHODCALLTYPE CCEnroll::getCAStore( void)
|
|
{
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_CAStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*pbstrName = SysAllocString(m_CAStore.wszName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreName(
|
|
/* [in] */ BSTR bstrName) {
|
|
return(put_CAStoreNameWStr(bstrName));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreType(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstrType = BSTRFromMB(m_CAStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreType(
|
|
/* [in] */ BSTR bstrType) {
|
|
return(put_CAStoreTypeWStr(bstrType));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreFlags(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdwFlags) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdwFlags = m_CAStore.dwFlags;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// This method is only safe for scripting if it's parameter is safe.
|
|
// See VerifyStoreFlagsSafeForScripting().
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreFlags(
|
|
/* [in] */ LONG dwFlags) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// If we're marked as safe for scripting, see if the flags passed in are safe:
|
|
if (0 != m_dwEnabledSafteyOptions && !VerifyStoreFlagsSafeForScripting(dwFlags))
|
|
goto AccessDeniedError;
|
|
|
|
if(m_CAStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
m_fCAStoreOpenFlagsModified = TRUE;
|
|
m_CAStore.dwFlags = dwFlags;
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_CAStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*szwName = CopyWideString(m_CAStore.wszName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreNameWStr(
|
|
/* [in] */ LPWSTR szwName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_CAStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_CAStore.wszName != wszCA)
|
|
MyCoTaskMemFree(m_CAStore.wszName);
|
|
if( (m_CAStore.wszName = CopyWideString(szwName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreTypeWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*szwType = WideFromMB(m_CAStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreTypeWStr(
|
|
/* [in] */ LPWSTR szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_CAStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_CAStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_CAStore.szType);
|
|
if( (m_CAStore.szType = MBFromWide(szwType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
//
|
|
// ROOT STORE
|
|
//
|
|
HCERTSTORE STDMETHODCALLTYPE CCEnroll::getROOTHStore( void)
|
|
{
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_RootStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*pbstrName = SysAllocString(m_RootStore.wszName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreName(
|
|
/* [in] */ BSTR bstrName) {
|
|
return(put_RootStoreNameWStr(bstrName));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreType(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstrType = BSTRFromMB(m_RootStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreType(
|
|
/* [in] */ BSTR bstrType) {
|
|
return(put_RootStoreTypeWStr(bstrType));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreFlags(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdwFlags) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdwFlags = m_RootStore.dwFlags;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// This method is only safe for scripting if it's parameter is safe.
|
|
// See VerifyStoreFlagsSafeForScripting().
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreFlags(
|
|
/* [in] */ LONG dwFlags) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// If we're marked as safe for scripting, see if the flags passed in are safe:
|
|
if (0 != m_dwEnabledSafteyOptions) {
|
|
// see if the caller passed safe flags:
|
|
if (!VerifyStoreFlagsSafeForScripting(dwFlags))
|
|
goto AccessDeniedError;
|
|
|
|
// extra check for root store: don't allow CERT_SYSTEM_STORE_LOCAL_MACHINE for the root store.
|
|
// if they want to install a machine cert through script, it'll go to the CA store:
|
|
// NOTE: we don't modify the store name if m_RootStore.hStore is NULL, as we'll return E_ACCESSDENIED
|
|
// anyway, and we shouldn't modify this on error.
|
|
if (NULL == m_RootStore.hStore) {
|
|
if (dwFlags & CERT_SYSTEM_STORE_LOCAL_MACHINE) {
|
|
m_RootStore.wszName = wszCA;
|
|
} else {
|
|
m_RootStore.wszName = wszROOT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_RootStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
m_fRootStoreOpenFlagsModified = TRUE;
|
|
m_RootStore.dwFlags = dwFlags;
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_RootStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*szwName = CopyWideString(m_RootStore.wszName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreNameWStr(
|
|
/* [in] */ LPWSTR szwName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_RootStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_RootStore.wszName != wszROOT && m_RootStore.wszName != wszCA)
|
|
MyCoTaskMemFree(m_RootStore.wszName);
|
|
if( (m_RootStore.wszName = CopyWideString(szwName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreTypeWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*szwType = WideFromMB(m_RootStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreTypeWStr(
|
|
/* [in] */ LPWSTR szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_RootStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_RootStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_RootStore.szType);
|
|
if( (m_RootStore.szType = MBFromWide(szwType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
//
|
|
// REQUEST STORE
|
|
//
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_RequestStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*pbstrName = SysAllocString(m_RequestStore.wszName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreName(
|
|
/* [in] */ BSTR bstrName) {
|
|
return(put_RequestStoreNameWStr(bstrName));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreType(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstrType = BSTRFromMB(m_RequestStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreType(
|
|
/* [in] */ BSTR bstrType) {
|
|
return(put_RequestStoreTypeWStr(bstrType));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreFlags(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdwFlags) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdwFlags = m_RequestStore.dwFlags;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// This method is only safe for scripting if it's parameter is safe.
|
|
// See VerifyStoreFlagsSafeForScripting().
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreFlags(
|
|
/* [in] */ LONG dwFlags) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// If we're marked as safe for scripting, see if the flags passed in are safe:
|
|
if (0 != m_dwEnabledSafteyOptions && !VerifyStoreFlagsSafeForScripting(dwFlags))
|
|
goto AccessDeniedError;
|
|
|
|
if(m_RequestStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
|
|
// set the request store flags
|
|
m_RequestStore.dwFlags = dwFlags;
|
|
m_fRequestStoreOpenFlagsModified = TRUE;
|
|
|
|
// track the My store location to the request store, only if the my store has not been modified
|
|
// do NOT set the modify bit for the my store, this is a default
|
|
if(!m_fMyStoreOpenFlagsModified) {
|
|
m_MyStore.dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
|
|
m_MyStore.dwFlags |= (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK);
|
|
m_keyProvInfo.dwFlags |= KeyLocationFromStoreLocation(m_MyStore.dwFlags);
|
|
}
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwName) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_RequestStore.wszName == NULL)
|
|
return(ERROR_UNKNOWN_PROPERTY);
|
|
|
|
if( (*szwName = CopyWideString(m_RequestStore.wszName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreNameWStr(
|
|
/* [in] */ LPWSTR szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_RequestStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_RequestStore.wszName != wszREQUEST)
|
|
MyCoTaskMemFree(m_RequestStore.wszName);
|
|
if( (m_RequestStore.wszName = CopyWideString(szwType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreTypeWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*szwType = WideFromMB(m_RequestStore.szType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreTypeWStr(
|
|
/* [in] */ LPWSTR szwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
if(m_RequestStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_RequestStore.szType != szSystemStore)
|
|
MyCoTaskMemFree(m_RequestStore.szType);
|
|
if( (m_RequestStore.szType = MBFromWide(szwType)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
//
|
|
// Provider Stuff
|
|
//
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ContainerName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrContainer) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstrContainer = SysAllocString(m_keyProvInfo.pwszContainerName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ContainerName(
|
|
/* [in] */ BSTR bstrContainer) {
|
|
return(put_ContainerNameWStr(bstrContainer));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstrProvider) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstrProvider = SysAllocString(m_keyProvInfo.pwszProvName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderName(
|
|
/* [in] */ BSTR bstrProvider) {
|
|
return(put_ProviderNameWStr(bstrProvider));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderType(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdwType) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdwType = m_keyProvInfo.dwProvType;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderType(
|
|
/* [in] */ LONG dwType) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if(m_hProv != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else
|
|
m_keyProvInfo.dwProvType = dwType;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_KeySpec(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdw) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdw = m_keyProvInfo.dwKeySpec;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_KeySpec(
|
|
/* [in] */ LONG dwKeySpec) {
|
|
HRESULT hr;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_hProv != NULL)
|
|
{
|
|
hr = E_ACCESSDENIED;
|
|
goto NullProvError;
|
|
}
|
|
|
|
if (m_fSMIMESetByClient)
|
|
{
|
|
//SMIME is set by the client
|
|
if (m_fEnableSMIMECapabilities && AT_SIGNATURE == dwKeySpec)
|
|
{
|
|
//try to set signature key spec also SMIME
|
|
hr = XENROLL_E_KEYSPEC_SMIME_MISMATCH;
|
|
goto MismatchError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//currently smime is not set by user
|
|
//turn on SMIME for according to key spec
|
|
m_fEnableSMIMECapabilities = (dwKeySpec == AT_KEYEXCHANGE);
|
|
}
|
|
m_keyProvInfo.dwKeySpec = dwKeySpec;
|
|
m_fKeySpecSetByClient = TRUE;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
TRACE_ERROR(NullProvError)
|
|
TRACE_ERROR(MismatchError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ClientId(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdw) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdw = m_lClientId;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ClientId(
|
|
/* [in] */ LONG dw) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_lClientId = dw;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_IncludeSubjectKeyID(
|
|
/* [retval][out] */ BOOL __RPC_FAR *pfInclude) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pfInclude = m_fIncludeSubjectKeyID;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_IncludeSubjectKeyID(
|
|
/* [in] */ BOOL fInclude) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fIncludeSubjectKeyID = fInclude;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderFlags(
|
|
/* [retval][out] */ LONG __RPC_FAR *pdwFlags) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdwFlags = m_keyProvInfo.dwFlags;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// This method is only safe for scripting if it's parameter is safe.
|
|
// See VerifyProviderFlagsSafeForScripting().
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderFlags(
|
|
/* [in] */ LONG dwFlags) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// If we're marked as safe for scripting, see if the flags passed in are safe:
|
|
if (0 != m_dwEnabledSafteyOptions && !VerifyProviderFlagsSafeForScripting(dwFlags))
|
|
goto AccessDeniedError;
|
|
|
|
if(m_hProv != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else
|
|
m_keyProvInfo.dwFlags = dwFlags;
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
SET_HRESULT(AccessDeniedError, E_ACCESSDENIED);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ContainerNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwContainer) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*szwContainer = CopyWideString(m_keyProvInfo.pwszContainerName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ContainerNameWStr(
|
|
/* [in] */ LPWSTR szwContainer) {
|
|
HRESULT hr = S_OK;
|
|
|
|
if(szwContainer == NULL)
|
|
return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_hProv != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if( m_keyProvInfo.pwszContainerName != wszEmpty)
|
|
MyCoTaskMemFree(m_keyProvInfo.pwszContainerName);
|
|
if( (m_keyProvInfo.pwszContainerName = CopyWideString(szwContainer)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szwProvider) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*szwProvider = CopyWideString(m_keyProvInfo.pwszProvName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderNameWStr(
|
|
/* [in] */ LPWSTR szwProvider) {
|
|
HRESULT hr = S_OK;
|
|
|
|
if(szwProvider == NULL)
|
|
return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_hProv != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if (0 != wcscmp(m_keyProvInfo.pwszProvName, szwProvider))
|
|
{
|
|
if( m_keyProvInfo.pwszProvName != wszEmpty )
|
|
MyCoTaskMemFree(m_keyProvInfo.pwszProvName);
|
|
if( (m_keyProvInfo.pwszProvName = CopyWideString(szwProvider)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
//one last thing, free/null cached prov handle
|
|
if (NULL != m_hVerifyProv)
|
|
{
|
|
CryptReleaseContext(m_hVerifyProv, 0);
|
|
m_hVerifyProv = NULL;
|
|
}
|
|
// csp is changed, reset key size cache
|
|
m_dwXhgKeyLenMax = 0;
|
|
m_dwXhgKeyLenMin = 0;
|
|
m_dwXhgKeyLenDef = 0;
|
|
m_dwXhgKeyLenInc = 0;
|
|
m_dwSigKeyLenMax = 0;
|
|
m_dwSigKeyLenMin = 0;
|
|
m_dwSigKeyLenDef = 0;
|
|
m_dwSigKeyLenInc = 0;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
//
|
|
// Other Stuff
|
|
//
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_UseExistingKeySet(
|
|
/* [retval][out] */ BOOL __RPC_FAR *fUseExistingKeys) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fUseExistingKeys = m_fUseExistingKey;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_UseExistingKeySet(
|
|
/* [in] */ BOOL fUseExistingKeys) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fUseExistingKey = fUseExistingKeys;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_GenKeyFlags(
|
|
/* [retval][out] */ LONG __RPC_FAR * pdwFlags) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*pdwFlags = m_dwGenKeyFlags;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_GenKeyFlags(
|
|
/* [in] */ LONG dwFlags) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_dwGenKeyFlags = dwFlags;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_DeleteRequestCert(
|
|
/* [retval][out] */ BOOL __RPC_FAR *fBool) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fBool = m_fDeleteRequestCert;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_DeleteRequestCert(
|
|
/* [in] */ BOOL fBool) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fDeleteRequestCert = fBool;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_WriteCertToCSP(
|
|
/* [retval][out] */ BOOL __RPC_FAR *fBool) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fBool = m_fWriteCertToCSP;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_WriteCertToCSP(
|
|
/* [in] */ BOOL fBool) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fWriteCertToCSP = fBool;
|
|
m_fWriteCertToCSPModified = TRUE;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_WriteCertToUserDS(
|
|
/* [retval][out] */ BOOL __RPC_FAR *fBool) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fBool = m_fWriteCertToUserDS;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_WriteCertToUserDS(
|
|
/* [in] */ BOOL fBool) {
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
return E_ACCESSDENIED;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fWriteCertToUserDS = fBool;
|
|
m_fWriteCertToUserDSModified = TRUE;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_EnableT61DNEncoding(
|
|
/* [retval][out] */ BOOL __RPC_FAR *fBool) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fBool = (m_dwT61DNEncoding == CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG);
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_EnableT61DNEncoding(
|
|
/* [in] */ BOOL fBool) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if(fBool)
|
|
m_dwT61DNEncoding = CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG;
|
|
else
|
|
m_dwT61DNEncoding = 0;
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_SPCFileName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstr) {
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstr = SysAllocString(m_wszSPCFileName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_SPCFileName(
|
|
/* [in] */ BSTR bstr) {
|
|
return(put_SPCFileNameWStr(bstr));
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_PVKFileName(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstr) {
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*pbstr = SysAllocString(m_wszPVKFileName)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_PVKFileName(
|
|
/* [in] */ BSTR bstr) {
|
|
return(put_PVKFileNameWStr(bstr));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_HashAlgorithm(
|
|
/* [retval][out] */ BSTR __RPC_FAR *pbstr) {
|
|
|
|
LPWSTR wszAlg = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
assert(pbstr != NULL);
|
|
*pbstr = NULL;
|
|
|
|
if( (hr = get_HashAlgorithmWStr(&wszAlg)) == S_OK ) {
|
|
|
|
if( (*pbstr = SysAllocString(wszAlg)) == NULL )
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(wszAlg != NULL)
|
|
MyCoTaskMemFree(wszAlg);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_HashAlgorithm(
|
|
/* [in] */ BSTR bstr) {
|
|
return(put_HashAlgorithmWStr(bstr));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::enumContainers(
|
|
/* [in] */ LONG dwIndex,
|
|
/* [out][retval] */ BSTR __RPC_FAR *pbstr) {
|
|
|
|
LPWSTR pwsz = NULL;
|
|
HRESULT hr;
|
|
|
|
assert(pbstr != NULL);
|
|
|
|
if((hr = enumContainersWStr(dwIndex, &pwsz)) != S_OK)
|
|
goto EnumContainerError;
|
|
|
|
if( (*pbstr = SysAllocString(pwsz)) == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto ErrorSysAllocString;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(pwsz != NULL)
|
|
MyCoTaskMemFree(pwsz);
|
|
return(hr);
|
|
|
|
TRACE_ERROR(EnumContainerError);
|
|
TRACE_ERROR(ErrorSysAllocString);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::enumProviders(
|
|
/* [in] */ LONG dwIndex,
|
|
/* [in] */ LONG dwFlags,
|
|
/* [out][retval] */ BSTR __RPC_FAR *pbstrProvName) {
|
|
HRESULT hr;
|
|
LPWSTR pwszProvName = NULL;
|
|
|
|
assert(pbstrProvName != NULL);
|
|
*pbstrProvName = NULL;
|
|
|
|
if( (hr = enumProvidersWStr(dwIndex, dwFlags, &pwszProvName)) != S_OK)
|
|
goto EnumProvidersError;
|
|
|
|
if( (*pbstrProvName = SysAllocString(pwszProvName)) == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto ErrorSysAllocString;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
|
|
if(pwszProvName != NULL)
|
|
MyCoTaskMemFree(pwszProvName);
|
|
|
|
return(hr);
|
|
|
|
TRACE_ERROR(EnumProvidersError);
|
|
TRACE_ERROR(ErrorSysAllocString);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::createFilePKCS10WStr(
|
|
/* [in] */ LPCWSTR DNName,
|
|
/* [in] */ LPCWSTR Usage,
|
|
/* [in] */ LPCWSTR wszPKCS10FileName) {
|
|
|
|
HRESULT hr;
|
|
BSTR bstrPKCS10 = NULL;
|
|
|
|
// get the pkcs 10
|
|
if( (hr = createPKCS10WStrBStr(
|
|
DNName,
|
|
Usage,
|
|
&bstrPKCS10)) != S_OK)
|
|
{
|
|
goto ErrorCreatePKCS10;
|
|
}
|
|
|
|
// save it to file
|
|
hr = BStringToFile(bstrPKCS10, wszPKCS10FileName);
|
|
if (S_OK != hr)
|
|
{
|
|
goto ErrorBStringToFile;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(bstrPKCS10 != NULL)
|
|
SysFreeString(bstrPKCS10);
|
|
|
|
return(hr);
|
|
|
|
|
|
TRACE_ERROR(ErrorBStringToFile);
|
|
TRACE_ERROR(ErrorCreatePKCS10);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::acceptFilePKCS7WStr(
|
|
/* [in] */ LPCWSTR wszPKCS7FileName)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blob;
|
|
|
|
ZeroMemory(&blob, sizeof(blob));
|
|
|
|
hr = xeStringToBinaryFromFile(
|
|
wszPKCS7FileName,
|
|
&blob.pbData,
|
|
&blob.cbData,
|
|
CRYPT_STRING_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeStringToBinaryFromFileError;
|
|
}
|
|
|
|
// accept the blob
|
|
hr = acceptPKCS7Blob(&blob);
|
|
|
|
ErrorReturn:
|
|
if (NULL != blob.pbData)
|
|
{
|
|
MyCoTaskMemFree(blob.pbData);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(xeStringToBinaryFromFileError)
|
|
}
|
|
|
|
BOOL GetAlgAndBitLen(
|
|
HCRYPTPROV hProv,
|
|
ALG_ID * pAlg,
|
|
DWORD * pdwBitLen,
|
|
DWORD dwFlags)
|
|
{
|
|
static BOOL fNew = TRUE;
|
|
PROV_ENUMALGS_EX enumAlgsEx;
|
|
PROV_ENUMALGS enumAlgs;
|
|
DWORD cb = 0;
|
|
|
|
*pAlg = 0;
|
|
*pdwBitLen = 0;
|
|
|
|
if(fNew) {
|
|
|
|
cb = sizeof(enumAlgsEx);
|
|
if(CryptGetProvParam(
|
|
hProv,
|
|
PP_ENUMALGS_EX,
|
|
(BYTE *) &enumAlgsEx,
|
|
&cb,
|
|
dwFlags)) {
|
|
|
|
*pAlg = enumAlgsEx.aiAlgid;
|
|
*pdwBitLen = enumAlgsEx.dwMaxLen;
|
|
|
|
return(TRUE);
|
|
|
|
} else if(dwFlags != 0)
|
|
fNew = FALSE;
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
// otherwise do the old stuff
|
|
cb = sizeof(PROV_ENUMALGS);
|
|
if(CryptGetProvParam(
|
|
hProv,
|
|
PP_ENUMALGS,
|
|
(BYTE *) &enumAlgs,
|
|
&cb,
|
|
dwFlags) ) {
|
|
|
|
*pAlg = enumAlgs.aiAlgid;
|
|
*pdwBitLen = enumAlgs.dwBitLen;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
HRESULT
|
|
CreateSMimeExtension(
|
|
IN HCRYPTPROV hProv,
|
|
OUT BYTE **ppbSMime,
|
|
OUT DWORD *pcbSMime)
|
|
{
|
|
#define CINCSMIMECAP 20
|
|
HRESULT hr;
|
|
|
|
DWORD dwBitLen;
|
|
DWORD i;
|
|
DWORD cbE;
|
|
BYTE *pbE = NULL;
|
|
DWORD dwFlags;
|
|
PCCRYPT_OID_INFO pOidInfo = NULL;
|
|
CRYPT_SMIME_CAPABILITIES smimeCaps;
|
|
DWORD crgsmimeCap = 0;
|
|
ALG_ID AlgID;
|
|
BYTE *pb = NULL;
|
|
DWORD cb = 0;
|
|
|
|
memset(&smimeCaps, 0, sizeof(CRYPT_SMIME_CAPABILITIES));
|
|
|
|
smimeCaps.rgCapability = (PCRYPT_SMIME_CAPABILITY) LocalAlloc(LPTR, CINCSMIMECAP * sizeof(CRYPT_SMIME_CAPABILITY));
|
|
if (NULL == smimeCaps.rgCapability)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
crgsmimeCap = CINCSMIMECAP;
|
|
|
|
dwFlags = CRYPT_FIRST; //first item
|
|
while (GetAlgAndBitLen(hProv, &AlgID, &dwBitLen, dwFlags))
|
|
{
|
|
pbE = NULL;
|
|
cbE = 0;
|
|
dwFlags = 0; //next item
|
|
|
|
if(ALG_CLASS_DATA_ENCRYPT == GET_ALG_CLASS(AlgID))
|
|
{
|
|
if(AlgID == CALG_RC2 || AlgID == CALG_RC4)
|
|
{
|
|
// encode the usage
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_INTEGER,
|
|
&dwBitLen,
|
|
pbE, // pbEncoded
|
|
&cbE))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptEncodeObjectError;
|
|
}
|
|
if (NULL != pbE)
|
|
{
|
|
break;
|
|
}
|
|
pbE = (BYTE *)LocalAlloc(LPTR, cbE);
|
|
if (NULL == pbE)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
// convert to an oid,
|
|
pOidInfo = xeCryptFindOIDInfo(
|
|
CRYPT_OID_INFO_ALGID_KEY,
|
|
(void *) &AlgID,
|
|
CRYPT_ENCRYPT_ALG_OID_GROUP_ID);
|
|
if(NULL == pOidInfo)
|
|
{
|
|
// don't crash on an error, just say we don't known it.
|
|
if (NULL != pbE) {
|
|
LocalFree(pbE);
|
|
}
|
|
pbE = NULL;
|
|
continue;
|
|
}
|
|
|
|
// make sure we have enough room
|
|
if(smimeCaps.cCapability >= crgsmimeCap)
|
|
{
|
|
PCRYPT_SMIME_CAPABILITY pSmimeCapsTmp;
|
|
|
|
//increment the size
|
|
crgsmimeCap += CINCSMIMECAP;
|
|
pSmimeCapsTmp = (PCRYPT_SMIME_CAPABILITY)LocalReAlloc(
|
|
smimeCaps.rgCapability,
|
|
crgsmimeCap * sizeof(CRYPT_SMIME_CAPABILITY),
|
|
LMEM_MOVEABLE | LMEM_ZEROINIT);
|
|
if(NULL == pSmimeCapsTmp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
smimeCaps.rgCapability = pSmimeCapsTmp;
|
|
}
|
|
|
|
smimeCaps.rgCapability[smimeCaps.cCapability].pszObjId = (char *) pOidInfo->pszOID;
|
|
smimeCaps.rgCapability[smimeCaps.cCapability].Parameters.pbData = pbE;
|
|
smimeCaps.rgCapability[smimeCaps.cCapability].Parameters.cbData = cbE;
|
|
smimeCaps.cCapability++;
|
|
pbE = NULL; // We'll free pbE through the struct we just assigned. NULL out so we don't double-free.
|
|
}
|
|
|
|
// encode the capabilities
|
|
while (TRUE)
|
|
{
|
|
if (!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
PKCS_SMIME_CAPABILITIES,
|
|
&smimeCaps,
|
|
pb,
|
|
&cb))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptEncodeObjectError;
|
|
}
|
|
if (NULL != pb)
|
|
{
|
|
break;
|
|
}
|
|
pb = (BYTE *)LocalAlloc(LPTR, cb);
|
|
}
|
|
*ppbSMime = pb;
|
|
*pcbSMime = cb;
|
|
pb = NULL;
|
|
|
|
hr = S_OK;
|
|
|
|
ErrorReturn:
|
|
if(NULL != smimeCaps.rgCapability)
|
|
{
|
|
for (i = 0; i < smimeCaps.cCapability; ++i)
|
|
{
|
|
if (NULL != smimeCaps.rgCapability[i].Parameters.pbData)
|
|
{
|
|
LocalFree(smimeCaps.rgCapability[i].Parameters.pbData);
|
|
}
|
|
}
|
|
LocalFree(smimeCaps.rgCapability);
|
|
}
|
|
if(NULL != pb)
|
|
{
|
|
LocalFree(pb);
|
|
}
|
|
if (NULL != pbE)
|
|
{
|
|
LocalFree(pbE);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(CryptEncodeObjectError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
}
|
|
|
|
|
|
#if DBG
|
|
void DebugGetContainerSD(HCRYPTPROV hProv)
|
|
{
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
DWORD cbSD;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!CryptGetProvParam(
|
|
hProv,
|
|
PP_KEYSET_SEC_DESCR,
|
|
(BYTE*)pSD,
|
|
&cbSD,
|
|
DACL_SECURITY_INFORMATION))
|
|
{
|
|
break;
|
|
}
|
|
if (NULL != pSD)
|
|
{
|
|
break;
|
|
}
|
|
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, cbSD);
|
|
if (NULL == pSD)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (NULL != pSD)
|
|
{
|
|
LocalFree(pSD);
|
|
}
|
|
}
|
|
#endif //DBG
|
|
|
|
//get the current user sids
|
|
HRESULT
|
|
GetCurrentUserInfo(
|
|
OUT PTOKEN_USER *ppUserInfo,
|
|
OUT BOOL *pfAdmin)
|
|
{
|
|
HRESULT hr;
|
|
PTOKEN_USER pUserInfo = NULL;
|
|
DWORD dwSize = 0;
|
|
HANDLE hToken = NULL;
|
|
HANDLE hDupToken = NULL;
|
|
PSID psidAdministrators = NULL;
|
|
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
|
|
HANDLE hThread;
|
|
HANDLE hProcess;
|
|
|
|
//init
|
|
*pfAdmin = FALSE;
|
|
|
|
if (!AllocateAndInitializeSid(
|
|
&siaNtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&psidAdministrators))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto AllocateAndInitializeSidError;
|
|
}
|
|
|
|
hThread = GetCurrentThread();
|
|
if (NULL == hThread)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetCurrentThreadError;
|
|
}
|
|
|
|
// Get the access token for current thread
|
|
if (!OpenThreadToken(
|
|
hThread,
|
|
TOKEN_QUERY | TOKEN_DUPLICATE,
|
|
FALSE,
|
|
&hToken))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
if(HRESULT_FROM_WIN32(ERROR_NO_TOKEN) != hr)
|
|
{
|
|
goto OpenThreadTokenError;
|
|
}
|
|
//get process token instead
|
|
hProcess = GetCurrentProcess();
|
|
if (NULL == hProcess)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetCurrentProcessError;
|
|
}
|
|
|
|
hToken = NULL;
|
|
if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_DUPLICATE, &hToken))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto OpenProcessTokenError;
|
|
}
|
|
}
|
|
|
|
// CheckTokenMembership must operate on impersonation token, so make one
|
|
if (!DuplicateToken(hToken, SecurityIdentification, &hDupToken))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto DuplicateTokenError;
|
|
}
|
|
|
|
if (!MyCheckTokenMembership(hDupToken, psidAdministrators, pfAdmin))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CheckTokenMembershipError;
|
|
}
|
|
|
|
//get current user sid
|
|
while (TRUE)
|
|
{
|
|
if (!GetTokenInformation(
|
|
hToken,
|
|
TokenUser,
|
|
pUserInfo,
|
|
dwSize,
|
|
&dwSize))
|
|
{
|
|
if (NULL != pUserInfo ||
|
|
ERROR_INSUFFICIENT_BUFFER != GetLastError())
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetTokenInformationError;
|
|
}
|
|
}
|
|
|
|
if (NULL != pUserInfo)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pUserInfo = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, dwSize);
|
|
if (NULL == pUserInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
}
|
|
|
|
if (NULL != ppUserInfo)
|
|
{
|
|
*ppUserInfo = pUserInfo;
|
|
pUserInfo = NULL;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pUserInfo)
|
|
{
|
|
LocalFree(pUserInfo);
|
|
}
|
|
if (NULL != hToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
if (NULL != hDupToken)
|
|
{
|
|
CloseHandle(hDupToken);
|
|
}
|
|
if (NULL != psidAdministrators)
|
|
{
|
|
FreeSid(psidAdministrators);
|
|
}
|
|
|
|
return hr;
|
|
|
|
TRACE_ERROR(LocalAllocError)
|
|
TRACE_ERROR(GetTokenInformationError)
|
|
TRACE_ERROR(OpenProcessTokenError)
|
|
TRACE_ERROR(GetCurrentProcessError)
|
|
TRACE_ERROR(CheckTokenMembershipError)
|
|
TRACE_ERROR(DuplicateTokenError)
|
|
TRACE_ERROR(OpenThreadTokenError)
|
|
TRACE_ERROR(GetCurrentThreadError)
|
|
TRACE_ERROR(AllocateAndInitializeSidError)
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SetKeyContainerSecurityForNULLDacl(
|
|
HCRYPTPROV hProv,
|
|
DWORD dwFlags,
|
|
PTOKEN_USER pUserInfo)
|
|
{
|
|
DWORD ccNeeded;
|
|
HRESULT hr;
|
|
LPWSTR wszSD = NULL;
|
|
LPWSTR wszUserSid = NULL;
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
// We want the security descriptor for the new keyset to look like so:
|
|
//
|
|
// ACES:
|
|
// NT AUTHORITY\SYSTEM:F
|
|
// BUILTIN\Administrators:F
|
|
//
|
|
//
|
|
#define SDDL_NEW_KEYSET_START L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;"
|
|
#define SDDL_NEW_KEYSET_END L")"
|
|
|
|
if (!ConvertSidToStringSidW(pUserInfo->User.Sid, &wszUserSid)) {
|
|
goto ConvertSidToStringSidError;
|
|
}
|
|
|
|
ccNeeded = (DWORD)(wcslen(SDDL_NEW_KEYSET_START) + wcslen(wszUserSid) + wcslen(SDDL_NEW_KEYSET_END) + 1);
|
|
wszSD = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*ccNeeded);
|
|
if (NULL == wszSD) {
|
|
goto MemoryError;
|
|
}
|
|
|
|
wcscpy(wszSD, SDDL_NEW_KEYSET_START);
|
|
wcscat(wszSD, wszUserSid);
|
|
wcscat(wszSD, SDDL_NEW_KEYSET_END);
|
|
|
|
|
|
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(wszSD, SDDL_REVISION_1, &pSD, NULL)) {
|
|
goto ConvertStringSecurityDescriptorToSecurityDescriptorWError;
|
|
}
|
|
|
|
if (!IsValidSecurityDescriptor(pSD)) {
|
|
goto IsValidSecurityDescriptorError;
|
|
}
|
|
|
|
#if DBG
|
|
DebugGetContainerSD(hProv); //just for ntsd debug
|
|
#endif
|
|
|
|
if (!CryptSetProvParam(hProv, PP_KEYSET_SEC_DESCR, (BYTE*)pSD, DACL_SECURITY_INFORMATION)) {
|
|
goto CryptSetProvParamError;
|
|
}
|
|
|
|
#if DBG
|
|
DebugGetContainerSD(hProv); //just for ntsd debug
|
|
#endif
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != wszSD)
|
|
{
|
|
LocalFree(wszSD);
|
|
}
|
|
if (NULL != wszUserSid)
|
|
{
|
|
LocalFree(wszUserSid);
|
|
}
|
|
if (NULL != pSD)
|
|
{
|
|
LocalFree(pSD);
|
|
}
|
|
return hr;
|
|
|
|
|
|
SET_HRESULT(ConvertSidToStringSidError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(ConvertStringSecurityDescriptorToSecurityDescriptorWError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(CryptSetProvParamError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(IsValidSecurityDescriptorError, HRESULT_FROM_WIN32(ERROR_INVALID_SECURITY_DESCR));
|
|
SET_HRESULT(MemoryError, E_OUTOFMEMORY);
|
|
}
|
|
|
|
|
|
// This function ACLs new keysets (as 3rd party CSPs and downlevel CSPs may not do this correctly.
|
|
// Should *not* call this function on existing keysets (as ACLs may have been set differently by admins)
|
|
//
|
|
HRESULT
|
|
SetKeyContainerSecurity(
|
|
HCRYPTPROV hProv,
|
|
DWORD dwFlags)
|
|
{
|
|
HRESULT hr;
|
|
PSECURITY_DESCRIPTOR pNewSD = NULL;
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
|
|
DWORD cbSD;
|
|
ACL_SIZE_INFORMATION AclInfo;
|
|
|
|
PTOKEN_USER pUserInfo = NULL;
|
|
PACL pNewAcl = NULL;
|
|
LPVOID pAce;
|
|
DWORD dwIndex;
|
|
BYTE AceType;
|
|
PACL pAcl;
|
|
BOOL fDacl = TRUE;
|
|
BOOL fDef = FALSE;
|
|
BOOL fAdmin;
|
|
BOOL fKeepSystemSid;
|
|
BOOL fMachineKeySet = (0x0 != (dwFlags & CRYPT_MACHINE_KEYSET)) ?
|
|
TRUE : FALSE;
|
|
|
|
PSID pSidSystem = NULL;
|
|
PSID pSidAdministrators = NULL;
|
|
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
//get the current user info
|
|
hr = GetCurrentUserInfo(&pUserInfo, &fAdmin);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetCurrentUserInfoError;
|
|
}
|
|
|
|
//get the current sd from key container
|
|
while (TRUE)
|
|
{
|
|
if (!CryptGetProvParam(
|
|
hProv,
|
|
PP_KEYSET_SEC_DESCR,
|
|
(BYTE*)pSD,
|
|
&cbSD,
|
|
DACL_SECURITY_INFORMATION))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptGetProvParamError;
|
|
}
|
|
if (NULL != pSD)
|
|
{
|
|
break;
|
|
}
|
|
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, cbSD);
|
|
if (NULL == pSD)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
//get acl from sd
|
|
if (!GetSecurityDescriptorDacl(
|
|
pSD,
|
|
&fDacl,
|
|
&pAcl,
|
|
&fDef))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetSecurityDescriptorDaclError;
|
|
}
|
|
if (!fDacl)
|
|
{
|
|
//if no dacl, quit
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
goto GetSecurityDescriptorDaclError;
|
|
}
|
|
if (NULL == pAcl)
|
|
{
|
|
#if 0
|
|
//this means allow everyone access the key which is unexpected,
|
|
hr = SetKeyContainerSecurityForNULLDacl(hProv, dwFlags, pUserInfo);
|
|
#endif
|
|
// BUGBUG: The NULL DACL stuff doesn't work on downlevels because it requires SDDL. We don't
|
|
// have time to fix for windows update, but we should revisit this later
|
|
hr = S_OK;
|
|
goto done;
|
|
}
|
|
|
|
//get acl info
|
|
if (!GetAclInformation(
|
|
pAcl,
|
|
&AclInfo,
|
|
sizeof(AclInfo),
|
|
AclSizeInformation))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetAclInformationError;
|
|
}
|
|
|
|
//allocate enough for new dacl since we just remove aces
|
|
pNewAcl = (PACL)LocalAlloc(LMEM_ZEROINIT, AclInfo.AclBytesInUse);
|
|
if (NULL == pNewAcl)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
if (!InitializeAcl(pNewAcl, AclInfo.AclBytesInUse, ACL_REVISION))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto InitializeAclError;
|
|
}
|
|
|
|
fKeepSystemSid = fAdmin && fMachineKeySet;
|
|
if (fKeepSystemSid)
|
|
{
|
|
//get system sid to later use
|
|
if (!AllocateAndInitializeSid(
|
|
&siaNtAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&pSidSystem))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto AllocateAndInitializeSidError;
|
|
}
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid(&siaNtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&pSidAdministrators
|
|
))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto AllocateAndInitializeSidError;
|
|
}
|
|
|
|
//go through each ace, get only current user aces
|
|
for (dwIndex = 0; dwIndex < AclInfo.AceCount; ++dwIndex)
|
|
{
|
|
if (!GetAce(pAcl, dwIndex, &pAce))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetAceError;
|
|
}
|
|
AceType = ((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType;
|
|
if (ACCESS_ALLOWED_ACE_TYPE == AceType)
|
|
{
|
|
if (EqualSid(pUserInfo->User.Sid, (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart))
|
|
|| (fKeepSystemSid && EqualSid(pSidSystem, (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart)))
|
|
|| EqualSid(pSidAdministrators, (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart)))
|
|
{
|
|
//add current user ace or system ace into new acl
|
|
if (!AddAccessAllowedAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
((PACCESS_ALLOWED_ACE)pAce)->Mask,
|
|
(PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart)))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto AddAccessAllowedAceError;
|
|
}
|
|
}
|
|
}
|
|
else if (ACCESS_DENIED_ACE_TYPE == AceType)
|
|
{
|
|
//add all deny ace into new acl
|
|
if (!AddAccessDeniedAce(
|
|
pNewAcl,
|
|
ACL_REVISION,
|
|
((PACCESS_ALLOWED_ACE)pAce)->Mask,
|
|
(PSID)&(((PACCESS_DENIED_ACE)pAce)->SidStart)))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto AddAccessDeniedAceError;
|
|
}
|
|
}
|
|
}
|
|
|
|
// initialize a security descriptor.
|
|
pNewSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
if (pNewSD == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
|
|
if (!InitializeSecurityDescriptor(pNewSD, SECURITY_DESCRIPTOR_REVISION))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto InitializeSecurityDescriptorError;
|
|
}
|
|
|
|
// add the ACL to the security descriptor.
|
|
if (!SetSecurityDescriptorDacl(
|
|
pNewSD,
|
|
TRUE, // fDaclPresent flag
|
|
pNewAcl,
|
|
FALSE)) // not a default DACL
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto SetSecurityDescriptorDaclError;
|
|
}
|
|
|
|
//ok, set sd to be protected
|
|
if (!MySetSecurityDescriptorControl(
|
|
pNewSD,
|
|
SE_DACL_PROTECTED,
|
|
SE_DACL_PROTECTED))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto SetSecurityDescriptorControlError;
|
|
}
|
|
|
|
if (!IsValidSecurityDescriptor(pNewSD))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto IsValidSecurityDescriptorError;
|
|
}
|
|
|
|
#if DBG
|
|
DebugGetContainerSD(hProv); //just for ntsd debug
|
|
#endif
|
|
|
|
//now we just set it
|
|
if (!CryptSetProvParam(
|
|
hProv,
|
|
PP_KEYSET_SEC_DESCR,
|
|
(BYTE*)pNewSD,
|
|
DACL_SECURITY_INFORMATION))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptSetProvParamError;
|
|
}
|
|
|
|
#if DBG
|
|
DebugGetContainerSD(hProv); //just for ntsd debug
|
|
#endif
|
|
|
|
done:
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pSD)
|
|
{
|
|
LocalFree(pSD);
|
|
}
|
|
if (NULL != pUserInfo)
|
|
{
|
|
LocalFree(pUserInfo);
|
|
}
|
|
if (NULL != pNewAcl)
|
|
{
|
|
LocalFree(pNewAcl);
|
|
}
|
|
if (NULL != pNewSD)
|
|
{
|
|
LocalFree(pNewSD);
|
|
}
|
|
if (NULL != pSidSystem)
|
|
{
|
|
FreeSid(pSidSystem);
|
|
}
|
|
if (NULL != pSidAdministrators)
|
|
{
|
|
FreeSid(pSidAdministrators);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(CryptSetProvParamError)
|
|
TRACE_ERROR(SetSecurityDescriptorDaclError)
|
|
TRACE_ERROR(InitializeSecurityDescriptorError)
|
|
TRACE_ERROR(LocalAllocError)
|
|
TRACE_ERROR(AddAccessAllowedAceError)
|
|
TRACE_ERROR(AddAccessDeniedAceError)
|
|
TRACE_ERROR(GetAceError)
|
|
TRACE_ERROR(GetCurrentUserInfoError)
|
|
TRACE_ERROR(InitializeAclError)
|
|
TRACE_ERROR(GetAclInformationError)
|
|
TRACE_ERROR(GetSecurityDescriptorDaclError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
TRACE_ERROR(CryptGetProvParamError)
|
|
TRACE_ERROR(SetSecurityDescriptorControlError)
|
|
TRACE_ERROR(IsValidSecurityDescriptorError)
|
|
TRACE_ERROR(AllocateAndInitializeSidError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::createPKCS10WStr(
|
|
/* [in] */ LPCWSTR DNName,
|
|
/* [in] */ LPCWSTR wszPurpose,
|
|
/* [out] */ PCRYPT_DATA_BLOB pPkcs10Blob)
|
|
{
|
|
#define EndExt 5
|
|
|
|
#define EndAttr 6
|
|
|
|
HCRYPTPROV hProv = NULL;
|
|
HCRYPTKEY hKey = NULL;
|
|
|
|
CERT_REQUEST_INFO reqInfo;
|
|
|
|
CERT_EXTENSIONS Extensions;
|
|
PCERT_EXTENSION pExtCur = NULL;
|
|
PCERT_EXTENSION rgExtension = NULL;
|
|
CRYPT_ATTRIBUTE rgAttribute[EndAttr];
|
|
CRYPT_ATTR_BLOB blobExt;
|
|
CRYPT_ATTR_BLOB blobCSPAttr;
|
|
CRYPT_CSP_PROVIDER CSPProvider;
|
|
CRYPT_ATTR_BLOB blobOSVAttr;
|
|
CRYPT_ATTR_BLOB blobSMIMEPKCS7;
|
|
CERT_NAME_VALUE cnvOSVer;
|
|
OSVERSIONINFO osvInfo;
|
|
|
|
DWORD iExt = 0;
|
|
CRYPT_BIT_BLOB bbKeyUsage;
|
|
BYTE bKeyUsage;
|
|
|
|
CERT_SIGNED_CONTENT_INFO SignatureInfo;
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD errBefore = GetLastError();
|
|
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
HCERTSTORE hStore = NULL;
|
|
DWORD ssFlags = 0;
|
|
|
|
HANDLE hFile = NULL;
|
|
CRYPT_DATA_BLOB blobData;
|
|
|
|
DWORD cb = 0;
|
|
char * pszPurpose = NULL;
|
|
char * szStart = NULL;
|
|
char * szEnd = NULL;
|
|
char szVersion[45] = {0};
|
|
|
|
BOOL fAddCodeSign = FALSE;
|
|
DWORD cPassedEKU = 0;
|
|
DWORD i = 0;
|
|
BOOL fRet;
|
|
BYTE *pbSMime = NULL;
|
|
BYTE *pbKU = NULL;
|
|
BYTE *pbEKU = NULL;
|
|
PPROP_STACK pProp;
|
|
CRYPT_ATTR_BLOB blobClientId;
|
|
DWORD cPublicKeyInfo = 0;
|
|
BYTE *pbSubjectKeyHashExtension = NULL;
|
|
DWORD cbSubjectKeyHashExtension = 0;
|
|
DWORD dwErr;
|
|
|
|
LPWSTR pwszNotSafeRequesting = NULL;
|
|
LPWSTR pwszTitle = NULL;
|
|
|
|
//
|
|
// Declaration of extensions we need. The extensions with matching OIDs will be added
|
|
// to the temporary cert context created by this method.
|
|
//
|
|
LPSTR rgszExtensionOIDs[] = {
|
|
szOID_ENROLL_CERTTYPE_EXTENSION,
|
|
szOID_CERTIFICATE_TEMPLATE
|
|
};
|
|
|
|
// An array of the extensions we need to add to the certificate
|
|
CERT_EXTENSION rgNeededExtensions[sizeof(rgszExtensionOIDs) / sizeof(LPSTR)];
|
|
|
|
// Need to put the array in a CERT_EXTENSIONS struct.
|
|
CERT_EXTENSIONS ceExtensions;
|
|
ceExtensions.rgExtension = &rgNeededExtensions[0];
|
|
ceExtensions.cExtension = 0;
|
|
|
|
CRYPT_KEY_PROV_INFO keyProvInfoT;
|
|
CERT_ENHKEY_USAGE enhKeyUsage;
|
|
|
|
CRYPT_DATA_BLOB blobPKCS7;
|
|
CRYPT_DATA_BLOB blobRenewAttr;
|
|
RequestFlags requestFlags;
|
|
CRYPT_DATA_BLOB requestInfoBlob;
|
|
CRYPT_DATA_BLOB blobRenewalCert;
|
|
|
|
ALG_ID rgAlg[2];
|
|
PCCRYPT_OID_INFO pOidInfo = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// for the life of our procedure.
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
assert(pPkcs10Blob != NULL);
|
|
|
|
// clean out the PKCS 10
|
|
memset(&Extensions, 0, sizeof(CERT_EXTENSIONS));
|
|
memset(&rgAttribute, 0, sizeof(rgAttribute));
|
|
memset(&reqInfo, 0, sizeof(CERT_REQUEST_INFO));
|
|
memset(&SignatureInfo, 0, sizeof(SignatureInfo));
|
|
memset(&blobData, 0, sizeof(CRYPT_DATA_BLOB));
|
|
memset(&enhKeyUsage, 0, sizeof(CERT_ENHKEY_USAGE ));
|
|
memset(pPkcs10Blob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB));
|
|
memset(&blobRenewAttr, 0, sizeof(CRYPT_DATA_BLOB));
|
|
memset(&requestFlags, 0, sizeof(RequestFlags));
|
|
memset(&requestInfoBlob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
memset(&CSPProvider, 0, sizeof(CRYPT_CSP_PROVIDER));
|
|
memset(&cnvOSVer, 0, sizeof(CERT_NAME_VALUE));
|
|
memset(&osvInfo, 0, sizeof(OSVERSIONINFO));
|
|
memset(&blobSMIMEPKCS7, 0, sizeof(CRYPT_ATTR_BLOB));
|
|
memset(&rgNeededExtensions[0], 0, sizeof(rgNeededExtensions));
|
|
ZeroMemory(&blobExt, sizeof(blobExt));
|
|
memset(&blobCSPAttr, 0, sizeof(CRYPT_ATTR_BLOB));
|
|
memset(&blobOSVAttr, 0, sizeof(CRYPT_ATTR_BLOB));
|
|
memset(&blobClientId, 0, sizeof(CRYPT_ATTR_BLOB));
|
|
|
|
reqInfo.dwVersion = CERT_REQUEST_V1;
|
|
|
|
// Creating a request is not safe for scripting: pop up a warning dialog if called from script
|
|
if (0 != m_dwEnabledSafteyOptions) {
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle);
|
|
if (S_OK != hr) {
|
|
SetLastError(hr);
|
|
goto xeLoadRCStringError;
|
|
}
|
|
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_REQUESTING_CERT, &pwszNotSafeRequesting);
|
|
if (S_OK != hr) {
|
|
SetLastError(hr);
|
|
goto xeLoadRCStringError;
|
|
}
|
|
|
|
if (IDYES != MessageBoxU(NULL, pwszNotSafeRequesting, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
SetLastError(hr);
|
|
goto CancelledError;
|
|
}
|
|
}
|
|
|
|
if(!m_fUseExistingKey)
|
|
{
|
|
// attempt to get a new keyset
|
|
if((hProv = GetProv(CRYPT_NEWKEYSET)) == NULL) {
|
|
|
|
// in the hardware token case, there may only be a finite number of containers
|
|
// if you run out, then use the default container. The Default container can
|
|
// be specified by either a NULL or empty container name.
|
|
// this is behavior requested by the smart cards, in particular smart card enrollment.
|
|
if( m_fReuseHardwareKeyIfUnableToGenNew &&
|
|
GetLastError() == NTE_TOKEN_KEYSET_STORAGE_FULL) {
|
|
|
|
// set it to the default container name
|
|
if( m_keyProvInfo.pwszContainerName != wszEmpty )
|
|
MyCoTaskMemFree(m_keyProvInfo.pwszContainerName);
|
|
m_keyProvInfo.pwszContainerName = wszEmpty;
|
|
|
|
// say we want to use an exiting key.
|
|
m_fUseExistingKey = TRUE;
|
|
}
|
|
else
|
|
goto ErrorCryptAcquireContext;
|
|
}
|
|
}
|
|
|
|
// if we are to use an existing key
|
|
if(m_fUseExistingKey) {
|
|
|
|
if((hProv = GetProv(0)) == NULL)
|
|
goto ErrorCryptAcquireContext;
|
|
}
|
|
|
|
// we have the keyset, now make sure we have the key gen'ed
|
|
if(!CryptGetUserKey(
|
|
hProv,
|
|
m_keyProvInfo.dwKeySpec,
|
|
&hKey))
|
|
{
|
|
//in case of smartcard csp, above call could be failed from
|
|
//PIN Cancel button, don't go next to try genkey
|
|
//also notice different csp could return different cancel errors
|
|
dwErr = GetLastError();
|
|
if (SCARD_W_CANCELLED_BY_USER == dwErr ||
|
|
ERROR_CANCELLED == dwErr ||
|
|
ERROR_ACCESS_DENIED == dwErr)
|
|
{
|
|
goto CryptGetUserKeyCancelError;
|
|
}
|
|
|
|
// doesn't exist so gen it
|
|
assert(hKey == NULL);
|
|
|
|
// if the cached key is non-NULL, free it to prevent memory leaks
|
|
if (NULL != m_hCachedKey)
|
|
{
|
|
CryptDestroyKey(m_hCachedKey);
|
|
m_hCachedKey = NULL;
|
|
}
|
|
|
|
if(!CryptGenKey( hProv,
|
|
m_keyProvInfo.dwKeySpec,
|
|
m_dwGenKeyFlags | CRYPT_ARCHIVABLE,
|
|
&m_hCachedKey) )
|
|
{
|
|
//could be cancelled by user? don't make next try
|
|
dwErr = GetLastError();
|
|
if (SCARD_W_CANCELLED_BY_USER == dwErr ||
|
|
ERROR_CANCELLED == dwErr ||
|
|
ERROR_ACCESS_DENIED == dwErr)
|
|
{
|
|
goto ErrorCryptGenKey;
|
|
}
|
|
|
|
//this error may be caused by not supporting CRYPT_ARCHIVABLE
|
|
//we should check against error NTE_BAD_FLAGS but I doubt all
|
|
//csps return consistent error code
|
|
//let's try one more time without archivable flag
|
|
assert(NULL == m_hCachedKey);
|
|
DWORD dwGenKeyFlags = m_dwGenKeyFlags;
|
|
if (NULL != m_PrivateKeyArchiveCertificate && m_fNewRequestMethod && (0 == (dwGenKeyFlags & CRYPT_EXPORTABLE)))
|
|
{
|
|
// We want ARCHIVABLE but not EXPORTABLE, so we needed the CRYPT_ARCHIVAL bit. Give up.
|
|
goto ErrorCryptGenKey;
|
|
}
|
|
|
|
if (!CryptGenKey(
|
|
hProv,
|
|
m_keyProvInfo.dwKeySpec,
|
|
dwGenKeyFlags,
|
|
&hKey))
|
|
{
|
|
goto ErrorCryptGenKey;
|
|
}
|
|
}
|
|
|
|
//try to set key container ACL with owner ACE only (NOTE: only do this for creation!)
|
|
hr = SetKeyContainerSecurity(hProv, m_keyProvInfo.dwFlags);
|
|
#if DBG
|
|
if (S_OK != hr)
|
|
{
|
|
goto SetKeyContainerSecurityError;
|
|
}
|
|
#endif //DBG
|
|
hr = S_OK; //free build, no error checking here, if fails, live with it
|
|
}
|
|
|
|
|
|
if (NULL != hKey)
|
|
{
|
|
// don't need the hKey on existing key, so get rid of it
|
|
CryptDestroyKey(hKey);
|
|
}
|
|
if ((NULL == m_PrivateKeyArchiveCertificate || !m_fNewRequestMethod) &&
|
|
NULL != m_hCachedKey)
|
|
{
|
|
//we don't need cache it, destroy it as soon as key is gen(ed)
|
|
CryptDestroyKey(m_hCachedKey);
|
|
m_hCachedKey = NULL;
|
|
}
|
|
|
|
// now get the public key out into m_pPublicKeyInfo
|
|
// m_pPublicKeyInfo is internal use for cache
|
|
if (NULL != m_pPublicKeyInfo)
|
|
{
|
|
LocalFree(m_pPublicKeyInfo);
|
|
m_pPublicKeyInfo = NULL;
|
|
}
|
|
while (TRUE)
|
|
{
|
|
if(!CryptExportPublicKeyInfo(hProv,
|
|
m_keyProvInfo.dwKeySpec,
|
|
X509_ASN_ENCODING,
|
|
m_pPublicKeyInfo,
|
|
&cPublicKeyInfo))
|
|
{
|
|
goto ErrorCryptExportPublicKeyInfo;
|
|
}
|
|
if (NULL != m_pPublicKeyInfo)
|
|
{
|
|
break;
|
|
}
|
|
m_pPublicKeyInfo = (PCERT_PUBLIC_KEY_INFO)LocalAlloc(
|
|
LMEM_FIXED, cPublicKeyInfo);
|
|
if (NULL == m_pPublicKeyInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
reqInfo.SubjectPublicKeyInfo = *m_pPublicKeyInfo;
|
|
|
|
// get the Subject DN only if one is specified
|
|
reqInfo.Subject.pbData = NULL;
|
|
while (TRUE)
|
|
{
|
|
if( !MyCertStrToNameW(
|
|
CRYPT_ASN_ENCODING,
|
|
DNName,
|
|
0 | m_dwT61DNEncoding,
|
|
NULL,
|
|
reqInfo.Subject.pbData,
|
|
&reqInfo.Subject.cbData,
|
|
NULL))
|
|
{
|
|
if (CRYPT_E_INVALID_X500_STRING == GetLastError() &&
|
|
L'\0' == DNName[0])
|
|
{
|
|
//this is likely on W95, W98, or NT4 with some IEs
|
|
//crypt32 doesn't support empty DN conversion
|
|
//hard code here
|
|
reqInfo.Subject.cbData = 2;
|
|
reqInfo.Subject.pbData = (BYTE *)LocalAlloc(LMEM_FIXED,
|
|
reqInfo.Subject.cbData);
|
|
if (NULL == reqInfo.Subject.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
reqInfo.Subject.pbData[0] = 0x30;
|
|
reqInfo.Subject.pbData[1] = 0x0;
|
|
//done
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
goto ErrorCertStrToNameW;
|
|
}
|
|
}
|
|
if (NULL != reqInfo.Subject.pbData)
|
|
{
|
|
break;
|
|
}
|
|
reqInfo.Subject.pbData = (BYTE *)LocalAlloc(LMEM_FIXED,
|
|
reqInfo.Subject.cbData);
|
|
if (NULL == reqInfo.Subject.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
// allocate room for the extensions
|
|
cb = (CountStackExtension(m_fNewRequestMethod) + EndExt) * sizeof(CERT_EXTENSION);
|
|
rgExtension = (PCERT_EXTENSION)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == rgExtension)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
memset(rgExtension, 0, cb);
|
|
cb = 0;
|
|
|
|
if (!m_fUseClientKeyUsage)
|
|
{
|
|
// Make Key Usage
|
|
rgExtension[iExt].pszObjId = szOID_KEY_USAGE;
|
|
rgExtension[iExt].fCritical = TRUE;
|
|
|
|
// AT_SIGNATURE
|
|
if( m_keyProvInfo.dwKeySpec == AT_SIGNATURE)
|
|
bKeyUsage =
|
|
CERT_DIGITAL_SIGNATURE_KEY_USAGE |
|
|
CERT_NON_REPUDIATION_KEY_USAGE;
|
|
|
|
//AT_KEYEXCHANGE, limited for EMAIL single use
|
|
// email may not work if signature is present
|
|
else if(m_fLimitExchangeKeyToEncipherment)
|
|
bKeyUsage =
|
|
CERT_KEY_ENCIPHERMENT_KEY_USAGE |
|
|
CERT_DATA_ENCIPHERMENT_KEY_USAGE;
|
|
|
|
// AT_KEYEXCHANGE and AT_SIGNATURE dual key
|
|
// This is the normal case for AT_KEYEXCHANGE since CAPI will sign with this.
|
|
else
|
|
bKeyUsage =
|
|
CERT_KEY_ENCIPHERMENT_KEY_USAGE |
|
|
CERT_DATA_ENCIPHERMENT_KEY_USAGE |
|
|
CERT_DIGITAL_SIGNATURE_KEY_USAGE |
|
|
CERT_NON_REPUDIATION_KEY_USAGE;
|
|
|
|
bbKeyUsage.pbData = &bKeyUsage;
|
|
bbKeyUsage.cbData = 1;
|
|
bbKeyUsage.cUnusedBits = 1;
|
|
|
|
// encode the usage
|
|
rgExtension[iExt].Value.pbData = NULL;
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_KEY_USAGE,
|
|
&bbKeyUsage,
|
|
pbKU,
|
|
&rgExtension[iExt].Value.cbData))
|
|
{
|
|
goto ErrorEncodeKeyUsage;
|
|
}
|
|
if (NULL != pbKU)
|
|
{
|
|
rgExtension[iExt].Value.pbData = pbKU;
|
|
//done
|
|
break;
|
|
}
|
|
pbKU = (BYTE *)LocalAlloc(LMEM_FIXED, rgExtension[iExt].Value.cbData);
|
|
if (NULL == pbKU)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
iExt++;
|
|
}
|
|
|
|
if(m_fEnableSMIMECapabilities)
|
|
{
|
|
// add SMIME extension for symmetric algorithms
|
|
rgExtension[iExt].pszObjId = szOID_RSA_SMIMECapabilities;
|
|
rgExtension[iExt].fCritical = FALSE;
|
|
hr = CreateSMimeExtension(
|
|
hProv,
|
|
&pbSMime,
|
|
&rgExtension[iExt].Value.cbData);
|
|
if (S_OK != hr)
|
|
{
|
|
goto CreateSMimeExtensionError;
|
|
}
|
|
rgExtension[iExt].Value.pbData = pbSMime;
|
|
iExt++;
|
|
}
|
|
|
|
if (m_fHonorIncludeSubjectKeyID && m_fIncludeSubjectKeyID)
|
|
{
|
|
hr = myCreateSubjectKeyIdentifierExtension(
|
|
m_pPublicKeyInfo,
|
|
&pbSubjectKeyHashExtension,
|
|
&cbSubjectKeyHashExtension);
|
|
if (S_OK != hr)
|
|
{
|
|
goto myCreateSubjectKeyIdentifierExtensionError;
|
|
}
|
|
//add subject key ID hash extension into PKCS10
|
|
rgExtension[iExt].pszObjId = szOID_SUBJECT_KEY_IDENTIFIER;
|
|
rgExtension[iExt].fCritical = FALSE;
|
|
rgExtension[iExt].Value.pbData = pbSubjectKeyHashExtension;
|
|
rgExtension[iExt].Value.cbData = cbSubjectKeyHashExtension;
|
|
iExt++;
|
|
}
|
|
|
|
if(wszPurpose != NULL) {
|
|
cb = 0;
|
|
while (TRUE)
|
|
{
|
|
if(0 == (cb = WideCharToMultiByte(
|
|
0, 0, wszPurpose, -1, pszPurpose, cb, NULL, NULL)))
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
goto ErrorCantConvertPurpose;
|
|
}
|
|
if (NULL != pszPurpose)
|
|
{
|
|
break;
|
|
}
|
|
pszPurpose = (CHAR*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pszPurpose)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
szStart = pszPurpose;
|
|
|
|
// remove leading blanks
|
|
while(*szStart == ',' || *szStart == ' ')
|
|
*szStart++ = '\0';
|
|
|
|
while( szStart[0] != '\0' ) {
|
|
|
|
// find the next string
|
|
szEnd = szStart;
|
|
while(*szEnd != ',' && *szEnd != ' ' && *szEnd != '\0')
|
|
szEnd++;
|
|
|
|
// remove trailing blanks
|
|
while(*szEnd == ',' || *szEnd == ' ')
|
|
*szEnd++ = '\0';
|
|
|
|
enhKeyUsage.cUsageIdentifier++;
|
|
|
|
// see if this implies codesigning
|
|
fAddCodeSign |= !strcmp(szStart, SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID) ||
|
|
!strcmp(szStart, SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID);
|
|
|
|
// go to next string
|
|
szStart = szEnd;
|
|
}
|
|
|
|
// count the codesign EKU once
|
|
cPassedEKU = enhKeyUsage.cUsageIdentifier;
|
|
if(fAddCodeSign)
|
|
enhKeyUsage.cUsageIdentifier++;
|
|
|
|
// encode the extension
|
|
if(enhKeyUsage.cUsageIdentifier != 0) {
|
|
|
|
// allocate the EKU array
|
|
enhKeyUsage.rgpszUsageIdentifier = (LPSTR *)LocalAlloc(LMEM_FIXED,
|
|
enhKeyUsage.cUsageIdentifier * sizeof(LPSTR));
|
|
if (NULL == enhKeyUsage.rgpszUsageIdentifier)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
|
|
// add the EKU's
|
|
szStart = pszPurpose;
|
|
for(i=0; i<cPassedEKU; i++) {
|
|
|
|
while(*szStart == '\0')
|
|
szStart++;
|
|
|
|
enhKeyUsage.rgpszUsageIdentifier[i] = szStart;
|
|
|
|
while(*szStart != '\0')
|
|
szStart++;
|
|
|
|
}
|
|
|
|
// add the code sign EKU
|
|
if(fAddCodeSign)
|
|
enhKeyUsage.rgpszUsageIdentifier[enhKeyUsage.cUsageIdentifier - 1] = szOID_PKIX_KP_CODE_SIGNING;
|
|
|
|
// Deal with the policy, or purpose
|
|
rgExtension[iExt].pszObjId = szOID_ENHANCED_KEY_USAGE ;
|
|
rgExtension[iExt].fCritical = FALSE;
|
|
|
|
// encode the enhanced key usage
|
|
rgExtension[iExt].Value.cbData = 0;
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
|
|
&enhKeyUsage,
|
|
pbEKU, // pbEncoded
|
|
&rgExtension[iExt].Value.cbData))
|
|
{
|
|
goto ErrorEncodeEnhKeyUsage;
|
|
}
|
|
if (NULL != pbEKU)
|
|
{
|
|
//got it, done
|
|
rgExtension[iExt].Value.pbData = pbEKU;
|
|
break;
|
|
}
|
|
pbEKU = (BYTE *)LocalAlloc(LMEM_FIXED,
|
|
rgExtension[iExt].Value.cbData);
|
|
if (NULL == pbEKU)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
iExt++;
|
|
}
|
|
}
|
|
|
|
assert(EndExt >= iExt);
|
|
|
|
// now add all of the user defined extensions
|
|
pExtCur = NULL;
|
|
while(NULL != (pExtCur = EnumStackExtension(pExtCur, m_fNewRequestMethod)) ) {
|
|
rgExtension[iExt] = *pExtCur;
|
|
iExt++;
|
|
}
|
|
|
|
// fill in the extensions structure
|
|
Extensions.cExtension = iExt;
|
|
Extensions.rgExtension = rgExtension;
|
|
|
|
// encode the extensions
|
|
reqInfo.cAttribute = 0;
|
|
reqInfo.rgAttribute = rgAttribute;
|
|
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING, X509_EXTENSIONS,
|
|
&Extensions,
|
|
blobExt.pbData, // pbEncoded
|
|
&blobExt.cbData))
|
|
{
|
|
goto ErrorEncodeExtensions;
|
|
}
|
|
if (NULL != blobExt.pbData)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
blobExt.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, blobExt.cbData);
|
|
if (NULL == blobExt.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
if (m_fOID_V2)
|
|
{
|
|
//use new rsa oid
|
|
rgAttribute[reqInfo.cAttribute].pszObjId = szOID_RSA_certExtensions;
|
|
}
|
|
else
|
|
{
|
|
//use microsoft oid for w2k clients
|
|
rgAttribute[reqInfo.cAttribute].pszObjId = szOID_CERT_EXTENSIONS;
|
|
}
|
|
rgAttribute[reqInfo.cAttribute].cValue = 1;
|
|
rgAttribute[reqInfo.cAttribute].rgValue = &blobExt;
|
|
|
|
// put in the CSP attribute
|
|
if( !GetSignatureFromHPROV(
|
|
hProv,
|
|
&CSPProvider.Signature.pbData,
|
|
&CSPProvider.Signature.cbData
|
|
) )
|
|
goto ErrorGetSignatureFromHPROV;
|
|
|
|
CSPProvider.pwszProviderName = m_keyProvInfo.pwszProvName;
|
|
CSPProvider.dwKeySpec = m_keyProvInfo.dwKeySpec;
|
|
|
|
while (TRUE)
|
|
{
|
|
if( !CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
szOID_ENROLLMENT_CSP_PROVIDER,
|
|
&CSPProvider,
|
|
blobCSPAttr.pbData, // pbEncoded
|
|
&blobCSPAttr.cbData))
|
|
{
|
|
goto ErrorEncodeCSPAttr;
|
|
}
|
|
if (NULL != blobCSPAttr.pbData)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
blobCSPAttr.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, blobCSPAttr.cbData);
|
|
if (NULL == blobCSPAttr.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
reqInfo.cAttribute++;
|
|
rgAttribute[reqInfo.cAttribute].pszObjId = szOID_ENROLLMENT_CSP_PROVIDER;
|
|
rgAttribute[reqInfo.cAttribute].cValue = 1;
|
|
rgAttribute[reqInfo.cAttribute].rgValue = &blobCSPAttr;
|
|
|
|
// get the OSVersion
|
|
osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if(!GetVersionExA(&osvInfo))
|
|
goto ErrorGetVersionEx;
|
|
|
|
wsprintfA(szVersion, "%d.%d.%d.%d",
|
|
osvInfo.dwMajorVersion,
|
|
osvInfo.dwMinorVersion,
|
|
osvInfo.dwBuildNumber,
|
|
osvInfo.dwPlatformId);
|
|
|
|
cnvOSVer.dwValueType = CERT_RDN_IA5_STRING;
|
|
cnvOSVer.Value.cbData = (DWORD)strlen(szVersion);
|
|
cnvOSVer.Value.pbData = (BYTE *) szVersion;
|
|
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_ANY_STRING,
|
|
&cnvOSVer,
|
|
blobOSVAttr.pbData, // pbEncoded
|
|
&blobOSVAttr.cbData))
|
|
{
|
|
goto ErrorEncodeOSVAttr;
|
|
}
|
|
if (NULL != blobOSVAttr.pbData)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
blobOSVAttr.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, blobOSVAttr.cbData);
|
|
if (NULL == blobOSVAttr.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
reqInfo.cAttribute++;
|
|
rgAttribute[reqInfo.cAttribute].pszObjId = szOID_OS_VERSION;
|
|
rgAttribute[reqInfo.cAttribute].cValue = 1;
|
|
rgAttribute[reqInfo.cAttribute].rgValue = &blobOSVAttr;
|
|
|
|
// put in the renewal cert if present
|
|
if(m_pCertContextRenewal != NULL && m_fHonorRenew) {
|
|
|
|
reqInfo.cAttribute++;
|
|
|
|
blobRenewAttr.pbData = m_pCertContextRenewal->pbCertEncoded;
|
|
blobRenewAttr.cbData = m_pCertContextRenewal->cbCertEncoded;
|
|
|
|
rgAttribute[reqInfo.cAttribute].pszObjId = szOID_RENEWAL_CERTIFICATE;
|
|
rgAttribute[reqInfo.cAttribute].cValue = 1;
|
|
rgAttribute[reqInfo.cAttribute].rgValue = &blobRenewAttr;
|
|
}
|
|
|
|
if (m_fNewRequestMethod && XECI_DISABLE != m_lClientId)
|
|
{
|
|
//put client id as attribute
|
|
hr = myEncodeRequestClientAttributeFromClientId(
|
|
m_lClientId,
|
|
&blobClientId.pbData,
|
|
&blobClientId.cbData);
|
|
if (S_OK != hr)
|
|
{
|
|
//for any reasons, don't include client ID
|
|
hr = put_ClientId(XECI_DISABLE);
|
|
if (S_OK != hr)
|
|
{
|
|
goto putClientIdError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
reqInfo.cAttribute++;
|
|
rgAttribute[reqInfo.cAttribute].pszObjId = szOID_REQUEST_CLIENT_INFO;
|
|
rgAttribute[reqInfo.cAttribute].cValue = 1;
|
|
rgAttribute[reqInfo.cAttribute].rgValue = &blobClientId;
|
|
}
|
|
}
|
|
|
|
// NOTE: On error we always return BAD ALGID
|
|
// this is because sometimes we get an no more data enum error
|
|
// that doesn't help.
|
|
// get the signature oid
|
|
if( !GetCapiHashAndSigAlgId(rgAlg) ) {
|
|
SetLastError((DWORD)NTE_BAD_ALGID);
|
|
goto ErrorGetCapiHashAndSigAlgId;
|
|
}
|
|
|
|
// Convert to an oid
|
|
if( (NULL == (pOidInfo = xeCryptFindOIDInfo(
|
|
CRYPT_OID_INFO_SIGN_KEY,
|
|
(void *) rgAlg,
|
|
CRYPT_SIGN_ALG_OID_GROUP_ID)) ) ) {
|
|
SetLastError((DWORD)NTE_BAD_ALGID);
|
|
goto ErrorCryptFindOIDInfo;
|
|
}
|
|
|
|
// we always know we have at least 1 attribute, and we have been zero based, now go to 1 based.
|
|
reqInfo.cAttribute++;
|
|
SignatureInfo.SignatureAlgorithm.pszObjId = (char *) pOidInfo->pszOID;
|
|
#if DBG
|
|
//SignatureInfo.ToBeSigned.pbData should be null at the first
|
|
assert(NULL == SignatureInfo.ToBeSigned.pbData);
|
|
#endif
|
|
// encode PKCS10
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING, X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&reqInfo,
|
|
SignatureInfo.ToBeSigned.pbData, // pbEncoded
|
|
&SignatureInfo.ToBeSigned.cbData))
|
|
{
|
|
goto ErrorEncodePKCS10ToBeSigned;
|
|
}
|
|
if (NULL != SignatureInfo.ToBeSigned.pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
SignatureInfo.ToBeSigned.pbData = (BYTE *)
|
|
LocalAlloc(LMEM_FIXED, SignatureInfo.ToBeSigned.cbData);
|
|
if (NULL == SignatureInfo.ToBeSigned.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
// create the signature Info
|
|
// Don't care if xchange or signature key in dwkeySpec because
|
|
// we are signing with the key that is in the PKCS10
|
|
#if DBG
|
|
assert(NULL == SignatureInfo.Signature.pbData);
|
|
#endif
|
|
while (TRUE)
|
|
{
|
|
if(!CryptSignCertificate(
|
|
hProv,
|
|
m_keyProvInfo.dwKeySpec,
|
|
CRYPT_ASN_ENCODING,
|
|
SignatureInfo.ToBeSigned.pbData,
|
|
SignatureInfo.ToBeSigned.cbData,
|
|
&SignatureInfo.SignatureAlgorithm,
|
|
NULL, // reserved
|
|
SignatureInfo.Signature.pbData, // pbSignature
|
|
&SignatureInfo.Signature.cbData))
|
|
{
|
|
goto ErrorCryptSignCertificatePKCS10;
|
|
}
|
|
if (NULL != SignatureInfo.Signature.pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
SignatureInfo.Signature.pbData = (BYTE *)
|
|
LocalAlloc(LMEM_FIXED, SignatureInfo.Signature.cbData);
|
|
if (NULL == SignatureInfo.Signature.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
// encode the final signed request
|
|
if( !CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_CERT,
|
|
&SignatureInfo,
|
|
NULL,
|
|
&pPkcs10Blob->cbData
|
|
) ||
|
|
(pPkcs10Blob->pbData = (BYTE *)
|
|
MyCoTaskMemAlloc(pPkcs10Blob->cbData)) == NULL ||
|
|
!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_CERT,
|
|
&SignatureInfo,
|
|
pPkcs10Blob->pbData,
|
|
&pPkcs10Blob->cbData
|
|
) ) {
|
|
goto ErrorEncodePKCS10Request;
|
|
}
|
|
|
|
// go ahead and make the pkcs 7
|
|
if((m_pCertContextRenewal != NULL ||
|
|
m_pCertContextSigner != NULL) &&
|
|
m_fHonorRenew &&
|
|
!m_fCMCFormat) //if CMC, don't make pkcs7
|
|
{
|
|
|
|
// create a pkcs7 signed by the old cert
|
|
if(S_OK != CreatePKCS7RequestFromRequest(
|
|
pPkcs10Blob,
|
|
(NULL != m_pCertContextRenewal) ? m_pCertContextRenewal :
|
|
m_pCertContextSigner,
|
|
&blobPKCS7) )
|
|
goto ErrorCreatePKCS7RARequestFromPKCS10;
|
|
|
|
assert(pPkcs10Blob->pbData != NULL);
|
|
MyCoTaskMemFree(pPkcs10Blob->pbData);
|
|
*pPkcs10Blob = blobPKCS7;
|
|
memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
}
|
|
|
|
ssFlags = CERT_CREATE_SELFSIGN_NO_SIGN;
|
|
if(m_wszPVKFileName[0] != 0)
|
|
ssFlags |= CERT_CREATE_SELFSIGN_NO_KEY_INFO;
|
|
|
|
// Get the cert extensions we wish to add to the certificate.
|
|
// Search for the extensions we need.
|
|
{
|
|
PCERT_EXTENSION pCertExtCertTypeName = NULL;
|
|
while(NULL != (pCertExtCertTypeName = EnumStackExtension(pCertExtCertTypeName, m_fNewRequestMethod)) ) {
|
|
for (DWORD dTmp = 0; dTmp < sizeof(rgszExtensionOIDs) / sizeof(LPSTR); dTmp++) {
|
|
if (0 == strcmp(rgszExtensionOIDs[dTmp], pCertExtCertTypeName->pszObjId))
|
|
rgNeededExtensions[(ceExtensions.cExtension)++] = *pCertExtCertTypeName;
|
|
}
|
|
}
|
|
|
|
// Even if we didn't find all of the extensions we wanted, continue ...
|
|
}
|
|
|
|
assert(pCertContext == NULL);
|
|
pCertContext = MyCertCreateSelfSignCertificate(
|
|
hProv,
|
|
&reqInfo.Subject,
|
|
ssFlags,
|
|
&m_keyProvInfo,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
(ceExtensions.cExtension > 0) ? &ceExtensions : NULL
|
|
);
|
|
if (NULL == pCertContext)
|
|
goto ErrorCertCreateSelfSignCertificate;
|
|
|
|
// now put the pass thru data on the cert
|
|
requestFlags.fWriteToCSP = (m_fWriteCertToCSP != 0);
|
|
requestFlags.fWriteToDS = (m_fWriteCertToUserDS != 0);
|
|
requestFlags.openFlags = m_RequestStore.dwFlags;
|
|
|
|
#if DBG
|
|
assert(NULL == requestInfoBlob.pbData);
|
|
#endif
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
XENROLL_REQUEST_INFO,
|
|
&requestFlags,
|
|
requestInfoBlob.pbData,
|
|
&requestInfoBlob.cbData))
|
|
{
|
|
goto ErrorEncodeRequestInfoBlob;
|
|
}
|
|
if (NULL != requestInfoBlob.pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
requestInfoBlob.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, requestInfoBlob.cbData);
|
|
if (NULL == requestInfoBlob.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
// set the property on the dummy request cert.
|
|
if( !CertSetCertificateContextProperty(
|
|
pCertContext,
|
|
XENROLL_PASS_THRU_PROP_ID,
|
|
0,
|
|
&requestInfoBlob) )
|
|
goto ErrorCertSetCertificateContextProperty;
|
|
|
|
if(m_pCertContextRenewal != NULL && m_fHonorRenew) {
|
|
|
|
blobRenewalCert.pbData = m_pCertContextRenewal->pbCertEncoded;
|
|
blobRenewalCert.cbData = m_pCertContextRenewal->cbCertEncoded;
|
|
|
|
// set the renewal property if any
|
|
if( !CertSetCertificateContextProperty(
|
|
pCertContext,
|
|
XENROLL_RENEWAL_CERTIFICATE_PROP_ID,
|
|
0,
|
|
&blobRenewalCert) )
|
|
goto ErrorCertSetCertificateContextProperty;
|
|
}
|
|
|
|
// save the private key away if needed
|
|
if(m_wszPVKFileName[0] != 0) {
|
|
|
|
// open the PVK File
|
|
if( (hFile = CreateOpenFileSafely2(m_wszPVKFileName, IDS_PVK_C, IDS_PVK_O)) == NULL )
|
|
goto ErrorCreatePVKFile;
|
|
|
|
assert(m_keyProvInfo.dwKeySpec == AT_SIGNATURE || m_keyProvInfo.dwKeySpec == AT_KEYEXCHANGE);
|
|
|
|
// write out the private key
|
|
if( !PrivateKeySave(
|
|
hProv,
|
|
hFile,
|
|
m_keyProvInfo.dwKeySpec,
|
|
NULL,
|
|
m_wszPVKFileName,
|
|
0
|
|
) ) {
|
|
goto ErrorPrivateKeySave;
|
|
}
|
|
|
|
// put a different kind of propery in the store that just points to the pvk file
|
|
keyProvInfoT = m_keyProvInfo;
|
|
keyProvInfoT.pwszContainerName = m_wszPVKFileName;
|
|
if( !CreatePvkProperty(&keyProvInfoT, &blobData) )
|
|
goto ErrorCreatePvkProperty;
|
|
|
|
// This is really not needed, it is only nice for other tools
|
|
// like makecert or signcode to be able to look at a cert without
|
|
// specifying a .PVK file if the cert points to the .pvk file.
|
|
// So we don't care if this actually fail, which it will on Auth2 and
|
|
// SP3 Crypt32.dll since Phil was so kind as to not allow any unknown property
|
|
// to be set on the cert --- BAD PHIL!
|
|
CertSetCertificateContextProperty(
|
|
pCertContext,
|
|
CERT_PVK_FILE_PROP_ID,
|
|
0,
|
|
&blobData);
|
|
|
|
// only delete the keyset if the key was not pre-existing
|
|
// this is if we write it out to a PVK file only
|
|
// This is safe for scripting since we just generated this and we are putting it to
|
|
// a pvk file. We really aren't deleting the key.
|
|
if (!m_fNewRequestMethod)
|
|
{
|
|
//keep old behavior for createPKCS10 call
|
|
if(!m_fUseExistingKey)
|
|
GetProv(CRYPT_DELETEKEYSET);
|
|
}
|
|
}
|
|
|
|
//set all properties from the caller
|
|
pProp = EnumStackProperty(NULL);
|
|
while (NULL != pProp)
|
|
{
|
|
//goto request cert
|
|
if (!CertSetCertificateContextProperty(
|
|
pCertContext,
|
|
pProp->lPropId,
|
|
0,
|
|
&pProp->prop))
|
|
{
|
|
goto ErrorCertSetCertificateContextProperty;
|
|
}
|
|
pProp = EnumStackProperty(pProp);
|
|
}
|
|
|
|
// open the request cert store
|
|
if( (hStore = GetStore(StoreREQUEST)) == NULL)
|
|
goto ErrorCertOpenRequestStore;
|
|
|
|
//if old pending request exists, free it first
|
|
fRet = CertFreeCertificateContext(m_pCertContextPendingRequest);
|
|
#if DBG
|
|
assert(fRet);
|
|
#endif //DBG
|
|
m_pCertContextPendingRequest = NULL;
|
|
|
|
// save the temp cert
|
|
if( !MySafeCertAddCertificateContextToStore(
|
|
hStore,
|
|
pCertContext,
|
|
CERT_STORE_ADD_NEW,
|
|
&m_pCertContextPendingRequest,
|
|
m_dwEnabledSafteyOptions) ) {
|
|
goto ErrorCertAddToRequestStore;
|
|
}
|
|
|
|
// Remove the cached HASH.
|
|
if (m_hashBlobPendingRequest.pbData != NULL)
|
|
{
|
|
LocalFree(m_hashBlobPendingRequest.pbData);
|
|
m_hashBlobPendingRequest.pbData = NULL;
|
|
}
|
|
|
|
CommonReturn:
|
|
|
|
if(pCertContext != NULL)
|
|
CertFreeCertificateContext(pCertContext);
|
|
if(hFile != NULL)
|
|
CloseHandle(hFile);
|
|
if(blobData.pbData != NULL)
|
|
MyCoTaskMemFree(blobData.pbData);
|
|
if(blobPKCS7.pbData != NULL)
|
|
MyCoTaskMemFree(blobPKCS7.pbData);
|
|
if(CSPProvider.Signature.pbData)
|
|
LocalFree(CSPProvider.Signature.pbData);
|
|
if (NULL != pbSMime)
|
|
{
|
|
LocalFree(pbSMime);
|
|
}
|
|
if (NULL != reqInfo.Subject.pbData)
|
|
{
|
|
LocalFree(reqInfo.Subject.pbData);
|
|
}
|
|
if (NULL != rgExtension)
|
|
{
|
|
LocalFree(rgExtension);
|
|
}
|
|
if (NULL != pbKU)
|
|
{
|
|
LocalFree(pbKU);
|
|
}
|
|
if (NULL != pbEKU)
|
|
{
|
|
LocalFree(pbEKU);
|
|
}
|
|
if (NULL != pszPurpose)
|
|
{
|
|
LocalFree(pszPurpose);
|
|
}
|
|
if (NULL != enhKeyUsage.rgpszUsageIdentifier)
|
|
{
|
|
LocalFree(enhKeyUsage.rgpszUsageIdentifier);
|
|
}
|
|
if (NULL != blobExt.pbData)
|
|
{
|
|
LocalFree(blobExt.pbData);
|
|
}
|
|
if (NULL != blobCSPAttr.pbData)
|
|
{
|
|
LocalFree(blobCSPAttr.pbData);
|
|
}
|
|
if (NULL != blobOSVAttr.pbData)
|
|
{
|
|
LocalFree(blobOSVAttr.pbData);
|
|
}
|
|
if (NULL != SignatureInfo.ToBeSigned.pbData)
|
|
{
|
|
LocalFree(SignatureInfo.ToBeSigned.pbData);
|
|
}
|
|
if (NULL != SignatureInfo.Signature.pbData)
|
|
{
|
|
LocalFree(SignatureInfo.Signature.pbData);
|
|
}
|
|
if (NULL != requestInfoBlob.pbData)
|
|
{
|
|
LocalFree(requestInfoBlob.pbData);
|
|
}
|
|
if (NULL != blobClientId.pbData)
|
|
{
|
|
LocalFree(blobClientId.pbData);
|
|
}
|
|
if (NULL != pbSubjectKeyHashExtension)
|
|
{
|
|
LocalFree(pbSubjectKeyHashExtension);
|
|
}
|
|
if (NULL != pwszNotSafeRequesting)
|
|
{
|
|
LocalFree(pwszNotSafeRequesting);
|
|
}
|
|
if (NULL != pwszTitle)
|
|
{
|
|
LocalFree(pwszTitle);
|
|
}
|
|
|
|
// don't know if we have an error or not
|
|
// but I do know the errBefore is set properly
|
|
SetLastError(errBefore);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
// on error return a NULL
|
|
if(pPkcs10Blob->pbData != NULL)
|
|
MyCoTaskMemFree(pPkcs10Blob->pbData);
|
|
memset(pPkcs10Blob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorGetSignatureFromHPROV);
|
|
TRACE_ERROR(ErrorEncodeCSPAttr);
|
|
TRACE_ERROR(ErrorCertSetCertificateContextProperty);
|
|
TRACE_ERROR(ErrorCryptAcquireContext);
|
|
TRACE_ERROR(ErrorCryptGenKey);
|
|
TRACE_ERROR(ErrorCryptExportPublicKeyInfo);
|
|
TRACE_ERROR(ErrorCertStrToNameW);
|
|
TRACE_ERROR(ErrorEncodeKeyUsage);
|
|
TRACE_ERROR(ErrorEncodeEnhKeyUsage);
|
|
TRACE_ERROR(ErrorEncodeExtensions);
|
|
TRACE_ERROR(ErrorEncodePKCS10ToBeSigned);
|
|
TRACE_ERROR(ErrorCryptSignCertificatePKCS10);
|
|
TRACE_ERROR(ErrorEncodePKCS10Request);
|
|
TRACE_ERROR(ErrorCantConvertPurpose);
|
|
TRACE_ERROR(ErrorCertOpenRequestStore);
|
|
TRACE_ERROR(ErrorCertAddToRequestStore);
|
|
TRACE_ERROR(ErrorCreatePVKFile);
|
|
TRACE_ERROR(ErrorPrivateKeySave);
|
|
TRACE_ERROR(ErrorCreatePvkProperty);
|
|
TRACE_ERROR(ErrorCertCreateSelfSignCertificate);
|
|
TRACE_ERROR(ErrorEncodeRequestInfoBlob);
|
|
TRACE_ERROR(ErrorCreatePKCS7RARequestFromPKCS10);
|
|
TRACE_ERROR(ErrorGetCapiHashAndSigAlgId);
|
|
TRACE_ERROR(ErrorCryptFindOIDInfo);
|
|
TRACE_ERROR(ErrorEncodeOSVAttr);
|
|
TRACE_ERROR(ErrorGetVersionEx);
|
|
TRACE_ERROR(CancelledError);
|
|
TRACE_ERROR(CreateSMimeExtensionError);
|
|
TRACE_ERROR(OutOfMemoryError);
|
|
TRACE_ERROR(putClientIdError);
|
|
TRACE_ERROR(myCreateSubjectKeyIdentifierExtensionError)
|
|
TRACE_ERROR(xeLoadRCStringError);
|
|
TRACE_ERROR(CryptGetUserKeyCancelError)
|
|
#if DBG
|
|
TRACE_ERROR(SetKeyContainerSecurityError)
|
|
#endif //DBG
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::acceptPKCS7Blob(
|
|
/* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7) {
|
|
|
|
HRESULT hr;
|
|
HRESULT hr2 = S_OK;
|
|
LONG dwKeySpec = 0;
|
|
PCCERT_CONTEXT pCertContextMy = NULL;
|
|
PCCERT_CONTEXT pCertContextRequest = NULL;
|
|
PCCERT_CONTEXT pCertContextEnd = NULL;
|
|
HANDLE hFile = NULL;
|
|
DWORD cb = 0;
|
|
HCRYPTPROV hProv = NULL;
|
|
HCRYPTKEY hKey = NULL;
|
|
HCERTSTORE hStoreDS = NULL;
|
|
HCERTSTORE hStoreRequest = NULL;
|
|
HCERTSTORE hStoreMy = NULL;
|
|
LPWSTR pwszTitle = NULL;
|
|
LPWSTR pwszNotSafeAccepting = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// Accepting a request is not safe for scripting: pop up a warning dialog if called from script
|
|
if (0 != m_dwEnabledSafteyOptions) {
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle);
|
|
if (S_OK != hr)
|
|
goto xeLoadRCStringError;
|
|
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_ACCEPTING_CERT, &pwszNotSafeAccepting);
|
|
if (S_OK != hr)
|
|
goto xeLoadRCStringError;
|
|
|
|
if (IDYES != MessageBoxU(NULL, pwszNotSafeAccepting, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
goto CancelledError;
|
|
}
|
|
}
|
|
|
|
// get the end entity cert
|
|
hr2 = GetEndEntityCert(pBlobPKCS7, TRUE, &pCertContextEnd);
|
|
if (S_OK != hr2 && XENROLL_E_CANNOT_ADD_ROOT_CERT != hr2)
|
|
{
|
|
hr = hr2;
|
|
goto ErrorGetEndEntityCert;
|
|
}
|
|
|
|
if(m_fDeleteRequestCert)
|
|
{
|
|
if ((hStoreRequest = GetStore(StoreREQUEST)) == NULL)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertOpenRequestStore;
|
|
}
|
|
|
|
// check to see if this is in the request store
|
|
if ((pCertContextRequest = CertFindCertificateInStore(
|
|
hStoreRequest,
|
|
CRYPT_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_PUBLIC_KEY,
|
|
(void *) &pCertContextEnd->pCertInfo->SubjectPublicKeyInfo,
|
|
NULL)) != NULL)
|
|
{
|
|
CertDeleteCertificateFromStore(pCertContextRequest);
|
|
pCertContextRequest = NULL;
|
|
}
|
|
}
|
|
|
|
cb = 0;
|
|
// if the cert is to be written to the CSP,
|
|
// put it there but only if we have keys
|
|
if (m_fWriteCertToCSP &&
|
|
CertGetCertificateContextProperty(
|
|
pCertContextEnd,
|
|
CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb))
|
|
{
|
|
if ((hProv = GetProv(0)) == NULL)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCryptAcquireContext;
|
|
}
|
|
|
|
// This can't fail
|
|
get_KeySpec(&dwKeySpec);
|
|
|
|
if (!CryptGetUserKey(
|
|
hProv,
|
|
dwKeySpec,
|
|
&hKey))
|
|
{
|
|
hKey = NULL;
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCryptGetUserKey;
|
|
}
|
|
|
|
// always attempt to write the cert to the csp
|
|
if (!CryptSetKeyParam(
|
|
hKey,
|
|
KP_CERTIFICATE,
|
|
pCertContextEnd->pbCertEncoded,
|
|
0))
|
|
{
|
|
// only return an error if it is a smart card error
|
|
// otherwise ignore the error
|
|
if (SCODE_FACILITY(GetLastError()) == FACILITY_SCARD)
|
|
{
|
|
//return error code from writing cert to csp
|
|
//important to save the error code before following clean up
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
//if can't write cert back to smartcard, remove the cert from my store
|
|
if ((hStoreMy = GetStore(StoreMY)) == NULL)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertOpenMyStore;
|
|
}
|
|
|
|
// check to see if this is in the MY store
|
|
if ((pCertContextMy = CertFindCertificateInStore(
|
|
hStoreMy,
|
|
CRYPT_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_PUBLIC_KEY,
|
|
(void *) &pCertContextEnd->pCertInfo->SubjectPublicKeyInfo,
|
|
NULL)) != NULL)
|
|
{
|
|
//try to remove it
|
|
CertDeleteCertificateFromStore(pCertContextMy);
|
|
pCertContextMy = NULL;
|
|
}
|
|
if (!m_fUseExistingKey)
|
|
{
|
|
GetProv(CRYPT_DELETEKEYSET);
|
|
}
|
|
//error any way
|
|
goto ErrorWriteToCSP;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_fWriteCertToUserDS)
|
|
{
|
|
// otherwise attempt to open the store
|
|
if ((hStoreDS = CertOpenStore(
|
|
CERT_STORE_PROV_SYSTEM,
|
|
X509_ASN_ENCODING,
|
|
NULL,
|
|
CERT_SYSTEM_STORE_CURRENT_USER,
|
|
L"UserDS")) == NULL)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCertOpenDSStore;
|
|
}
|
|
|
|
if (!CertAddCertificateContextToStore(
|
|
hStoreDS,
|
|
pCertContextEnd,
|
|
CERT_STORE_ADD_NEW,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorAddCertificateContextToDSStore;
|
|
}
|
|
|
|
CertCloseStore(hStoreDS, 0);
|
|
hStoreDS = NULL;
|
|
|
|
}
|
|
|
|
// determine if he wants to save the spc file
|
|
if (m_wszSPCFileName[0] != 0)
|
|
{
|
|
// open the spc file
|
|
hFile = CreateOpenFileSafely2(m_wszSPCFileName, IDS_SPC_C, IDS_SPC_O);
|
|
if (NULL == hFile)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorCreateSPCFile;
|
|
}
|
|
|
|
// write the spc
|
|
assert(pBlobPKCS7->pbData != NULL);
|
|
cb = 0;
|
|
if (!WriteFile(
|
|
hFile,
|
|
pBlobPKCS7->pbData,
|
|
pBlobPKCS7->cbData,
|
|
&cb,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto ErrorWriteSPCFile;
|
|
}
|
|
}
|
|
|
|
if (S_OK != hr2)
|
|
{
|
|
//return hr2 error
|
|
hr = hr2;
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
ErrorReturn:
|
|
|
|
if(hKey != NULL)
|
|
CryptDestroyKey(hKey);
|
|
if(hFile != NULL)
|
|
CloseHandle(hFile);
|
|
|
|
if(pCertContextEnd != NULL)
|
|
CertFreeCertificateContext(pCertContextEnd);
|
|
if(hStoreDS != NULL)
|
|
CertCloseStore(hStoreDS, 0);
|
|
if (NULL != pwszNotSafeAccepting)
|
|
LocalFree(pwszNotSafeAccepting);
|
|
if (NULL != pwszTitle)
|
|
LocalFree(pwszTitle);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
TRACE_ERROR(ErrorWriteToCSP);
|
|
TRACE_ERROR(ErrorCreateSPCFile);
|
|
TRACE_ERROR(ErrorWriteSPCFile);
|
|
TRACE_ERROR(ErrorGetEndEntityCert);
|
|
TRACE_ERROR(ErrorCryptAcquireContext);
|
|
TRACE_ERROR(ErrorCryptGetUserKey);
|
|
TRACE_ERROR(ErrorCertOpenDSStore);
|
|
TRACE_ERROR(ErrorAddCertificateContextToDSStore);
|
|
TRACE_ERROR(ErrorCertOpenRequestStore);
|
|
TRACE_ERROR(ErrorCertOpenMyStore);
|
|
TRACE_ERROR(CancelledError);
|
|
TRACE_ERROR(xeLoadRCStringError);
|
|
}
|
|
|
|
PCCERT_CONTEXT STDMETHODCALLTYPE CCEnroll::getCertContextFromPKCS7(
|
|
/* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7) {
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pCert;
|
|
|
|
// get the end entity cert
|
|
hr = GetEndEntityCert(pBlobPKCS7, FALSE, &pCert);
|
|
#if DBG
|
|
if (S_OK != hr)
|
|
{
|
|
assert(NULL == pCert);
|
|
}
|
|
#endif //DBG
|
|
return pCert;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::enumProvidersWStr(
|
|
/* [in] */ LONG dwIndex,
|
|
/* [in] */ LONG dwFlags,
|
|
/* [out] */ LPWSTR __RPC_FAR *ppwsz) {
|
|
|
|
DWORD iLast = 0;
|
|
LONG i;
|
|
DWORD dwProvType = 0;
|
|
DWORD cb = 0;
|
|
HRESULT hr = S_OK;
|
|
DWORD errBefore = GetLastError();
|
|
|
|
assert(ppwsz != NULL);
|
|
*ppwsz = NULL;
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
for(i=0; i<=dwIndex; i++) {
|
|
|
|
do {
|
|
|
|
cb = 0;
|
|
if( !CryptEnumProvidersU(
|
|
iLast,
|
|
0,
|
|
0,
|
|
&dwProvType,
|
|
NULL,
|
|
&cb
|
|
) ) {
|
|
|
|
// only skip if entry is bad
|
|
if( GetLastError() != NTE_PROV_TYPE_ENTRY_BAD)
|
|
goto ErrorCryptEnumProvidersU;
|
|
}
|
|
iLast++;
|
|
} while((CRYPT_ENUM_ALL_PROVIDERS & dwFlags) != CRYPT_ENUM_ALL_PROVIDERS &&
|
|
dwProvType != m_keyProvInfo.dwProvType);
|
|
}
|
|
|
|
iLast--;
|
|
if( (*ppwsz = (LPWSTR) MyCoTaskMemAlloc(cb)) == NULL ||
|
|
!CryptEnumProvidersU(
|
|
iLast,
|
|
0,
|
|
0,
|
|
&dwProvType,
|
|
*ppwsz,
|
|
&cb
|
|
) ) {
|
|
goto ErrorCryptEnumProvidersU;
|
|
}
|
|
|
|
CommonReturn:
|
|
|
|
SetLastError(errBefore);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
if(*ppwsz != NULL)
|
|
{
|
|
MyCoTaskMemFree(*ppwsz);
|
|
*ppwsz = NULL;
|
|
}
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorCryptEnumProvidersU);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::enumContainersWStr(
|
|
/* [in] */ LONG dwIndex,
|
|
/* [out] */ LPWSTR __RPC_FAR *ppwsz) {
|
|
|
|
DWORD errBefore = GetLastError();
|
|
DWORD cb = 0;
|
|
LONG i = 0;
|
|
char * psz = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
assert(ppwsz != NULL);
|
|
*ppwsz = NULL;
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
goto AccessDeniedError;
|
|
|
|
hr = GetVerifyProv();
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetVerifyProvError;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
if(!CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
PP_ENUMCONTAINERS,
|
|
(BYTE*)psz,
|
|
&cb,
|
|
CRYPT_FIRST))
|
|
{
|
|
goto ErrorCryptGetProvParam;
|
|
}
|
|
if (NULL != psz)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
psz = (char*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == psz)
|
|
{
|
|
goto ErrorOutOfMem;
|
|
}
|
|
}
|
|
|
|
for(i=1; i<=dwIndex; i++) {
|
|
//assume 1st enum buffer size is big enough for all?
|
|
if( !CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
PP_ENUMCONTAINERS,
|
|
(BYTE *) psz,
|
|
&cb,
|
|
0) )
|
|
goto ErrorCryptGetProvParam;
|
|
}
|
|
|
|
if( (*ppwsz = WideFromMB(psz)) == NULL )
|
|
goto ErrorOutOfMem;
|
|
|
|
|
|
CommonReturn:
|
|
if (NULL != psz)
|
|
{
|
|
LocalFree(psz);
|
|
}
|
|
|
|
SetLastError(errBefore);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
if(*ppwsz != NULL)
|
|
MyCoTaskMemFree(*ppwsz);
|
|
*ppwsz = NULL;
|
|
|
|
goto CommonReturn;
|
|
|
|
|
|
SET_ERROR(AccessDeniedError, E_ACCESSDENIED);
|
|
TRACE_ERROR(GetVerifyProvError);
|
|
TRACE_ERROR(ErrorCryptGetProvParam);
|
|
TRACE_ERROR(ErrorOutOfMem);
|
|
}
|
|
|
|
|
|
HRESULT CCEnroll::PKCS10ToCert(IN HCERTSTORE hCertStore,
|
|
IN CRYPT_DATA_BLOB pkcs10Blob,
|
|
OUT PCCERT_CONTEXT *ppCertContext)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
PCERT_REQUEST_INFO pReqInfo = NULL;
|
|
|
|
// Input validation:
|
|
if (NULL == hCertStore || NULL == pkcs10Blob.pbData || NULL == ppCertContext)
|
|
return E_INVALIDARG;
|
|
|
|
if( !MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
&pkcs10Blob,
|
|
CERT_QUERY_CONTENT_FLAG_PKCS10,
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
CRYPT_DECODE_ALLOC_FLAG,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
(const void **) &pReqInfo) )
|
|
goto MyCryptQueryObjectError;
|
|
|
|
if ( NULL == (*ppCertContext = CertFindCertificateInStore
|
|
(hCertStore,
|
|
CRYPT_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_PUBLIC_KEY,
|
|
(void *) &pReqInfo->SubjectPublicKeyInfo,
|
|
NULL)) )
|
|
goto CertFindCertificateInStoreError;
|
|
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
if (NULL != pReqInfo) { LocalFree(pReqInfo); } // Allocated in CryptQueryObject().
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CertFindCertificateInStoreError, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MyCryptQueryObjectError, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
HRESULT CCEnroll::PKCS7ToCert(IN HCERTSTORE hCertStore,
|
|
IN CRYPT_DATA_BLOB pkcs7Blob,
|
|
OUT PCCERT_CONTEXT *ppCertContext)
|
|
{
|
|
CRYPT_DATA_BLOB pkcs10Blob;
|
|
CRYPT_VERIFY_MESSAGE_PARA VerifyPara;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// Init locals:
|
|
ZeroMemory(&pkcs10Blob, sizeof(pkcs10Blob));
|
|
ZeroMemory(&VerifyPara, sizeof(VerifyPara));
|
|
|
|
VerifyPara.cbSize = sizeof(VerifyPara);
|
|
VerifyPara.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
|
|
|
|
if (!MyCryptVerifyMessageSignature
|
|
(&VerifyPara,
|
|
0, // dwSignerIndex
|
|
pkcs7Blob.pbData,
|
|
pkcs7Blob.cbData,
|
|
pkcs10Blob.pbData,
|
|
&(pkcs10Blob.cbData),
|
|
NULL // ppSignerCert
|
|
) || 0 == pkcs10Blob.cbData)
|
|
goto MyCryptVerifyMessageSignatureError;
|
|
|
|
if (NULL == (pkcs10Blob.pbData = (PBYTE)LocalAlloc(LPTR, pkcs10Blob.cbData)))
|
|
goto MemoryError;
|
|
|
|
if (!MyCryptVerifyMessageSignature
|
|
(&VerifyPara,
|
|
0, // dwSignerIndex
|
|
pkcs7Blob.pbData,
|
|
pkcs7Blob.cbData,
|
|
pkcs10Blob.pbData,
|
|
&pkcs10Blob.cbData,
|
|
NULL // ppSignerCert
|
|
))
|
|
goto MyCryptVerifyMessageSignatureError;
|
|
|
|
hr = this->PKCS10ToCert(hCertStore, pkcs10Blob, ppCertContext);
|
|
|
|
CommonReturn:
|
|
if (NULL != pkcs10Blob.pbData) { LocalFree(pkcs10Blob.pbData); }
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(MemoryError, E_OUTOFMEMORY);
|
|
SET_HRESULT(MyCryptVerifyMessageSignatureError, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::freeRequestInfoBlob(
|
|
/* [in] */ CRYPT_DATA_BLOB pkcs7OrPkcs10) {
|
|
|
|
DWORD dwContentType = NULL;
|
|
HCERTSTORE hStoreRequest = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
// We're not supposed to delete the cert anyway, so we're done!
|
|
if (!m_fDeleteRequestCert)
|
|
return S_OK;
|
|
|
|
if (NULL == pkcs7OrPkcs10.pbData)
|
|
return E_INVALIDARG;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// Step 1) Determine if we have a PKCS7 or a PKCS10:
|
|
//
|
|
if( !MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
&pkcs7OrPkcs10,
|
|
(CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_PKCS10),
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
0,
|
|
NULL,
|
|
&dwContentType, // OUT: PKCS10 or PKCS7
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL) )
|
|
goto MyCryptQueryObjectError;
|
|
|
|
// Step 2) Find a cert context with a matching public key in the request store:
|
|
//
|
|
|
|
if (NULL == (hStoreRequest = GetStore(StoreREQUEST)))
|
|
goto UnexpectedError;
|
|
|
|
switch (dwContentType)
|
|
{
|
|
case CERT_QUERY_CONTENT_PKCS7_SIGNED:
|
|
hr = this->PKCS7ToCert(hStoreRequest, pkcs7OrPkcs10, &pCertContext);
|
|
if (S_OK != hr)
|
|
{
|
|
if (CRYPT_E_NOT_FOUND == hr)
|
|
{
|
|
//freeRequestInfo could be called when cert is not issued
|
|
//PKCS7 could be CMC which is signed by request key and
|
|
//cert is not in local store yet. We try cached cert
|
|
if (NULL != m_pCertContextPendingRequest)
|
|
{
|
|
//looks we still have cached request cert handle
|
|
pCertContext = CertDuplicateCertificateContext(
|
|
m_pCertContextPendingRequest);
|
|
if (NULL == pCertContext)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertDuplicateCertificateContextError;
|
|
}
|
|
}
|
|
else if (NULL != m_hashBlobPendingRequest.pbData &&
|
|
0 < m_hashBlobPendingRequest.cbData)
|
|
{
|
|
//don't have cached request handle but thumbprint exists
|
|
//retrieve the request cert handle from store
|
|
pCertContext = CertFindCertificateInStore(
|
|
hStoreRequest, //request store
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_HASH,
|
|
&m_hashBlobPendingRequest,
|
|
NULL);
|
|
if (NULL == pCertContext)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertFindCertificateInStoreError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//sorry, don't know which cert to be free
|
|
//however, can try to find public key from PKCS7
|
|
goto PKCS7ToCertError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//other errors
|
|
goto PKCS7ToCertError;
|
|
}
|
|
}
|
|
break;
|
|
case CERT_QUERY_CONTENT_PKCS10:
|
|
if (S_OK != (hr = this->PKCS10ToCert(hStoreRequest, pkcs7OrPkcs10, &pCertContext)))
|
|
goto PKCS10ToCertError;
|
|
break;
|
|
default:
|
|
goto InvalidContentTypeError;
|
|
}
|
|
|
|
if (!CertDeleteCertificateFromStore(pCertContext))
|
|
{
|
|
// pCertContext is freed even when CertDeleteCertificateFromStore() returns an error.
|
|
pCertContext = NULL;
|
|
goto CertDeleteCertificateFromStoreError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
CommonReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); }
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CertDeleteCertificateFromStoreError, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(PKCS7ToCertError, hr);
|
|
SET_HRESULT(PKCS10ToCertError, hr);
|
|
SET_HRESULT(InvalidContentTypeError, E_INVALIDARG);
|
|
SET_HRESULT(MyCryptQueryObjectError, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(UnexpectedError, E_UNEXPECTED);
|
|
TRACE_ERROR(CertDuplicateCertificateContextError)
|
|
TRACE_ERROR(CertFindCertificateInStoreError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_SPCFileNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szw) {
|
|
HRESULT hr = S_OK;
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( (*szw = CopyWideString(m_wszSPCFileName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_SPCFileNameWStr(
|
|
/* [in] */ LPWSTR pwsz) {
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if(pwsz == NULL)
|
|
return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if( m_wszSPCFileName != wszEmpty)
|
|
MyCoTaskMemFree(m_wszSPCFileName);
|
|
if( (m_wszSPCFileName = CopyWideString(pwsz)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_PVKFileNameWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *szw) {
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if( (*szw = CopyWideString(m_wszPVKFileName)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_PVKFileNameWStr(
|
|
/* [in] */ LPWSTR pwsz) {
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if(pwsz == NULL)
|
|
return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if( m_wszPVKFileName != wszEmpty)
|
|
MyCoTaskMemFree(m_wszPVKFileName);
|
|
if( (m_wszPVKFileName = CopyWideString(pwsz)) == NULL )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
else
|
|
m_dwGenKeyFlags |= CRYPT_EXPORTABLE; //why???
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_HashAlgorithmWStr(
|
|
/* [out] */ LPWSTR __RPC_FAR *ppwsz) {
|
|
|
|
PCCRYPT_OID_INFO pOidInfo = NULL;
|
|
ALG_ID rgAlg[2];
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
assert(ppwsz != NULL);
|
|
*ppwsz = NULL;
|
|
|
|
if( !GetCapiHashAndSigAlgId(rgAlg) )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// Convert to an oid
|
|
else if( (NULL == (pOidInfo = xeCryptFindOIDInfo(
|
|
CRYPT_OID_INFO_ALGID_KEY,
|
|
(void *) &rgAlg[0],
|
|
CRYPT_HASH_ALG_OID_GROUP_ID)) ) ) {
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
else if( (*ppwsz = WideFromMB(pOidInfo->pszOID)) == NULL)
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_HashAlgorithmWStr(
|
|
/* [in] */ LPWSTR pwsz) {
|
|
|
|
HRESULT hr = S_OK;
|
|
char * szObjId = NULL;
|
|
PCCRYPT_OID_INFO pOidInfo = NULL;
|
|
|
|
if(pwsz == NULL) {
|
|
return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
|
|
}
|
|
|
|
if(!_wcsicmp(L"SHA1", pwsz))
|
|
szObjId = CopyAsciiString(szOID_OIWSEC_sha1);
|
|
else if(!_wcsicmp(L"MD5", pwsz))
|
|
szObjId = CopyAsciiString(szOID_RSA_MD5RSA);
|
|
else if(!_wcsicmp(L"MD2", pwsz))
|
|
szObjId = CopyAsciiString(szOID_RSA_MD2RSA);
|
|
else
|
|
szObjId = MBFromWide(pwsz);
|
|
|
|
// something went wrong
|
|
if(szObjId == NULL)
|
|
return(MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
|
|
// find the hashing algid
|
|
if( (NULL == (pOidInfo = xeCryptFindOIDInfo(
|
|
CRYPT_OID_INFO_OID_KEY,
|
|
szObjId,
|
|
0)) ) )
|
|
{
|
|
//XIAOHS: CryptFindOIDInfo does not set the LastError in this case.
|
|
//AV in xEnroll. See bug# 189320
|
|
//hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
hr=NTE_BAD_ALGID;
|
|
}
|
|
|
|
assert(szObjId != NULL);
|
|
MyCoTaskMemFree(szObjId);
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(hr == S_OK) {
|
|
if( pOidInfo->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID ||
|
|
pOidInfo->dwGroupId == CRYPT_SIGN_ALG_OID_GROUP_ID )
|
|
m_HashAlgId = pOidInfo->Algid;
|
|
else
|
|
hr = CRYPT_E_NOT_FOUND;
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_HashAlgID(
|
|
LONG hashAlgID
|
|
) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_HashAlgId = hashAlgID;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_HashAlgID(
|
|
LONG * hashAlgID
|
|
) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*hashAlgID = m_HashAlgId;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_RenewalCertificate(
|
|
/* [out] */ PCCERT_CONTEXT __RPC_FAR *ppCertContext) {
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
*ppCertContext = NULL;
|
|
|
|
if( m_pCertContextRenewal == NULL)
|
|
return(MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
if( NULL == (*ppCertContext = CertDuplicateCertificateContext(m_pCertContextRenewal)) )
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_RenewalCertificate(
|
|
/* [in] */ PCCERT_CONTEXT pCertContext)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pGoodCertContext= NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
hr = GetGoodCertContext(pCertContext, &pGoodCertContext);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetGoodCertContextError;
|
|
}
|
|
|
|
if(m_pCertContextRenewal != NULL)
|
|
{
|
|
CertFreeCertificateContext(m_pCertContextRenewal);
|
|
}
|
|
m_pCertContextRenewal = pGoodCertContext;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return hr;
|
|
|
|
TRACE_ERROR(GetGoodCertContextError);
|
|
}
|
|
|
|
BOOL
|
|
CCEnroll::CopyAndPushStackExtension(
|
|
PCERT_EXTENSION pExt,
|
|
BOOL fCMC)
|
|
{
|
|
|
|
DWORD cb = 0;
|
|
DWORD cbOid = 0;
|
|
PEXT_STACK pExtStackEle = NULL;
|
|
PBYTE pb = NULL;
|
|
PEXT_STACK *ppExtStack = NULL;
|
|
DWORD *pcExtStack = NULL;
|
|
|
|
assert(pExt != NULL);
|
|
|
|
// allocate the space
|
|
cbOid = POINTERROUND((DWORD)strlen(pExt->pszObjId) + 1); //ia64 align
|
|
cb = sizeof(EXT_STACK) + cbOid + pExt->Value.cbData;
|
|
if(NULL == (pb = (PBYTE) malloc(cb))) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
// set my pointers
|
|
pExtStackEle = (PEXT_STACK) pb;
|
|
pb += sizeof(EXT_STACK);
|
|
pExtStackEle->ext.pszObjId = (LPSTR) pb;
|
|
pb += cbOid;
|
|
pExtStackEle->ext.Value.pbData = pb;
|
|
|
|
// set the values
|
|
strcpy(pExtStackEle->ext.pszObjId, pExt->pszObjId);
|
|
pExtStackEle->ext.fCritical = pExt->fCritical;
|
|
pExtStackEle->ext.Value.cbData = pExt->Value.cbData;
|
|
memcpy(pExtStackEle->ext.Value.pbData, pExt->Value.pbData, pExt->Value.cbData);
|
|
|
|
// insert on the list
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
ppExtStack = fCMC ? &m_pExtStackNew : &m_pExtStack;
|
|
pcExtStack = fCMC ? &m_cExtStackNew : &m_cExtStack;
|
|
pExtStackEle->pNext = *ppExtStack;
|
|
*ppExtStack = pExtStackEle;
|
|
(*pcExtStack)++;
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
PCERT_EXTENSION
|
|
CCEnroll::PopStackExtension(
|
|
BOOL fCMC)
|
|
{
|
|
|
|
PEXT_STACK pExtStackEle = NULL;
|
|
PEXT_STACK *ppExtStack = NULL;
|
|
DWORD *pcExtStack = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
ppExtStack = fCMC ? &m_pExtStackNew : &m_pExtStack;
|
|
if(NULL != *ppExtStack)
|
|
{
|
|
pExtStackEle = *ppExtStack;
|
|
*ppExtStack = (*ppExtStack)->pNext;
|
|
pcExtStack = fCMC ? &m_cExtStackNew : &m_cExtStack;
|
|
(*pcExtStack)--;
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return((PCERT_EXTENSION) pExtStackEle);
|
|
}
|
|
|
|
DWORD
|
|
CCEnroll::CountStackExtension(BOOL fCMC)
|
|
{
|
|
DWORD cExt = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
cExt = fCMC ? m_cExtStackNew : m_cExtStack;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(cExt);
|
|
}
|
|
|
|
PCERT_EXTENSION
|
|
CCEnroll::EnumStackExtension(
|
|
PCERT_EXTENSION pExtLast,
|
|
BOOL fCMC)
|
|
{
|
|
PEXT_STACK pExtStackEle = (PEXT_STACK)pExtLast;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(NULL == pExtStackEle)
|
|
{
|
|
pExtStackEle = fCMC ? m_pExtStackNew : m_pExtStack;
|
|
}
|
|
else
|
|
{
|
|
pExtStackEle = pExtStackEle->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return((PCERT_EXTENSION) pExtStackEle);
|
|
}
|
|
|
|
void
|
|
CCEnroll::FreeAllStackExtension(void)
|
|
{
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
//free cmc extensions
|
|
while(0 != m_cExtStackNew)
|
|
{
|
|
FreeStackExtension(PopStackExtension(TRUE));
|
|
}
|
|
|
|
//free old client extensions
|
|
while(0 != m_cExtStack)
|
|
{
|
|
FreeStackExtension(PopStackExtension(FALSE));
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
}
|
|
|
|
void CCEnroll::FreeStackExtension(PCERT_EXTENSION pExt) {
|
|
if(pExt != NULL)
|
|
free(pExt);
|
|
}
|
|
|
|
//obselete call for new client
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::AddExtensionsToRequest(
|
|
/* [in] */ PCERT_EXTENSIONS pCertExtensions)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD i = 0;
|
|
|
|
assert(pCertExtensions != NULL);
|
|
|
|
for(i = 0; i < pCertExtensions->cExtension; i++)
|
|
{
|
|
//push into old extension stack
|
|
if(!CopyAndPushStackExtension(&pCertExtensions->rgExtension[i], FALSE))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
BOOL
|
|
CCEnroll::CopyAndPushStackAttribute(
|
|
PCRYPT_ATTRIBUTE pAttr,
|
|
BOOL fCMC)
|
|
{
|
|
DWORD i = 0;
|
|
DWORD cb = 0;
|
|
DWORD cbOid = 0;
|
|
PATTR_STACK pAttrStackEle = NULL;
|
|
PBYTE pb = NULL;
|
|
PATTR_STACK *ppAttrStack = NULL;
|
|
DWORD *pcAttrStack = NULL;
|
|
|
|
assert(pAttr != NULL);
|
|
|
|
// allocate the space
|
|
cb = sizeof(ATTR_STACK);
|
|
//make sure aligned for ia64
|
|
cbOid = POINTERROUND((DWORD)strlen(pAttr->pszObjId) + 1);
|
|
cb += cbOid;
|
|
cb += sizeof(CRYPT_ATTR_BLOB) * pAttr->cValue;
|
|
for(i=0; i<pAttr->cValue; i++)
|
|
cb += POINTERROUND(pAttr->rgValue[i].cbData); //pointer align
|
|
|
|
if(NULL == (pb = (PBYTE) malloc(cb))) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return(FALSE);
|
|
}
|
|
|
|
// set my pointers
|
|
pAttrStackEle = (PATTR_STACK) pb;
|
|
pb += sizeof(ATTR_STACK);
|
|
pAttrStackEle->attr.pszObjId = (LPSTR) pb;
|
|
pb += cbOid;
|
|
strcpy(pAttrStackEle->attr.pszObjId, pAttr->pszObjId);
|
|
|
|
pAttrStackEle->attr.cValue = pAttr->cValue;
|
|
pAttrStackEle->attr.rgValue = (PCRYPT_ATTR_BLOB) pb;
|
|
pb += sizeof(CRYPT_ATTR_BLOB) * pAttr->cValue;
|
|
for(i=0; i<pAttr->cValue; i++) {
|
|
pAttrStackEle->attr.rgValue[i].pbData = pb;
|
|
pAttrStackEle->attr.rgValue[i].cbData = pAttr->rgValue[i].cbData;
|
|
memcpy(pAttrStackEle->attr.rgValue[i].pbData, pAttr->rgValue[i].pbData, pAttr->rgValue[i].cbData);
|
|
pb += POINTERROUND(pAttr->rgValue[i].cbData);
|
|
}
|
|
assert( pb == ((BYTE *) pAttrStackEle) + cb );
|
|
|
|
// insert on the list
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
ppAttrStack = fCMC ? &m_pAttrStackNew : &m_pAttrStack;
|
|
pcAttrStack = fCMC ? &m_cAttrStackNew : &m_cAttrStack;
|
|
pAttrStackEle->pNext = *ppAttrStack;
|
|
*ppAttrStack = pAttrStackEle;
|
|
(*pcAttrStack)++;
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
PCRYPT_ATTRIBUTE
|
|
CCEnroll::PopStackAttribute(BOOL fCMC)
|
|
{
|
|
PATTR_STACK pAttrStackEle = NULL;
|
|
PATTR_STACK *ppAttrStack = NULL;
|
|
DWORD *pcAttrStack = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
ppAttrStack = fCMC ? &m_pAttrStackNew : &m_pAttrStack;
|
|
|
|
if(NULL != *ppAttrStack)
|
|
{
|
|
pAttrStackEle = *ppAttrStack;
|
|
*ppAttrStack = (*ppAttrStack)->pNext;
|
|
pcAttrStack = fCMC ? &m_cAttrStackNew : &m_cAttrStack;
|
|
(*pcAttrStack)--;
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return((PCRYPT_ATTRIBUTE) pAttrStackEle);
|
|
}
|
|
|
|
DWORD
|
|
CCEnroll::CountStackAttribute(BOOL fCMC)
|
|
{
|
|
DWORD cAttr = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
cAttr = fCMC ? m_cAttrStackNew : m_cAttrStack;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(cAttr);
|
|
}
|
|
|
|
PCRYPT_ATTRIBUTE
|
|
CCEnroll::EnumStackAttribute(
|
|
PCRYPT_ATTRIBUTE pAttrLast,
|
|
BOOL fCMC)
|
|
{
|
|
PATTR_STACK pAttrStackEle = (PATTR_STACK) pAttrLast;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(NULL == pAttrLast)
|
|
{
|
|
pAttrStackEle = fCMC ? m_pAttrStackNew : m_pAttrStack;
|
|
}
|
|
else
|
|
{
|
|
pAttrStackEle = pAttrStackEle->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return((PCRYPT_ATTRIBUTE) pAttrStackEle);
|
|
}
|
|
|
|
void CCEnroll::FreeAllStackAttribute(void)
|
|
{
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
while(0 != m_cAttrStackNew)
|
|
{
|
|
FreeStackAttribute(PopStackAttribute(TRUE));
|
|
}
|
|
|
|
while(0 != m_cAttrStack)
|
|
{
|
|
FreeStackAttribute(PopStackAttribute(FALSE));
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
}
|
|
|
|
void CCEnroll::FreeStackAttribute(PCRYPT_ATTRIBUTE pAttr) {
|
|
if(pAttr != NULL)
|
|
free(pAttr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::AddAuthenticatedAttributesToPKCS7Request(
|
|
/* [in] */ PCRYPT_ATTRIBUTES pAttributes)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD i;
|
|
|
|
for(i = 0; i < pAttributes->cAttr; i++)
|
|
{
|
|
if(!CopyAndPushStackAttribute(&pAttributes->rgAttr[i], FALSE))
|
|
{
|
|
hr = (MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
break;
|
|
}
|
|
//put into cmc stack too
|
|
if(!CopyAndPushStackAttribute(&pAttributes->rgAttr[i], TRUE))
|
|
{
|
|
hr = (MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::CreatePKCS7RequestFromRequest(
|
|
/* [in] */ PCRYPT_DATA_BLOB pRequest,
|
|
/* [in] */ PCCERT_CONTEXT pSigningRACertContext,
|
|
/* [out] */ PCRYPT_DATA_BLOB pPkcs7Blob) {
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD errBefore = GetLastError();
|
|
CRYPT_SIGN_MESSAGE_PARA signMsgPara;
|
|
PCCRYPT_OID_INFO pOidInfo = NULL;
|
|
PCRYPT_ATTRIBUTE pAttrCur = NULL;
|
|
DWORD i;
|
|
ALG_ID rgAlg[2];
|
|
CRYPT_KEY_PROV_INFO *pKeyProvInfo = NULL;
|
|
DWORD cb = 0;
|
|
|
|
assert(pSigningRACertContext != NULL);
|
|
assert(pRequest != NULL);
|
|
assert(pPkcs7Blob != NULL);
|
|
|
|
memset(&signMsgPara, 0, sizeof(CRYPT_SIGN_MESSAGE_PARA));
|
|
memset(pPkcs7Blob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
if( !GetCapiHashAndSigAlgId(rgAlg) )
|
|
goto ErrorGetCapiHashAndSigAlgId;
|
|
|
|
// find out what the oid is
|
|
if( (NULL == (pOidInfo = xeCryptFindOIDInfo(
|
|
CRYPT_OID_INFO_ALGID_KEY,
|
|
(void *) &rgAlg[0],
|
|
CRYPT_HASH_ALG_OID_GROUP_ID)) ) )
|
|
{
|
|
SetLastError((DWORD)NTE_BAD_ALGID);
|
|
goto ErrorCryptFindOIDInfo;
|
|
}
|
|
|
|
// now add all of the user defined extensions
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
signMsgPara.cAuthAttr = CountStackAttribute(m_fNewRequestMethod);
|
|
|
|
signMsgPara.rgAuthAttr = (PCRYPT_ATTRIBUTE)LocalAlloc(LMEM_FIXED,
|
|
signMsgPara.cAuthAttr * sizeof(CRYPT_ATTRIBUTE));
|
|
if( NULL == signMsgPara.rgAuthAttr)
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
goto ErrorOutOfMemory;
|
|
}
|
|
|
|
i = 0;
|
|
pAttrCur = NULL;
|
|
while(NULL != (pAttrCur = EnumStackAttribute(pAttrCur, m_fNewRequestMethod)) ) {
|
|
signMsgPara.rgAuthAttr[i] = *pAttrCur;
|
|
i++;
|
|
}
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
signMsgPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
|
|
signMsgPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
|
|
signMsgPara.pSigningCert = pSigningRACertContext;
|
|
signMsgPara.HashAlgorithm.pszObjId = (char *) pOidInfo->pszOID;
|
|
signMsgPara.cMsgCert = 1;
|
|
signMsgPara.rgpMsgCert = &pSigningRACertContext;
|
|
|
|
//get key prov info
|
|
while (TRUE)
|
|
{
|
|
if(!CertGetCertificateContextProperty(
|
|
pSigningRACertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
pKeyProvInfo,
|
|
&cb))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertGetCertificateContextPropertyError;
|
|
}
|
|
if (NULL != pKeyProvInfo)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
pKeyProvInfo = (CRYPT_KEY_PROV_INFO*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pKeyProvInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto ErrorOutOfMemory;
|
|
}
|
|
}
|
|
if (0x0 != (pKeyProvInfo->dwFlags & CRYPT_SILENT))
|
|
{
|
|
//have to set silent through msg param
|
|
signMsgPara.dwFlags |= CRYPT_MESSAGE_SILENT_KEYSET_FLAG;
|
|
}
|
|
|
|
|
|
if( !CryptSignMessage(
|
|
&signMsgPara,
|
|
FALSE,
|
|
1,
|
|
(const BYTE **) &pRequest->pbData,
|
|
&pRequest->cbData ,
|
|
NULL,
|
|
&pPkcs7Blob->cbData) ||
|
|
(pPkcs7Blob->pbData = (BYTE *)
|
|
MyCoTaskMemAlloc(pPkcs7Blob->cbData)) == NULL ||
|
|
!CryptSignMessage(
|
|
&signMsgPara,
|
|
FALSE,
|
|
1,
|
|
(const BYTE **) &pRequest->pbData,
|
|
&pRequest->cbData ,
|
|
pPkcs7Blob->pbData,
|
|
&pPkcs7Blob->cbData) )
|
|
goto ErrorCryptSignMessage;
|
|
|
|
CommonReturn:
|
|
if (NULL != pKeyProvInfo)
|
|
{
|
|
LocalFree(pKeyProvInfo);
|
|
}
|
|
if (NULL != signMsgPara.rgAuthAttr)
|
|
{
|
|
LocalFree(signMsgPara.rgAuthAttr);
|
|
}
|
|
|
|
// don't know if we have an error or not
|
|
// but I do know the errBefore is set properly
|
|
SetLastError(errBefore);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
|
|
// on error return a NULL
|
|
if(pPkcs7Blob->pbData != NULL)
|
|
MyCoTaskMemFree(pPkcs7Blob->pbData);
|
|
memset(pPkcs7Blob, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorGetCapiHashAndSigAlgId);
|
|
TRACE_ERROR(ErrorCryptSignMessage);
|
|
TRACE_ERROR(ErrorCryptFindOIDInfo);
|
|
TRACE_ERROR(ErrorOutOfMemory);
|
|
TRACE_ERROR(CertGetCertificateContextPropertyError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::AddNameValuePairToSignatureWStr(
|
|
/* [in] */ LPWSTR pwszName,
|
|
/* [in] */ LPWSTR pwszValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
assert(pwszName != NULL && pwszValue != NULL);
|
|
|
|
CRYPT_ENROLLMENT_NAME_VALUE_PAIR nameValuePair = {pwszName, pwszValue};
|
|
CRYPT_ATTR_BLOB blobAttr;
|
|
CRYPT_ATTRIBUTE attr = {szOID_ENROLLMENT_NAME_VALUE_PAIR, 1, &blobAttr};
|
|
CRYPT_ATTRIBUTES attrs = {1, &attr};
|
|
|
|
memset(&blobAttr, 0, sizeof(CRYPT_ATTR_BLOB));
|
|
|
|
hr = xeEncodeNameValuePair(
|
|
&nameValuePair,
|
|
&blobAttr.pbData,
|
|
&blobAttr.cbData);
|
|
if (S_OK != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
hr = AddAuthenticatedAttributesToPKCS7Request(&attrs);
|
|
|
|
error:
|
|
if (NULL != blobAttr.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobAttr.pbData);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::AddCertTypeToRequestWStr(
|
|
LPWSTR szw) {
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD errBefore = GetLastError();
|
|
|
|
CERT_NAME_VALUE nameValue;
|
|
CERT_EXTENSION ext;
|
|
CERT_EXTENSIONS exts = {1, &ext};
|
|
|
|
memset(&ext, 0, sizeof(CERT_EXTENSION));
|
|
|
|
nameValue.dwValueType = CERT_RDN_BMP_STRING;
|
|
nameValue.Value.cbData = 0;
|
|
nameValue.Value.pbData = (PBYTE) szw;
|
|
|
|
ext.pszObjId = szOID_ENROLL_CERTTYPE_EXTENSION;
|
|
|
|
if( !CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
&nameValue,
|
|
NULL,
|
|
&ext.Value.cbData
|
|
) )
|
|
goto ErrorCryptEncodeObject;
|
|
|
|
ext.Value.pbData = (PBYTE)LocalAlloc(LMEM_FIXED, ext.Value.cbData);
|
|
if(NULL == ext.Value.pbData)
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
goto ErrorOutOfMemory;
|
|
}
|
|
|
|
if( !CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
&nameValue,
|
|
ext.Value.pbData,
|
|
&ext.Value.cbData
|
|
) )
|
|
goto ErrorCryptEncodeObject;
|
|
|
|
if(S_OK != AddExtensionsToRequest(&exts))
|
|
goto ErrorAddExtensionsToRequest;
|
|
|
|
//put cert template extension into CMC stack
|
|
if(!CopyAndPushStackExtension(&ext, TRUE))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CopyAndPushStackExtensionError;
|
|
}
|
|
|
|
CommonReturn:
|
|
if (NULL != ext.Value.pbData)
|
|
{
|
|
LocalFree(ext.Value.pbData);
|
|
}
|
|
|
|
// don't know if we have an error or not
|
|
// but I do know the errBefore is set properly
|
|
SetLastError(errBefore);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorCryptEncodeObject);
|
|
TRACE_ERROR(ErrorAddExtensionsToRequest);
|
|
TRACE_ERROR(ErrorOutOfMemory);
|
|
TRACE_ERROR(CopyAndPushStackExtensionError);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::AddCertTypeToRequestWStrEx(
|
|
IN LONG lType,
|
|
IN LPCWSTR pwszOIDOrName,
|
|
IN LONG lMajorVersion,
|
|
IN BOOL fMinorVersion,
|
|
IN LONG lMinorVersion)
|
|
{
|
|
HRESULT hr;
|
|
LPCSTR lpszStructType;
|
|
CERT_NAME_VALUE nameValue;
|
|
CERT_TEMPLATE_EXT Template;
|
|
VOID *pv;
|
|
CERT_EXTENSION ext; //free pbData
|
|
DWORD cb = 0;
|
|
CHAR *pszOID = NULL;
|
|
|
|
//init
|
|
ZeroMemory(&ext, sizeof(ext));
|
|
ext.fCritical = FALSE;
|
|
|
|
if (NULL == pwszOIDOrName)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
|
|
switch (lType)
|
|
{
|
|
case XECT_EXTENSION_V1:
|
|
ext.pszObjId = szOID_ENROLL_CERTTYPE_EXTENSION;
|
|
nameValue.dwValueType = CERT_RDN_BMP_STRING;
|
|
nameValue.Value.cbData = 0;
|
|
nameValue.Value.pbData = (BYTE*)pwszOIDOrName;
|
|
pv = (VOID*)&nameValue;
|
|
lpszStructType = X509_UNICODE_ANY_STRING;
|
|
break;
|
|
case XECT_EXTENSION_V2:
|
|
ext.pszObjId = szOID_CERTIFICATE_TEMPLATE;
|
|
//convert wsz OID to ansi
|
|
while (TRUE)
|
|
{
|
|
cb = WideCharToMultiByte(
|
|
GetACP(),
|
|
0,
|
|
pwszOIDOrName,
|
|
-1,
|
|
pszOID,
|
|
cb,
|
|
NULL,
|
|
NULL);
|
|
if (0 == cb)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto WideCharToMultiByteError;
|
|
}
|
|
if (NULL != pszOID)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pszOID = (CHAR*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pszOID)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
ZeroMemory(&Template, sizeof(Template));
|
|
Template.pszObjId = pszOID;
|
|
Template.dwMajorVersion = lMajorVersion;
|
|
Template.fMinorVersion = fMinorVersion;
|
|
Template.dwMinorVersion = lMinorVersion;
|
|
pv = (VOID*)&Template;
|
|
lpszStructType = X509_CERTIFICATE_TEMPLATE;
|
|
break;
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
break;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!CryptEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
lpszStructType,
|
|
pv,
|
|
ext.Value.pbData,
|
|
&ext.Value.cbData))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptEncodeObjectError;
|
|
}
|
|
if (NULL != ext.Value.pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
ext.Value.pbData = (BYTE*)LocalAlloc(LMEM_FIXED, ext.Value.cbData);
|
|
if (NULL == ext.Value.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
//put cert template extension into CMC stack
|
|
if(!CopyAndPushStackExtension(&ext, TRUE))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CopyAndPushStackExtensionError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pszOID)
|
|
{
|
|
LocalFree(pszOID);
|
|
}
|
|
if (NULL != ext.Value.pbData)
|
|
{
|
|
LocalFree(ext.Value.pbData);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(InvalidArgError)
|
|
TRACE_ERROR(CopyAndPushStackExtensionError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
TRACE_ERROR(CryptEncodeObjectError)
|
|
TRACE_ERROR(WideCharToMultiByteError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::getProviderTypeWStr(
|
|
IN LPCWSTR pwszProvName,
|
|
OUT LONG * plProvType)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i = 0;
|
|
DWORD cb;
|
|
DWORD dwProvType;
|
|
WCHAR *pwszEnumProvName = NULL;
|
|
|
|
if (NULL == pwszProvName)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
|
|
//init
|
|
*plProvType = -1;
|
|
|
|
while (TRUE)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
if (!CryptEnumProvidersU(
|
|
i,
|
|
NULL,
|
|
0,
|
|
&dwProvType,
|
|
pwszEnumProvName,
|
|
&cb))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
if (MY_HRESULT_FROM_WIN32(NTE_PROV_TYPE_ENTRY_BAD) == hr)
|
|
{
|
|
//skip bad one and goto next
|
|
assert(NULL == pwszEnumProvName);
|
|
break; //skip this one
|
|
}
|
|
//error
|
|
goto CryptEnumProvidersUError;
|
|
}
|
|
if (NULL != pwszEnumProvName)
|
|
{
|
|
//get the current csp name
|
|
break;
|
|
}
|
|
pwszEnumProvName = (WCHAR*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pwszEnumProvName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
if (NULL != pwszEnumProvName)
|
|
{
|
|
if (0 == _wcsicmp(pwszProvName, pwszEnumProvName))
|
|
{
|
|
//found matched name
|
|
*plProvType = (LONG)dwProvType;
|
|
break; //out of outer loop
|
|
}
|
|
}
|
|
//not mached, go to next one
|
|
++i;
|
|
if (NULL != pwszEnumProvName)
|
|
{
|
|
LocalFree(pwszEnumProvName);
|
|
pwszEnumProvName = NULL;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pwszEnumProvName)
|
|
{
|
|
LocalFree(pwszEnumProvName);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(InvalidArgError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
TRACE_ERROR(CryptEnumProvidersUError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::InstallPKCS7Blob(
|
|
/* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7)
|
|
{
|
|
return InstallPKCS7BlobEx(pBlobPKCS7, NULL);
|
|
}
|
|
|
|
HRESULT CCEnroll::InstallPKCS7BlobEx(
|
|
/* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7,
|
|
/* [out] */ LONG *plCertInstalled)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD errBefore = GetLastError();
|
|
HCERTSTORE hStoreMsg = NULL;
|
|
LPWSTR pwszTitle = NULL;
|
|
LPWSTR pwszNotSafeAccepting = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// Accepting a request is not safe for scripting: pop up a warning dialog if called from script
|
|
if (0 != m_dwEnabledSafteyOptions) {
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle);
|
|
if (S_OK != hr) {
|
|
SetLastError(hr);
|
|
goto xeLoadRCStringError;
|
|
}
|
|
|
|
hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_ACCEPTING_CERT, &pwszNotSafeAccepting);
|
|
if (S_OK != hr) {
|
|
SetLastError(hr);
|
|
goto xeLoadRCStringError;
|
|
}
|
|
|
|
if (IDYES != MessageBoxU(NULL, pwszNotSafeAccepting, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
SetLastError(hr);
|
|
goto CancelledError;
|
|
}
|
|
}
|
|
|
|
if( !MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
pBlobPKCS7,
|
|
(CERT_QUERY_CONTENT_FLAG_CERT |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
|
|
CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE |
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED) ,
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&hStoreMsg,
|
|
NULL,
|
|
NULL) )
|
|
goto ErrorCryptQueryObject;
|
|
|
|
hr = AddCertsToStores(hStoreMsg, plCertInstalled);
|
|
//don't treat cancel as error but return the err code
|
|
if (S_OK != hr && MY_HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
|
|
{
|
|
goto ErrorAddCertsToStores;
|
|
}
|
|
|
|
CommonReturn:
|
|
|
|
if(hStoreMsg != NULL)
|
|
CertCloseStore(hStoreMsg, 0);
|
|
if (NULL != pwszNotSafeAccepting)
|
|
LocalFree(pwszNotSafeAccepting);
|
|
if (NULL != pwszTitle)
|
|
LocalFree(pwszTitle);
|
|
|
|
// don't know if we have an error or not
|
|
// but I do know the errBefore is set properly
|
|
SetLastError(errBefore);
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorCryptQueryObject);
|
|
TRACE_ERROR(ErrorAddCertsToStores);
|
|
TRACE_ERROR(CancelledError);
|
|
TRACE_ERROR(xeLoadRCStringError);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::InstallPKCS7(
|
|
/* [in] */ BSTR wszPKCS7)
|
|
{
|
|
CRYPT_DATA_BLOB blobPKCS7;
|
|
|
|
assert(wszPKCS7 != NULL);
|
|
|
|
// just put into a blob
|
|
memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB));
|
|
blobPKCS7.cbData = SysStringByteLen(wszPKCS7);
|
|
blobPKCS7.pbData = (PBYTE) wszPKCS7;
|
|
|
|
// install the blob
|
|
return(InstallPKCS7Blob(&blobPKCS7));
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::InstallPKCS7Ex(
|
|
/* [in] */ BSTR wszPKCS7,
|
|
/* [out] */ LONG __RPC_FAR *plCertInstalled)
|
|
{
|
|
CRYPT_DATA_BLOB blobPKCS7;
|
|
|
|
assert(wszPKCS7 != NULL);
|
|
|
|
// just put into a blob
|
|
memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB));
|
|
blobPKCS7.cbData = SysStringByteLen(wszPKCS7);
|
|
blobPKCS7.pbData = (PBYTE) wszPKCS7;
|
|
|
|
// install the blob
|
|
return(InstallPKCS7BlobEx(&blobPKCS7, plCertInstalled));
|
|
}
|
|
|
|
|
|
// this is a scary routine. Put in for louis, use at your own risk.
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::Reset(void)
|
|
{
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
Destruct();
|
|
hr = Init();
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::GetSupportedKeySpec(
|
|
LONG __RPC_FAR *pdwKeySpec) {
|
|
|
|
DWORD errBefore = GetLastError();
|
|
DWORD hr = S_OK;
|
|
DWORD cb = sizeof(DWORD);
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
assert(pdwKeySpec != NULL);
|
|
*pdwKeySpec = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
hr = GetVerifyProv();
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetVerifyProvError;
|
|
}
|
|
|
|
if( !CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
PP_KEYSPEC,
|
|
(BYTE *) pdwKeySpec,
|
|
&cb,
|
|
0
|
|
) )
|
|
goto ErrorCryptGetProvParam;
|
|
|
|
CommonReturn:
|
|
|
|
SetLastError(errBefore);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorCryptGetProvParam);
|
|
TRACE_ERROR(GetVerifyProvError);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::GetKeyLenEx(
|
|
LONG lSizeSpec,
|
|
LONG lKeySpec,
|
|
LONG __RPC_FAR *pdwKeySize)
|
|
{
|
|
BOOL fKeyX;
|
|
BOOL fKeyInc = FALSE;
|
|
DWORD dwKeySize = 0xFFFFFFFF;
|
|
DWORD cb;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
switch (lKeySpec)
|
|
{
|
|
case XEKL_KEYSPEC_KEYX:
|
|
fKeyX = TRUE;
|
|
break;
|
|
case XEKL_KEYSPEC_SIG:
|
|
fKeyX = FALSE;
|
|
break;
|
|
default:
|
|
//invalid parameter
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
|
|
switch (lSizeSpec)
|
|
{
|
|
case XEKL_KEYSIZE_MIN:
|
|
case XEKL_KEYSIZE_MAX:
|
|
case XEKL_KEYSIZE_DEFAULT:
|
|
break;
|
|
case XEKL_KEYSIZE_INC:
|
|
fKeyInc = TRUE;
|
|
break;
|
|
default:
|
|
//invalid parameter
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
|
|
if (!fKeyInc)
|
|
{
|
|
DWORD dwAlg = (fKeyX ? ALG_CLASS_KEY_EXCHANGE : ALG_CLASS_SIGNATURE);
|
|
|
|
*pdwKeySize = GetKeySizeInfo(lSizeSpec, dwAlg);
|
|
|
|
if(0xFFFFFFFF == *pdwKeySize)
|
|
{
|
|
*pdwKeySize = 0;
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetKeySizeInfoError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((fKeyX && (0 != m_dwXhgKeyLenInc)) ||
|
|
(!fKeyX && (0 != m_dwSigKeyLenInc)))
|
|
{
|
|
//we got the cached inc size
|
|
if (fKeyX)
|
|
{
|
|
*pdwKeySize = m_dwXhgKeyLenInc;
|
|
}
|
|
else
|
|
{
|
|
*pdwKeySize = m_dwSigKeyLenInc;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = GetVerifyProv();
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetVerifyProvError;
|
|
}
|
|
|
|
//init
|
|
*pdwKeySize = 0;
|
|
cb = sizeof(dwKeySize);
|
|
if (!CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
fKeyX ? PP_KEYX_KEYSIZE_INC : PP_SIG_KEYSIZE_INC,
|
|
(BYTE*)&dwKeySize,
|
|
&cb,
|
|
0))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptGetProvParamError;
|
|
}
|
|
else
|
|
{
|
|
*pdwKeySize = dwKeySize;
|
|
//cache it
|
|
if (fKeyX)
|
|
{
|
|
m_dwXhgKeyLenInc = dwKeySize;
|
|
}
|
|
else
|
|
{
|
|
m_dwSigKeyLenInc = dwKeySize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
TRACE_ERROR(GetVerifyProvError);
|
|
TRACE_ERROR(CryptGetProvParamError)
|
|
TRACE_ERROR(InvalidArgError)
|
|
TRACE_ERROR(GetKeySizeInfoError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::GetKeyLen(
|
|
BOOL fMin,
|
|
BOOL fExchange,
|
|
LONG __RPC_FAR *pdwKeySize) {
|
|
|
|
DWORD hr = S_OK;
|
|
LONG lKeySizeSpec = (fMin ? XEKL_KEYSIZE_MIN : XEKL_KEYSIZE_MAX);
|
|
|
|
if(fExchange)
|
|
*pdwKeySize = GetKeySizeInfo(lKeySizeSpec, ALG_CLASS_KEY_EXCHANGE);
|
|
else
|
|
*pdwKeySize = GetKeySizeInfo(lKeySizeSpec, ALG_CLASS_SIGNATURE);
|
|
|
|
if(*pdwKeySize == 0xFFFFFFFF) {
|
|
*pdwKeySize = 0;
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
DWORD CCEnroll::GetKeySizeInfo(
|
|
LONG lKeySizeSpec,
|
|
DWORD algClass) {
|
|
|
|
DWORD cb = sizeof(PROV_ENUMALGS_EX);
|
|
HRESULT hr = S_OK;
|
|
DWORD errBefore = GetLastError();
|
|
DWORD dwFlags = CRYPT_FIRST;
|
|
PROV_ENUMALGS_EX algInfo;
|
|
DWORD dwKeySize = 0xFFFFFFFF;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
#ifdef DBG
|
|
//only accept two flags
|
|
assert(ALG_CLASS_KEY_EXCHANGE == algClass ||
|
|
ALG_CLASS_SIGNATURE == algClass);
|
|
#endif //DBG
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
memset(&algInfo, 0, sizeof(algInfo));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if ((ALG_CLASS_KEY_EXCHANGE == algClass && 0 != m_dwXhgKeyLenMax) ||
|
|
(ALG_CLASS_SIGNATURE == algClass && 0 != m_dwSigKeyLenMax))
|
|
{
|
|
//got cached sizes, use only KeyLenMax as check
|
|
#if DBG
|
|
if (ALG_CLASS_KEY_EXCHANGE == algClass)
|
|
{
|
|
assert(0 != m_dwXhgKeyLenMin);
|
|
assert(0 != m_dwXhgKeyLenDef);
|
|
}
|
|
if (ALG_CLASS_SIGNATURE == algClass)
|
|
{
|
|
assert(0 != m_dwSigKeyLenMin);
|
|
assert(0 != m_dwSigKeyLenDef);
|
|
}
|
|
#endif //DBG
|
|
//OK, cached, easy
|
|
}
|
|
else
|
|
{
|
|
#if DBG
|
|
if (ALG_CLASS_KEY_EXCHANGE == algClass)
|
|
{
|
|
assert(0 == m_dwXhgKeyLenMin);
|
|
assert(0 == m_dwXhgKeyLenDef);
|
|
}
|
|
if (ALG_CLASS_SIGNATURE == algClass)
|
|
{
|
|
assert(0 == m_dwSigKeyLenMin);
|
|
assert(0 == m_dwSigKeyLenDef);
|
|
}
|
|
#endif //DBG
|
|
hr = GetVerifyProv();
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetVerifyProvError;
|
|
}
|
|
|
|
while (CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
PP_ENUMALGS_EX,
|
|
(BYTE *) &algInfo,
|
|
&cb,
|
|
dwFlags))
|
|
{
|
|
// get rid of CRYPT_FIRST flag
|
|
dwFlags = 0;
|
|
|
|
if (ALG_CLASS_KEY_EXCHANGE == GET_ALG_CLASS(algInfo.aiAlgid))
|
|
{
|
|
//cache them
|
|
m_dwXhgKeyLenMax = algInfo.dwMaxLen;
|
|
m_dwXhgKeyLenMin = algInfo.dwMinLen;
|
|
m_dwXhgKeyLenDef = algInfo.dwDefaultLen;
|
|
}
|
|
else if (ALG_CLASS_SIGNATURE == GET_ALG_CLASS(algInfo.aiAlgid))
|
|
{
|
|
m_dwSigKeyLenMax = algInfo.dwMaxLen;
|
|
m_dwSigKeyLenMin = algInfo.dwMinLen;
|
|
m_dwSigKeyLenDef = algInfo.dwDefaultLen;
|
|
}
|
|
|
|
//see if we cache all sizes through single enum loop
|
|
if (0 != m_dwXhgKeyLenMax &&
|
|
0 != m_dwXhgKeyLenMin &&
|
|
0 != m_dwXhgKeyLenDef &&
|
|
0 != m_dwSigKeyLenMax &&
|
|
0 != m_dwSigKeyLenMin &&
|
|
0 != m_dwSigKeyLenDef)
|
|
{
|
|
//looks we cached all
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we got here,
|
|
// either PP_ENUMALGS_EX is not supported by CSP , should return error
|
|
// or csp doesn't support specified algorithm, should ERROR_NO_MORE_ITEMS
|
|
|
|
err = GetLastError();
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
if (err != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
goto ErrorCryptGetProvParam;
|
|
}
|
|
// should be ERROR_NO_MORE_ITEMS
|
|
if ((ALG_CLASS_KEY_EXCHANGE == algClass && 0 != m_dwXhgKeyLenMax) ||
|
|
(ALG_CLASS_SIGNATURE == algClass && 0 != m_dwSigKeyLenMax))
|
|
{
|
|
//we may get here because the csp is signature or exchange only
|
|
//so we cannot cache both once
|
|
SetLastError(ERROR_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
SetLastError((DWORD)NTE_BAD_ALGID);
|
|
}
|
|
}
|
|
|
|
//should have all sizes
|
|
if(XEKL_KEYSIZE_MIN == lKeySizeSpec)
|
|
{
|
|
if (ALG_CLASS_KEY_EXCHANGE == algClass)
|
|
{
|
|
dwKeySize = m_dwXhgKeyLenMin;
|
|
}
|
|
else
|
|
{
|
|
dwKeySize = m_dwSigKeyLenMin;
|
|
}
|
|
}
|
|
else if (XEKL_KEYSIZE_MAX == lKeySizeSpec)
|
|
{
|
|
if (ALG_CLASS_KEY_EXCHANGE == algClass)
|
|
{
|
|
dwKeySize = m_dwXhgKeyLenMax;
|
|
}
|
|
else
|
|
{
|
|
dwKeySize = m_dwSigKeyLenMax;
|
|
}
|
|
}
|
|
else if (XEKL_KEYSIZE_DEFAULT == lKeySizeSpec)
|
|
{
|
|
if (ALG_CLASS_KEY_EXCHANGE == algClass)
|
|
{
|
|
dwKeySize = m_dwXhgKeyLenDef;
|
|
}
|
|
else
|
|
{
|
|
dwKeySize = m_dwSigKeyLenDef;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
|
|
SetLastError(errBefore);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(dwKeySize);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(GetVerifyProvError);
|
|
TRACE_ERROR(ErrorCryptGetProvParam);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::EnumAlgs(
|
|
/* [in] */ LONG dwIndex,
|
|
/* [in] */ LONG algMask,
|
|
/* [out] */ LONG __RPC_FAR *pdwAlgID) {
|
|
|
|
DWORD errBefore = GetLastError();
|
|
PROV_ENUMALGS enumAlgs;
|
|
DWORD cb = sizeof(enumAlgs);
|
|
LONG i = 0;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwFlags;
|
|
BOOL f1st = TRUE;
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
memset(&enumAlgs, 0, sizeof(enumAlgs));
|
|
assert(pdwAlgID != NULL);
|
|
*pdwAlgID = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
hr = GetVerifyProv();
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetVerifyProvError;
|
|
}
|
|
|
|
if (MAXDWORD != m_dwLastAlgIndex &&
|
|
((DWORD)dwIndex) == m_dwLastAlgIndex + 1)
|
|
{
|
|
//continue enum
|
|
dwFlags = 0;
|
|
while (f1st || (DWORD)algMask != GET_ALG_CLASS(enumAlgs.aiAlgid))
|
|
{
|
|
if(!CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
PP_ENUMALGS,
|
|
(BYTE*)&enumAlgs,
|
|
&cb,
|
|
dwFlags))
|
|
{
|
|
goto ErrorCryptGetProvParam;
|
|
}
|
|
f1st = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwFlags = CRYPT_FIRST;
|
|
for (i = 0; i <= dwIndex; i++)
|
|
{
|
|
if(!CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
PP_ENUMALGS,
|
|
(BYTE*)&enumAlgs,
|
|
&cb,
|
|
dwFlags))
|
|
{
|
|
goto ErrorCryptGetProvParam;
|
|
}
|
|
dwFlags = 0;
|
|
|
|
// if we have not hit something we are counting, do it again
|
|
if ((DWORD)algMask != GET_ALG_CLASS(enumAlgs.aiAlgid))
|
|
{
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
//update cached index
|
|
m_dwLastAlgIndex = dwIndex;
|
|
|
|
*pdwAlgID = enumAlgs.aiAlgid;
|
|
|
|
CommonReturn:
|
|
SetLastError(errBefore);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
//error, reset index
|
|
m_dwLastAlgIndex = MAXDWORD;
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(GetVerifyProvError);
|
|
TRACE_ERROR(ErrorCryptGetProvParam);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::GetAlgNameWStr(
|
|
/* [in] */ LONG algID,
|
|
/* [out] */ LPWSTR __RPC_FAR *ppwsz) {
|
|
|
|
DWORD errBefore = GetLastError();
|
|
PROV_ENUMALGS enumAlgs;
|
|
DWORD cb = sizeof(enumAlgs);
|
|
HRESULT hr = S_OK;
|
|
DWORD dwFlags = CRYPT_FIRST;
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
memset(&enumAlgs, 0, sizeof(enumAlgs));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
hr = GetVerifyProv();
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetVerifyProvError;
|
|
}
|
|
|
|
do {
|
|
|
|
if( !CryptGetProvParam(
|
|
m_hVerifyProv,
|
|
PP_ENUMALGS,
|
|
(BYTE *) &enumAlgs,
|
|
&cb,
|
|
dwFlags) )
|
|
goto ErrorCryptGetProvParam;
|
|
|
|
dwFlags = 0;
|
|
|
|
} while((DWORD)algID != enumAlgs.aiAlgid);
|
|
|
|
if( (*ppwsz = WideFromMB(enumAlgs.szName)) == NULL )
|
|
goto ErrorOutOfMem;
|
|
|
|
CommonReturn:
|
|
|
|
SetLastError(errBefore);
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(GetVerifyProvError);
|
|
TRACE_ERROR(ErrorCryptGetProvParam);
|
|
TRACE_ERROR(ErrorOutOfMem);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::GetAlgName(
|
|
/* [in] */ LONG algID,
|
|
/* [out][retval] */ BSTR __RPC_FAR *pbstr) {
|
|
|
|
DWORD errBefore = GetLastError();
|
|
LPWSTR pwsz = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
assert(pbstr != NULL);
|
|
|
|
if((hr = GetAlgNameWStr(algID, &pwsz)) != S_OK)
|
|
goto ErrorgetAlgNameWStr;
|
|
|
|
if( (*pbstr = SysAllocString(pwsz)) == NULL )
|
|
goto ErrorSysAllocString;
|
|
|
|
CommonReturn:
|
|
|
|
if(pwsz != NULL)
|
|
MyCoTaskMemFree(pwsz);
|
|
|
|
SetLastError(errBefore);
|
|
return(hr);
|
|
|
|
ErrorReturn:
|
|
|
|
if(GetLastError() == ERROR_SUCCESS)
|
|
SetLastError((DWORD)E_UNEXPECTED);
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
// We have an error, make sure we set it.
|
|
errBefore = GetLastError();
|
|
|
|
goto CommonReturn;
|
|
|
|
TRACE_ERROR(ErrorgetAlgNameWStr);
|
|
TRACE_ERROR(ErrorSysAllocString);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_ReuseHardwareKeyIfUnableToGenNew(
|
|
/* [retval][out] */ BOOL __RPC_FAR *fBool) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fBool = m_fReuseHardwareKeyIfUnableToGenNew;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_ReuseHardwareKeyIfUnableToGenNew(
|
|
/* [in] */ BOOL fBool) {
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fReuseHardwareKeyIfUnableToGenNew = fBool;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreMy(
|
|
HCERTSTORE hStore
|
|
) {
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_MyStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
|
|
else {
|
|
if(m_MyStore.wszName != wszMY)
|
|
MyCoTaskMemFree(m_MyStore.wszName);
|
|
|
|
m_MyStore.wszName = NULL;
|
|
m_MyStore.hStore = CertDuplicateStore(hStore);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreCA(
|
|
HCERTSTORE hStore
|
|
) {
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_CAStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_CAStore.wszName != wszCA)
|
|
MyCoTaskMemFree(m_CAStore.wszName);
|
|
|
|
m_CAStore.wszName = NULL;
|
|
m_CAStore.hStore = CertDuplicateStore(hStore);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreROOT(
|
|
HCERTSTORE hStore
|
|
) {
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_RootStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_RootStore.wszName != wszROOT && m_RootStore.wszName != wszCA)
|
|
MyCoTaskMemFree(m_RootStore.wszName);
|
|
|
|
m_RootStore.wszName = NULL;
|
|
m_RootStore.hStore = CertDuplicateStore(hStore);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreRequest(
|
|
HCERTSTORE hStore
|
|
) {
|
|
HRESULT hr = S_OK;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(m_RequestStore.hStore != NULL)
|
|
hr = E_ACCESSDENIED;
|
|
else {
|
|
if(m_RequestStore.wszName != wszREQUEST)
|
|
MyCoTaskMemFree(m_RequestStore.wszName);
|
|
|
|
m_RequestStore.wszName = NULL;
|
|
m_RequestStore.hStore = CertDuplicateStore(hStore);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_LimitExchangeKeyToEncipherment(
|
|
BOOL fBool
|
|
) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fLimitExchangeKeyToEncipherment = fBool;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_LimitExchangeKeyToEncipherment(
|
|
BOOL * fBool
|
|
) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fBool = m_fLimitExchangeKeyToEncipherment;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::put_EnableSMIMECapabilities(
|
|
BOOL fSMIME
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (m_fKeySpecSetByClient)
|
|
{
|
|
//SMIME is set by the client
|
|
if (AT_SIGNATURE == m_keyProvInfo.dwKeySpec && fSMIME)
|
|
{
|
|
//try to set signature key spec also SMIME
|
|
hr = XENROLL_E_KEYSPEC_SMIME_MISMATCH;
|
|
goto MismatchError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//user didn't set key spec
|
|
//determine the spec accordingly
|
|
m_keyProvInfo.dwKeySpec = fSMIME ? AT_KEYEXCHANGE : AT_SIGNATURE;
|
|
}
|
|
m_fEnableSMIMECapabilities = fSMIME;
|
|
m_fSMIMESetByClient = TRUE;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(hr);
|
|
|
|
TRACE_ERROR(MismatchError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::get_EnableSMIMECapabilities(
|
|
BOOL * fBool
|
|
) {
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
*fBool = m_fEnableSMIMECapabilities;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return(S_OK);
|
|
}
|
|
|
|
//ICEnroll4
|
|
|
|
HRESULT
|
|
GetCertificateContextFromBStr(
|
|
IN BSTR bstrCert,
|
|
OUT PCCERT_CONTEXT *ppCert)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
BYTE *pbCert = NULL;
|
|
DWORD cbCert = 0;
|
|
|
|
// could be any form, binary or base64
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryW(
|
|
(WCHAR*)bstrCert,
|
|
SysStringLen(bstrCert),
|
|
CRYPT_STRING_ANY,
|
|
pbCert,
|
|
&cbCert,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptStringToBinaryWError;
|
|
}
|
|
if (NULL != pbCert)
|
|
{
|
|
break; //done
|
|
}
|
|
pbCert = (BYTE*)LocalAlloc(LMEM_FIXED, cbCert);
|
|
if (NULL == pbCert)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
pCert = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
pbCert,
|
|
cbCert);
|
|
if (NULL == pCert)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertCreateCertificateContextError;
|
|
}
|
|
*ppCert = pCert;
|
|
pCert = NULL;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pbCert)
|
|
{
|
|
LocalFree(pbCert);
|
|
}
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
return (hr);
|
|
|
|
TRACE_ERROR(CertCreateCertificateContextError)
|
|
TRACE_ERROR(MyCryptStringToBinaryWError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::put_PrivateKeyArchiveCertificate(
|
|
IN BSTR bstrCert)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pPrivateKeyArchiveCert = NULL;
|
|
|
|
if (NULL != bstrCert)
|
|
{
|
|
hr = GetCertificateContextFromBStr(bstrCert, &pPrivateKeyArchiveCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetCertificateContextFromBStrError;
|
|
}
|
|
}
|
|
|
|
// set key archive certificate
|
|
hr = SetPrivateKeyArchiveCertificate(pPrivateKeyArchiveCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto SetPrivateKeyArchiveCertificateError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pPrivateKeyArchiveCert)
|
|
{
|
|
CertFreeCertificateContext(pPrivateKeyArchiveCert);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(GetCertificateContextFromBStrError)
|
|
TRACE_ERROR(SetPrivateKeyArchiveCertificateError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::get_PrivateKeyArchiveCertificate(
|
|
OUT BSTR __RPC_FAR *pbstrCert)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pPrivateKeyArchiveCert = NULL;
|
|
CRYPT_DATA_BLOB blobCert;
|
|
|
|
//init
|
|
*pbstrCert = NULL;
|
|
|
|
pPrivateKeyArchiveCert = GetPrivateKeyArchiveCertificate();
|
|
|
|
if (NULL != pPrivateKeyArchiveCert)
|
|
{
|
|
blobCert.pbData = pPrivateKeyArchiveCert->pbCertEncoded;
|
|
blobCert.cbData = pPrivateKeyArchiveCert->cbCertEncoded;
|
|
hr = BlobToBstring(&blobCert, CRYPT_STRING_BASE64HEADER, pbstrCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BlobToBstringError;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pPrivateKeyArchiveCert)
|
|
{
|
|
CertFreeCertificateContext(pPrivateKeyArchiveCert);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(BlobToBstringError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::put_ThumbPrint(IN BSTR bstrThumbPrint)
|
|
{
|
|
CRYPT_DATA_BLOB hashBlob;
|
|
HRESULT hr;
|
|
|
|
if (bstrThumbPrint == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
hashBlob.cbData = 0;
|
|
hashBlob.pbData = NULL;
|
|
|
|
if (!MyCryptStringToBinaryW
|
|
((WCHAR*)bstrThumbPrint,
|
|
SysStringLen(bstrThumbPrint),
|
|
CRYPT_STRING_BASE64,
|
|
hashBlob.pbData,
|
|
&hashBlob.cbData,
|
|
NULL,
|
|
NULL))
|
|
goto MyCryptToBinaryErr;
|
|
|
|
hashBlob.pbData = (LPBYTE)LocalAlloc(LPTR, hashBlob.cbData);
|
|
if (NULL == hashBlob.pbData)
|
|
goto MemoryErr;
|
|
|
|
if (!MyCryptStringToBinaryW
|
|
((WCHAR*)bstrThumbPrint,
|
|
SysStringLen(bstrThumbPrint),
|
|
CRYPT_STRING_BASE64,
|
|
hashBlob.pbData,
|
|
&hashBlob.cbData,
|
|
NULL,
|
|
NULL))
|
|
goto MyCryptToBinaryErr;
|
|
|
|
hr = this->put_ThumbPrintWStr(hashBlob);
|
|
|
|
ErrorReturn:
|
|
if (NULL != hashBlob.pbData) { LocalFree(hashBlob.pbData); }
|
|
return hr;
|
|
|
|
SET_HRESULT(MyCryptToBinaryErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::put_ThumbPrintWStr(IN CRYPT_DATA_BLOB hashBlob)
|
|
{
|
|
if (hashBlob.pbData == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
if (m_hashBlobPendingRequest.pbData != NULL)
|
|
{
|
|
LocalFree(m_hashBlobPendingRequest.pbData);
|
|
m_hashBlobPendingRequest.pbData = NULL;
|
|
}
|
|
|
|
m_hashBlobPendingRequest.cbData = hashBlob.cbData;
|
|
m_hashBlobPendingRequest.pbData = (LPBYTE)LocalAlloc(LPTR, m_hashBlobPendingRequest.cbData);
|
|
|
|
if (m_hashBlobPendingRequest.pbData == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
CopyMemory(m_hashBlobPendingRequest.pbData, hashBlob.pbData, hashBlob.cbData);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::get_ThumbPrint(OUT BSTR __RPC_FAR *pbstrThumbPrint)
|
|
{
|
|
CRYPT_DATA_BLOB hashBlob;
|
|
DWORD cchThumbPrintStr;
|
|
HRESULT hr;
|
|
WCHAR *pwszThumbPrint = NULL;
|
|
int i, n;
|
|
|
|
// Input validation:
|
|
if (pbstrThumbPrint == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
// Initialize locals:
|
|
ZeroMemory(&hashBlob, sizeof(hashBlob));
|
|
*pbstrThumbPrint = NULL;
|
|
|
|
if (S_OK != (hr = this->get_ThumbPrintWStr(&hashBlob)))
|
|
goto ErrorReturn;
|
|
|
|
hashBlob.pbData = (LPBYTE)LocalAlloc(LPTR, hashBlob.cbData);
|
|
if (NULL == hashBlob.pbData)
|
|
goto MemoryErr;
|
|
|
|
if (S_OK != (hr = this->get_ThumbPrintWStr(&hashBlob)))
|
|
goto ErrorReturn;
|
|
|
|
// Now we have a binary thumbprint. Convert this to base64:
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptBinaryToStringW(
|
|
hashBlob.pbData,
|
|
hashBlob.cbData,
|
|
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR,
|
|
pwszThumbPrint,
|
|
&cchThumbPrintStr))
|
|
{
|
|
goto MyCryptToStringErr;
|
|
}
|
|
if (NULL != pwszThumbPrint)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pwszThumbPrint = (WCHAR*)LocalAlloc(LMEM_FIXED,
|
|
cchThumbPrintStr * sizeof(WCHAR));
|
|
if (NULL == pwszThumbPrint)
|
|
{
|
|
goto MemoryErr;
|
|
}
|
|
}
|
|
|
|
//make sure no new line and CR
|
|
n = (int)wcslen(pwszThumbPrint);
|
|
for (i = n - 1; i > -1; --i)
|
|
{
|
|
if (L'\r' != pwszThumbPrint[i] &&
|
|
L'\n' != pwszThumbPrint[i])
|
|
{
|
|
break; //done
|
|
}
|
|
pwszThumbPrint[i] = L'\0'; //null it
|
|
}
|
|
|
|
// Ok, we've acquired the HASH. Now copy it to the out parameter:
|
|
*pbstrThumbPrint = SysAllocString(pwszThumbPrint);
|
|
if (NULL == *pbstrThumbPrint)
|
|
{
|
|
goto MemoryErr;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != hashBlob.pbData)
|
|
{
|
|
LocalFree(hashBlob.pbData);
|
|
}
|
|
if (NULL != pwszThumbPrint)
|
|
{
|
|
LocalFree(pwszThumbPrint);
|
|
}
|
|
return hr;
|
|
|
|
SET_HRESULT(MyCryptToStringErr, MY_HRESULT_FROM_WIN32(GetLastError()))
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::get_ThumbPrintWStr(IN OUT PCRYPT_DATA_BLOB pHashBlob) {
|
|
HRESULT hr = S_OK;
|
|
|
|
// Input validation:
|
|
if (NULL == pHashBlob)
|
|
return E_INVALIDARG;
|
|
|
|
// TWO CASES:
|
|
//
|
|
// 1) the thumbprint has been explicitly set by an external caller.
|
|
// 2) the thumbprint _wasn't_ explicitly set. In this case, use the thumbprint
|
|
// of the request generated by the last call to createPKCS10().
|
|
//
|
|
// CASE 1:
|
|
//
|
|
if (NULL != m_hashBlobPendingRequest.pbData)
|
|
{
|
|
if (NULL != pHashBlob->pbData)
|
|
{
|
|
if (pHashBlob->cbData < m_hashBlobPendingRequest.cbData) {
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
|
}
|
|
else {
|
|
CopyMemory(pHashBlob->pbData, m_hashBlobPendingRequest.pbData, m_hashBlobPendingRequest.cbData);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
pHashBlob->cbData = m_hashBlobPendingRequest.cbData;
|
|
return hr;
|
|
}
|
|
// CASE 2:
|
|
//
|
|
else
|
|
{
|
|
if (NULL == m_pCertContextPendingRequest)
|
|
return E_POINTER;
|
|
|
|
// Executes at most twice.
|
|
if (!CertGetCertificateContextProperty
|
|
(m_pCertContextPendingRequest,
|
|
CERT_HASH_PROP_ID,
|
|
(LPVOID)(pHashBlob->pbData),
|
|
&(pHashBlob->cbData)))
|
|
{
|
|
return MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::binaryToString(
|
|
IN LONG Flags,
|
|
IN BSTR strBinary,
|
|
OUT BSTR *pstrEncoded)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobBinary;
|
|
WCHAR *pwszEncoded = NULL;
|
|
|
|
blobBinary.pbData = (BYTE*)strBinary;
|
|
blobBinary.cbData = SysStringByteLen(strBinary);
|
|
|
|
hr = binaryBlobToString(Flags, &blobBinary, &pwszEncoded);
|
|
if (S_OK != hr)
|
|
{
|
|
goto binaryBlobToStringError;
|
|
}
|
|
|
|
*pstrEncoded = SysAllocString(pwszEncoded);
|
|
if (NULL == pstrEncoded)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto SysAllocStringLenError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pwszEncoded)
|
|
{
|
|
MyCoTaskMemFree(pwszEncoded);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(binaryBlobToStringError);
|
|
TRACE_ERROR(SysAllocStringLenError);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::stringToBinary(
|
|
IN LONG Flags,
|
|
IN BSTR strEncoded,
|
|
OUT BSTR *pstrBinary)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobBinary;
|
|
|
|
ZeroMemory(&blobBinary, sizeof(blobBinary));
|
|
|
|
hr = stringToBinaryBlob(Flags, (LPCWSTR)strEncoded, &blobBinary, NULL, NULL);
|
|
if (S_OK != hr)
|
|
{
|
|
goto stringToBinaryBlobError;
|
|
}
|
|
*pstrBinary = SysAllocStringLen(
|
|
(OLECHAR*)blobBinary.pbData, blobBinary.cbData);
|
|
if (NULL == *pstrBinary)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto SysAllocStringLenError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != blobBinary.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobBinary.pbData);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(stringToBinaryBlobError);
|
|
TRACE_ERROR(SysAllocStringLenError);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::addExtensionToRequest(
|
|
IN LONG Flags,
|
|
IN BSTR strName,
|
|
IN BSTR strValue)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobValue;
|
|
DWORD cchStrValue = SysStringLen(strValue);
|
|
BYTE *pbExtVal = NULL;
|
|
DWORD cbExtVal = 0;
|
|
|
|
//convert to binary in case base64 etc.
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryW(
|
|
(WCHAR*)strValue,
|
|
cchStrValue,
|
|
CRYPT_STRING_ANY,
|
|
pbExtVal,
|
|
&cbExtVal,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptStringToBinaryWError;
|
|
}
|
|
if (NULL != pbExtVal)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pbExtVal = (BYTE*)LocalAlloc(LMEM_FIXED, cbExtVal);
|
|
if (NULL == pbExtVal)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
}
|
|
|
|
blobValue.pbData = pbExtVal;
|
|
blobValue.cbData = cbExtVal;
|
|
|
|
hr = addExtensionToRequestWStr(Flags, strName, &blobValue);
|
|
if (S_OK != hr)
|
|
{
|
|
goto addExtensionToRequestWStrError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pbExtVal)
|
|
{
|
|
LocalFree(pbExtVal);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(MyCryptStringToBinaryWError)
|
|
TRACE_ERROR(LocalAllocError)
|
|
TRACE_ERROR(addExtensionToRequestWStrError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::addAttributeToRequest(
|
|
IN LONG Flags,
|
|
IN BSTR strName,
|
|
IN BSTR strValue)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobValue;
|
|
DWORD cchStrValue = SysStringLen(strValue);
|
|
BYTE *pbAttVal = NULL;
|
|
DWORD cbAttVal = 0;
|
|
|
|
//convert to binary in case base64 etc.
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryW(
|
|
(WCHAR*)strValue,
|
|
cchStrValue,
|
|
CRYPT_STRING_ANY,
|
|
pbAttVal,
|
|
&cbAttVal,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptStringToBinaryWError;
|
|
}
|
|
if (NULL != pbAttVal)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pbAttVal = (BYTE*)LocalAlloc(LMEM_FIXED, cbAttVal);
|
|
if (NULL == pbAttVal)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
}
|
|
|
|
blobValue.pbData = pbAttVal;
|
|
blobValue.cbData = cbAttVal;
|
|
|
|
hr = addAttributeToRequestWStr(Flags, strName, &blobValue);
|
|
if (S_OK != hr)
|
|
{
|
|
goto addAttributeToRequestWStrError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pbAttVal)
|
|
{
|
|
LocalFree(pbAttVal);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(MyCryptStringToBinaryWError)
|
|
TRACE_ERROR(LocalAllocError)
|
|
TRACE_ERROR(addAttributeToRequestWStrError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::addNameValuePairToRequest(
|
|
IN LONG Flags, //not used
|
|
IN BSTR strName,
|
|
IN BSTR strValue)
|
|
{
|
|
return addNameValuePairToRequestWStr(Flags, strName, strValue);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::addBlobPropertyToCertificate(
|
|
IN LONG lPropertyId,
|
|
IN LONG lFlags,
|
|
IN BSTR strProperty)
|
|
{
|
|
CRYPT_DATA_BLOB blob;
|
|
|
|
blob.pbData = (BYTE*)strProperty;
|
|
blob.cbData = SysStringByteLen(strProperty);
|
|
if (0x0 != (XECP_STRING_PROPERTY & lFlags))
|
|
{
|
|
//this is a string property, including null
|
|
blob.cbData += sizeof(WCHAR);
|
|
}
|
|
|
|
return addBlobPropertyToCertificateWStr(lPropertyId, lFlags, &blob);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::put_SignerCertificate(
|
|
IN BSTR bstrCert)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pSignerCert = NULL;
|
|
|
|
if (NULL != bstrCert)
|
|
{
|
|
hr = GetCertificateContextFromBStr(bstrCert, &pSignerCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetCertificateContextFromBStrError;
|
|
}
|
|
}
|
|
|
|
// set key archive certificate
|
|
hr = SetSignerCertificate(pSignerCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto SetSignerCertificateError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pSignerCert)
|
|
{
|
|
CertFreeCertificateContext(pSignerCert);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(GetCertificateContextFromBStrError)
|
|
TRACE_ERROR(SetSignerCertificateError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::resetExtensions()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
FreeAllStackExtension();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::resetAttributes()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
FreeAllStackAttribute();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createRequest(
|
|
IN LONG Flags,
|
|
IN BSTR strDNName,
|
|
IN BSTR strUsage,
|
|
OUT BSTR *pstrRequest)
|
|
{
|
|
return createRequestWStrBStr(
|
|
Flags,
|
|
(LPCWSTR)strDNName,
|
|
(LPCWSTR)strUsage,
|
|
CRYPT_STRING_BASE64REQUESTHEADER,
|
|
pstrRequest);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createFileRequest(
|
|
IN LONG Flags,
|
|
IN BSTR strDNName,
|
|
IN BSTR strUsage,
|
|
IN BSTR strRequestFileName)
|
|
{
|
|
return createFileRequestWStr(Flags, (LPCWSTR)strDNName, (LPCWSTR)strUsage, (LPCWSTR)strRequestFileName);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::acceptResponse(
|
|
IN BSTR bstrResponse)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobResponse;
|
|
DWORD cchStrResponse;
|
|
|
|
ZeroMemory(&blobResponse, sizeof(blobResponse));
|
|
|
|
if (NULL == bstrResponse)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
goto InvalidParameterError;
|
|
}
|
|
|
|
//assume a string
|
|
cchStrResponse = SysStringLen(bstrResponse);
|
|
|
|
//convert to binary in case base64 etc.
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryW(
|
|
(WCHAR*)bstrResponse,
|
|
cchStrResponse,
|
|
CRYPT_STRING_ANY,
|
|
blobResponse.pbData,
|
|
&blobResponse.cbData,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptStringToBinaryWError;
|
|
}
|
|
if (NULL != blobResponse.pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
blobResponse.pbData = (BYTE*)LocalAlloc(
|
|
LMEM_FIXED, blobResponse.cbData);
|
|
if (NULL == blobResponse.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
}
|
|
|
|
// accept the blob
|
|
hr = acceptResponseBlob(&blobResponse);
|
|
if (S_OK != hr)
|
|
{
|
|
goto acceptResponseBlobError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != blobResponse.pbData)
|
|
{
|
|
LocalFree(blobResponse.pbData);
|
|
}
|
|
return (hr);
|
|
|
|
TRACE_ERROR(acceptResponseBlobError)
|
|
TRACE_ERROR(InvalidParameterError)
|
|
TRACE_ERROR(MyCryptStringToBinaryWError)
|
|
TRACE_ERROR(LocalAllocError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::acceptFileResponse(
|
|
IN BSTR bstrResponseFileName)
|
|
{
|
|
return acceptFileResponseWStr((LPCWSTR)bstrResponseFileName);
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::GetCertFromResponseBlobToBStr(
|
|
IN CRYPT_DATA_BLOB *pBlobResponse,
|
|
OUT BSTR *pstrCert)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobCert;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
|
|
hr = getCertContextFromResponseBlob(
|
|
pBlobResponse,
|
|
&pCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto getCertContextFromResponseBlobError;
|
|
}
|
|
|
|
assert(NULL != pCert);
|
|
|
|
blobCert.pbData = pCert->pbCertEncoded;
|
|
blobCert.cbData = pCert->cbCertEncoded;
|
|
hr = BlobToBstring(&blobCert, CRYPT_STRING_BASE64HEADER, pstrCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BlobToBstringError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(getCertContextFromResponseBlobError)
|
|
TRACE_ERROR(BlobToBstringError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::getCertFromResponse(
|
|
IN BSTR strResponse,
|
|
OUT BSTR *pstrCert)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobResponse;
|
|
|
|
ZeroMemory(&blobResponse, sizeof(blobResponse));
|
|
|
|
if (NULL == strResponse)
|
|
{
|
|
hr = E_POINTER;
|
|
goto NullPointerError;
|
|
}
|
|
|
|
hr = BstringToBlob(strResponse, &blobResponse);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BstringToBlobError;
|
|
}
|
|
|
|
hr = GetCertFromResponseBlobToBStr(
|
|
&blobResponse,
|
|
pstrCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetCertFromResponseBlobToBStrError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
return hr;
|
|
|
|
TRACE_ERROR(NullPointerError)
|
|
TRACE_ERROR(BstringToBlobError)
|
|
TRACE_ERROR(GetCertFromResponseBlobToBStrError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::getCertFromFileResponse(
|
|
IN BSTR strResponseFileName,
|
|
OUT BSTR *pstrCert)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobResponse;
|
|
|
|
ZeroMemory(&blobResponse, sizeof(blobResponse));
|
|
|
|
hr = xeStringToBinaryFromFile(
|
|
(LPCWSTR)strResponseFileName,
|
|
&blobResponse.pbData,
|
|
&blobResponse.cbData,
|
|
CRYPT_STRING_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeStringToBinaryFromFileError;
|
|
}
|
|
|
|
hr = GetCertFromResponseBlobToBStr(
|
|
&blobResponse,
|
|
pstrCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetCertFromResponseBlobToBStrError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != blobResponse.pbData)
|
|
{
|
|
LocalFree(blobResponse.pbData);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(xeStringToBinaryFromFileError)
|
|
TRACE_ERROR(GetCertFromResponseBlobToBStrError)
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createPFX(
|
|
IN BSTR strPassword,
|
|
OUT BSTR *pstrPFX)
|
|
{
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
return E_ACCESSDENIED;
|
|
return createPFXWStrBStr((LPCWSTR)strPassword, pstrPFX);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createFilePFX(
|
|
IN BSTR strPassword,
|
|
IN BSTR strPFXFileName)
|
|
{
|
|
return createFilePFXWStr((LPCWSTR)strPassword, (LPCWSTR)strPFXFileName);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::setPendingRequestInfo(
|
|
IN LONG lRequestID,
|
|
IN BSTR strCADNS,
|
|
IN BSTR strCAName,
|
|
IN BSTR strFriendlyName
|
|
)
|
|
{
|
|
return setPendingRequestInfoWStr(
|
|
lRequestID,
|
|
(LPCWSTR)strCADNS,
|
|
(LPCWSTR)strCAName,
|
|
(LPCWSTR)strFriendlyName);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::enumPendingRequest(
|
|
IN LONG lIndex,
|
|
IN LONG lDesiredProperty,
|
|
OUT VARIANT *pvarProperty
|
|
)
|
|
{
|
|
CRYPT_DATA_BLOB dataBlobProperty;
|
|
HRESULT hr;
|
|
LONG lProperty;
|
|
VARIANT varProperty;
|
|
|
|
// See if we're initializing an enumeration. If so, just dispatch to
|
|
// enumPendingRequestWStr:
|
|
if (XEPR_ENUM_FIRST == lIndex) {
|
|
return enumPendingRequestWStr(XEPR_ENUM_FIRST, 0, NULL);
|
|
}
|
|
|
|
// Input validation:
|
|
if (lIndex < 0 || NULL == pvarProperty)
|
|
return E_INVALIDARG;
|
|
|
|
// Initialize locals:
|
|
memset(&varProperty, 0, sizeof(VARIANT));
|
|
memset(&dataBlobProperty, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
switch (lDesiredProperty)
|
|
{
|
|
case XEPR_REQUESTID:
|
|
case XEPR_VERSION:
|
|
if (S_OK != (hr = enumPendingRequestWStr(lIndex, lDesiredProperty, &lProperty)))
|
|
goto ErrorReturn;
|
|
|
|
varProperty.vt = VT_I4;
|
|
varProperty.lVal = lProperty;
|
|
*pvarProperty = varProperty;
|
|
goto CommonReturn;
|
|
|
|
case XEPR_CANAME:
|
|
case XEPR_CAFRIENDLYNAME:
|
|
case XEPR_CADNS:
|
|
case XEPR_HASH:
|
|
case XEPR_V1TEMPLATENAME:
|
|
case XEPR_V2TEMPLATEOID:
|
|
dataBlobProperty.cbData = 0;
|
|
dataBlobProperty.pbData = NULL;
|
|
|
|
// Determine the size of the property we desire.
|
|
hr = enumPendingRequestWStr(lIndex, lDesiredProperty, (LPVOID)&dataBlobProperty);
|
|
if (S_OK != hr || 0 == dataBlobProperty.cbData)
|
|
goto ErrorReturn;
|
|
|
|
dataBlobProperty.pbData = (LPBYTE)LocalAlloc(LPTR, dataBlobProperty.cbData);
|
|
if (NULL == dataBlobProperty.pbData)
|
|
goto MemoryErr;
|
|
|
|
// Request the property, using our newly allocated buffer.
|
|
hr = enumPendingRequestWStr(lIndex, lDesiredProperty, (LPVOID)&dataBlobProperty);
|
|
if (hr != S_OK)
|
|
goto ErrorReturn;
|
|
|
|
varProperty.vt = VT_BSTR;
|
|
varProperty.bstrVal = SysAllocStringByteLen((LPCSTR)dataBlobProperty.pbData, dataBlobProperty.cbData);
|
|
if (NULL == varProperty.bstrVal)
|
|
goto MemoryErr;
|
|
|
|
*pvarProperty = varProperty;
|
|
goto CommonReturn;
|
|
|
|
case XEPR_DATE:
|
|
goto NotImplErr;
|
|
|
|
default:
|
|
goto InvalidArgErr;
|
|
}
|
|
|
|
CommonReturn:
|
|
if (NULL != dataBlobProperty.pbData) { LocalFree(dataBlobProperty.pbData); }
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
if (NULL != varProperty.bstrVal) { SysFreeString(varProperty.bstrVal); }
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(InvalidArgErr, E_INVALIDARG);
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
SET_HRESULT(NotImplErr, E_NOTIMPL);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::removePendingRequest(
|
|
IN BSTR bstrThumbPrint
|
|
)
|
|
{
|
|
CRYPT_DATA_BLOB hashBlob;
|
|
HRESULT hr;
|
|
|
|
if (bstrThumbPrint == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
hashBlob.cbData = 0;
|
|
hashBlob.pbData = NULL;
|
|
|
|
if (!MyCryptStringToBinaryW
|
|
((WCHAR*)bstrThumbPrint,
|
|
SysStringLen(bstrThumbPrint),
|
|
CRYPT_STRING_ANY,
|
|
hashBlob.pbData,
|
|
&hashBlob.cbData,
|
|
NULL,
|
|
NULL))
|
|
goto MyCryptToBinaryErr;
|
|
|
|
hashBlob.pbData = (LPBYTE)LocalAlloc(LPTR, hashBlob.cbData);
|
|
if (NULL == hashBlob.pbData)
|
|
goto MemoryErr;
|
|
|
|
if (!MyCryptStringToBinaryW
|
|
((WCHAR*)bstrThumbPrint,
|
|
SysStringLen(bstrThumbPrint),
|
|
CRYPT_STRING_ANY,
|
|
hashBlob.pbData,
|
|
&hashBlob.cbData,
|
|
NULL,
|
|
NULL))
|
|
goto MyCryptToBinaryErr;
|
|
|
|
hr = this->removePendingRequestWStr(hashBlob);
|
|
|
|
CommonReturn:
|
|
if (NULL != hashBlob.pbData) { LocalFree(hashBlob.pbData); }
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(MyCryptToBinaryErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
}
|
|
|
|
//IEnroll4
|
|
|
|
HRESULT
|
|
myCertGetNameString(
|
|
IN PCCERT_CONTEXT pCert,
|
|
IN BOOL fIssuer,
|
|
OUT WCHAR **ppwszName)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwFlags = fIssuer ? CERT_NAME_ISSUER_FLAG : 0;
|
|
DWORD dwTypePara;
|
|
WCHAR *pwszName = NULL;
|
|
DWORD cch = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
cch = CertGetNameStringW(
|
|
pCert,
|
|
CERT_NAME_SIMPLE_DISPLAY_TYPE,
|
|
dwFlags,
|
|
(void*)&dwTypePara,
|
|
pwszName,
|
|
cch);
|
|
if (0 == cch)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertGetNameStringError;
|
|
}
|
|
if (NULL != pwszName)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pwszName = (WCHAR*)LocalAlloc(LMEM_FIXED, cch * sizeof(WCHAR));
|
|
if (NULL == pwszName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
*ppwszName = pwszName;
|
|
pwszName = NULL;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pwszName)
|
|
{
|
|
LocalFree(pwszName);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(CertGetNameStringError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
}
|
|
|
|
HRESULT CCEnroll::GetGoodCertContext(
|
|
IN PCCERT_CONTEXT pCertContext,
|
|
OUT PCCERT_CONTEXT *ppGoodCertContext)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pGoodCertContext = NULL;
|
|
DWORD cb;
|
|
|
|
//init
|
|
*ppGoodCertContext = NULL;
|
|
|
|
if(pCertContext == NULL)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
goto InvalidParameterError;
|
|
}
|
|
|
|
//see if the passed cert has kpi
|
|
if(CertGetCertificateContextProperty(
|
|
pCertContext,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&cb))
|
|
{
|
|
//this means kpi exists, passed cert is good
|
|
pGoodCertContext = CertDuplicateCertificateContext(pCertContext);
|
|
if (NULL == pGoodCertContext)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertDuplicateCertificateContextError;
|
|
}
|
|
}
|
|
|
|
*ppGoodCertContext = pGoodCertContext;
|
|
pGoodCertContext = NULL;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pGoodCertContext)
|
|
{
|
|
CertFreeCertificateContext(pGoodCertContext);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(InvalidParameterError)
|
|
TRACE_ERROR(CertDuplicateCertificateContextError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::SetSignerCertificate(
|
|
IN PCCERT_CONTEXT pCertContext)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pCertGoodContext = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
hr = GetGoodCertContext(pCertContext, &pCertGoodContext);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetGoodCertContextError;
|
|
}
|
|
if(NULL != m_pCertContextSigner)
|
|
{
|
|
CertFreeCertificateContext(m_pCertContextSigner);
|
|
}
|
|
m_pCertContextSigner = pCertGoodContext;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return hr;
|
|
|
|
TRACE_ERROR(GetGoodCertContextError)
|
|
}
|
|
|
|
HRESULT
|
|
VerifyPrivateKeyArchiveCertificate(
|
|
IN PCCERT_CONTEXT pCert)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CHAIN_PARA ChainParams;
|
|
CERT_CHAIN_POLICY_PARA ChainPolicy;
|
|
CERT_CHAIN_POLICY_STATUS PolicyStatus;
|
|
CERT_CHAIN_CONTEXT const *pCertChain = NULL;
|
|
char *apszCAXchgOids[] = {szOID_KP_CA_EXCHANGE};
|
|
WCHAR *pwszSubject = NULL;
|
|
WCHAR *pwszIssuer = NULL;
|
|
WCHAR *pwszDesignedSubject = NULL;
|
|
|
|
//easy check to make sure ca exchange cert issuer and subject
|
|
//names are in convention
|
|
hr = myCertGetNameString(
|
|
pCert,
|
|
FALSE,
|
|
&pwszSubject);
|
|
if (S_OK != hr)
|
|
{
|
|
goto myCertGetNameStringError;
|
|
}
|
|
|
|
hr = myCertGetNameString(
|
|
pCert,
|
|
TRUE,
|
|
&pwszIssuer);
|
|
if (S_OK != hr)
|
|
{
|
|
goto myCertGetNameStringError;
|
|
}
|
|
|
|
hr = myAddNameSuffix(
|
|
pwszIssuer,
|
|
wszCNXCHGSUFFIX,
|
|
cchCOMMONNAMEMAX_XELIB,
|
|
&pwszDesignedSubject);
|
|
if (S_OK != hr)
|
|
{
|
|
goto myAddNameSuffixError;
|
|
}
|
|
|
|
if (0 != wcscmp(pwszSubject, pwszDesignedSubject))
|
|
{
|
|
//unexpected, they should match
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
|
|
ZeroMemory(&ChainParams, sizeof(ChainParams));
|
|
ChainParams.cbSize = sizeof(ChainParams);
|
|
ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
|
|
ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = apszCAXchgOids;
|
|
ChainParams.RequestedUsage.Usage.cUsageIdentifier = ARRAYSIZE(apszCAXchgOids);
|
|
|
|
//get cert chain 1st
|
|
if (!MyCertGetCertificateChain(
|
|
NULL, //HHCE_CURRENT_USER
|
|
pCert, //ca exchange cert
|
|
NULL, //use current system time
|
|
NULL, //no additional stores
|
|
&ChainParams, //chain params
|
|
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, // Make sure that none of the certs in the chain were revoked
|
|
NULL, //reserved
|
|
&pCertChain))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertGetCertificateChainError;
|
|
}
|
|
|
|
ZeroMemory(&ChainPolicy, sizeof(ChainPolicy));
|
|
ChainPolicy.cbSize = sizeof(ChainPolicy);
|
|
ChainPolicy.dwFlags = CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG;
|
|
|
|
ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
|
|
PolicyStatus.cbSize = sizeof(PolicyStatus);
|
|
PolicyStatus.lChainIndex = -1;
|
|
PolicyStatus.lElementIndex = -1;
|
|
|
|
//verify the chain
|
|
if (!MyCertVerifyCertificateChainPolicy(
|
|
CERT_CHAIN_POLICY_BASE,
|
|
pCertChain,
|
|
&ChainPolicy,
|
|
&PolicyStatus))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertVerifyCertificateChainPolicyError;
|
|
}
|
|
|
|
if (S_OK != PolicyStatus.dwError)
|
|
{
|
|
//chain back to root fails
|
|
hr = PolicyStatus.dwError;
|
|
goto CertVerifyCertificateChainPolicyError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pCertChain)
|
|
{
|
|
MyCertFreeCertificateChain(pCertChain);
|
|
}
|
|
if (NULL != pwszSubject)
|
|
{
|
|
LocalFree(pwszSubject);
|
|
}
|
|
if (NULL != pwszDesignedSubject)
|
|
{
|
|
LocalFree(pwszDesignedSubject);
|
|
}
|
|
if (NULL != pwszIssuer)
|
|
{
|
|
LocalFree(pwszIssuer);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(CertGetCertificateChainError)
|
|
TRACE_ERROR(CertVerifyCertificateChainPolicyError)
|
|
TRACE_ERROR(InvalidArgError)
|
|
TRACE_ERROR(myCertGetNameStringError)
|
|
TRACE_ERROR(myAddNameSuffixError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::SetPrivateKeyArchiveCertificate(
|
|
IN PCCERT_CONTEXT pPrivateKeyArchiveCert)
|
|
{
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
|
|
if (NULL != pPrivateKeyArchiveCert)
|
|
{
|
|
//duplicate the cert
|
|
pCert = CertDuplicateCertificateContext(pPrivateKeyArchiveCert);
|
|
if (NULL == pCert)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertDuplicateCertificateContextError;
|
|
}
|
|
|
|
//verify ca exchange cert
|
|
hr = VerifyPrivateKeyArchiveCertificate(pCert);
|
|
if (S_OK != hr)
|
|
{
|
|
goto VerifyPrivateKeyArchiveCertificateError;
|
|
}
|
|
}
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (NULL != m_PrivateKeyArchiveCertificate)
|
|
{
|
|
CertFreeCertificateContext(m_PrivateKeyArchiveCertificate);
|
|
}
|
|
m_PrivateKeyArchiveCertificate = pCert;
|
|
pCert = NULL;
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
return (hr);
|
|
|
|
TRACE_ERROR(CertDuplicateCertificateContextError)
|
|
TRACE_ERROR(VerifyPrivateKeyArchiveCertificateError)
|
|
}
|
|
|
|
PCCERT_CONTEXT STDMETHODCALLTYPE
|
|
CCEnroll::GetPrivateKeyArchiveCertificate(void)
|
|
{
|
|
PCCERT_CONTEXT pCert = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (NULL != m_PrivateKeyArchiveCertificate)
|
|
{
|
|
pCert = CertDuplicateCertificateContext(m_PrivateKeyArchiveCertificate);
|
|
}
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return pCert;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::binaryBlobToString(
|
|
IN LONG Flags,
|
|
IN PCRYPT_DATA_BLOB pblobBinary,
|
|
OUT LPWSTR *ppwszString)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszEncoded = NULL;
|
|
DWORD dwEncoded = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptBinaryToStringW(
|
|
pblobBinary->pbData,
|
|
pblobBinary->cbData,
|
|
Flags,
|
|
pwszEncoded,
|
|
&dwEncoded))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptBinaryToStringError;
|
|
}
|
|
if (NULL != pwszEncoded)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
//dwEncoded includes null terminator
|
|
pwszEncoded = (WCHAR*)MyCoTaskMemAlloc(dwEncoded * sizeof(WCHAR));
|
|
if (NULL == pwszEncoded)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto MyCoTaskMemAllocError;
|
|
}
|
|
}
|
|
|
|
*ppwszString = pwszEncoded;
|
|
pwszEncoded = NULL;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pwszEncoded)
|
|
{
|
|
MyCoTaskMemFree(pwszEncoded);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(MyCoTaskMemAllocError)
|
|
TRACE_ERROR(MyCryptBinaryToStringError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::stringToBinaryBlob(
|
|
IN LONG Flags,
|
|
IN LPCWSTR pwszString,
|
|
OUT PCRYPT_DATA_BLOB pblobBinary,
|
|
OUT LONG *pdwSkip,
|
|
OUT LONG *pdwFlags)
|
|
{
|
|
HRESULT hr;
|
|
size_t nLength = wcslen(pwszString);
|
|
|
|
if (nLength*sizeof(WCHAR) > (DWORD)-1)
|
|
goto InvalidArgError;
|
|
|
|
//init
|
|
pblobBinary->pbData = NULL;
|
|
pblobBinary->cbData = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryW(
|
|
pwszString,
|
|
(DWORD)nLength,
|
|
Flags,
|
|
pblobBinary->pbData,
|
|
&pblobBinary->cbData,
|
|
(DWORD*)pdwSkip,
|
|
(DWORD*)pdwFlags))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptStringToBinaryWError;
|
|
}
|
|
if (NULL != pblobBinary->pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pblobBinary->pbData = (BYTE*)MyCoTaskMemAlloc(pblobBinary->cbData);
|
|
if (NULL == pblobBinary->pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto MyCoTaskMemAllocError;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
return hr;
|
|
|
|
SET_HRESULT(InvalidArgError, E_INVALIDARG);
|
|
TRACE_ERROR(MyCryptStringToBinaryWError)
|
|
TRACE_ERROR(MyCoTaskMemAllocError)
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::addExtensionToRequestWStr(
|
|
IN LONG Flags,
|
|
IN LPCWSTR pwszName,
|
|
IN PCRYPT_DATA_BLOB pblobValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CERT_EXTENSION ext;
|
|
CERT_EXTENSION *pExt = NULL; //enum 1st
|
|
CHAR *pszName = NULL;
|
|
|
|
//convert wsz oid to sz oid
|
|
hr = xeWSZToSZ(pwszName, &pszName);
|
|
if (S_OK != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
while (NULL != (pExt = EnumStackExtension(pExt, TRUE)))
|
|
{
|
|
if (0 == strcmp(pszName, pExt->pszObjId))
|
|
{
|
|
//already had the extension, can't have more than 1
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
//check to see if it is key usage extension
|
|
if (0 == strcmp(pszName, szOID_KEY_USAGE))
|
|
{
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
m_fUseClientKeyUsage = TRUE;
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
}
|
|
|
|
ZeroMemory(&ext, sizeof(ext));
|
|
ext.fCritical = Flags;
|
|
ext.pszObjId = pszName;
|
|
ext.Value = *pblobValue;
|
|
|
|
if(!CopyAndPushStackExtension(&ext, TRUE))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
error:
|
|
if (NULL != pszName)
|
|
{
|
|
MyCoTaskMemFree(pszName);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::addAttributeToRequestWStr(
|
|
IN LONG /*Flags*/,
|
|
IN LPCWSTR pwszName,
|
|
IN PCRYPT_DATA_BLOB pblobValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CRYPT_ATTR_BLOB attrBlob;
|
|
CRYPT_ATTRIBUTE attr;
|
|
CHAR *pszName = NULL;
|
|
|
|
//convert wsz oid to sz oid
|
|
hr = xeWSZToSZ(pwszName, &pszName);
|
|
if (S_OK != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
ZeroMemory(&attr, sizeof(attr));
|
|
attrBlob = *pblobValue;
|
|
attr.pszObjId = pszName;
|
|
attr.cValue = 1;
|
|
attr.rgValue = &attrBlob;
|
|
|
|
if(!CopyAndPushStackAttribute(&attr, TRUE))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
error:
|
|
if (NULL != pszName)
|
|
{
|
|
MyCoTaskMemFree(pszName);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::addNameValuePairToRequestWStr(
|
|
IN LONG /*Flags*/,
|
|
IN LPCWSTR pwszName,
|
|
IN LPCWSTR pwszValue)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
assert(pwszName != NULL && pwszValue != NULL);
|
|
|
|
CRYPT_ENROLLMENT_NAME_VALUE_PAIR nameValuePair =
|
|
{const_cast<LPWSTR>(pwszName), const_cast<LPWSTR>(pwszValue)};
|
|
CRYPT_ATTR_BLOB blobAttr;
|
|
CRYPT_ATTRIBUTE attr = {szOID_ENROLLMENT_NAME_VALUE_PAIR, 1, &blobAttr};
|
|
|
|
memset(&blobAttr, 0, sizeof(CRYPT_ATTR_BLOB));
|
|
|
|
hr = xeEncodeNameValuePair(
|
|
&nameValuePair,
|
|
&blobAttr.pbData,
|
|
&blobAttr.cbData);
|
|
if (S_OK != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
if(!CopyAndPushStackAttribute(&attr, TRUE))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
error:
|
|
if (NULL != blobAttr.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobAttr.pbData);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::addBlobPropertyToCertificateWStr(
|
|
IN LONG lPropertyId,
|
|
IN LONG lFlags,
|
|
IN PCRYPT_DATA_BLOB pBlobProp)
|
|
{
|
|
HRESULT hr;
|
|
PPROP_STACK pProp;
|
|
PPROP_STACK pPropEle = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (NULL == pBlobProp ||
|
|
NULL == pBlobProp->pbData ||
|
|
0 == pBlobProp->cbData)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
goto InvalidParameterError;
|
|
}
|
|
|
|
// Don't allow arbitrary properties to be set on the request from a script
|
|
// (could be a security risk, we should only allow a small set)
|
|
if (0 != m_dwEnabledSafteyOptions && !IsDesiredProperty(lPropertyId))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
|
goto InvalidParameterError;
|
|
}
|
|
|
|
//check if the same property exists
|
|
pProp = EnumStackProperty(NULL);
|
|
while (NULL != pProp)
|
|
{
|
|
if (pProp->lPropId == lPropertyId)
|
|
{
|
|
//exists already
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
|
goto PropertyExistError;
|
|
}
|
|
pProp = EnumStackProperty(pProp);
|
|
}
|
|
|
|
pPropEle = (PPROP_STACK)LocalAlloc(LMEM_ZEROINIT, sizeof(PROP_STACK));
|
|
if (NULL == pPropEle)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
|
|
pPropEle->lPropId = lPropertyId;
|
|
pPropEle->lFlags = lFlags;
|
|
pPropEle->prop.pbData = (BYTE*)LocalAlloc(LMEM_FIXED, pBlobProp->cbData);
|
|
if (NULL == pPropEle->prop.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
CopyMemory(pPropEle->prop.pbData, pBlobProp->pbData, pBlobProp->cbData);
|
|
pPropEle->prop.cbData = pBlobProp->cbData;
|
|
|
|
//put into stack
|
|
pPropEle->pNext = m_pPropStack;
|
|
m_pPropStack = pPropEle; //assign m_pPropStack
|
|
m_cPropStack++; //increment of m_cPropStack
|
|
pPropEle = NULL;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pPropEle)
|
|
{
|
|
if (NULL != pPropEle->prop.pbData)
|
|
{
|
|
LocalFree(pPropEle->prop.pbData);
|
|
}
|
|
LocalFree(pPropEle);
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return hr;
|
|
|
|
TRACE_ERROR(InvalidParameterError)
|
|
TRACE_ERROR(PropertyExistError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
}
|
|
|
|
PPROP_STACK
|
|
CCEnroll::EnumStackProperty(PPROP_STACK pProp)
|
|
{
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if(NULL == pProp)
|
|
{
|
|
//1st one
|
|
pProp = m_pPropStack;
|
|
}
|
|
else
|
|
{
|
|
pProp = pProp->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return pProp;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CCEnroll::resetBlobProperties()
|
|
{
|
|
PPROP_STACK pPropEle;
|
|
PPROP_STACK pPropNext;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
pPropEle = m_pPropStack;
|
|
while (NULL != pPropEle)
|
|
{
|
|
//save it to temp
|
|
pPropNext = EnumStackProperty(pPropEle);
|
|
//free the current ele
|
|
if (NULL != pPropEle->prop.pbData)
|
|
{
|
|
LocalFree(pPropEle->prop.pbData);
|
|
}
|
|
LocalFree(pPropEle);
|
|
pPropEle = pPropNext;
|
|
}
|
|
m_pPropStack = NULL;
|
|
m_cPropStack = 0;
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::GetKeyArchivePKCS7(
|
|
OUT CRYPT_ATTR_BLOB *pBlobKeyArchivePKCS7)
|
|
{
|
|
HRESULT hr;
|
|
HCRYPTPROV hProv;
|
|
HCRYPTKEY hKey = NULL;
|
|
BYTE *pBlobPrivateKey = NULL;
|
|
DWORD cBlobPrivateKey = 0;
|
|
CRYPT_ENCRYPT_MESSAGE_PARA cemp;
|
|
ALG_ID algId[] = {CALG_3DES, CALG_RC4, CALG_RC2, ALG_TYPE_ANY};
|
|
CRYPT_OID_INFO const *pOidInfo = NULL;
|
|
DWORD i = 0;
|
|
|
|
//init
|
|
pBlobKeyArchivePKCS7->pbData = NULL;
|
|
pBlobKeyArchivePKCS7->cbData = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
//make sure key archival cert is set
|
|
assert(NULL != m_PrivateKeyArchiveCertificate);
|
|
|
|
PCCERT_CONTEXT apCert[] = {m_PrivateKeyArchiveCertificate};
|
|
|
|
//get user private key
|
|
hProv = GetProv(0); //existing key container handle
|
|
if (NULL == hProv)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptAcquireContextError;
|
|
}
|
|
|
|
if (NULL == m_hCachedKey)
|
|
{
|
|
//likely used existing key
|
|
if(!CryptGetUserKey(
|
|
hProv,
|
|
m_keyProvInfo.dwKeySpec,
|
|
&hKey))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptGetUserKeyError;
|
|
}
|
|
}
|
|
|
|
//export private key
|
|
while (TRUE)
|
|
{
|
|
if (!CryptExportKey(
|
|
NULL != hKey ? hKey : m_hCachedKey,
|
|
NULL, //don't encrypt
|
|
PRIVATEKEYBLOB,
|
|
0,
|
|
pBlobPrivateKey,
|
|
&cBlobPrivateKey))
|
|
{
|
|
//map to xenroll error
|
|
hr = XENROLL_E_KEY_NOT_EXPORTABLE;
|
|
goto CryptExportKeyError;
|
|
}
|
|
if (NULL != pBlobPrivateKey)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
pBlobPrivateKey = (BYTE*)MyCoTaskMemAlloc(cBlobPrivateKey);
|
|
if (NULL == pBlobPrivateKey)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
if (NULL == m_hCachedKey)
|
|
{
|
|
//it could be csp not supporting CRYPT_ARCHIVABLE
|
|
//got private key, now let's take care of key permission
|
|
if (0x0 == (m_dwGenKeyFlags & CRYPT_EXPORTABLE))
|
|
{
|
|
// user didn't ask exportable, turn it off
|
|
DWORD dwFlags = 0;
|
|
DWORD dwSize = sizeof(dwFlags);
|
|
if (!CryptGetKeyParam(
|
|
hKey,
|
|
KP_PERMISSIONS,
|
|
(BYTE*)&dwFlags,
|
|
&dwSize,
|
|
0))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptGetKeyParamError;
|
|
}
|
|
#if DBG
|
|
assert(dwSize = sizeof(dwFlags));
|
|
// make sure was on
|
|
assert(0x0 != (dwFlags & CRYPT_EXPORT));
|
|
#endif
|
|
//turn off exportable
|
|
dwFlags = dwFlags & (~CRYPT_EXPORT);
|
|
if (!CryptSetKeyParam(
|
|
hKey,
|
|
KP_PERMISSIONS,
|
|
(BYTE*)&dwFlags,
|
|
0))
|
|
{
|
|
//hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
//goto CryptSetKeyParamError;
|
|
hr = S_OK; //UNDONE, even ms csps have problem with this
|
|
}
|
|
}
|
|
}
|
|
|
|
//prepare for encryption
|
|
ZeroMemory(&cemp, sizeof(cemp)); //avoid 0 assignment
|
|
cemp.cbSize = sizeof(cemp);
|
|
cemp.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
|
|
hr = S_OK; //critical init for double while loop
|
|
|
|
while (ALG_TYPE_ANY != algId[i])
|
|
{
|
|
pOidInfo = xeCryptFindOIDInfo(
|
|
CRYPT_OID_INFO_ALGID_KEY,
|
|
&algId[i],
|
|
CRYPT_ENCRYPT_ALG_OID_GROUP_ID);
|
|
if (NULL != pOidInfo)
|
|
{
|
|
cemp.ContentEncryptionAlgorithm.pszObjId =
|
|
const_cast<char *>(pOidInfo->pszOID);
|
|
//encryt into pkcs7
|
|
while (TRUE)
|
|
{
|
|
if (!CryptEncryptMessage(
|
|
&cemp,
|
|
sizeof(apCert)/sizeof(apCert[0]),
|
|
apCert,
|
|
pBlobPrivateKey,
|
|
cBlobPrivateKey,
|
|
pBlobKeyArchivePKCS7->pbData,
|
|
&pBlobKeyArchivePKCS7->cbData))
|
|
{
|
|
//save the 1st error code
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
#ifdef DBG
|
|
assert(NULL == pBlobKeyArchivePKCS7->pbData);
|
|
#endif
|
|
break; //break inner while loop
|
|
}
|
|
if (NULL != pBlobKeyArchivePKCS7->pbData)
|
|
{
|
|
//done, got encrypted blob
|
|
//ignore error from previous alg tries
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
pBlobKeyArchivePKCS7->pbData = (BYTE*)MyCoTaskMemAlloc(
|
|
pBlobKeyArchivePKCS7->cbData);
|
|
if (NULL == pBlobKeyArchivePKCS7->pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
//done, out of outer while loop
|
|
break;
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
if (NULL == pOidInfo)
|
|
{
|
|
hr = CRYPT_E_NOT_FOUND;
|
|
goto CryptElemNotFoundError;
|
|
}
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
goto CryptEncryptMessageError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
//now let's destroy cached key handle
|
|
if (NULL != m_hCachedKey)
|
|
{
|
|
CryptDestroyKey(m_hCachedKey);
|
|
m_hCachedKey = NULL; //critical to reset
|
|
}
|
|
//note, do above before leaving critical section
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
if (NULL != pBlobPrivateKey)
|
|
{
|
|
SecureZeroMemory(pBlobPrivateKey, cBlobPrivateKey);
|
|
MyCoTaskMemFree(pBlobPrivateKey);
|
|
}
|
|
if (NULL != hKey)
|
|
{
|
|
CryptDestroyKey(hKey);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(CryptEncryptMessageError)
|
|
TRACE_ERROR(CryptAcquireContextError)
|
|
TRACE_ERROR(CryptGetUserKeyError)
|
|
TRACE_ERROR(CryptExportKeyError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
TRACE_ERROR(CryptElemNotFoundError)
|
|
//TRACE_ERROR(CryptSetKeyParamError)
|
|
TRACE_ERROR(CryptGetKeyParamError)
|
|
}
|
|
|
|
HRESULT
|
|
GetKeyProvInfoFromCert(
|
|
IN PCCERT_CONTEXT pCert,
|
|
OUT DWORD *pdwKeySpec,
|
|
OUT HCRYPTPROV *phProv)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_KEY_PROV_INFO *pKeyProvInfo = NULL;
|
|
DWORD cb = 0;
|
|
HCRYPTPROV hProv = NULL;
|
|
|
|
if (NULL == pCert || NULL == phProv || NULL == pdwKeySpec)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
if(!CertGetCertificateContextProperty(
|
|
pCert,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
pKeyProvInfo,
|
|
&cb))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertGetCertificateContextPropertyError;
|
|
}
|
|
if (NULL != pKeyProvInfo)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
pKeyProvInfo = (CRYPT_KEY_PROV_INFO*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pKeyProvInfo)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
if (!CryptAcquireContextU(
|
|
&hProv,
|
|
pKeyProvInfo->pwszContainerName,
|
|
pKeyProvInfo->pwszProvName,
|
|
pKeyProvInfo->dwProvType,
|
|
pKeyProvInfo->dwFlags))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptAcquireContextUError;
|
|
}
|
|
*phProv = hProv;
|
|
hProv = NULL;
|
|
*pdwKeySpec = pKeyProvInfo->dwKeySpec;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pKeyProvInfo)
|
|
{
|
|
LocalFree(pKeyProvInfo);
|
|
}
|
|
if (NULL != hProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(CryptAcquireContextUError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
TRACE_ERROR(CertGetCertificateContextPropertyError)
|
|
TRACE_ERROR(InvalidArgError)
|
|
}
|
|
|
|
HRESULT
|
|
xeCreateKeyArchivalHashAttribute(
|
|
IN CRYPT_HASH_BLOB *pBlobKAHash,
|
|
OUT CRYPT_ATTR_BLOB *pBlobKAAttr)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbData = NULL;
|
|
DWORD cbData = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
if(!CryptEncodeObject(
|
|
CRYPT_ASN_ENCODING,
|
|
X509_OCTET_STRING,
|
|
(void*)pBlobKAHash,
|
|
pbData,
|
|
&cbData))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CryptEncodeObjectError;
|
|
}
|
|
|
|
if (NULL != pbData)
|
|
{
|
|
//done
|
|
break;
|
|
}
|
|
|
|
pbData = (BYTE*)LocalAlloc(LMEM_FIXED, cbData);
|
|
if (NULL == pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
}
|
|
pBlobKAAttr->pbData = pbData;
|
|
pBlobKAAttr->cbData = cbData;
|
|
pbData = NULL;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pbData)
|
|
{
|
|
LocalFree(pbData);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(CryptEncodeObjectError)
|
|
TRACE_ERROR(LocalAllocError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createRequestWStr(
|
|
IN LONG Flags,
|
|
IN LPCWSTR pwszDNName,
|
|
IN LPCWSTR pwszUsage,
|
|
OUT PCRYPT_DATA_BLOB pblobRequest)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobPKCS10;
|
|
CRYPT_ATTR_BLOB blobKeyArchivePKCS7;
|
|
ALG_ID rgAlg[2];
|
|
PCCRYPT_OID_INFO pOidInfo;
|
|
CERT_EXTENSION *rgExt = NULL;
|
|
DWORD cExt = 0;
|
|
CERT_EXTENSION *pExt = NULL; //for enum 1st
|
|
CRYPT_ATTRIBUTE *rgAttr = NULL;
|
|
DWORD cAttr = 0;
|
|
CRYPT_ATTRIBUTE *pAttr = NULL; //for enum 1st
|
|
CRYPT_ATTRIBUTES rgAttributes;
|
|
CRYPT_ATTRIBUTE *rgUnauthAttr = NULL; //init
|
|
DWORD cUnauthAttr = 0; //init
|
|
DWORD cb;
|
|
HCRYPTPROV hProvSigner = NULL;
|
|
DWORD dwKeySpecSigner = 0;
|
|
PCCERT_CONTEXT pCertSigner = NULL; //just init, no free
|
|
HCRYPTPROV hRequestProv = NULL;
|
|
BYTE *pbSubjectKeyHash = NULL;
|
|
DWORD cbSubjectKeyHash = 0;
|
|
CRYPT_HASH_BLOB blobKAHash;
|
|
CRYPT_ATTR_BLOB blobKAHashAttr;
|
|
CRYPT_ATTRIBUTE attrKAHash =
|
|
{szOID_ENCRYPTED_KEY_HASH, 1, &blobKAHashAttr};
|
|
|
|
ZeroMemory(&blobPKCS10, sizeof(blobPKCS10));
|
|
ZeroMemory(&blobKeyArchivePKCS7, sizeof(blobKeyArchivePKCS7));
|
|
ZeroMemory(&blobKAHash, sizeof(blobKAHash));
|
|
ZeroMemory(&blobKAHashAttr, sizeof(blobKAHashAttr));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// BUG 533202: should block key archival when re-using key (from script)
|
|
if (0 != m_dwEnabledSafteyOptions && NULL != m_PrivateKeyArchiveCertificate && m_fUseExistingKey) {
|
|
hr = E_ACCESSDENIED;
|
|
goto AccessDeniedError;
|
|
}
|
|
|
|
m_fNewRequestMethod = TRUE; //critical
|
|
m_fOID_V2 = TRUE;
|
|
m_fCMCFormat = FALSE;
|
|
m_fHonorIncludeSubjectKeyID = FALSE;
|
|
|
|
switch (Flags)
|
|
{
|
|
case XECR_CMC:
|
|
{
|
|
if (NULL != m_pCertContextRenewal &&
|
|
NULL != m_pCertContextSigner)
|
|
{
|
|
//don't support both on yet
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
goto NotSupportedError;
|
|
}
|
|
|
|
m_fCMCFormat = TRUE;
|
|
m_fHonorIncludeSubjectKeyID = TRUE;
|
|
// create pkcs 10 first
|
|
hr = createPKCS10WStr(
|
|
pwszDNName,
|
|
pwszUsage, //wszPurpose,
|
|
&blobPKCS10);
|
|
if(S_OK != hr)
|
|
{
|
|
goto createPKCS10WStrError;
|
|
}
|
|
//set it back
|
|
m_fCMCFormat = FALSE;
|
|
|
|
//get all extensions
|
|
cb = CountStackExtension(TRUE) * sizeof(CERT_EXTENSION);
|
|
if (0 < cb)
|
|
{
|
|
rgExt = (CERT_EXTENSION*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == rgExt)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
ZeroMemory(rgExt, cb);
|
|
while(NULL != (pExt = EnumStackExtension(pExt, TRUE)))
|
|
{
|
|
rgExt[cExt] = *pExt;
|
|
cExt++;
|
|
}
|
|
}
|
|
|
|
//get all attributes including namevalue pair
|
|
cb = CountStackAttribute(TRUE) * sizeof(CRYPT_ATTRIBUTE);
|
|
if (NULL != m_PrivateKeyArchiveCertificate)
|
|
{
|
|
//add one more attribute to hold encrypted key hash
|
|
cb += sizeof(CRYPT_ATTRIBUTE);
|
|
}
|
|
if (0 < cb)
|
|
{
|
|
rgAttr = (CRYPT_ATTRIBUTE*)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == rgAttr)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
ZeroMemory(rgAttr, cb);
|
|
while(NULL != (pAttr = EnumStackAttribute(pAttr, TRUE)))
|
|
{
|
|
rgAttr[cAttr] = *pAttr;
|
|
cAttr++;
|
|
}
|
|
rgAttributes.rgAttr = rgAttr;
|
|
rgAttributes.cAttr = cAttr;
|
|
}
|
|
|
|
if (NULL != m_PrivateKeyArchiveCertificate)
|
|
{
|
|
hr = GetKeyArchivePKCS7(&blobKeyArchivePKCS7);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetKeyArchivePKCS7Error;
|
|
}
|
|
rgUnauthAttr = (CRYPT_ATTRIBUTE*)LocalAlloc(LMEM_FIXED,
|
|
sizeof(CRYPT_ATTRIBUTE));
|
|
if (NULL == rgUnauthAttr)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
rgUnauthAttr->pszObjId = szOID_ARCHIVED_KEY_ATTR;
|
|
rgUnauthAttr->cValue = 1;
|
|
rgUnauthAttr->rgValue = &blobKeyArchivePKCS7;
|
|
++cUnauthAttr;
|
|
|
|
//if key archival cert is set, should save the hash
|
|
//of the encrypted private key
|
|
|
|
hr = myCalculateKeyArchivalHash(
|
|
blobKeyArchivePKCS7.pbData,
|
|
blobKeyArchivePKCS7.cbData,
|
|
&blobKAHash.pbData,
|
|
&blobKAHash.cbData);
|
|
if (S_OK != hr)
|
|
{
|
|
goto myCalculateKeyArchivalHashError;
|
|
}
|
|
|
|
if (!CertSetCertificateContextProperty(
|
|
m_pCertContextPendingRequest, //use pending cert
|
|
CERT_ARCHIVED_KEY_HASH_PROP_ID,
|
|
0,
|
|
&blobKAHash))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertSetCertificateContextPropertyError;
|
|
}
|
|
|
|
hr = xeCreateKeyArchivalHashAttribute(
|
|
&blobKAHash,
|
|
&blobKAHashAttr);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeCreateKeyArchivalHashAttributeError;
|
|
}
|
|
|
|
//add this attribute into the array
|
|
rgAttr[cAttr] = attrKAHash;
|
|
cAttr++;
|
|
rgAttributes.rgAttr = rgAttr;
|
|
rgAttributes.cAttr = cAttr;
|
|
}
|
|
|
|
//client may set m_HashAlgId but it is not guaranteed
|
|
//GetCapiHashAndSigAlgId will determine which one
|
|
//is actually used
|
|
if (!GetCapiHashAndSigAlgId(rgAlg))
|
|
{
|
|
hr = NTE_BAD_ALGID;
|
|
goto GetCapiHashAndSigAlgIdError;
|
|
}
|
|
pOidInfo = xeCryptFindOIDInfo(
|
|
CRYPT_OID_INFO_ALGID_KEY,
|
|
(void*)rgAlg, //point to rgAlg[0]
|
|
CRYPT_HASH_ALG_OID_GROUP_ID);
|
|
if (NULL == pOidInfo)
|
|
{
|
|
goto xeCryptFindOIDInfoError;
|
|
}
|
|
|
|
if (NULL != m_pCertContextRenewal)
|
|
{
|
|
pCertSigner = m_pCertContextRenewal;
|
|
}
|
|
if (NULL != m_pCertContextSigner)
|
|
{
|
|
pCertSigner = m_pCertContextSigner;
|
|
}
|
|
if (NULL != pCertSigner)
|
|
{
|
|
//get signer key prov info
|
|
hr = GetKeyProvInfoFromCert(
|
|
pCertSigner,
|
|
&dwKeySpecSigner,
|
|
&hProvSigner);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetKeyProvInfoFromCertError;
|
|
}
|
|
}
|
|
|
|
//this is CMC, honor anyway
|
|
if (m_fIncludeSubjectKeyID)
|
|
{
|
|
hr = myGetPublicKeyHash(
|
|
NULL,
|
|
m_pPublicKeyInfo,
|
|
&pbSubjectKeyHash,
|
|
&cbSubjectKeyHash);
|
|
if (S_OK != hr)
|
|
{
|
|
goto myGetPublicKeyHashError;
|
|
}
|
|
}
|
|
hRequestProv = GetProv(0);
|
|
if (NULL == hRequestProv)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto GetProvError;
|
|
}
|
|
|
|
//ok, now call cmc create
|
|
hr = BuildCMCRequest(
|
|
m_lClientId,
|
|
FALSE, //fNestedCMCRequest
|
|
blobPKCS10.pbData,
|
|
blobPKCS10.cbData,
|
|
rgExt,
|
|
cExt,
|
|
(0 != cAttr) ? &rgAttributes : NULL,
|
|
(0 != cAttr) ? 1 : 0,
|
|
rgUnauthAttr,
|
|
cUnauthAttr,
|
|
pbSubjectKeyHash,
|
|
cbSubjectKeyHash,
|
|
hRequestProv,
|
|
m_keyProvInfo.dwKeySpec,
|
|
pOidInfo->pszOID,
|
|
pCertSigner,
|
|
hProvSigner,
|
|
dwKeySpecSigner,
|
|
NULL, //pOidInfo->pszOID, //this seems to me not necessary because we passed the cert context
|
|
&pblobRequest->pbData,
|
|
&pblobRequest->cbData);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BuildCMCRequestError;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case XECR_PKCS7:
|
|
if ((NULL == m_pCertContextRenewal &&
|
|
NULL == m_pCertContextSigner) ||
|
|
NULL != m_PrivateKeyArchiveCertificate)
|
|
{
|
|
//renew cert is not set, can't make it pkcs7
|
|
//pkcs7 can't support key archival
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
// old method will return pkcs7
|
|
hr = createPKCS10WStr(
|
|
pwszDNName,
|
|
pwszUsage, //wszPurpose,
|
|
pblobRequest);
|
|
if(S_OK != hr)
|
|
{
|
|
goto createPKCS10WStrError;
|
|
}
|
|
break;
|
|
|
|
case XECR_PKCS10_V1_5:
|
|
m_fOID_V2 = FALSE;
|
|
//fall through
|
|
case XECR_PKCS10_V2_0:
|
|
|
|
if (NULL != m_PrivateKeyArchiveCertificate)
|
|
{
|
|
//pkcs10 can't support key archival
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
m_fHonorRenew = FALSE; //avoid return pkcs7
|
|
//for new PKCS10 we allow include subject key id extension
|
|
m_fHonorIncludeSubjectKeyID = TRUE;
|
|
// call old method
|
|
hr = createPKCS10WStr(
|
|
pwszDNName,
|
|
pwszUsage, //wszPurpose,
|
|
pblobRequest);
|
|
if(S_OK != hr)
|
|
{
|
|
goto createPKCS10WStrError;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
break;
|
|
}
|
|
|
|
//in all cases, we called createPKCS10WStr
|
|
if(m_wszPVKFileName[0] != 0 && !m_fUseExistingKey)
|
|
{
|
|
//we hold on this until possible cmc is created
|
|
GetProv(CRYPT_DELETEKEYSET);
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
m_fNewRequestMethod = FALSE; //critical
|
|
m_fOID_V2 = FALSE; //critical for backward compatiability
|
|
m_fHonorRenew = TRUE; //critical
|
|
m_fHonorIncludeSubjectKeyID = TRUE; //critical for backward compt.
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
if (NULL != rgExt)
|
|
{
|
|
LocalFree(rgExt);
|
|
}
|
|
if (NULL != rgAttr)
|
|
{
|
|
LocalFree(rgAttr);
|
|
}
|
|
if (NULL != rgUnauthAttr)
|
|
{
|
|
LocalFree(rgUnauthAttr);
|
|
}
|
|
if (NULL != blobKeyArchivePKCS7.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobKeyArchivePKCS7.pbData);
|
|
}
|
|
if (NULL != blobPKCS10.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobPKCS10.pbData);
|
|
}
|
|
if (NULL != hProvSigner)
|
|
{
|
|
CryptReleaseContext(hProvSigner, 0);
|
|
}
|
|
if (NULL != pbSubjectKeyHash)
|
|
{
|
|
LocalFree(pbSubjectKeyHash);
|
|
}
|
|
if (NULL != blobKAHash.pbData)
|
|
{
|
|
LocalFree(blobKAHash.pbData);
|
|
}
|
|
if (NULL != blobKAHashAttr.pbData)
|
|
{
|
|
LocalFree(blobKAHashAttr.pbData);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(AccessDeniedError);
|
|
TRACE_ERROR(createPKCS10WStrError)
|
|
TRACE_ERROR(BuildCMCRequestError)
|
|
TRACE_ERROR(InvalidArgError)
|
|
TRACE_ERROR(GetCapiHashAndSigAlgIdError)
|
|
TRACE_ERROR(GetKeyArchivePKCS7Error)
|
|
TRACE_ERROR(xeCryptFindOIDInfoError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
TRACE_ERROR(GetKeyProvInfoFromCertError)
|
|
TRACE_ERROR(NotSupportedError)
|
|
TRACE_ERROR(GetProvError)
|
|
TRACE_ERROR(myGetPublicKeyHashError)
|
|
TRACE_ERROR(CertSetCertificateContextPropertyError)
|
|
TRACE_ERROR(myCalculateKeyArchivalHashError)
|
|
TRACE_ERROR(xeCreateKeyArchivalHashAttributeError)
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::BlobToBstring(
|
|
IN CRYPT_DATA_BLOB *pBlob,
|
|
IN DWORD dwFlag,
|
|
OUT BSTR *pBString)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszB64;
|
|
DWORD cch;
|
|
|
|
//init
|
|
*pBString = NULL;
|
|
|
|
// BASE64 encode blob
|
|
pwszB64 = NULL;
|
|
cch = 0;
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptBinaryToStringW(
|
|
pBlob->pbData,
|
|
pBlob->cbData,
|
|
dwFlag,
|
|
pwszB64,
|
|
&cch))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptBinaryToStringWError;
|
|
}
|
|
if (NULL != pwszB64)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
pwszB64 = (WCHAR *)LocalAlloc(LMEM_FIXED, cch * sizeof(WCHAR));
|
|
if (NULL == pwszB64)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto OutOfMemoryError;
|
|
}
|
|
}
|
|
|
|
// SysAllocStringLen
|
|
*pBString = SysAllocStringLen(pwszB64, cch);
|
|
if(NULL == *pBString)
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
hr = E_OUTOFMEMORY;
|
|
goto SysAllocStringLenError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != pwszB64)
|
|
{
|
|
LocalFree(pwszB64);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(MyCryptBinaryToStringWError)
|
|
TRACE_ERROR(SysAllocStringLenError)
|
|
TRACE_ERROR(OutOfMemoryError)
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::BstringToBlob(
|
|
IN BSTR bString,
|
|
OUT CRYPT_DATA_BLOB *pBlob)
|
|
{
|
|
HRESULT hr;
|
|
|
|
assert(NULL != pBlob);
|
|
|
|
//init
|
|
pBlob->pbData = NULL;
|
|
pBlob->cbData = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
if (!MyCryptStringToBinaryW(
|
|
(LPCWSTR)bString,
|
|
SysStringLen(bString),
|
|
CRYPT_STRING_ANY,
|
|
pBlob->pbData,
|
|
&pBlob->cbData,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto MyCryptStringToBinaryWError;
|
|
}
|
|
if (NULL != pBlob->pbData)
|
|
{
|
|
break; //done
|
|
}
|
|
pBlob->pbData = (BYTE*)MyCoTaskMemAlloc(pBlob->cbData);
|
|
if (NULL == pBlob->pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto MyCoTaskMemAllocError;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
return(hr);
|
|
|
|
TRACE_ERROR(MyCoTaskMemAllocError)
|
|
TRACE_ERROR(MyCryptStringToBinaryWError)
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::createRequestWStrBStr(
|
|
IN LONG Flags,
|
|
IN LPCWSTR pwszDNName,
|
|
IN LPCWSTR pwszUsage,
|
|
IN DWORD dwFlag,
|
|
OUT BSTR __RPC_FAR *pbstrRequest)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobRequest;
|
|
|
|
memset(&blobRequest, 0, sizeof(blobRequest));
|
|
|
|
hr = createRequestWStr(Flags, pwszDNName, pwszUsage, &blobRequest);
|
|
if (S_OK != hr)
|
|
{
|
|
goto createRequestWStrError;
|
|
}
|
|
|
|
// convert to bstr
|
|
hr = BlobToBstring(&blobRequest, dwFlag, pbstrRequest);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BlobToBstringError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(NULL != blobRequest.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobRequest.pbData);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(createRequestWStrError)
|
|
TRACE_ERROR(BlobToBstringError)
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::BStringToFile(
|
|
IN BSTR bString,
|
|
IN LPCWSTR pwszFileName)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hFile = NULL;
|
|
DWORD cb = 0;
|
|
LPSTR sz = NULL;
|
|
size_t nLength;
|
|
|
|
sz = MBFromWide(bString);
|
|
if(NULL == sz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto MBFromWideError;
|
|
}
|
|
|
|
nLength = strlen(sz);
|
|
if (nLength > (DWORD)-1)
|
|
goto InvalidArgError;
|
|
|
|
|
|
// open the file
|
|
hFile = CreateFileSafely(pwszFileName);
|
|
if (NULL == hFile)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CreateFileFileSafelyError;
|
|
}
|
|
|
|
// write the pkcs10
|
|
if(!WriteFile(
|
|
hFile,
|
|
sz,
|
|
(DWORD)nLength,
|
|
&cb,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto WriteFileError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(NULL != hFile)
|
|
{
|
|
CloseHandle(hFile);
|
|
}
|
|
if(NULL != sz)
|
|
{
|
|
MyCoTaskMemFree(sz);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(CreateFileFileSafelyError)
|
|
SET_HRESULT(InvalidArgError, E_INVALIDARG);
|
|
TRACE_ERROR(MBFromWideError)
|
|
TRACE_ERROR(WriteFileError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createFileRequestWStr(
|
|
IN LONG Flags,
|
|
IN LPCWSTR pwszDNName,
|
|
IN LPCWSTR pwszUsage,
|
|
IN LPCWSTR pwszRequestFileName)
|
|
{
|
|
HRESULT hr;
|
|
BSTR bstrRequest = NULL;
|
|
|
|
// get the Request
|
|
hr = createRequestWStrBStr(
|
|
Flags,
|
|
pwszDNName,
|
|
pwszUsage,
|
|
CRYPT_STRING_BASE64REQUESTHEADER,
|
|
&bstrRequest);
|
|
if(S_OK != hr)
|
|
{
|
|
goto createRequestWStrBStrError;
|
|
}
|
|
|
|
// save it to file
|
|
hr = BStringToFile(bstrRequest, pwszRequestFileName);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BStringToFileError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(NULL != bstrRequest)
|
|
{
|
|
SysFreeString(bstrRequest);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(createRequestWStrBStrError)
|
|
TRACE_ERROR(BStringToFileError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::acceptResponseBlob(
|
|
IN PCRYPT_DATA_BLOB pblobResponse)
|
|
{
|
|
HRESULT hr_old = S_OK;
|
|
HRESULT hr;
|
|
XCMCRESPONSE *prgResponse = NULL;
|
|
DWORD cResponse = 0;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
//check in parameter
|
|
if (NULL == pblobResponse)
|
|
{
|
|
hr = E_POINTER;
|
|
goto NullPointerError;
|
|
}
|
|
if (NULL == pblobResponse->pbData ||
|
|
0 == pblobResponse->cbData)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto InvalidArgError;
|
|
}
|
|
|
|
//make sure init archived key hash
|
|
ZeroMemory(&m_blobResponseKAHash, sizeof(m_blobResponseKAHash));
|
|
|
|
hr_old = ParseCMCResponse(
|
|
pblobResponse->pbData,
|
|
pblobResponse->cbData,
|
|
NULL,
|
|
&prgResponse,
|
|
&cResponse);
|
|
//note, if for any reasons above failed, try pkcs7
|
|
if (S_OK == hr_old)
|
|
{
|
|
if (1 < cResponse)
|
|
{
|
|
//not supported yet
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
goto NotSupportedError;
|
|
}
|
|
#if DBG
|
|
//make sure not zero, should be 1
|
|
assert(1 == cResponse);
|
|
#endif //DBG
|
|
|
|
//check response status
|
|
if (CMC_STATUS_SUCCESS != prgResponse->StatusInfo.dwStatus)
|
|
{
|
|
hr = prgResponse->StatusInfo.dwStatus; //take status error
|
|
goto CMCResponseStatusError;
|
|
}
|
|
|
|
//some code here to get encrypted archived key hash from the response
|
|
//and make m_blobResponseKAHash point to the hash data
|
|
if (NULL != prgResponse->pbEncryptedKeyHash)
|
|
{
|
|
m_blobResponseKAHash.pbData = prgResponse->pbEncryptedKeyHash;
|
|
m_blobResponseKAHash.cbData = prgResponse->cbEncryptedKeyHash;
|
|
}
|
|
}
|
|
|
|
//note, hr_old may not be S_OK, accept the response as pkcs7
|
|
hr = acceptPKCS7Blob(pblobResponse);
|
|
if (S_OK != hr)
|
|
{
|
|
if (S_OK != hr_old)
|
|
{
|
|
//return old error instead of new one
|
|
hr = hr_old;
|
|
}
|
|
goto acceptPKCS7BlobError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
//reset hash to zero
|
|
ZeroMemory(&m_blobResponseKAHash, sizeof(m_blobResponseKAHash));
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
if (NULL != prgResponse)
|
|
{
|
|
FreeCMCResponse(prgResponse, cResponse);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(acceptPKCS7BlobError)
|
|
TRACE_ERROR(CMCResponseStatusError)
|
|
TRACE_ERROR(NotSupportedError)
|
|
TRACE_ERROR(InvalidArgError)
|
|
TRACE_ERROR(NullPointerError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::acceptFileResponseWStr(
|
|
IN LPCWSTR pwszResponseFileName)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blob;
|
|
|
|
ZeroMemory(&blob, sizeof(blob));
|
|
|
|
hr = xeStringToBinaryFromFile(
|
|
pwszResponseFileName,
|
|
&blob.pbData,
|
|
&blob.cbData,
|
|
CRYPT_STRING_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeStringToBinaryFromFileError;
|
|
}
|
|
|
|
// accept the blob
|
|
hr = acceptResponseBlob(&blob);
|
|
|
|
ErrorReturn:
|
|
if (NULL != blob.pbData)
|
|
{
|
|
LocalFree(blob.pbData);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(xeStringToBinaryFromFileError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::getCertContextFromResponseBlob(
|
|
IN PCRYPT_DATA_BLOB pblobResponse,
|
|
OUT PCCERT_CONTEXT *ppCertContext)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == ppCertContext)
|
|
{
|
|
hr = E_POINTER;
|
|
goto NullPointerError;
|
|
}
|
|
|
|
//???should check response status?
|
|
|
|
//response is already in pkcs7
|
|
hr = GetEndEntityCert(pblobResponse, FALSE, ppCertContext);
|
|
if (S_OK != hr)
|
|
{
|
|
goto GetEndEntityCertError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
return hr;
|
|
|
|
TRACE_ERROR(NullPointerError)
|
|
TRACE_ERROR(GetEndEntityCertError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::getCertContextFromFileResponseWStr(
|
|
IN LPCWSTR pwszResponseFileName,
|
|
OUT PCCERT_CONTEXT *ppCertContext)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobResponse;
|
|
|
|
ZeroMemory(&blobResponse, sizeof(blobResponse));
|
|
|
|
// could be any form, binary or base64
|
|
hr = xeStringToBinaryFromFile(
|
|
pwszResponseFileName,
|
|
&blobResponse.pbData,
|
|
&blobResponse.cbData,
|
|
CRYPT_STRING_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
goto xeStringToBinaryFromFileError;
|
|
}
|
|
|
|
hr = getCertContextFromResponseBlob(
|
|
&blobResponse,
|
|
ppCertContext);
|
|
if (S_OK != hr)
|
|
{
|
|
goto getCertContextFromResponseBlobError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != blobResponse.pbData)
|
|
{
|
|
LocalFree(blobResponse.pbData);
|
|
}
|
|
return hr;
|
|
|
|
TRACE_ERROR(xeStringToBinaryFromFileError)
|
|
TRACE_ERROR(getCertContextFromResponseBlobError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createPFXWStr(
|
|
IN LPCWSTR pwszPassword,
|
|
OUT PCRYPT_DATA_BLOB pblobPFX)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hMemStore = NULL;
|
|
DWORD i;
|
|
CERT_CHAIN_CONTEXT const *pCertChainContext = NULL;
|
|
CERT_CHAIN_PARA CertChainPara;
|
|
CERT_SIMPLE_CHAIN *pSimpleChain;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if (NULL == pblobPFX)
|
|
{
|
|
goto EPointerError;
|
|
}
|
|
|
|
if (NULL == m_pCertContextStatic)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto UnexpectedError;
|
|
}
|
|
|
|
// create a memory store for cert and chain
|
|
hMemStore = CertOpenStore(
|
|
CERT_STORE_PROV_MEMORY,
|
|
X509_ASN_ENCODING,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
if (NULL == hMemStore)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertOpenStoreError;
|
|
}
|
|
|
|
ZeroMemory(&CertChainPara, sizeof(CertChainPara));
|
|
CertChainPara.cbSize = sizeof(CertChainPara);
|
|
|
|
// try to build cert and chain
|
|
if (!MyCertGetCertificateChain(
|
|
HCCE_CURRENT_USER,
|
|
m_pCertContextStatic,
|
|
NULL,
|
|
NULL,
|
|
&CertChainPara,
|
|
0,
|
|
NULL,
|
|
&pCertChainContext))
|
|
{
|
|
//use 1st hr error
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
//try local machine
|
|
if (!MyCertGetCertificateChain(
|
|
HCCE_LOCAL_MACHINE,
|
|
m_pCertContextStatic,
|
|
NULL,
|
|
NULL,
|
|
&CertChainPara,
|
|
0,
|
|
NULL,
|
|
&pCertChainContext))
|
|
{
|
|
//still use 1st hr
|
|
goto MyCertGetCertificateChainError;
|
|
}
|
|
}
|
|
|
|
// make sure there is at least 1 simple chain
|
|
if (0 == pCertChainContext->cChain)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
goto NoCertificateChainError;
|
|
}
|
|
|
|
//add chain to memory store
|
|
pSimpleChain = pCertChainContext->rgpChain[0];
|
|
for (i = 0; i < pSimpleChain->cElement; i++)
|
|
{
|
|
if (!CertAddCertificateContextToStore(
|
|
hMemStore,
|
|
pSimpleChain->rgpElement[i]->pCertContext,
|
|
CERT_STORE_ADD_REPLACE_EXISTING,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CertAddCertificateContextToStoreError;
|
|
}
|
|
}
|
|
|
|
pblobPFX->pbData = NULL;
|
|
while (TRUE)
|
|
{
|
|
if (!PFXExportCertStore(
|
|
hMemStore,
|
|
pblobPFX,
|
|
pwszPassword,
|
|
EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto PFXExportCertStoreError;
|
|
}
|
|
if (NULL != pblobPFX->pbData)
|
|
{
|
|
//got it, done
|
|
break;
|
|
}
|
|
pblobPFX->pbData = (BYTE*)MyCoTaskMemAlloc(pblobPFX->cbData);
|
|
if (NULL == pblobPFX->pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto MyCoTaskMemAllocError;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
if (pCertChainContext != NULL)
|
|
{
|
|
MyCertFreeCertificateChain(pCertChainContext);
|
|
}
|
|
if (NULL != hMemStore)
|
|
{
|
|
CertCloseStore(hMemStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
return hr;
|
|
|
|
|
|
TRACE_ERROR(UnexpectedError)
|
|
TRACE_ERROR(CertOpenStoreError)
|
|
TRACE_ERROR(PFXExportCertStoreError)
|
|
TRACE_ERROR(MyCoTaskMemAllocError)
|
|
TRACE_ERROR(CertAddCertificateContextToStoreError)
|
|
TRACE_ERROR(NoCertificateChainError)
|
|
TRACE_ERROR(MyCertGetCertificateChainError)
|
|
SET_HRESULT(EPointerError, E_POINTER)
|
|
}
|
|
|
|
HRESULT
|
|
CCEnroll::createPFXWStrBStr(
|
|
IN LPCWSTR pwszPassword,
|
|
OUT BSTR __RPC_FAR *pbstrPFX)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobPFX;
|
|
|
|
memset(&blobPFX, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
hr = createPFXWStr(pwszPassword, &blobPFX);
|
|
if (S_OK != hr)
|
|
{
|
|
goto createPFXWStrError;
|
|
}
|
|
|
|
// convert pfx to bstr
|
|
hr = BlobToBstring(&blobPFX, CRYPT_STRING_BASE64, pbstrPFX);
|
|
if (S_OK != hr)
|
|
{
|
|
goto BlobToBstringError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(NULL != blobPFX.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobPFX.pbData);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(createPFXWStrError)
|
|
TRACE_ERROR(BlobToBstringError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::createFilePFXWStr(
|
|
IN LPCWSTR pwszPassword,
|
|
IN LPCWSTR pwszPFXFileName)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hFile = NULL;
|
|
DWORD cb = 0;
|
|
CRYPT_DATA_BLOB blobPFX;
|
|
|
|
memset(&blobPFX, 0, sizeof(CRYPT_DATA_BLOB));
|
|
|
|
hr = createPFXWStr(pwszPassword, &blobPFX);
|
|
if (S_OK != hr)
|
|
{
|
|
goto createPFXWStrError;
|
|
}
|
|
|
|
// open the file
|
|
hFile = CreateFileSafely(pwszPFXFileName);
|
|
if (NULL == hFile)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto CreateFileFileSafelyError;
|
|
}
|
|
|
|
// write the pkcs10
|
|
if(!WriteFile(
|
|
hFile,
|
|
blobPFX.pbData,
|
|
blobPFX.cbData,
|
|
&cb,
|
|
NULL))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
goto WriteFileError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if(NULL != hFile)
|
|
{
|
|
CloseHandle(hFile);
|
|
}
|
|
if(NULL != blobPFX.pbData)
|
|
{
|
|
MyCoTaskMemFree(blobPFX.pbData);
|
|
}
|
|
return(hr);
|
|
|
|
TRACE_ERROR(createPFXWStrError)
|
|
TRACE_ERROR(CreateFileFileSafelyError)
|
|
TRACE_ERROR(WriteFileError)
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::setPendingRequestInfoWStr(
|
|
IN LONG lRequestID,
|
|
IN LPCWSTR pwszCADNS,
|
|
IN LPCWSTR pwszCAName,
|
|
IN LPCWSTR pwszFriendlyName
|
|
)
|
|
{
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// Define locally-scoped helper functions:
|
|
//
|
|
//------------------------------------------------------------
|
|
|
|
CEnrollLocalScope(SetPendingRequestInfoHelper):
|
|
// Finds the appropriate cert context to set pending info on using the following algorithm:
|
|
// 1) If a hash value HAS NOT been specified, use the cached cert request.
|
|
// 2) If a hash value HAS been specified, search the request store for a cert with an equivalent
|
|
// hash value and return it. If no such cert can be found, return an error code.
|
|
HRESULT GetPendingRequestCertContext(IN HCERTSTORE hStoreRequest,
|
|
IN CRYPT_DATA_BLOB hashBlob,
|
|
IN PCCERT_CONTEXT pCertContextCachedPendingRequest,
|
|
OUT PCCERT_CONTEXT *pCertContextPendingRequest)
|
|
{
|
|
EquivalentHashCertContextFilter filter(hashBlob);
|
|
|
|
if (hashBlob.pbData == NULL)
|
|
{
|
|
// We haven't specified a particular context, use the one we've cached.
|
|
*pCertContextPendingRequest = CertDuplicateCertificateContext(pCertContextCachedPendingRequest);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
// Returns the first certificate in the request store with a hash matching
|
|
// pHashBlob.
|
|
return FilteredCertEnumCertificatesInStore
|
|
(hStoreRequest, NULL, &filter, pCertContextPendingRequest);
|
|
}
|
|
}
|
|
|
|
|
|
DWORD GetPendingInfoBlobSize(IN LONG lRequestID,
|
|
IN LPCWSTR pwszCADNS,
|
|
IN LPCWSTR pwszCAName,
|
|
IN LPCWSTR pwszFriendlyName)
|
|
{
|
|
assert(pwszCADNS != NULL && pwszCAName != NULL && pwszFriendlyName != NULL);
|
|
|
|
return (DWORD)(sizeof(lRequestID) + // Request ID
|
|
sizeof(DWORD) + // wcslen(pwszCADNS)
|
|
sizeof(WCHAR) * (wcslen(pwszCADNS) + 1) + // pwszCADNS
|
|
sizeof(DWORD) + // wcslen(pwszCAName)
|
|
sizeof(WCHAR) * (wcslen(pwszCAName) + 1) + // pwszCAName
|
|
sizeof(DWORD) + // wcslen(pwszFriendlyName)
|
|
sizeof(WCHAR) * (wcslen(pwszFriendlyName) + 1) // pwszFriendlyName
|
|
);
|
|
}
|
|
|
|
|
|
// Combines the supplied pending request information into a CRYPT_DATA_BLOB
|
|
// See wincrypt.h for the format.
|
|
void MakePendingInfoBlob(IN LONG lRequestID,
|
|
IN LPCWSTR pwszCADNS,
|
|
IN LPCWSTR pwszCAName,
|
|
IN LPCWSTR pwszFriendlyName,
|
|
OUT CRYPT_DATA_BLOB pendingInfoBlob)
|
|
{
|
|
LPBYTE pbBlob;
|
|
|
|
// None of the inputs should be NULL.
|
|
assert(pwszCADNS != NULL && pwszCAName != NULL && pwszFriendlyName != NULL);
|
|
|
|
// Declare an array of the strings we wish to write to the pending info blob
|
|
struct StringsToWrite {
|
|
DWORD cc;
|
|
LPCWSTR pwsz;
|
|
} rgStrings[] = {
|
|
{ (DWORD)wcslen(pwszCADNS) + 1, pwszCADNS },
|
|
{ (DWORD)wcslen(pwszCAName) + 1, pwszCAName },
|
|
{ (DWORD)wcslen(pwszFriendlyName) + 1, pwszFriendlyName }
|
|
};
|
|
|
|
// Write the request ID to the blob
|
|
pbBlob = pendingInfoBlob.pbData;
|
|
memcpy(pbBlob, &lRequestID, sizeof(lRequestID));
|
|
pbBlob += sizeof(lRequestID);
|
|
|
|
// Write all strings to the blob
|
|
for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStrings); dwIndex++)
|
|
{
|
|
memcpy(pbBlob, &rgStrings[dwIndex].cc, sizeof(rgStrings[dwIndex].cc));
|
|
pbBlob += sizeof(rgStrings[dwIndex].cc);
|
|
memcpy(pbBlob, rgStrings[dwIndex].pwsz, rgStrings[dwIndex].cc * sizeof(WCHAR));
|
|
pbBlob += rgStrings[dwIndex].cc * sizeof(WCHAR);
|
|
}
|
|
|
|
assert(pbBlob == (pendingInfoBlob.pbData + pendingInfoBlob.cbData));
|
|
}
|
|
CEnrollEndLocalScope;
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// Begin procedure body.
|
|
//
|
|
//------------------------------------------------------------
|
|
|
|
CRYPT_DATA_BLOB pendingInfoBlob;
|
|
HCERTSTORE hStoreRequest;
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContextPendingRequest = NULL;
|
|
|
|
ZeroMemory(&pendingInfoBlob, sizeof(pendingInfoBlob));
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// Input validation:
|
|
if (lRequestID < 0 || pwszCADNS == NULL || pwszCAName == NULL)
|
|
goto InvalidArgErr;
|
|
|
|
// NULL is a valid value for pwszFriendlyName. If friendly name is NULL, replace with the empty string:
|
|
if (pwszFriendlyName == NULL) { pwszFriendlyName = L""; }
|
|
|
|
if (NULL == (hStoreRequest = GetStore(StoreREQUEST)) )
|
|
goto GetStoreErr;
|
|
|
|
// Use our locally-scoped helper function to acquire the appropriate certificate context.
|
|
if (S_OK != (hr = local.GetPendingRequestCertContext
|
|
(hStoreRequest,
|
|
m_hashBlobPendingRequest,
|
|
m_pCertContextPendingRequest,
|
|
&pCertContextPendingRequest)))
|
|
goto GetPendingRequestCertContextErr;
|
|
|
|
// Allocate memory for our pending info blob:
|
|
pendingInfoBlob.cbData = local.GetPendingInfoBlobSize
|
|
(lRequestID,
|
|
pwszCADNS,
|
|
pwszCAName,
|
|
pwszFriendlyName);
|
|
pendingInfoBlob.pbData = (LPBYTE)LocalAlloc(LPTR, pendingInfoBlob.cbData);
|
|
if (NULL == pendingInfoBlob.pbData)
|
|
goto MemoryErr;
|
|
|
|
// Combine our arguments into a "pending info" blob.
|
|
local.MakePendingInfoBlob
|
|
(lRequestID,
|
|
pwszCADNS,
|
|
pwszCAName,
|
|
pwszFriendlyName,
|
|
pendingInfoBlob);
|
|
|
|
// Use our pending info blob to assign the certificate context property.
|
|
if (!CertSetCertificateContextProperty
|
|
(pCertContextPendingRequest,
|
|
CERT_ENROLLMENT_PROP_ID,
|
|
0,
|
|
&pendingInfoBlob))
|
|
{
|
|
// Failed to set the context property.
|
|
goto CertSetCertificateContextPropertyErr;
|
|
}
|
|
|
|
// We've completed successfully.
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
if (NULL != pendingInfoBlob.pbData) { LocalFree(pendingInfoBlob.pbData); }
|
|
if (NULL != pCertContextPendingRequest) { CertFreeCertificateContext(pCertContextPendingRequest); }
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CertSetCertificateContextPropertyErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(GetPendingRequestCertContextErr, hr);
|
|
SET_HRESULT(GetStoreErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(InvalidArgErr, E_INVALIDARG);
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//
|
|
// THIS METHOD IS NOT SAFE FOR SCRIPTING
|
|
//
|
|
//--------------------------------------------------------------------------------
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::enumPendingRequestWStr(
|
|
IN LONG lIndex,
|
|
IN LONG lDesiredProperty,
|
|
OUT LPVOID ppProperty
|
|
)
|
|
{
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// Define locally scoped helper functions.
|
|
//
|
|
//------------------------------------------------------------
|
|
|
|
CEnrollLocalScope(EnumPendingRequestHelper):
|
|
CRYPT_DATA_BLOB dataBlob;
|
|
|
|
HRESULT GetContextPropertySimple(PCCERT_CONTEXT pCertContext, DWORD dwPropID)
|
|
{
|
|
BOOL fDone = FALSE;
|
|
dataBlob.pbData = NULL;
|
|
dataBlob.cbData = 0x150;
|
|
|
|
do {
|
|
if (dataBlob.pbData != NULL) { LocalFree(dataBlob.pbData); }
|
|
|
|
dataBlob.pbData = (LPBYTE)LocalAlloc(LPTR, dataBlob.cbData);
|
|
if (dataBlob.pbData == NULL) { return E_OUTOFMEMORY; }
|
|
|
|
if (!CertGetCertificateContextProperty
|
|
(pCertContext,
|
|
dwPropID,
|
|
(LPVOID)dataBlob.pbData,
|
|
&(dataBlob.cbData)))
|
|
{
|
|
if (GetLastError() != ERROR_MORE_DATA)
|
|
return MY_HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
else
|
|
{
|
|
fDone = TRUE;
|
|
}
|
|
} while (!fDone);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// Extracts the next packed string from our pending info blob.
|
|
// If pbString is non-NULL, it must be large enough to hold the entire string.
|
|
LPBYTE GetNextString(IN LPBYTE pbBlob, OUT DWORD *pcbSize, OUT LPBYTE pbString) {
|
|
DWORD dwSize;
|
|
|
|
memcpy(&dwSize, pbBlob, sizeof(DWORD));
|
|
dwSize *= sizeof(WCHAR); // Convert to count in bytes.
|
|
if (NULL != pcbSize) {
|
|
*pcbSize = dwSize;
|
|
}
|
|
pbBlob += sizeof(DWORD);
|
|
|
|
if (NULL != pbString) {
|
|
memcpy(pbString, pbBlob, dwSize);
|
|
}
|
|
pbBlob += dwSize;
|
|
|
|
return pbBlob;
|
|
}
|
|
|
|
|
|
HRESULT getRequestID(PCCERT_CONTEXT pCertContext, long *pplProperty) {
|
|
HRESULT hr;
|
|
if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID)))
|
|
*pplProperty = *((long *)dataBlob.pbData);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT getCAName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) {
|
|
DWORD dwSize;
|
|
HRESULT hr;
|
|
LPBYTE pb;
|
|
|
|
if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID)))
|
|
{
|
|
pb = dataBlob.pbData + sizeof(DWORD); // pb points to DNS Name blob
|
|
pb = GetNextString(pb, NULL, NULL); // pb points to CA Name blob
|
|
GetNextString(pb, &dwSize, NULL); // dwSize = size in chars of CA Name
|
|
|
|
// If pbData is NULL, we're just doing a size check.
|
|
if (pDataBlobProperty->pbData != NULL)
|
|
{
|
|
if (pDataBlobProperty->cbData < dwSize)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
|
}
|
|
else
|
|
{
|
|
GetNextString(pb, NULL, pDataBlobProperty->pbData);
|
|
}
|
|
}
|
|
|
|
pDataBlobProperty->cbData = dwSize;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT getCADNSName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) {
|
|
DWORD dwSize;
|
|
HRESULT hr;
|
|
LPBYTE pb;
|
|
|
|
if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID)))
|
|
{
|
|
pb = dataBlob.pbData + sizeof(DWORD); // pb points to DNS Name blob
|
|
GetNextString(pb, &dwSize, NULL); // dwSize = size in chars of CA Name
|
|
|
|
// If pbData is NULL, we're just doing a size check.
|
|
if (pDataBlobProperty->pbData != NULL)
|
|
{
|
|
if (pDataBlobProperty->cbData < dwSize)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
|
}
|
|
else
|
|
{
|
|
GetNextString(pb, NULL, pDataBlobProperty->pbData);
|
|
}
|
|
}
|
|
|
|
pDataBlobProperty->cbData = dwSize;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT getCAFriendlyName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) {
|
|
DWORD dwSize;
|
|
HRESULT hr;
|
|
LPBYTE pb;
|
|
|
|
if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID)))
|
|
{
|
|
// Set pb to point to the start of the CA name blob
|
|
pb = dataBlob.pbData + sizeof(DWORD); // pb points to DNS Name blob
|
|
pb = GetNextString(pb, NULL, NULL); // pb points to CA Name blob
|
|
pb = GetNextString(pb, NULL, NULL); // pb points to Friendly Name blob
|
|
|
|
// dwSize <-- size in chars of CA Name
|
|
GetNextString(pb, &dwSize, NULL);
|
|
|
|
// If pbData is NULL, we're just doing a size check.
|
|
if (pDataBlobProperty->pbData != NULL)
|
|
{
|
|
if (pDataBlobProperty->cbData < dwSize)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
|
}
|
|
else
|
|
{
|
|
GetNextString(pb, NULL, pDataBlobProperty->pbData);
|
|
}
|
|
}
|
|
|
|
pDataBlobProperty->cbData = dwSize;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT getHash(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) {
|
|
HRESULT hr;
|
|
|
|
if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_HASH_PROP_ID)))
|
|
{
|
|
// If pbData is NULL, we're just doing a size check.
|
|
if (pDataBlobProperty->pbData != NULL)
|
|
{
|
|
if (pDataBlobProperty->cbData < dataBlob.cbData)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA);
|
|
}
|
|
else
|
|
{
|
|
memcpy(pDataBlobProperty->pbData, dataBlob.pbData, dataBlob.cbData);
|
|
}
|
|
}
|
|
|
|
pDataBlobProperty->cbData = dataBlob.cbData;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT getDate(PCCERT_CONTEXT pCertContext, PFILETIME pftProperty) {
|
|
*pftProperty = pCertContext->pCertInfo->NotAfter;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT getTemplateName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) {
|
|
CERT_NAME_VALUE *pCertTemplateNameValue = NULL;
|
|
DWORD cbCertTemplateNameValue;
|
|
DWORD cbRequired = 0;
|
|
HRESULT hr = S_OK;
|
|
PCERT_EXTENSION pCertTemplateExtension = NULL;
|
|
|
|
if (NULL == (pCertTemplateExtension = CertFindExtension
|
|
(szOID_ENROLL_CERTTYPE_EXTENSION,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension)))
|
|
return E_INVALIDARG;
|
|
|
|
if (!CryptDecodeObject
|
|
(pCertContext->dwCertEncodingType,
|
|
X509_UNICODE_ANY_STRING,
|
|
pCertTemplateExtension->Value.pbData,
|
|
pCertTemplateExtension->Value.cbData,
|
|
0,
|
|
NULL,
|
|
&cbCertTemplateNameValue) || (cbCertTemplateNameValue == 0))
|
|
goto CryptDecodeObjectErr;
|
|
|
|
pCertTemplateNameValue = (CERT_NAME_VALUE *)LocalAlloc(LPTR, cbCertTemplateNameValue);
|
|
if (NULL == pCertTemplateNameValue)
|
|
goto MemoryErr;
|
|
|
|
if (!CryptDecodeObject
|
|
(pCertContext->dwCertEncodingType,
|
|
X509_UNICODE_ANY_STRING,
|
|
pCertTemplateExtension->Value.pbData,
|
|
pCertTemplateExtension->Value.cbData,
|
|
0,
|
|
(void *)(pCertTemplateNameValue),
|
|
&cbCertTemplateNameValue))
|
|
goto CryptDecodeObjectErr;
|
|
|
|
cbRequired = sizeof(WCHAR) * (DWORD)(wcslen((LPWSTR)(pCertTemplateNameValue->Value.pbData)) + 1);
|
|
if (NULL != pDataBlobProperty->pbData)
|
|
{
|
|
// Make sure we've allocated a large enough buffer:
|
|
if (pDataBlobProperty->cbData < cbRequired) { goto MoreDataErr; }
|
|
|
|
// Write the template name to the OUT param:
|
|
wcscpy((LPWSTR)pDataBlobProperty->pbData, (LPWSTR)(pCertTemplateNameValue->Value.pbData));
|
|
}
|
|
|
|
hr = S_OK;
|
|
CommonReturn:
|
|
// Assign the size of the template name to the cb of the OUT param.
|
|
// This should be done for all code paths.
|
|
pDataBlobProperty->cbData = cbRequired;
|
|
|
|
// Free resources:
|
|
if (NULL != pCertTemplateNameValue) { LocalFree(pCertTemplateNameValue); }
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CryptDecodeObjectErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MoreDataErr, MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
}
|
|
|
|
HRESULT getTemplateOID(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) {
|
|
CERT_TEMPLATE_EXT *pCertTemplateExt = NULL;
|
|
DWORD cbCertTemplateExt = 0;
|
|
DWORD cbRequired = 0;
|
|
HRESULT hr;
|
|
LPWSTR pwszOID = NULL;
|
|
PCERT_EXTENSION pCertExtension = NULL;
|
|
|
|
if (NULL == (pCertExtension = CertFindExtension
|
|
(szOID_CERTIFICATE_TEMPLATE,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension)))
|
|
return E_INVALIDARG;
|
|
|
|
if (FALSE == CryptDecodeObject
|
|
(pCertContext->dwCertEncodingType,
|
|
X509_CERTIFICATE_TEMPLATE,
|
|
pCertExtension->Value.pbData,
|
|
pCertExtension->Value.cbData,
|
|
0,
|
|
NULL,
|
|
&cbCertTemplateExt) || (cbCertTemplateExt == 0))
|
|
goto CryptDecodeObjectErr;
|
|
|
|
pCertTemplateExt = (CERT_TEMPLATE_EXT *)LocalAlloc(LPTR, cbCertTemplateExt);
|
|
if (NULL == pCertTemplateExt)
|
|
goto MemoryErr;
|
|
|
|
if (FALSE == CryptDecodeObject
|
|
(pCertContext->dwCertEncodingType,
|
|
X509_CERTIFICATE_TEMPLATE,
|
|
pCertExtension->Value.pbData,
|
|
pCertExtension->Value.cbData,
|
|
0,
|
|
(void *)(pCertTemplateExt),
|
|
&cbCertTemplateExt))
|
|
goto CryptDecodeObjectErr;
|
|
|
|
cbRequired = sizeof(WCHAR) * (DWORD)(strlen(pCertTemplateExt->pszObjId) + 1);
|
|
|
|
// See if we're just doing a size check:
|
|
if (NULL != pDataBlobProperty->pbData)
|
|
{
|
|
// Make sure we've allocated a large enough buffer:
|
|
if (pDataBlobProperty->cbData < cbRequired) { goto MoreDataErr; }
|
|
|
|
// Convert the OID to a LPWSTR:
|
|
pwszOID = WideFromMB(pCertTemplateExt->pszObjId);
|
|
if (NULL == pwszOID)
|
|
goto WideFromMBErr;
|
|
|
|
// Write the template OID to the OUT param:
|
|
wcscpy((LPWSTR)pDataBlobProperty->pbData, pwszOID);
|
|
}
|
|
|
|
hr = S_OK;
|
|
CommonReturn:
|
|
// Assign the size of the OID to the cb of the OUT param.
|
|
// This should be done for all code paths.
|
|
pDataBlobProperty->cbData = cbRequired;
|
|
|
|
// Free resources:
|
|
if (NULL != pCertTemplateExt) { LocalFree(pCertTemplateExt); }
|
|
if (NULL != pwszOID) { MyCoTaskMemFree(pwszOID); }
|
|
|
|
return hr;
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CryptDecodeObjectErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
SET_HRESULT(MoreDataErr, MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA));
|
|
SET_HRESULT(WideFromMBErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
HRESULT getVersion(PCCERT_CONTEXT pCertContext, long *plVersion) {
|
|
CERT_TEMPLATE_EXT *pCertTemplateExt = NULL;
|
|
DWORD cbCertTemplateExt = 0;
|
|
HRESULT hr;
|
|
PCERT_EXTENSION pCertExtension = NULL;
|
|
|
|
if (NULL == (pCertExtension = CertFindExtension
|
|
(szOID_CERTIFICATE_TEMPLATE,
|
|
pCertContext->pCertInfo->cExtension,
|
|
pCertContext->pCertInfo->rgExtension)))
|
|
return E_INVALIDARG;
|
|
|
|
if (FALSE == CryptDecodeObject
|
|
(pCertContext->dwCertEncodingType,
|
|
X509_CERTIFICATE_TEMPLATE,
|
|
pCertExtension->Value.pbData,
|
|
pCertExtension->Value.cbData,
|
|
0,
|
|
NULL,
|
|
&cbCertTemplateExt) || (cbCertTemplateExt == 0))
|
|
goto CryptDecodeObjectErr;
|
|
|
|
pCertTemplateExt = (CERT_TEMPLATE_EXT *)LocalAlloc(LPTR, cbCertTemplateExt);
|
|
if (NULL == pCertTemplateExt)
|
|
goto MemoryErr;
|
|
|
|
if (FALSE == CryptDecodeObject
|
|
(pCertContext->dwCertEncodingType,
|
|
X509_CERTIFICATE_TEMPLATE,
|
|
pCertExtension->Value.pbData,
|
|
pCertExtension->Value.cbData,
|
|
0,
|
|
(void *)(pCertTemplateExt),
|
|
&cbCertTemplateExt))
|
|
goto CryptDecodeObjectErr;
|
|
|
|
*plVersion = (long)pCertTemplateExt->dwMajorVersion;
|
|
hr = S_OK;
|
|
CommonReturn:
|
|
// Free resources:
|
|
if (NULL != pCertTemplateExt) { LocalFree(pCertTemplateExt); }
|
|
|
|
return hr;
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CryptDecodeObjectErr, MY_HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
}
|
|
|
|
void InitLocalScope() {
|
|
dataBlob.cbData = 0;
|
|
dataBlob.pbData = NULL;
|
|
}
|
|
|
|
void FreeLocalScope() { if (dataBlob.pbData != NULL) { LocalFree(dataBlob.pbData); } }
|
|
|
|
CEnrollEndLocalScope;
|
|
|
|
//------------------------------------------------------------
|
|
//
|
|
// Begin procedure body.
|
|
//
|
|
//------------------------------------------------------------
|
|
|
|
// FIXME: index is 0 based, correct?
|
|
// m_dwLastPendingRequestIndex = 0;
|
|
// m_pCertContextLastEnumerated
|
|
|
|
HCERTSTORE hStoreRequest = NULL;
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
// Input validiation:
|
|
if (lIndex != XEPR_ENUM_FIRST && (lIndex < 0 || (ppProperty == NULL)))
|
|
return E_INVALIDARG;
|
|
|
|
if (0 != m_dwEnabledSafteyOptions) // not safe for scripting
|
|
return E_ACCESSDENIED;
|
|
|
|
// Init:
|
|
local.InitLocalScope();
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
if ( NULL == (hStoreRequest = GetStore(StoreREQUEST)) )
|
|
goto ErrorCertOpenRequestStore;
|
|
|
|
// If we're passed the ENUM_FIRST flag, reconstruct a snapshot of the request store.
|
|
//
|
|
if (lIndex == XEPR_ENUM_FIRST)
|
|
{
|
|
if (NULL != this->m_pPendingRequestTable) { delete this->m_pPendingRequestTable; }
|
|
|
|
this->m_pPendingRequestTable = new PendingRequestTable;
|
|
if (NULL == this->m_pPendingRequestTable)
|
|
goto MemoryErr;
|
|
|
|
if (S_OK != (hr = this->m_pPendingRequestTable->construct(hStoreRequest)))
|
|
goto ErrorConstructPendingTable;
|
|
|
|
// All done, return.
|
|
goto CommonReturn;
|
|
}
|
|
|
|
// We want the lIndex'th element the request store.
|
|
// First, ensure that the enumeration is initialized:
|
|
if (NULL == m_pPendingRequestTable)
|
|
goto PointerErr;
|
|
|
|
// Index past the end of the table.
|
|
if (this->m_pPendingRequestTable->size() <= (DWORD)lIndex)
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pCertContext = (*this->m_pPendingRequestTable)[(DWORD)lIndex];
|
|
|
|
switch (lDesiredProperty)
|
|
{
|
|
case XEPR_REQUESTID: hr = local.getRequestID (pCertContext, (long *)ppProperty); break;
|
|
case XEPR_CANAME: hr = local.getCAName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break;
|
|
case XEPR_CAFRIENDLYNAME: hr = local.getCAFriendlyName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break;
|
|
case XEPR_CADNS: hr = local.getCADNSName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break;
|
|
case XEPR_DATE: hr = local.getDate (pCertContext, (PFILETIME)ppProperty); break;
|
|
case XEPR_V1TEMPLATENAME: hr = local.getTemplateName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break;
|
|
case XEPR_V2TEMPLATEOID: hr = local.getTemplateOID (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break;
|
|
case XEPR_VERSION: hr = local.getVersion (pCertContext, (long *)ppProperty); break;
|
|
case XEPR_HASH: hr = local.getHash (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break;
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
CommonReturn:
|
|
local.FreeLocalScope();
|
|
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
SET_HRESULT(PointerErr, E_POINTER);
|
|
TRACE_ERROR(ErrorCertOpenRequestStore);
|
|
TRACE_ERROR(ErrorConstructPendingTable);
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE
|
|
CCEnroll::removePendingRequestWStr
|
|
(IN CRYPT_DATA_BLOB thumbPrintBlob
|
|
)
|
|
{
|
|
EquivalentHashCertContextFilter equivHashFilter(thumbPrintBlob);
|
|
PendingCertContextFilter pendingCertFilter;
|
|
// combinedFilter now only allows PENDING requests which match the specified thumbprint.
|
|
CompositeCertContextFilter combinedFilter(&equivHashFilter, &pendingCertFilter);
|
|
|
|
HCERTSTORE hStoreRequest = NULL;
|
|
HRESULT hr;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
|
|
EnterCriticalSection(&m_csXEnroll);
|
|
|
|
// Input validation.
|
|
if (NULL == thumbPrintBlob.pbData)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
|
|
if ( NULL == (hStoreRequest = GetStore(StoreREQUEST)) )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (S_OK != (hr = FilteredCertEnumCertificatesInStore
|
|
(hStoreRequest,
|
|
NULL,
|
|
&combinedFilter,
|
|
&pCertContext)))
|
|
goto ErrorReturn;
|
|
|
|
if (!CertDeleteCertificateFromStore(pCertContext))
|
|
{
|
|
hr = MY_HRESULT_FROM_WIN32(GetLastError());
|
|
// CertDeleteCertificateFromStore *always* deletes the cert context.
|
|
pCertContext = NULL;
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
pCertContext = NULL;
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
LeaveCriticalSection(&m_csXEnroll);
|
|
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
if (pCertContext != NULL) { CertFreeCertificateContext(pCertContext); }
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
HRESULT FilteredCertEnumCertificatesInStore(IN HCERTSTORE hStore,
|
|
IN PCCERT_CONTEXT pCertContext,
|
|
IN CertContextFilter *pFilter,
|
|
OUT PCCERT_CONTEXT *pCertContextNext)
|
|
{
|
|
BOOL fFilterResult;
|
|
HRESULT hr = S_OK;
|
|
PCCERT_CONTEXT pCertContextPrev = pCertContext;
|
|
|
|
while (NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertContextPrev)))
|
|
{
|
|
if (S_OK != (hr = pFilter->accept(pCertContext, &fFilterResult)))
|
|
return hr;
|
|
|
|
if (fFilterResult) // We've found the next cert context in the filtered enumeration.
|
|
{
|
|
*pCertContextNext = pCertContext;
|
|
return S_OK;
|
|
}
|
|
pCertContextPrev = pCertContext;
|
|
}
|
|
|
|
return MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND);
|
|
}
|
|
|
|
static LPVOID MyLocalAlloc(ULONG cb) {
|
|
return((LPVOID) LocalAlloc(LPTR, (UINT) cb));
|
|
}
|
|
|
|
static LPVOID MyLocalRealloc(LPVOID ptr, ULONG cb) {
|
|
return((LPVOID) LocalReAlloc((HLOCAL) ptr, (UINT) cb, LMEM_MOVEABLE));
|
|
}
|
|
|
|
static void MyLocalFree(LPVOID ptr) {
|
|
LocalFree((HLOCAL) ptr);
|
|
}
|
|
|
|
|
|
//
|
|
// From xtan, an explanation of the "no-COM" APIs:
|
|
// "In early time xenroll interface IDs were not in uuid.lib so this
|
|
// was a convenient C interface for people to get xenroll COM interfaces without
|
|
// call CoCreateInstance. It is not in MSDN but it is in SDK headers.
|
|
// I created the same API for consistency when I created ICEnroll4."
|
|
//
|
|
void * WINAPI PGetIEnrollNoCOM(const IID &iid) {
|
|
|
|
void * pvoid = NULL;
|
|
IClassFactory * pIClassFactory = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
MyCoTaskMemAlloc = MyLocalAlloc;
|
|
MyCoTaskMemFree = MyLocalFree;
|
|
MyCoTaskMemRealloc = MyLocalRealloc;
|
|
|
|
if( S_OK != (hr = DllGetClassObject(CLSID_CEnroll2, IID_IClassFactory, (void **) &pIClassFactory)) ) {
|
|
pIClassFactory = NULL;
|
|
}
|
|
else if( S_OK != (hr = pIClassFactory->CreateInstance(NULL, iid, &pvoid)) ) {
|
|
pvoid = NULL;
|
|
}
|
|
|
|
if(pIClassFactory != NULL) {
|
|
pIClassFactory->Release();
|
|
pIClassFactory = NULL;
|
|
}
|
|
|
|
SetLastError(hr);
|
|
return(pvoid);
|
|
}
|
|
|
|
IEnroll * WINAPI PIEnrollGetNoCOM(void)
|
|
{
|
|
return( (IEnroll *) PGetIEnrollNoCOM(IID_IEnroll) );
|
|
}
|
|
|
|
IEnroll2 * WINAPI PIEnroll2GetNoCOM(void)
|
|
{
|
|
return( (IEnroll2 *) PGetIEnrollNoCOM(IID_IEnroll2) );
|
|
}
|
|
|
|
IEnroll4 * WINAPI PIEnroll4GetNoCOM(void)
|
|
{
|
|
return( (IEnroll4 *) PGetIEnrollNoCOM(IID_IEnroll4) );
|
|
}
|
|
|
|
HRESULT PendingRequestTable::resize(DWORD dwNewSize)
|
|
{
|
|
TableElem * newTable = NULL;
|
|
|
|
if (dwNewSize <= 0)
|
|
return E_INVALIDARG;
|
|
|
|
newTable = (TableElem *)LocalAlloc(LPTR, sizeof(TableElem) * dwNewSize);
|
|
if (NULL == newTable)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (NULL != this->table)
|
|
{
|
|
memcpy(newTable, this->table, this->dwElemSize * sizeof(TableElem));
|
|
LocalFree(this->table);
|
|
}
|
|
|
|
this->dwElemSize = dwNewSize;
|
|
this->table = newTable;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT PendingRequestTable::add(TableElem tePendingRequest)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (this->dwElemCount > this->dwElemSize) { return E_UNEXPECTED; }
|
|
else if (this->dwElemCount == this->dwElemSize)
|
|
{
|
|
// Need to allocate more memory:
|
|
DWORD dwNewSize = this->dwElemSize < 100 ? 100 : this->dwElemSize * 2;
|
|
|
|
if (S_OK != (hr = this->resize(dwNewSize)))
|
|
return hr;
|
|
}
|
|
|
|
this->table[this->dwElemCount++] = tePendingRequest;
|
|
return S_OK;
|
|
}
|
|
|
|
PendingRequestTable::PendingRequestTable() : table(NULL), dwElemSize(0), dwElemCount(0)
|
|
{ }
|
|
|
|
PendingRequestTable::~PendingRequestTable()
|
|
{
|
|
if (NULL != this->table)
|
|
{
|
|
for (DWORD dwIndex = 0; dwIndex < dwElemCount; dwIndex++)
|
|
{
|
|
CertFreeCertificateContext(this->table[dwIndex].pCertContext);
|
|
}
|
|
|
|
LocalFree(this->table);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HRESULT PendingRequestTable::construct(HCERTSTORE hStore)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PendingCertContextFilter pendingFilter;
|
|
PCCERT_CONTEXT pCertContext = NULL;
|
|
PCCERT_CONTEXT pCertContextPrev = NULL;
|
|
TableElem tePendingRequest;
|
|
|
|
// Enumerate all pending cert contexts, and add them to our table:
|
|
for (DWORD dwIndex = 0; TRUE; dwIndex++)
|
|
{
|
|
if (S_OK != (hr = FilteredCertEnumCertificatesInStore
|
|
(hStore,
|
|
pCertContextPrev,
|
|
&pendingFilter,
|
|
&pCertContext)))
|
|
break;
|
|
|
|
tePendingRequest.pCertContext = CertDuplicateCertificateContext(pCertContext);
|
|
this->add(tePendingRequest);
|
|
|
|
pCertContextPrev = pCertContext;
|
|
}
|
|
|
|
return hr == MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND) ? S_OK : hr;
|
|
}
|