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.
4145 lines
106 KiB
4145 lines
106 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 2001
|
|
|
|
Module Name:
|
|
|
|
Windows for Smart Cards Base CSP
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
Dan Griffin
|
|
|
|
Notes:
|
|
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4201)
|
|
// Disable error C4201 in public header
|
|
// nonstandard extension used : nameless struct/union
|
|
#include <winscard.h>
|
|
#pragma warning(pop)
|
|
|
|
#include <cspdk.h>
|
|
#include <md5.h>
|
|
#include <stdlib.h>
|
|
#include "basecsp.h"
|
|
#include "cardmod.h"
|
|
#include "datacach.h"
|
|
#include "pincache.h"
|
|
#include "pinlib.h"
|
|
#include "resource.h"
|
|
#include "debug.h"
|
|
#include "compress.h"
|
|
|
|
extern DWORD
|
|
WINAPI
|
|
Asn1UtilAdjustEncodedLength(
|
|
IN const BYTE *pbDER,
|
|
IN DWORD cbDER
|
|
);
|
|
|
|
//
|
|
// Debugging Macros
|
|
//
|
|
#define LOG_BEGIN_FUNCTION(x) \
|
|
{ DebugLog((DEB_TRACE_CSP, "%s: Entering\n", #x)); }
|
|
|
|
#define LOG_END_FUNCTION(x, y) \
|
|
{ DebugLog((DEB_TRACE_CSP, "%s: Leaving, status: 0x%x\n", #x, y)); }
|
|
|
|
#define LOG_BEGIN_CRYPTOAPI(x) \
|
|
{ DebugLog((DEB_TRACE_CRYPTOAPI, "%s: Entering\n", #x)); }
|
|
|
|
#define LOG_END_CRYPTOAPI(x, y) \
|
|
{ DebugLog((DEB_TRACE_CRYPTOAPI, "%s: Leaving, status: 0x%x\n", #x, y)); }
|
|
//
|
|
// When receiving an encoded certificate from the calling application,
|
|
// the current interface doesn't include a length, so we have to try
|
|
// to determine the length of the encoded blob ourselves. If there's an
|
|
// encoding error, we'll just walk off the end of the buffer, so set this
|
|
// maximum.
|
|
//
|
|
#define cbENCODED_CERT_OVERFLOW 5000 // Bytes
|
|
|
|
#define PROVPATH "SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\"
|
|
#define PROVPATH_LEN sizeof(PROVPATH)
|
|
|
|
//
|
|
// Local structure definitions
|
|
//
|
|
|
|
//
|
|
// This is a node for the list of algorithms supported by this CSP and a given
|
|
// card.
|
|
//
|
|
typedef struct _SUPPORTED_ALGORITHM
|
|
{
|
|
struct _SUPPORTED_ALGORITHM *pNext;
|
|
PROV_ENUMALGS_EX EnumalgsEx;
|
|
} SUPPORTED_ALGORITHM, *PSUPPORTED_ALGORITHM;
|
|
|
|
//
|
|
// Type: LOCAL_USER_CONTEXT
|
|
//
|
|
// This is the HCRYPTPROV type for the base CSP.
|
|
//
|
|
#define LOCAL_USER_CONTEXT_CURRENT_VERSION 1
|
|
|
|
typedef struct _LOCAL_USER_CONTEXT
|
|
{
|
|
DWORD dwVersion;
|
|
PCARD_STATE pCardState;
|
|
CSP_REG_SETTINGS RegSettings;
|
|
BOOL fHoldingTransaction;
|
|
BYTE bContainerIndex;
|
|
|
|
// This is a multi-string of all of the container names present on
|
|
// the card associated with this context. This member is only used
|
|
// by CryptGetProvParam PP_ENUMCONTAINERS. Access is not synchronized.
|
|
LPSTR mszEnumContainers;
|
|
LPSTR mszCurrentEnumContainer;
|
|
|
|
// This is a list of algorithms supported by this CSP and card. This is
|
|
// only accessed via CryptGetProvParam PP_ENUMALGS and PP_ENUMALGS_EX.
|
|
// Access is not synchronized.
|
|
PSUPPORTED_ALGORITHM pSupportedAlgs;
|
|
PSUPPORTED_ALGORITHM pCurrentAlg;
|
|
|
|
} LOCAL_USER_CONTEXT, *PLOCAL_USER_CONTEXT;
|
|
|
|
//
|
|
// Type: LOCAL_KEY_CONTEXT
|
|
//
|
|
// This is the HCRYPTKEY type for the base CSP.
|
|
//
|
|
typedef struct _LOCAL_KEY_CONTEXT
|
|
{
|
|
PBYTE pbArchivablePrivateKey;
|
|
DWORD cbArchivablePrivateKey;
|
|
|
|
} LOCAL_KEY_CONTEXT, *PLOCAL_KEY_CONTEXT;
|
|
|
|
//
|
|
// Type: LOCAL_HASH_CONTEXT
|
|
//
|
|
// This is the HCRYPTHASH type for the base CSP.
|
|
//
|
|
/*
|
|
typedef struct _LOCAL_HASH_CONTEXT
|
|
{
|
|
//
|
|
// Don't need anything here yet.
|
|
//
|
|
|
|
} LOCAL_HASH_CONTEXT, *PLOCAL_HASH_CONTEXT;
|
|
*/
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
|
|
CSP_STRING g_Strings [] =
|
|
{
|
|
{ NULL, IDS_PINDIALOG_NEWPIN_MISMATCH },
|
|
{ NULL, IDS_PINDIALOG_MSGBOX_TITLE },
|
|
{ NULL, IDS_PINDIALOG_WRONG_PIN },
|
|
{ NULL, IDS_PINDIALOG_PIN_RETRIES }
|
|
};
|
|
|
|
CSP_STATE g_CspState;
|
|
|
|
CARD_KEY_SIZES DefaultCardKeySizes =
|
|
{
|
|
CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0
|
|
};
|
|
|
|
//
|
|
// Registry Initialization
|
|
//
|
|
|
|
//
|
|
// Function: RegConfigAddEntries
|
|
//
|
|
DWORD WINAPI RegConfigAddEntries(
|
|
IN HKEY hKey)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
DWORD iEntry = 0;
|
|
|
|
for ( iEntry = 0;
|
|
iEntry < sizeof(RegConfigValues) / sizeof(RegConfigValues[0]);
|
|
iEntry++)
|
|
{
|
|
dwSts = RegSetValueExW(
|
|
hKey,
|
|
RegConfigValues[iEntry].wszValueName,
|
|
0L,
|
|
REG_DWORD,
|
|
(LPBYTE) &RegConfigValues[iEntry].dwDefValue,
|
|
sizeof(DWORD));
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
}
|
|
|
|
Ret:
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: RegConfigGetSettings
|
|
//
|
|
DWORD WINAPI RegConfigGetSettings(
|
|
IN OUT PCSP_REG_SETTINGS pRegSettings)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
HKEY hKey = 0;
|
|
DWORD dwVal = 0;
|
|
DWORD cbVal = sizeof(DWORD);
|
|
|
|
dwSts = RegOpenProviderKey(&hKey, KEY_READ);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = RegQueryValueExW(
|
|
hKey,
|
|
wszREG_DEFAULT_KEY_LEN,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &dwVal,
|
|
&cbVal);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
pRegSettings->cDefaultPrivateKeyLenBits = dwVal;
|
|
dwVal = 0;
|
|
cbVal = sizeof(DWORD);
|
|
|
|
dwSts = RegQueryValueExW(
|
|
hKey,
|
|
wszREG_REQUIRE_CARD_KEY_GEN,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) &dwVal,
|
|
&cbVal);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
pRegSettings->fRequireOnCardPrivateKeyGen = (BOOL) dwVal;
|
|
dwVal = 0;
|
|
cbVal = sizeof(DWORD);
|
|
|
|
Ret:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// CSP State Management Routines
|
|
//
|
|
|
|
//
|
|
// Function: DeleteCspState
|
|
//
|
|
// Purpose: Delete the global state data structure for this CSP.
|
|
// Should be called during DLL_PROCESS_DETACH.
|
|
//
|
|
DWORD DeleteCspState(void)
|
|
{
|
|
CspDeleteCriticalSection(&g_CspState.cs);
|
|
|
|
if (0 != g_CspState.hCache)
|
|
CacheDeleteCache(g_CspState.hCache);
|
|
|
|
memset(&g_CspState, 0, sizeof(g_CspState));
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Function: InitializeCspState
|
|
//
|
|
// Purpose: Setup the global state data structure for this CSP.
|
|
// Should be called during DLL_PROCESS_ATTACH.
|
|
//
|
|
DWORD InitializeCspState(
|
|
IN HMODULE hCspModule)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
CACHE_INITIALIZE_INFO CacheInitInfo;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
memset(&g_CspState, 0, sizeof(g_CspState));
|
|
memset(&CacheInitInfo, 0, sizeof(CacheInitInfo));
|
|
|
|
g_CspState.hCspModule = hCspModule;
|
|
|
|
dwSts = CspInitializeCriticalSection(
|
|
&g_CspState.cs);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
CacheInitInfo.dwType = CACHE_TYPE_IN_PROC;
|
|
|
|
dwSts = CacheInitializeCache(
|
|
&g_CspState.hCache,
|
|
&CacheInitInfo);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
fSuccess = TRUE;
|
|
Ret:
|
|
if (FALSE == fSuccess)
|
|
DeleteCspState();
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: GetCspState
|
|
//
|
|
// Purpose: Acquire a pointer to the global state data structure
|
|
// for this CSP. This function should always be used,
|
|
// rather than referring to the global object directly.
|
|
//
|
|
DWORD GetCspState(
|
|
IN OUT PCSP_STATE *ppCspState)
|
|
{
|
|
DWORD dwSts;
|
|
|
|
dwSts = CspEnterCriticalSection(
|
|
&g_CspState.cs);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
return dwSts;
|
|
|
|
g_CspState.dwRefCount++;
|
|
|
|
CspLeaveCriticalSection(
|
|
&g_CspState.cs);
|
|
|
|
*ppCspState = &g_CspState;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Function: ReleaseCspState
|
|
//
|
|
// Purpose: Signal that the caller's pointer to the global
|
|
// state data structure is no longer being used.
|
|
//
|
|
DWORD ReleaseCspState(
|
|
IN OUT PCSP_STATE *ppCspState)
|
|
{
|
|
DWORD dwSts;
|
|
|
|
dwSts = CspEnterCriticalSection(
|
|
&g_CspState.cs);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
return dwSts;
|
|
|
|
g_CspState.dwRefCount--;
|
|
|
|
CspLeaveCriticalSection(
|
|
&g_CspState.cs);
|
|
|
|
*ppCspState = NULL;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Pin Management Routines
|
|
//
|
|
|
|
//
|
|
// Struct: VERIFY_PIN_CALLBACK_DATA
|
|
//
|
|
typedef struct _VERIFY_PIN_CALLBACK_DATA
|
|
{
|
|
PUSER_CONTEXT pUserCtx;
|
|
LPWSTR wszUserId;
|
|
} VERIFY_PIN_CALLBACK_DATA, *PVERIFY_PIN_CALLBACK_DATA;
|
|
|
|
//
|
|
// Callback for verifying a submitted pin, or requested pin change, from the
|
|
// user via the pin prompt UI.
|
|
//
|
|
DWORD WINAPI VerifyPinFromUICallback(
|
|
IN PPINCACHE_PINS pPins,
|
|
IN PVOID pvCallbackCtx)
|
|
{
|
|
PPIN_SHOW_GET_PIN_UI_INFO pInfo =
|
|
(PPIN_SHOW_GET_PIN_UI_INFO) pvCallbackCtx;
|
|
PVERIFY_PIN_CALLBACK_DATA pData =
|
|
(PVERIFY_PIN_CALLBACK_DATA) pInfo->pvCallbackContext;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pData->pUserCtx->pvLocalUserContext;
|
|
|
|
// Determine if a Change Pin operation has been requested
|
|
if (NULL != pPins->pbNewPin)
|
|
{
|
|
// A pin change needs to go through the caching layer to ensure that
|
|
// the cache and associated counters get updated.
|
|
return CspChangeAuthenticator(
|
|
pLocal->pCardState,
|
|
pData->wszUserId,
|
|
pPins->pbCurrentPin,
|
|
pPins->cbCurrentPin,
|
|
pPins->pbNewPin,
|
|
pPins->cbNewPin,
|
|
0,
|
|
&pInfo->cAttemptsRemaining);
|
|
}
|
|
|
|
// For the simple submit pin, this pin is directly from the user, so we
|
|
// pass it directly to the card rather than going through the caching
|
|
// layer.
|
|
return pLocal->pCardState->pCardData->pfnCardSubmitPin(
|
|
pLocal->pCardState->pCardData,
|
|
pData->wszUserId,
|
|
pPins->pbCurrentPin,
|
|
pPins->cbCurrentPin,
|
|
&pInfo->cAttemptsRemaining);
|
|
}
|
|
|
|
//
|
|
// Function: VerifyPinCallback
|
|
//
|
|
DWORD WINAPI VerifyPinCallback(
|
|
IN PPINCACHE_PINS pPins,
|
|
IN PVOID pvCallbackCtx)
|
|
{
|
|
PVERIFY_PIN_CALLBACK_DATA pData =
|
|
(PVERIFY_PIN_CALLBACK_DATA) pvCallbackCtx;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pData->pUserCtx->pvLocalUserContext;
|
|
|
|
// This pin is from the pin cache, so filter it through the caching layer.
|
|
return CspSubmitPin(
|
|
pLocal->pCardState,
|
|
pData->wszUserId,
|
|
pPins->pbCurrentPin,
|
|
pPins->cbCurrentPin,
|
|
NULL);
|
|
}
|
|
|
|
//
|
|
// Function: CspAuthenticateUser
|
|
//
|
|
DWORD WINAPI CspAuthenticateUser(
|
|
IN PUSER_CONTEXT pUserCtx)
|
|
{
|
|
VERIFY_PIN_CALLBACK_DATA CallbackCtx;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocalUserContext =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
PIN_SHOW_GET_PIN_UI_INFO PinUIInfo;
|
|
PINCACHE_PINS Pins;
|
|
|
|
LOG_BEGIN_FUNCTION(CspAuthenticateUser);
|
|
|
|
memset(&Pins, 0, sizeof(Pins));
|
|
memset(&PinUIInfo, 0, sizeof(PinUIInfo));
|
|
memset(&CallbackCtx, 0, sizeof(CallbackCtx));
|
|
|
|
CallbackCtx.pUserCtx = pUserCtx;
|
|
CallbackCtx.wszUserId = wszCARD_USER_USER;
|
|
|
|
dwError = PinCachePresentPin(
|
|
pLocalUserContext->pCardState->hPinCache,
|
|
VerifyPinCallback,
|
|
(PVOID) &CallbackCtx);
|
|
|
|
if (SCARD_W_CARD_NOT_AUTHENTICATED == dwError ||
|
|
ERROR_EMPTY == dwError ||
|
|
SCARD_W_WRONG_CHV == dwError)
|
|
{
|
|
PinCacheFlush(&pLocalUserContext->pCardState->hPinCache);
|
|
|
|
// No pin is cached. Is the context "silent"?
|
|
|
|
if (CRYPT_VERIFYCONTEXT & pUserCtx->dwFlags ||
|
|
CRYPT_SILENT & pUserCtx->dwFlags)
|
|
{
|
|
dwError = (DWORD) NTE_SILENT_CONTEXT;
|
|
goto Ret;
|
|
}
|
|
|
|
// Context is not silent. Show UI to let the user enter a pin.
|
|
|
|
pUserCtx->pVTableW->FuncReturnhWnd(&PinUIInfo.hClientWindow);
|
|
|
|
PinUIInfo.pStrings = g_Strings;
|
|
PinUIInfo.hDlgResourceModule = GetModuleHandle(L"basecsp.dll");
|
|
PinUIInfo.wszPrincipal = wszCARD_USER_USER;
|
|
PinUIInfo.pfnVerify = VerifyPinFromUICallback;
|
|
PinUIInfo.pvCallbackContext = (PVOID) &CallbackCtx;
|
|
PinUIInfo.wszCardName =
|
|
pLocalUserContext->pCardState->wszSerialNumber;
|
|
|
|
dwError = PinShowGetPinUI(&PinUIInfo);
|
|
|
|
if (ERROR_SUCCESS != dwError || NULL == PinUIInfo.pbPin)
|
|
goto Ret;
|
|
|
|
Pins.cbCurrentPin = PinUIInfo.cbPin;
|
|
Pins.pbCurrentPin = PinUIInfo.pbPin;
|
|
|
|
//
|
|
// The user entered a pin that has been successfully verified by the
|
|
// card. The Pin UI should have already converted the pin from
|
|
// string form into bytes that we can send to the card.
|
|
// Cache the pin.
|
|
//
|
|
dwError = PinCacheAdd(
|
|
&pLocalUserContext->pCardState->hPinCache,
|
|
&Pins,
|
|
VerifyPinCallback,
|
|
(PVOID) &CallbackCtx);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
}
|
|
|
|
pLocalUserContext->pCardState->fAuthenticated = TRUE;
|
|
|
|
Ret:
|
|
|
|
if (PinUIInfo.pbPin)
|
|
{
|
|
RtlSecureZeroMemory(PinUIInfo.pbPin, PinUIInfo.cbPin);
|
|
CspFreeH(PinUIInfo.pbPin);
|
|
}
|
|
|
|
LOG_END_FUNCTION(CspAuthenticateUser, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Frees the memory consumed by the supported algorithms list.
|
|
//
|
|
DWORD FreeSupportedAlgorithmsList(PLOCAL_USER_CONTEXT pLocal)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PSUPPORTED_ALGORITHM pCurrent = NULL;
|
|
|
|
DsysAssert(NULL != pLocal->pSupportedAlgs);
|
|
|
|
while (NULL != pLocal->pSupportedAlgs)
|
|
{
|
|
pCurrent = pLocal->pSupportedAlgs;
|
|
pLocal->pSupportedAlgs = pCurrent->pNext;
|
|
|
|
CspFreeH(pCurrent);
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Builds a list of algorithms supported by this CSP and smartcard.
|
|
//
|
|
DWORD BuildSupportedAlgorithmsList(PUSER_CONTEXT pUserCtx)
|
|
{
|
|
PLOCAL_USER_CONTEXT pLocal = (PLOCAL_USER_CONTEXT)
|
|
pUserCtx->pvLocalUserContext;
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
CARD_KEY_SIZES CardKeySizes;
|
|
PROV_ENUMALGS_EX EnumalgsEx;
|
|
DWORD cbData = sizeof(EnumalgsEx);
|
|
PSUPPORTED_ALGORITHM pCurrent = NULL;
|
|
DWORD dwFlag = CRYPT_FIRST;
|
|
|
|
DsysAssert(NULL != pLocal);
|
|
DsysAssert(NULL == pLocal->pSupportedAlgs);
|
|
|
|
memset(&CardKeySizes, 0, sizeof(CardKeySizes));
|
|
memset(&EnumalgsEx, 0, sizeof(EnumalgsEx));
|
|
|
|
while (TRUE == CryptGetProvParam(
|
|
pUserCtx->hSupportProv,
|
|
PP_ENUMALGS_EX,
|
|
(PBYTE) &EnumalgsEx,
|
|
&cbData,
|
|
dwFlag))
|
|
{
|
|
dwFlag = CRYPT_NEXT;
|
|
|
|
if (NULL == pCurrent)
|
|
{
|
|
// First item
|
|
pLocal->pSupportedAlgs = (PSUPPORTED_ALGORITHM) CspAllocH(
|
|
sizeof(SUPPORTED_ALGORITHM));
|
|
|
|
LOG_CHECK_ALLOC(pLocal->pSupportedAlgs);
|
|
|
|
pCurrent = pLocal->pSupportedAlgs;
|
|
}
|
|
else
|
|
{
|
|
// Adding an item
|
|
pCurrent->pNext = (PSUPPORTED_ALGORITHM) CspAllocH(
|
|
sizeof(SUPPORTED_ALGORITHM));
|
|
|
|
LOG_CHECK_ALLOC(pCurrent->pNext);
|
|
|
|
pCurrent = pCurrent->pNext;
|
|
}
|
|
|
|
memcpy(
|
|
&pCurrent->EnumalgsEx,
|
|
&EnumalgsEx,
|
|
sizeof(EnumalgsEx));
|
|
|
|
memset(&EnumalgsEx, 0, sizeof(EnumalgsEx));
|
|
|
|
// Special handling for public key algs since they depend on what the
|
|
// target card actually supports
|
|
switch (pCurrent->EnumalgsEx.aiAlgid)
|
|
{
|
|
case CALG_RSA_KEYX:
|
|
|
|
// If there's no CARD_STATE in this context, that should mean this
|
|
// is a VerifyContext with no card inserted. MMC expects that
|
|
// algorithm enumeration is successful without a card, so provide
|
|
// some default public key values in that case.
|
|
|
|
if (NULL == pLocal->pCardState)
|
|
{
|
|
DsysAssert(CRYPT_VERIFYCONTEXT & pUserCtx->dwFlags);
|
|
|
|
memcpy(
|
|
&CardKeySizes,
|
|
&DefaultCardKeySizes,
|
|
sizeof(CARD_KEY_SIZES));
|
|
|
|
break;
|
|
}
|
|
|
|
dwSts = CspQueryKeySizes(
|
|
pLocal->pCardState,
|
|
AT_KEYEXCHANGE,
|
|
0,
|
|
&CardKeySizes);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
break;
|
|
|
|
case CALG_RSA_SIGN:
|
|
|
|
if (NULL == pLocal->pCardState)
|
|
{
|
|
DsysAssert(CRYPT_VERIFYCONTEXT & pUserCtx->dwFlags);
|
|
|
|
memcpy(
|
|
&CardKeySizes,
|
|
&DefaultCardKeySizes,
|
|
sizeof(CARD_KEY_SIZES));
|
|
|
|
break;
|
|
}
|
|
|
|
dwSts = CspQueryKeySizes(
|
|
pLocal->pCardState,
|
|
AT_SIGNATURE,
|
|
0,
|
|
&CardKeySizes);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
break;
|
|
|
|
default:
|
|
// Go to the next alg
|
|
continue;
|
|
}
|
|
|
|
pCurrent->EnumalgsEx.dwDefaultLen = CardKeySizes.dwDefaultBitlen;
|
|
pCurrent->EnumalgsEx.dwMaxLen = CardKeySizes.dwMaximumBitlen;
|
|
pCurrent->EnumalgsEx.dwMinLen = CardKeySizes.dwMinimumBitlen;
|
|
|
|
memset(&CardKeySizes, 0, sizeof(CardKeySizes));
|
|
}
|
|
|
|
if (ERROR_NO_MORE_ITEMS == (dwSts = GetLastError()))
|
|
dwSts = ERROR_SUCCESS;
|
|
|
|
Ret:
|
|
|
|
if (ERROR_SUCCESS != dwSts && NULL != pLocal->pSupportedAlgs)
|
|
FreeSupportedAlgorithmsList(pLocal);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: DeleteLocalUserContext
|
|
//
|
|
void DeleteLocalUserContext(PLOCAL_USER_CONTEXT pLocalUserCtx)
|
|
{
|
|
if (NULL != pLocalUserCtx->mszEnumContainers)
|
|
{
|
|
CspFreeH(pLocalUserCtx->mszEnumContainers);
|
|
pLocalUserCtx->mszEnumContainers = NULL;
|
|
}
|
|
|
|
if (NULL != pLocalUserCtx->pSupportedAlgs)
|
|
FreeSupportedAlgorithmsList(pLocalUserCtx);
|
|
|
|
// Don't free the card state here, since those structures are shared.
|
|
pLocalUserCtx->pCardState = NULL;
|
|
}
|
|
|
|
//
|
|
// Function: CleanupContainerInfo
|
|
//
|
|
void CleanupContainerInfo(
|
|
IN OUT PCONTAINER_INFO pContainerInfo)
|
|
{
|
|
if (pContainerInfo->pbKeyExPublicKey)
|
|
{
|
|
CspFreeH(pContainerInfo->pbKeyExPublicKey);
|
|
pContainerInfo->pbKeyExPublicKey = NULL;
|
|
}
|
|
|
|
if (pContainerInfo->pbSigPublicKey)
|
|
{
|
|
CspFreeH(pContainerInfo->pbSigPublicKey);
|
|
pContainerInfo->pbSigPublicKey = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Function: GetKeyModulusLength
|
|
//
|
|
DWORD GetKeyModulusLength(
|
|
IN PUSER_CONTEXT pUserCtx,
|
|
IN DWORD dwKeySpec,
|
|
OUT PDWORD pcbModulus)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
CONTAINER_MAP_RECORD ContainerRecord;
|
|
|
|
*pcbModulus = 0;
|
|
|
|
memset(&ContainerRecord, 0, sizeof(ContainerRecord));
|
|
|
|
wcscpy(ContainerRecord.wszGuid, pUserCtx->wszBaseContainerName);
|
|
|
|
dwSts = ContainerMapFindContainer(
|
|
pLocal->pCardState,
|
|
&ContainerRecord,
|
|
NULL);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
switch (dwKeySpec)
|
|
{
|
|
case AT_SIGNATURE:
|
|
|
|
if (0 == ContainerRecord.wSigKeySizeBits)
|
|
{
|
|
dwSts = (DWORD) NTE_NO_KEY;
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbModulus = ContainerRecord.wSigKeySizeBits / 8;
|
|
break;
|
|
|
|
case AT_KEYEXCHANGE:
|
|
|
|
if (0 == ContainerRecord.wKeyExchangeKeySizeBits)
|
|
{
|
|
dwSts = (DWORD) NTE_NO_KEY;
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbModulus = ContainerRecord.wKeyExchangeKeySizeBits / 8;
|
|
break;
|
|
|
|
default:
|
|
|
|
dwSts = (DWORD) NTE_BAD_ALGID;
|
|
goto Ret;
|
|
}
|
|
|
|
Ret:
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Finds the index corresponding to a specified container in the card
|
|
// container map file. Returns the contents the container map file.
|
|
//
|
|
// The container name can optionally be omitted, in which case the map file
|
|
// is simply read and returned.
|
|
//
|
|
DWORD I_ContainerMapFind(
|
|
IN PCARD_STATE pCardState,
|
|
IN OPTIONAL LPWSTR wszContainerGuid,
|
|
OUT OPTIONAL PBYTE pbIndex,
|
|
OUT PCONTAINER_MAP_RECORD *ppContainerMapFile,
|
|
OUT PBYTE pcContainerMapFile)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
DATA_BLOB dbContainerMap;
|
|
BYTE iContainer = 0;
|
|
|
|
memset(&dbContainerMap, 0, sizeof(dbContainerMap));
|
|
|
|
*ppContainerMapFile = NULL;
|
|
*pcContainerMapFile = 0;
|
|
|
|
// Read the container map file from the card
|
|
dwSts = CspReadFile(
|
|
pCardState,
|
|
wszCONTAINER_MAP_FILE_FULL_PATH,
|
|
0,
|
|
&dbContainerMap.pbData,
|
|
&dbContainerMap.cbData);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (0 != dbContainerMap.cbData)
|
|
{
|
|
// Expect that the file contains an exact multiple of the record size
|
|
DsysAssert(0 == (dbContainerMap.cbData % sizeof(CONTAINER_MAP_RECORD)));
|
|
|
|
*ppContainerMapFile = (PCONTAINER_MAP_RECORD) dbContainerMap.pbData;
|
|
*pcContainerMapFile = (BYTE)
|
|
(dbContainerMap.cbData / sizeof(CONTAINER_MAP_RECORD));
|
|
dbContainerMap.pbData = NULL;
|
|
}
|
|
|
|
// See if caller just wanted us to return the map file contents
|
|
if (NULL == wszContainerGuid)
|
|
goto Ret;
|
|
|
|
for ( iContainer = 0;
|
|
iContainer < *pcContainerMapFile;
|
|
iContainer++)
|
|
{
|
|
if (0 == wcscmp(
|
|
wszContainerGuid,
|
|
(*ppContainerMapFile)[iContainer].wszGuid) &&
|
|
(CONTAINER_MAP_VALID_CONTAINER &
|
|
(*ppContainerMapFile)[iContainer].bFlags))
|
|
{
|
|
*pbIndex = iContainer;
|
|
goto Ret;
|
|
}
|
|
}
|
|
|
|
dwSts = NTE_BAD_KEYSET;
|
|
|
|
Ret:
|
|
|
|
if (dbContainerMap.pbData)
|
|
CspFreeH(dbContainerMap.pbData);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Returns the number of valid containers present on the card. Optionally,
|
|
// returns a list of the container names in a multi-string.
|
|
//
|
|
// The returned *mwszContainers pointer must be freed by the caller.
|
|
//
|
|
DWORD ContainerMapEnumContainers(
|
|
IN PCARD_STATE pCardState,
|
|
OUT PBYTE pcContainers,
|
|
OUT OPTIONAL LPWSTR *mwszContainers)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PCONTAINER_MAP_RECORD pContainerMap = NULL;
|
|
BYTE cContainerMap = 0;
|
|
BYTE iContainer = 0;
|
|
DWORD cchCurrent = 0;
|
|
DWORD cchCumulative = 0;
|
|
|
|
*pcContainers = 0;
|
|
|
|
if (NULL != mwszContainers)
|
|
*mwszContainers = NULL;
|
|
|
|
dwSts = I_ContainerMapFind(
|
|
pCardState,
|
|
NULL,
|
|
NULL,
|
|
&pContainerMap,
|
|
&cContainerMap);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// We'll make two passes through the container map file. The first pass
|
|
// counts the number of valid containers present. This allows us to make
|
|
// a single allocation large enough for a multi-string consisting of all
|
|
// of the valid container names. We'll pick up the names in the second
|
|
// pass through the file.
|
|
//
|
|
|
|
// Pass 1
|
|
for (iContainer = 0; iContainer < cContainerMap; iContainer++)
|
|
{
|
|
if (CONTAINER_MAP_VALID_CONTAINER & pContainerMap[iContainer].bFlags)
|
|
*pcContainers += 1;
|
|
}
|
|
|
|
if (0 == *pcContainers || NULL == mwszContainers)
|
|
goto Ret;
|
|
|
|
// Build a big enough buffer
|
|
*mwszContainers = (LPWSTR) CspAllocH(
|
|
((*pcContainers * (1 + MAX_CONTAINER_NAME_LEN)) + 1) * sizeof(WCHAR));
|
|
|
|
// Pass 2
|
|
for (iContainer = 0; iContainer < cContainerMap; iContainer++)
|
|
{
|
|
if (CONTAINER_MAP_VALID_CONTAINER & pContainerMap[iContainer].bFlags)
|
|
{
|
|
cchCurrent = wcslen(pContainerMap[iContainer].wszGuid);
|
|
|
|
memcpy(
|
|
*mwszContainers + cchCumulative,
|
|
pContainerMap[iContainer].wszGuid,
|
|
cchCurrent * sizeof(WCHAR));
|
|
|
|
cchCumulative += cchCurrent + 1;
|
|
}
|
|
}
|
|
|
|
Ret:
|
|
|
|
if (pContainerMap)
|
|
CspFreeH(pContainerMap);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Searches for the named container on the card. The container to look for
|
|
// must be in pContainer->wszGuid. If the container is not found,
|
|
// NTE_BAD_KEYSET is returned.
|
|
//
|
|
DWORD ContainerMapFindContainer(
|
|
IN PCARD_STATE pCardState,
|
|
IN OUT PCONTAINER_MAP_RECORD pContainer,
|
|
OUT OPTIONAL PBYTE pbContainerIndex)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PCONTAINER_MAP_RECORD pContainerMap = NULL;
|
|
BYTE bIndex = 0;
|
|
BYTE cContainerMap = 0;
|
|
|
|
dwSts = I_ContainerMapFind(
|
|
pCardState,
|
|
pContainer->wszGuid,
|
|
&bIndex,
|
|
&pContainerMap,
|
|
&cContainerMap);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
memcpy(
|
|
(PBYTE) pContainer,
|
|
(PBYTE) (pContainerMap + bIndex),
|
|
sizeof(CONTAINER_MAP_RECORD));
|
|
|
|
if (NULL != pbContainerIndex)
|
|
*pbContainerIndex = bIndex;
|
|
|
|
Ret:
|
|
|
|
if (pContainerMap)
|
|
CspFreeH(pContainerMap);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Searches for the default container on the card. If no default container is
|
|
// found, NTE_BAD_KEYSET is returned.
|
|
//
|
|
DWORD ContainerMapGetDefaultContainer(
|
|
IN PCARD_STATE pCardState,
|
|
OUT PCONTAINER_MAP_RECORD pContainer,
|
|
OUT OPTIONAL PBYTE pbContainerIndex)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PCONTAINER_MAP_RECORD pContainerMap = NULL;
|
|
BYTE cContainerMap = 0;
|
|
BYTE iContainer = 0;
|
|
|
|
dwSts = I_ContainerMapFind(
|
|
pCardState,
|
|
NULL,
|
|
NULL,
|
|
&pContainerMap,
|
|
&cContainerMap);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
for (iContainer = 0; iContainer < cContainerMap; iContainer++)
|
|
{
|
|
if ((pContainerMap[iContainer].bFlags &
|
|
CONTAINER_MAP_VALID_CONTAINER) &&
|
|
(pContainerMap[iContainer].bFlags &
|
|
CONTAINER_MAP_DEFAULT_CONTAINER))
|
|
{
|
|
memcpy(
|
|
(PBYTE) pContainer,
|
|
(PBYTE) (pContainerMap + iContainer),
|
|
sizeof(CONTAINER_MAP_RECORD));
|
|
|
|
if (NULL != pbContainerIndex)
|
|
*pbContainerIndex = iContainer;
|
|
|
|
goto Ret;
|
|
}
|
|
}
|
|
|
|
dwSts = NTE_BAD_KEYSET;
|
|
|
|
Ret:
|
|
|
|
if (pContainerMap)
|
|
CspFreeH(pContainerMap);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Sets the default container on the card.
|
|
//
|
|
DWORD ContainerMapSetDefaultContainer(
|
|
IN PCARD_STATE pCardState,
|
|
IN LPWSTR wszContainerGuid)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PCONTAINER_MAP_RECORD pContainerMap = NULL;
|
|
BYTE bIndex = 0;
|
|
BYTE cContainerMap = 0;
|
|
BYTE iContainer = 0;
|
|
DATA_BLOB dbContainerMap;
|
|
|
|
memset(&dbContainerMap, 0, sizeof(dbContainerMap));
|
|
|
|
dwSts = I_ContainerMapFind(
|
|
pCardState,
|
|
wszContainerGuid,
|
|
&bIndex,
|
|
&pContainerMap,
|
|
&cContainerMap);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// If some other container is currently marked as the default, unmark it.
|
|
//
|
|
|
|
for (iContainer = 0; iContainer < cContainerMap; iContainer++)
|
|
{
|
|
if (pContainerMap[iContainer].bFlags & CONTAINER_MAP_DEFAULT_CONTAINER)
|
|
pContainerMap[iContainer].bFlags &= ~CONTAINER_MAP_DEFAULT_CONTAINER;
|
|
}
|
|
|
|
pContainerMap[bIndex].bFlags |= CONTAINER_MAP_DEFAULT_CONTAINER;
|
|
|
|
dbContainerMap.pbData = (PBYTE) pContainerMap;
|
|
dbContainerMap.cbData = cContainerMap * sizeof(CONTAINER_MAP_RECORD);
|
|
|
|
// Write the updated map file to the card
|
|
dwSts = CspWriteFile(
|
|
pCardState,
|
|
wszCONTAINER_MAP_FILE_FULL_PATH,
|
|
0,
|
|
dbContainerMap.pbData,
|
|
dbContainerMap.cbData);
|
|
|
|
Ret:
|
|
|
|
if (pContainerMap)
|
|
CspFreeH(pContainerMap);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Adds a new container record to the container map. If the specified
|
|
// container already exists, replaces the existing keyset (if any) with
|
|
// the one provided.
|
|
//
|
|
// If cKeySizeBits is zero, assumes that a container with no keys is being
|
|
// added.
|
|
//
|
|
DWORD ContainerMapAddContainer(
|
|
IN PCARD_STATE pCardState,
|
|
IN LPWSTR pwszContainerGuid,
|
|
IN DWORD cKeySizeBits,
|
|
IN DWORD dwKeySpec,
|
|
IN BOOL fGetNameOnly,
|
|
OUT PBYTE pbContainerIndex)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PCONTAINER_MAP_RECORD pContainerMap = NULL;
|
|
BYTE cContainerMap = 0;
|
|
BYTE iContainer = 0;
|
|
DATA_BLOB dbContainerMap;
|
|
PCONTAINER_MAP_RECORD pNewMap = NULL;
|
|
BOOL fExistingContainer = FALSE;
|
|
|
|
memset(&dbContainerMap, 0, sizeof(dbContainerMap));
|
|
|
|
// See if this container already exists
|
|
dwSts = I_ContainerMapFind(
|
|
pCardState,
|
|
pwszContainerGuid,
|
|
&iContainer,
|
|
&pContainerMap,
|
|
&cContainerMap);
|
|
|
|
switch (dwSts)
|
|
{
|
|
case NTE_BAD_KEYSET:
|
|
|
|
//
|
|
// This is a new container that does not already exist.
|
|
// Look for an existing "empty" slot in the container map file
|
|
//
|
|
|
|
for (iContainer = 0; iContainer < cContainerMap; iContainer++)
|
|
{
|
|
if (0 == (pContainerMap[iContainer].bFlags &
|
|
CONTAINER_MAP_VALID_CONTAINER))
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
//
|
|
// This container already exists. The new keyset will be added to it,
|
|
// possibly replacing an existing keyset of the same type.
|
|
//
|
|
|
|
fExistingContainer = TRUE;
|
|
break;
|
|
|
|
default:
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Pass the container index that we're using back to the caller; that may
|
|
// be all that was requested.
|
|
//
|
|
|
|
*pbContainerIndex = iContainer;
|
|
|
|
if (fGetNameOnly)
|
|
goto Ret;
|
|
|
|
if (iContainer == cContainerMap)
|
|
{
|
|
//
|
|
// No empty slot was found in the container map. We'll have to grow
|
|
// the map and add the new container to the end.
|
|
//
|
|
|
|
pNewMap = (PCONTAINER_MAP_RECORD) CspAllocH(
|
|
(cContainerMap + 1) * sizeof(CONTAINER_MAP_RECORD));
|
|
|
|
LOG_CHECK_ALLOC(pNewMap);
|
|
|
|
memcpy(
|
|
(PBYTE) pNewMap,
|
|
(PBYTE) pContainerMap,
|
|
cContainerMap * sizeof(CONTAINER_MAP_RECORD));
|
|
|
|
CspFreeH(pContainerMap);
|
|
pContainerMap = pNewMap;
|
|
pNewMap = NULL;
|
|
cContainerMap++;
|
|
}
|
|
|
|
//
|
|
// Update the container map file and write it to the card
|
|
//
|
|
|
|
pContainerMap[iContainer].bFlags |= CONTAINER_MAP_VALID_CONTAINER;
|
|
|
|
if (0 != cKeySizeBits)
|
|
{
|
|
switch (dwKeySpec)
|
|
{
|
|
case AT_KEYEXCHANGE:
|
|
pContainerMap[iContainer].wKeyExchangeKeySizeBits = (WORD) cKeySizeBits;
|
|
break;
|
|
case AT_SIGNATURE:
|
|
pContainerMap[iContainer].wSigKeySizeBits = (WORD) cKeySizeBits;
|
|
break;
|
|
default:
|
|
dwSts = NTE_BAD_ALGID;
|
|
goto Ret;
|
|
}
|
|
}
|
|
|
|
if (FALSE == fExistingContainer)
|
|
{
|
|
wcscpy(
|
|
pContainerMap[iContainer].wszGuid,
|
|
pwszContainerGuid);
|
|
}
|
|
|
|
dbContainerMap.pbData = (PBYTE) pContainerMap;
|
|
dbContainerMap.cbData = cContainerMap * sizeof(CONTAINER_MAP_RECORD);
|
|
|
|
dwSts = CspWriteFile(
|
|
pCardState,
|
|
wszCONTAINER_MAP_FILE_FULL_PATH,
|
|
0,
|
|
dbContainerMap.pbData,
|
|
dbContainerMap.cbData);
|
|
|
|
Ret:
|
|
|
|
if (pContainerMap)
|
|
CspFreeH(pContainerMap);
|
|
if (pNewMap)
|
|
CspFreeH(pNewMap);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Deletes a container record from the container map. Returns NTE_BAD_KEYSET
|
|
// if the specified container does not exist.
|
|
//
|
|
// If the deleted container was the default, finds the first valid container
|
|
// remaining on the card and marks it as the new default.
|
|
//
|
|
DWORD ContainerMapDeleteContainer(
|
|
IN PCARD_STATE pCardState,
|
|
IN LPWSTR pwszContainerGuid,
|
|
OUT PBYTE pbContainerIndex)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PCONTAINER_MAP_RECORD pContainerMap = NULL;
|
|
BYTE dwIndex = 0;
|
|
BYTE cContainerMap = 0;
|
|
DATA_BLOB dbContainerMap;
|
|
BYTE iContainer = 0;
|
|
|
|
memset(&dbContainerMap, 0, sizeof(dbContainerMap));
|
|
|
|
//
|
|
// See if this container already exists. If it does, invalidate its entry
|
|
// in the map file and write the file back to the card.
|
|
//
|
|
|
|
dwSts = I_ContainerMapFind(
|
|
pCardState,
|
|
pwszContainerGuid,
|
|
&dwIndex,
|
|
&pContainerMap,
|
|
&cContainerMap);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (CONTAINER_MAP_DEFAULT_CONTAINER & pContainerMap[dwIndex].bFlags)
|
|
{
|
|
// Find a valid container to mark as the new default
|
|
|
|
for (iContainer = 0; iContainer < cContainerMap; iContainer++)
|
|
{
|
|
if (CONTAINER_MAP_VALID_CONTAINER &
|
|
pContainerMap[iContainer].bFlags)
|
|
{
|
|
pContainerMap[iContainer].bFlags |=
|
|
CONTAINER_MAP_DEFAULT_CONTAINER;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
memset(
|
|
(PBYTE) (pContainerMap + dwIndex),
|
|
0,
|
|
sizeof(CONTAINER_MAP_RECORD));
|
|
|
|
*pbContainerIndex = dwIndex;
|
|
|
|
//
|
|
// Update the container map file and write it to the card
|
|
//
|
|
|
|
dbContainerMap.pbData = (PBYTE) pContainerMap;
|
|
dbContainerMap.cbData = cContainerMap * sizeof(CONTAINER_MAP_RECORD);
|
|
|
|
dwSts = CspWriteFile(
|
|
pCardState,
|
|
wszCONTAINER_MAP_FILE_FULL_PATH,
|
|
0,
|
|
dbContainerMap.pbData,
|
|
dbContainerMap.cbData);
|
|
|
|
Ret:
|
|
|
|
if (pContainerMap)
|
|
CspFreeH(pContainerMap);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: ValidateCardHandle
|
|
//
|
|
// Purpose: Verify that the provided SCARDHANDLE is valid. If the handle
|
|
// is not valid, disconnect and flush the pin cache.
|
|
//
|
|
// Assume: pCardState critical section should currently be held by caller.
|
|
//
|
|
DWORD ValidateCardHandle(
|
|
IN PCARD_STATE pCardState,
|
|
IN BOOL fMayReleaseContextHandle,
|
|
OUT OPTIONAL BOOL *pfFlushPinCache)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
DWORD dwState = 0;
|
|
DWORD dwProtocol = 0;
|
|
DWORD cch = 0;
|
|
LPWSTR mszReaders = NULL;
|
|
BYTE rgbAtr [cbATR_BUFFER];
|
|
DWORD cbAtr = sizeof(rgbAtr);
|
|
PCARD_DATA pCardData = pCardState->pCardData;
|
|
|
|
LOG_BEGIN_FUNCTION(ValidateCardHandle);
|
|
|
|
cch = SCARD_AUTOALLOCATE;
|
|
dwSts = SCardStatusW(
|
|
pCardData->hScard,
|
|
(LPWSTR) &mszReaders,
|
|
&cch,
|
|
&dwState,
|
|
&dwProtocol,
|
|
rgbAtr,
|
|
&cbAtr);
|
|
|
|
if (mszReaders)
|
|
SCardFreeMemory(pCardData->hScard, mszReaders);
|
|
|
|
switch (dwSts)
|
|
{
|
|
case SCARD_W_RESET_CARD:
|
|
|
|
dwSts = SCardReconnect(
|
|
pCardData->hScard,
|
|
SCARD_SHARE_SHARED,
|
|
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
|
|
SCARD_LEAVE_CARD,
|
|
&dwProtocol);
|
|
|
|
if (ERROR_SUCCESS == dwSts)
|
|
// We're done if reconnect succeeded
|
|
goto Ret;
|
|
|
|
break;
|
|
|
|
case ERROR_SUCCESS:
|
|
if (SCARD_SPECIFIC == dwState)
|
|
// The card handle is still valid and ready to use. We're done.
|
|
goto Ret;
|
|
|
|
break;
|
|
|
|
default:
|
|
// This includes the case where the card status SCARD_W_REMOVED was
|
|
// returned. Nothing to do but disconnect, below.
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The card appears to have been withdrawan at some point, or some
|
|
// other problem occurred.
|
|
//
|
|
// We should not attempt to reconnect the card in any case other than
|
|
// RESET, since we wouldn't be sure that it's the same card without
|
|
// further checks. Instead just close the card handle and let the caller
|
|
// find the correct card again.
|
|
//
|
|
|
|
SCardDisconnect(
|
|
pCardData->hScard,
|
|
SCARD_LEAVE_CARD);
|
|
|
|
pCardData->hScard = 0;
|
|
dwSts = (DWORD) SCARD_E_INVALID_HANDLE;
|
|
|
|
if (fMayReleaseContextHandle)
|
|
{
|
|
SCardReleaseContext(
|
|
pCardData->hSCardCtx);
|
|
|
|
pCardData->hSCardCtx = 0;
|
|
}
|
|
|
|
if (NULL != pfFlushPinCache)
|
|
*pfFlushPinCache = TRUE;
|
|
|
|
Ret:
|
|
|
|
LOG_END_FUNCTION(ValidateCardHandle, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: FindCardBySerialNumber
|
|
//
|
|
// Purpose: Search for an existing card whose serial number is already
|
|
// known. This is necessary for a User Context associated with
|
|
// a card whose handle failed to reconnect.
|
|
//
|
|
DWORD FindCardBySerialNumber(
|
|
IN PUSER_CONTEXT pUserCtx)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
CARD_MATCH_DATA CardMatchData;
|
|
PCSP_STATE pCspState = NULL;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
|
|
memset(&CardMatchData, 0, sizeof(CardMatchData));
|
|
|
|
dwSts = GetCspState(&pCspState);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
CardMatchData.pwszSerialNumber =
|
|
pLocalUserCtx->pCardState->wszSerialNumber;
|
|
CardMatchData.dwCtxFlags = pUserCtx->dwFlags;
|
|
CardMatchData.dwMatchType = CARD_MATCH_TYPE_SERIAL_NUMBER;
|
|
CardMatchData.cchMatchedCard = MAX_PATH;
|
|
CardMatchData.cchMatchedReader = MAX_PATH;
|
|
CardMatchData.cchMatchedSerialNumber = MAX_PATH;
|
|
CardMatchData.pCspState = pCspState;
|
|
CardMatchData.dwShareMode = SCARD_SHARE_SHARED;
|
|
CardMatchData.dwPreferredProtocols =
|
|
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
|
|
|
|
// As a sanity check, disassociate this user context with its current
|
|
// Card State structure. If we find a match, it will be the same one,
|
|
// because we already know the serial number, but the user context
|
|
// shouldn't maintain this state until then.
|
|
pLocalUserCtx->pCardState = NULL;
|
|
|
|
// Try to find a matching card.
|
|
dwSts = FindCard(&CardMatchData);
|
|
|
|
if (ERROR_SUCCESS == dwSts)
|
|
pLocalUserCtx->pCardState = CardMatchData.pCardState;
|
|
|
|
Ret:
|
|
if (pCspState)
|
|
ReleaseCspState(&pCspState);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: BuildCertificateFilename
|
|
//
|
|
DWORD WINAPI
|
|
BuildCertificateFilename(
|
|
IN PUSER_CONTEXT pUserCtx,
|
|
IN DWORD dwKeySpec,
|
|
OUT LPWSTR *ppszFilename)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
BYTE bContainerIndex = 0;
|
|
DWORD cchFilename = 0;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
CONTAINER_MAP_RECORD ContainerRecord;
|
|
LPWSTR wszPrefix = NULL;
|
|
|
|
switch(dwKeySpec)
|
|
{
|
|
case AT_SIGNATURE:
|
|
wszPrefix = wszUSER_SIGNATURE_CERT_PREFIX;
|
|
break;
|
|
case AT_KEYEXCHANGE:
|
|
wszPrefix = wszUSER_KEYEXCHANGE_CERT_PREFIX;
|
|
break;
|
|
default:
|
|
dwSts = (DWORD) NTE_BAD_ALGID;
|
|
goto Ret;
|
|
}
|
|
|
|
memset(&ContainerRecord, 0, sizeof(ContainerRecord));
|
|
|
|
wcscpy(ContainerRecord.wszGuid, pUserCtx->wszBaseContainerName);
|
|
|
|
dwSts = ContainerMapFindContainer(
|
|
pLocal->pCardState,
|
|
&ContainerRecord,
|
|
&bContainerIndex);
|
|
|
|
cchFilename = wcslen(wszPrefix) + 2 + 1;
|
|
|
|
*ppszFilename = (LPWSTR) CspAllocH(sizeof(WCHAR) * cchFilename);
|
|
|
|
LOG_CHECK_ALLOC(*ppszFilename);
|
|
|
|
wsprintf(
|
|
*ppszFilename,
|
|
L"%s%02X",
|
|
wszPrefix,
|
|
bContainerIndex);
|
|
|
|
Ret:
|
|
if (ERROR_SUCCESS != dwSts && *ppszFilename)
|
|
{
|
|
CspFreeH(*ppszFilename);
|
|
*ppszFilename = NULL;
|
|
}
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: CspBeginTransaction
|
|
//
|
|
DWORD CspBeginTransaction(
|
|
IN PCARD_STATE pCardState)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
|
|
dwSts = CspEnterCriticalSection(&pCardState->cs);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = SCardBeginTransaction(pCardState->pCardData->hScard);
|
|
|
|
Ret:
|
|
if (ERROR_SUCCESS != dwSts)
|
|
CspLeaveCriticalSection(&pCardState->cs);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: CspEndTransaction
|
|
//
|
|
DWORD CspEndTransaction(
|
|
IN PCARD_STATE pCardState)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
DWORD dwAction =
|
|
pCardState->fAuthenticated ?
|
|
SCARD_RESET_CARD :
|
|
SCARD_LEAVE_CARD;
|
|
|
|
if (pCardState->fAuthenticated &&
|
|
pCardState->pCardData->pfnCardDeauthenticate)
|
|
{
|
|
// The card is currently in an authenticated state, and the card
|
|
// module has its own Deauthenticate function. Try to use the
|
|
// cardmod function instead using RESET_CARD in the
|
|
// SCardEndTransaction call. This can be a big perf improvement.
|
|
|
|
dwSts = pCardState->pCardData->pfnCardDeauthenticate(
|
|
pCardState->pCardData, wszCARD_USER_USER, 0);
|
|
|
|
// If the Deauthenticate succeeded, all that's left to do is release
|
|
// the transaction. If the Deauthenticate failed, we'll try one
|
|
// more time to RESET the card.
|
|
|
|
if (ERROR_SUCCESS == dwSts)
|
|
dwAction = SCARD_LEAVE_CARD;
|
|
}
|
|
|
|
dwSts = SCardEndTransaction(
|
|
pCardState->pCardData->hScard,
|
|
dwAction);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
// Bad news if we got here. Better try to close the card handle
|
|
// to cleanup.
|
|
SCardDisconnect(pCardState->pCardData->hScard, SCARD_RESET_CARD);
|
|
pCardState->pCardData->hScard = 0;
|
|
|
|
SCardReleaseContext(pCardState->pCardData->hSCardCtx);
|
|
pCardState->pCardData->hSCardCtx = 0;
|
|
}
|
|
else
|
|
pCardState->fAuthenticated = FALSE;
|
|
|
|
// We've left the transaction, so the "cached" cache file info is no
|
|
// longer reliable.
|
|
pCardState->fCacheFileValid = FALSE;
|
|
|
|
CspLeaveCriticalSection(&pCardState->cs);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: BeginCardCapiCall
|
|
//
|
|
// Purpose: Setup the user context and associated card context for a new
|
|
// Crypto API call. This includes:
|
|
// 1) Reconnecting to the card, if necessary.
|
|
// 2) Begin transaction.
|
|
//
|
|
DWORD BeginCardCapiCall(
|
|
IN PUSER_CONTEXT pUserCtx)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
BOOL fFlushPinCache = FALSE;
|
|
|
|
LOG_BEGIN_FUNCTION(BeginCardCapiCall);
|
|
|
|
DsysAssert(FALSE == pLocalUserCtx->fHoldingTransaction);
|
|
|
|
dwSts = CspEnterCriticalSection(
|
|
&pLocalUserCtx->pCardState->cs);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
return dwSts;
|
|
|
|
dwSts = ValidateCardHandle(
|
|
pLocalUserCtx->pCardState, TRUE, &fFlushPinCache);
|
|
|
|
if (ERROR_SUCCESS != dwSts || TRUE == fFlushPinCache)
|
|
// Flush the pin cache for this card. Not checking error code
|
|
// since we'll keep processing, anyway.
|
|
CspRemoveCachedPin(pLocalUserCtx->pCardState, wszCARD_USER_USER);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
//
|
|
// Could not connect to the card.
|
|
//
|
|
|
|
CspLeaveCriticalSection(
|
|
&pLocalUserCtx->pCardState->cs);
|
|
|
|
// Attempt to find the card again,
|
|
// possibly in a different reader.
|
|
dwSts = FindCardBySerialNumber(pUserCtx);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
}
|
|
else
|
|
CspLeaveCriticalSection(
|
|
&pLocalUserCtx->pCardState->cs);
|
|
|
|
// If the reconnect failed, bail now.
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
// Now Begin Transaction on the card.
|
|
dwSts = CspBeginTransaction(pLocalUserCtx->pCardState);
|
|
|
|
if (ERROR_SUCCESS == dwSts)
|
|
pLocalUserCtx->fHoldingTransaction = TRUE;
|
|
|
|
Ret:
|
|
|
|
LOG_END_FUNCTION(BeginCardCapiCall, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: EndCardCapiCall
|
|
//
|
|
// Purpose: Cleanup the user context and associated card context following
|
|
// the completion of a Crypto API call. This includes ending
|
|
// the transaction on the card.
|
|
//
|
|
DWORD EndCardCapiCall(
|
|
IN PUSER_CONTEXT pUserCtx)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
|
|
LOG_BEGIN_FUNCTION(EndCardCapiCall);
|
|
|
|
if (TRUE == pLocal->fHoldingTransaction)
|
|
{
|
|
dwSts = CspEndTransaction(pLocal->pCardState);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
// Something got screwed up and we weren't able to EndTransaction
|
|
// correctly. Expect that the SCard handles got released as a
|
|
// result.
|
|
|
|
DsysAssert(0 == pLocal->pCardState->pCardData->hScard);
|
|
DsysAssert(0 == pLocal->pCardState->pCardData->hSCardCtx);
|
|
}
|
|
|
|
// Even if the EndTransaction failed, we expect that the card handles
|
|
// got closed, and we expect that the Card State critsec is no
|
|
// longer held.
|
|
pLocal->fHoldingTransaction = FALSE;
|
|
}
|
|
|
|
LOG_END_FUNCTION(EndCardCapiCall, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: DeleteContainer
|
|
//
|
|
DWORD DeleteContainer(PUSER_CONTEXT pUserCtx)
|
|
{
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
LPWSTR wszFilename = NULL;
|
|
BYTE bContainerIndex = 0;
|
|
|
|
//
|
|
// Delete the certificate (if any) associated with the signature key
|
|
// (if any).
|
|
//
|
|
|
|
dwSts = BuildCertificateFilename(
|
|
pUserCtx, AT_SIGNATURE, &wszFilename);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
// Ignore error on this call - there may not be a cert associated
|
|
// with this container and we're just trying to cleanup as much as
|
|
// we can.
|
|
CspDeleteFile(
|
|
pLocal->pCardState,
|
|
0,
|
|
wszFilename);
|
|
|
|
CspFreeH(wszFilename);
|
|
wszFilename = NULL;
|
|
|
|
//
|
|
// Delete the key exchange cert (if any)
|
|
//
|
|
|
|
dwSts = BuildCertificateFilename(
|
|
pUserCtx, AT_KEYEXCHANGE, &wszFilename);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
CspDeleteFile(
|
|
pLocal->pCardState,
|
|
0,
|
|
wszFilename);
|
|
|
|
//
|
|
// Perform the delete operation on the card
|
|
//
|
|
|
|
dwSts = CspDeleteContainer(
|
|
pLocal->pCardState,
|
|
pLocal->bContainerIndex,
|
|
0);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Remove this container from the container map
|
|
//
|
|
|
|
dwSts = ContainerMapDeleteContainer(
|
|
pLocal->pCardState,
|
|
pUserCtx->wszBaseContainerName,
|
|
&bContainerIndex);
|
|
|
|
DsysAssert(bContainerIndex == pLocal->bContainerIndex);
|
|
|
|
Ret:
|
|
if (wszFilename)
|
|
CspFreeH(wszFilename);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Determines if the current context was acquired using CRYPT_VERIFYCONTEXT
|
|
// semantics.
|
|
//
|
|
// A VerifyContext is allowed for some calls if and only if the
|
|
// context has been associated with a specific card. The fAllowWithCardAccess
|
|
// param should be set to TRUE in those cases.
|
|
//
|
|
DWORD CheckForVerifyContext(
|
|
IN PUSER_CONTEXT pUserContext,
|
|
IN BOOL fAllowOnlyWithCardAccess)
|
|
{
|
|
PLOCAL_USER_CONTEXT pLocal = (PLOCAL_USER_CONTEXT)
|
|
pUserContext->pvLocalUserContext;
|
|
|
|
if (CRYPT_VERIFYCONTEXT & pUserContext->dwFlags)
|
|
{
|
|
if (fAllowOnlyWithCardAccess)
|
|
{
|
|
if (NULL != pLocal && NULL != pLocal->pCardState)
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
return NTE_BAD_FLAGS;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Function: LocalAcquireContext
|
|
//
|
|
DWORD LocalAcquireContext(
|
|
PUSER_CONTEXT pUserContext,
|
|
PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
PLOCAL_USER_CONTEXT pLocalUserContext = NULL;
|
|
DWORD dwSts;
|
|
CARD_MATCH_DATA CardMatchData;
|
|
LPWSTR pwsz = NULL;
|
|
PCSP_STATE pCspState = NULL;
|
|
DWORD cch = 0;
|
|
CONTAINER_MAP_RECORD ContainerRecord;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalAcquireContext);
|
|
|
|
memset(&CardMatchData, 0, sizeof(CardMatchData));
|
|
memset(&ContainerRecord, 0, sizeof(ContainerRecord));
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
// Determine if any container/reader information
|
|
// has been specified.
|
|
if (pUserContext->wszContainerNameFromCaller)
|
|
{
|
|
pwsz = (LPWSTR) pUserContext->wszContainerNameFromCaller;
|
|
|
|
if (0 == wcsncmp(L"\\\\.\\", pwsz, 4))
|
|
{
|
|
// A reader has been specified
|
|
pwsz += wcslen(L"\\\\.\\");
|
|
|
|
// pwsz now points to the reader name
|
|
|
|
CardMatchData.pwszContainerName =
|
|
wcschr(pwsz, L'\\') + 1;
|
|
|
|
cch = (DWORD) (CardMatchData.pwszContainerName - pwsz - 1);
|
|
|
|
CardMatchData.pwszReaderName = (LPWSTR) CspAllocH(
|
|
sizeof(WCHAR) * (1 + cch));
|
|
|
|
LOG_CHECK_ALLOC(CardMatchData.pwszReaderName);
|
|
|
|
memcpy(
|
|
CardMatchData.pwszReaderName,
|
|
pwsz,
|
|
sizeof(WCHAR) * cch);
|
|
}
|
|
else
|
|
{
|
|
CardMatchData.pwszContainerName = pwsz;
|
|
}
|
|
|
|
// Check and cleanup the specified container name
|
|
if (CardMatchData.pwszContainerName)
|
|
{
|
|
// Additional backslashes are not allowed.
|
|
if (wcschr(
|
|
CardMatchData.pwszContainerName,
|
|
L'\\'))
|
|
{
|
|
dwSts = (DWORD) NTE_BAD_KEYSET;
|
|
goto Ret;
|
|
}
|
|
|
|
// There may have just been a trailing '\'
|
|
// with no following container name, or the
|
|
// specified name may have just been the NULL string.
|
|
if (L'\0' == CardMatchData.pwszContainerName[0])
|
|
{
|
|
CardMatchData.pwszContainerName = NULL;
|
|
}
|
|
}
|
|
|
|
// Verify that the final container name isn't too long
|
|
if (NULL != CardMatchData.pwszContainerName &&
|
|
MAX_CONTAINER_NAME_LEN < wcslen(CardMatchData.pwszContainerName))
|
|
{
|
|
dwSts = (DWORD) NTE_BAD_KEYSET;
|
|
goto Ret;
|
|
}
|
|
}
|
|
|
|
// Get pointer to global CSP data; includes
|
|
// list of cached card information.
|
|
dwSts = GetCspState(&pCspState);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
// Setup the caller's cryptographic context.
|
|
pLocalUserContext = (PLOCAL_USER_CONTEXT) CspAllocH(sizeof(LOCAL_USER_CONTEXT));
|
|
|
|
LOG_CHECK_ALLOC(pLocalUserContext);
|
|
|
|
pLocalUserContext->dwVersion = LOCAL_USER_CONTEXT_CURRENT_VERSION;
|
|
|
|
// Prepare info for matching an available
|
|
// smart card to the caller's request.
|
|
CardMatchData.dwCtxFlags = pUserContext->dwFlags;
|
|
CardMatchData.dwMatchType = CARD_MATCH_TYPE_READER_AND_CONTAINER;
|
|
CardMatchData.cchMatchedCard = MAX_PATH;
|
|
CardMatchData.cchMatchedReader = MAX_PATH;
|
|
CardMatchData.cchMatchedSerialNumber = MAX_PATH;
|
|
CardMatchData.pCspState = pCspState;
|
|
CardMatchData.dwShareMode = SCARD_SHARE_SHARED;
|
|
CardMatchData.dwPreferredProtocols =
|
|
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
|
|
|
|
// Try to find a matching card.
|
|
dwSts = FindCard(&CardMatchData);
|
|
|
|
//
|
|
// Check for a VERIFYCONTEXT request in which no container specification
|
|
// has been made. A failed card match is fine in that case since
|
|
// this context will only be used to query generic CSP information.
|
|
//
|
|
|
|
if (ERROR_SUCCESS != dwSts &&
|
|
(CRYPT_VERIFYCONTEXT & pUserContext->dwFlags) &&
|
|
NULL == pUserContext->wszContainerNameFromCaller)
|
|
{
|
|
pUserContext->pvLocalUserContext = (PVOID) pLocalUserContext;
|
|
pLocalUserContext = NULL;
|
|
|
|
dwSts = ERROR_SUCCESS;
|
|
goto Ret;
|
|
}
|
|
|
|
// Any other non-success case is fatal
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
pLocalUserContext->pCardState = CardMatchData.pCardState;
|
|
pLocalUserContext->bContainerIndex = CardMatchData.bContainerIndex;
|
|
|
|
// Read configuration information out of the registry.
|
|
dwSts = RegConfigGetSettings(
|
|
&pLocalUserContext->RegSettings);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// If the caller requested a new container but didn't give a container
|
|
// name, create a Guid name now.
|
|
//
|
|
if (NULL == CardMatchData.pwszContainerName &&
|
|
(CRYPT_NEWKEYSET & pUserContext->dwFlags))
|
|
{
|
|
dwSts = CreateUuidContainerName(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
}
|
|
else if (NULL != CardMatchData.pwszContainerName)
|
|
{
|
|
// Caller did give a container name, or the default container is
|
|
// being used and we queried the name from the card during
|
|
// our search. Copy it into the user context.
|
|
|
|
pUserContext->wszBaseContainerName = (LPWSTR) CspAllocH(
|
|
sizeof(WCHAR) * (1 + wcslen(CardMatchData.pwszContainerName)));
|
|
|
|
LOG_CHECK_ALLOC(pUserContext->wszBaseContainerName);
|
|
|
|
wcscpy(
|
|
pUserContext->wszBaseContainerName,
|
|
CardMatchData.pwszContainerName);
|
|
}
|
|
|
|
//
|
|
// Associate context information for this CSP
|
|
//
|
|
pUserContext->pvLocalUserContext = (PVOID) pLocalUserContext;
|
|
|
|
if (NULL != pUserContext->wszBaseContainerName)
|
|
{
|
|
//
|
|
// Make a copy of the base container name to use as the "unique" container
|
|
// name, since for this CSP they're the same.
|
|
//
|
|
// The only reason we should skip this step is for VERIFY_CONTEXT.
|
|
//
|
|
|
|
pUserContext->wszUniqueContainerName = (LPWSTR) CspAllocH(
|
|
sizeof(WCHAR) * (1 + wcslen(pUserContext->wszBaseContainerName)));
|
|
|
|
LOG_CHECK_ALLOC(pUserContext->wszUniqueContainerName);
|
|
|
|
wcscpy(
|
|
pUserContext->wszUniqueContainerName,
|
|
pUserContext->wszBaseContainerName);
|
|
|
|
if (CRYPT_NEWKEYSET & pUserContext->dwFlags)
|
|
{
|
|
//
|
|
// Add-container requires us to
|
|
// authenticate to the card, since we'll need to write the updated
|
|
// container map.
|
|
//
|
|
|
|
dwSts = BeginCardCapiCall(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspAuthenticateUser(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = ContainerMapAddContainer(
|
|
pLocalUserContext->pCardState,
|
|
pUserContext->wszBaseContainerName,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
&pLocalUserContext->bContainerIndex);
|
|
|
|
//
|
|
// Determine if there is already a "default" container on this
|
|
// card. If not, mark the new one as default.
|
|
//
|
|
dwSts = ContainerMapGetDefaultContainer(
|
|
pLocalUserContext->pCardState,
|
|
&ContainerRecord,
|
|
NULL);
|
|
|
|
if (NTE_BAD_KEYSET == dwSts)
|
|
{
|
|
dwSts = ContainerMapSetDefaultContainer(
|
|
pLocalUserContext->pCardState,
|
|
pUserContext->wszBaseContainerName);
|
|
}
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DsysAssert(CRYPT_VERIFYCONTEXT & pUserContext->dwFlags);
|
|
}
|
|
|
|
//
|
|
// If caller has requested a Delete Keyset, then do that work now
|
|
// and cleanup the local user context at the end.
|
|
//
|
|
if (CRYPT_DELETEKEYSET & pUserContext->dwFlags)
|
|
{
|
|
dwSts = BeginCardCapiCall(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspAuthenticateUser(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = DeleteContainer(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
}
|
|
else
|
|
{
|
|
pLocalUserContext = NULL;
|
|
}
|
|
|
|
Ret:
|
|
|
|
if (pUserContext->pvLocalUserContext)
|
|
EndCardCapiCall(pUserContext);
|
|
|
|
if (pCspState)
|
|
ReleaseCspState(&pCspState);
|
|
|
|
if (pLocalUserContext)
|
|
{
|
|
pUserContext->pvLocalUserContext = NULL;
|
|
DeleteLocalUserContext(pLocalUserContext);
|
|
CspFreeH(pLocalUserContext);
|
|
}
|
|
|
|
if (CardMatchData.pwszReaderName)
|
|
CspFreeH(CardMatchData.pwszReaderName);
|
|
if (CardMatchData.fFreeContainerName &&
|
|
CardMatchData.pwszContainerName)
|
|
CspFreeH(CardMatchData.pwszContainerName);
|
|
|
|
LOG_END_CRYPTOAPI(LocalAcquireContext, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalReleaseContext
|
|
//
|
|
DWORD WINAPI
|
|
LocalReleaseContext(
|
|
IN PUSER_CONTEXT pUserCtx,
|
|
IN DWORD dwFlags,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalReleaseContext);
|
|
|
|
if (pLocal)
|
|
{
|
|
DeleteLocalUserContext(pLocal);
|
|
CspFreeH(pLocal);
|
|
pUserCtx->pvLocalUserContext = NULL;
|
|
}
|
|
|
|
LOG_END_CRYPTOAPI(LocalReleaseContext, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalGenKey
|
|
//
|
|
DWORD WINAPI
|
|
LocalGenKey(
|
|
IN PKEY_CONTEXT pKeyCtx,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
PUSER_CONTEXT pUserCtx = pKeyCtx->pUserContext;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
CARD_CAPABILITIES CardCapabilities;
|
|
HCRYPTKEY hKey = 0;
|
|
PBYTE pbKey = NULL;
|
|
DWORD cbKey = 0;
|
|
PLOCAL_KEY_CONTEXT pLocalKeyCtx = NULL;
|
|
BYTE bContainerIndex = 0;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalGenKey);
|
|
|
|
memset(&CardCapabilities, 0, sizeof(CardCapabilities));
|
|
|
|
if (CALG_RSA_KEYX == pKeyCtx->Algid)
|
|
pKeyCtx->Algid = AT_KEYEXCHANGE;
|
|
else if (CALG_RSA_SIGN == pKeyCtx->Algid)
|
|
pKeyCtx->Algid = AT_SIGNATURE;
|
|
|
|
if (AT_SIGNATURE == pKeyCtx->Algid ||
|
|
AT_KEYEXCHANGE == pKeyCtx->Algid)
|
|
{
|
|
// Public key call. Handle this here since we have to talk to the
|
|
// card. All other key algs will be handled in the support CSP.
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, FALSE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (CRYPT_EXPORTABLE & pKeyCtx->dwFlags)
|
|
{
|
|
dwSts = NTE_BAD_FLAGS;
|
|
goto Ret;
|
|
}
|
|
|
|
dwSts = BeginCardCapiCall(pUserCtx);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspQueryCapabilities(
|
|
pLocalUserCtx->pCardState,
|
|
&CardCapabilities);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (0 == pKeyCtx->cKeyBits)
|
|
pKeyCtx->cKeyBits = pLocalUserCtx->RegSettings.cDefaultPrivateKeyLenBits;
|
|
|
|
//
|
|
// If ARCHIVABLE is set, we don't gen the key on the card, since we
|
|
// don't want to force cards to support exportable private keys.
|
|
//
|
|
if ( CardCapabilities.fKeyGen &&
|
|
0 == (CRYPT_ARCHIVABLE & pKeyCtx->dwFlags))
|
|
{
|
|
dwSts = CspAuthenticateUser(pUserCtx);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspCreateContainer(
|
|
pLocalUserCtx->pCardState,
|
|
pLocalUserCtx->bContainerIndex,
|
|
CARD_CREATE_CONTAINER_KEY_GEN,
|
|
pKeyCtx->Algid,
|
|
pKeyCtx->cKeyBits,
|
|
NULL);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
}
|
|
else
|
|
{
|
|
// This card does not support on-card key generation. See
|
|
// if we're allowed to create our own key blob and import
|
|
// it.
|
|
|
|
if (pLocalUserCtx->RegSettings.fRequireOnCardPrivateKeyGen)
|
|
{
|
|
dwSts = (DWORD) SCARD_E_UNSUPPORTED_FEATURE;
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Create a new, exportable private key in the software CSP. Then
|
|
// export it and import it onto the card.
|
|
//
|
|
|
|
if (! CryptGenKey(
|
|
pUserCtx->hSupportProv,
|
|
pKeyCtx->Algid,
|
|
CRYPT_EXPORTABLE | (pKeyCtx->cKeyBits << 16),
|
|
&hKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
if (! CryptExportKey(
|
|
hKey,
|
|
0,
|
|
PRIVATEKEYBLOB,
|
|
0,
|
|
NULL,
|
|
&cbKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pbKey = (PBYTE) CspAllocH(cbKey);
|
|
|
|
LOG_CHECK_ALLOC(pbKey);
|
|
|
|
if (! CryptExportKey(
|
|
hKey,
|
|
0,
|
|
PRIVATEKEYBLOB,
|
|
0,
|
|
pbKey,
|
|
&cbKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
dwSts = CspAuthenticateUser(pUserCtx);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspCreateContainer(
|
|
pLocalUserCtx->pCardState,
|
|
pLocalUserCtx->bContainerIndex,
|
|
CARD_CREATE_CONTAINER_KEY_IMPORT,
|
|
pKeyCtx->Algid,
|
|
cbKey,
|
|
pbKey);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Check for CRYPT_ARCHIVABLE. If it's set, we'll keep a copy of
|
|
// the private key for the lifetime of this key context for the
|
|
// caller to export it.
|
|
//
|
|
|
|
if (CRYPT_ARCHIVABLE & pKeyCtx->dwFlags)
|
|
{
|
|
pLocalKeyCtx = (PLOCAL_KEY_CONTEXT) CspAllocH(
|
|
sizeof(LOCAL_KEY_CONTEXT));
|
|
|
|
LOG_CHECK_ALLOC(pLocalKeyCtx);
|
|
|
|
pLocalKeyCtx->pbArchivablePrivateKey = pbKey;
|
|
pLocalKeyCtx->cbArchivablePrivateKey = cbKey;
|
|
pbKey = NULL;
|
|
pKeyCtx->pvLocalKeyContext = (PVOID) pLocalKeyCtx;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the new key information for this container to the map file
|
|
//
|
|
|
|
dwSts = ContainerMapAddContainer(
|
|
pLocalUserCtx->pCardState,
|
|
pUserCtx->wszBaseContainerName,
|
|
pKeyCtx->cKeyBits,
|
|
pKeyCtx->Algid,
|
|
FALSE,
|
|
&bContainerIndex);
|
|
|
|
DsysAssert(bContainerIndex == pLocalUserCtx->bContainerIndex);
|
|
}
|
|
else
|
|
{
|
|
// Not a public key call, so handle in the support CSP.
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
}
|
|
|
|
Ret:
|
|
|
|
EndCardCapiCall(pUserCtx);
|
|
|
|
if (pbKey)
|
|
{
|
|
RtlSecureZeroMemory(pbKey, cbKey);
|
|
CspFreeH(pbKey);
|
|
}
|
|
|
|
if (hKey)
|
|
CryptDestroyKey(hKey);
|
|
|
|
LOG_END_CRYPTOAPI(LocalGenKey, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalDestroyKey
|
|
//
|
|
DWORD WINAPI
|
|
LocalDestroyKey(
|
|
IN OUT PKEY_CONTEXT pKeyContext,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
PLOCAL_KEY_CONTEXT pLocalKeyCtx =
|
|
(PLOCAL_KEY_CONTEXT) pKeyContext->pvLocalKeyContext;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalDestroyKey);
|
|
|
|
if (NULL != pLocalKeyCtx)
|
|
{
|
|
if (NULL != pLocalKeyCtx->pbArchivablePrivateKey)
|
|
{
|
|
RtlSecureZeroMemory(
|
|
pLocalKeyCtx->pbArchivablePrivateKey,
|
|
pLocalKeyCtx->cbArchivablePrivateKey);
|
|
CspFreeH(pLocalKeyCtx->pbArchivablePrivateKey);
|
|
pLocalKeyCtx->pbArchivablePrivateKey = NULL;
|
|
}
|
|
|
|
CspFreeH(pLocalKeyCtx);
|
|
pKeyContext->pvLocalKeyContext = NULL;
|
|
}
|
|
|
|
LOG_END_CRYPTOAPI(LocalDestroyKey, ERROR_SUCCESS);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Determines if an encoded certificate blob contains certain Enhanced Key
|
|
// Usage OIDs. The target OIDs are SmartCard Logon and Enrollment Agent.
|
|
// If either OID is present, the key container associated with this
|
|
// certificate should be considered the new default container on the target
|
|
// card.
|
|
//
|
|
DWORD CheckCertUsageForDefaultContainer(
|
|
PBYTE pbEncodedCert,
|
|
DWORD cbEncodedCert,
|
|
BOOL *pfMakeDefault)
|
|
{
|
|
DWORD dwSts = 0;
|
|
PCCERT_CONTEXT pCertCtx = NULL;
|
|
PCERT_ENHKEY_USAGE pUsage = NULL;
|
|
DWORD cbUsage = 0;
|
|
|
|
*pfMakeDefault = FALSE;
|
|
|
|
//
|
|
// Build a cert context from the encoded blob
|
|
//
|
|
|
|
pCertCtx = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
pbEncodedCert,
|
|
cbEncodedCert);
|
|
|
|
if (NULL == pCertCtx)
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Get an array of the EKU OIDs present in this cert
|
|
//
|
|
|
|
if (! CertGetEnhancedKeyUsage(
|
|
pCertCtx,
|
|
0,
|
|
NULL,
|
|
&cbUsage))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pUsage = (PCERT_ENHKEY_USAGE) CspAllocH(cbUsage);
|
|
|
|
if (NULL == pUsage)
|
|
{
|
|
dwSts = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
if (! CertGetEnhancedKeyUsage(
|
|
pCertCtx,
|
|
0,
|
|
pUsage,
|
|
&cbUsage))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Look for the two specific OIDs that would make this the new default
|
|
// cert/container
|
|
//
|
|
|
|
while (pUsage->cUsageIdentifier)
|
|
{
|
|
pUsage->cUsageIdentifier -= 1;
|
|
|
|
if (0 == strcmp(
|
|
szOID_KP_SMARTCARD_LOGON,
|
|
pUsage->rgpszUsageIdentifier[pUsage->cUsageIdentifier]) ||
|
|
0 == strcmp(
|
|
szOID_ENROLLMENT_AGENT,
|
|
pUsage->rgpszUsageIdentifier[pUsage->cUsageIdentifier]))
|
|
{
|
|
*pfMakeDefault = TRUE;
|
|
}
|
|
}
|
|
|
|
Ret:
|
|
|
|
if (pUsage)
|
|
CspFreeH(pUsage);
|
|
if (pCertCtx)
|
|
CertFreeCertificateContext(pCertCtx);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalSetKeyParam
|
|
//
|
|
DWORD WINAPI
|
|
LocalSetKeyParam(
|
|
IN PKEY_CONTEXT pKeyCtx,
|
|
IN DWORD dwParam,
|
|
IN CONST BYTE *pbData,
|
|
IN DWORD dwFlags,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
|
|
DWORD cbCert = 0;
|
|
DWORD cbCompressed = 0;
|
|
PBYTE pbCompressed = NULL;
|
|
LPWSTR wszCertFilename = NULL;
|
|
CARD_FILE_ACCESS_CONDITION Acl = EveryoneReadUserWriteAc;
|
|
DATA_BLOB CertData;
|
|
CARD_CAPABILITIES CardCapabilities;
|
|
BOOL fMakeDefault = FALSE;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalSetKeyParam);
|
|
|
|
memset(&CertData, 0, sizeof(CertData));
|
|
memset(&CardCapabilities, 0, sizeof(CardCapabilities));
|
|
|
|
switch (dwParam)
|
|
{
|
|
case KP_CERTIFICATE:
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, FALSE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Determine how long the encoded cert blob is.
|
|
//
|
|
__try
|
|
{
|
|
cbCert = Asn1UtilAdjustEncodedLength(
|
|
pbData, (DWORD) cbENCODED_CERT_OVERFLOW);
|
|
|
|
if (0 == cbCert || cbENCODED_CERT_OVERFLOW == cbCert)
|
|
{
|
|
dwSts = (DWORD) NTE_BAD_DATA;
|
|
goto Ret;
|
|
}
|
|
}
|
|
__except(EXCEPTION_ACCESS_VIOLATION == GetExceptionCode() ?
|
|
EXCEPTION_EXECUTE_HANDLER :
|
|
EXCEPTION_CONTINUE_SEARCH)
|
|
{
|
|
dwSts = (DWORD) NTE_BAD_DATA;
|
|
goto Ret;
|
|
}
|
|
|
|
// Begin a transaction and reconnect the card if necessary
|
|
dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Build the filename we'll use for this cert
|
|
//
|
|
dwSts = BuildCertificateFilename(
|
|
pKeyCtx->pUserContext, pKeyCtx->Algid, &wszCertFilename);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Determine if this certificate contains OIDs that should make the
|
|
// associated key container the new default.
|
|
//
|
|
dwSts = CheckCertUsageForDefaultContainer(
|
|
(PBYTE) pbData,
|
|
cbCert,
|
|
&fMakeDefault);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Determine the capabilities of the target card - we want to know
|
|
// whether it (or its card module) implements its own data
|
|
// compression.
|
|
//
|
|
|
|
dwSts = CspQueryCapabilities(
|
|
pLocalUserCtx->pCardState,
|
|
&CardCapabilities);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (FALSE == CardCapabilities.fCertificateCompression)
|
|
{
|
|
//
|
|
// If this card doesn't implement its own certificate compression
|
|
// then we will compress the cert.
|
|
//
|
|
// Find out how big the compressed cert will be
|
|
//
|
|
dwSts = CompressData(cbCert, NULL, &cbCompressed, NULL);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
pbCompressed = CspAllocH(cbCompressed);
|
|
|
|
LOG_CHECK_ALLOC(pbCompressed);
|
|
|
|
// Compress the cert
|
|
dwSts = CompressData(
|
|
cbCert,
|
|
(PBYTE) pbData,
|
|
&cbCompressed,
|
|
pbCompressed);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
CertData.cbData = cbCompressed;
|
|
CertData.pbData = pbCompressed;
|
|
}
|
|
else
|
|
{
|
|
CertData.cbData = cbCert;
|
|
CertData.pbData = (PBYTE) pbData;
|
|
}
|
|
|
|
//
|
|
// Authenticate to the card as User
|
|
//
|
|
dwSts = CspAuthenticateUser(pKeyCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Write the cert to the card.
|
|
//
|
|
dwSts = CspCreateFile(
|
|
pLocalUserCtx->pCardState,
|
|
wszCertFilename,
|
|
Acl);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspWriteFile(
|
|
pLocalUserCtx->pCardState,
|
|
wszCertFilename,
|
|
0,
|
|
CertData.pbData,
|
|
CertData.cbData);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (fMakeDefault)
|
|
{
|
|
dwSts = ContainerMapSetDefaultContainer(
|
|
pLocalUserCtx->pCardState,
|
|
pKeyCtx->pUserContext->wszBaseContainerName);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
break;
|
|
}
|
|
|
|
Ret:
|
|
|
|
EndCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (pbCompressed)
|
|
CspFreeH(pbCompressed);
|
|
if (wszCertFilename)
|
|
CspFreeH(wszCertFilename);
|
|
|
|
LOG_END_CRYPTOAPI(LocalSetKeyParam, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalGetKeyParam
|
|
//
|
|
DWORD WINAPI
|
|
LocalGetKeyParam(
|
|
IN PKEY_CONTEXT pKeyCtx,
|
|
IN DWORD dwParam,
|
|
OUT LPBYTE pbData,
|
|
IN OUT LPDWORD pcbDataLen,
|
|
IN DWORD dwFlags,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
|
|
LPWSTR wszCertFilename = NULL;
|
|
DATA_BLOB CertData;
|
|
DWORD cbUncompressed = 0;
|
|
CARD_CAPABILITIES CardCapabilities;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalGetKeyParam);
|
|
|
|
memset(&CertData, 0, sizeof(CertData));
|
|
memset(&CardCapabilities, 0, sizeof(CardCapabilities));
|
|
|
|
switch (dwParam)
|
|
{
|
|
case KP_CERTIFICATE:
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, TRUE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
// Note, reading the certificate files should not require
|
|
// authentication to the card, but we will Enter Transaction
|
|
// to be safe.
|
|
|
|
dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Get the name of the certificate file to read from the card.
|
|
//
|
|
dwSts = BuildCertificateFilename(
|
|
pKeyCtx->pUserContext, pKeyCtx->Algid, &wszCertFilename);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Read the file from the card.
|
|
//
|
|
dwSts = CspReadFile(
|
|
pLocalUserCtx->pCardState,
|
|
wszCertFilename,
|
|
0,
|
|
&CertData.pbData,
|
|
&CertData.cbData);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
if (SCARD_E_FILE_NOT_FOUND == dwSts)
|
|
dwSts = SCARD_E_NO_SUCH_CERTIFICATE;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
dwSts = CspQueryCapabilities(
|
|
pLocalUserCtx->pCardState,
|
|
&CardCapabilities);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (FALSE == CardCapabilities.fCertificateCompression)
|
|
{
|
|
//
|
|
// If this card doesn't implement its own certificate compression,
|
|
// then we expect the cert was compressed by the CSP.
|
|
//
|
|
// Find out how big the uncompressed cert will be
|
|
//
|
|
|
|
dwSts = UncompressData(
|
|
CertData.cbData,
|
|
CertData.pbData,
|
|
&cbUncompressed,
|
|
NULL);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Check the length of the caller's buffer, or if the caller is just
|
|
// querying for size.
|
|
//
|
|
if (*pcbDataLen < cbUncompressed || NULL == pbData)
|
|
{
|
|
*pcbDataLen = cbUncompressed;
|
|
|
|
if (NULL != pbData)
|
|
dwSts = ERROR_MORE_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbDataLen = cbUncompressed;
|
|
|
|
// Uncompress the cert into the caller's buffer
|
|
dwSts = UncompressData(
|
|
CertData.cbData,
|
|
CertData.pbData,
|
|
&cbUncompressed,
|
|
pbData);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
{
|
|
if (ERROR_INTERNAL_ERROR == dwSts)
|
|
dwSts = NTE_BAD_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This card does implement its own compression, so assume that
|
|
// we have received the cert uncompressed.
|
|
//
|
|
if (*pcbDataLen < CertData.cbData || NULL == pbData)
|
|
{
|
|
*pcbDataLen = CertData.cbData;
|
|
|
|
if (NULL != pbData)
|
|
dwSts = ERROR_MORE_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbDataLen = CertData.cbData;
|
|
|
|
memcpy(pbData, CertData.pbData, CertData.cbData);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
break;
|
|
}
|
|
|
|
Ret:
|
|
|
|
EndCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (CertData.pbData)
|
|
CspFreeH(CertData.pbData);
|
|
if (wszCertFilename)
|
|
CspFreeH(wszCertFilename);
|
|
|
|
LOG_END_CRYPTOAPI(LocalGetKeyParam, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalSetProvParam
|
|
//
|
|
DWORD WINAPI
|
|
LocalSetProvParam(
|
|
IN PUSER_CONTEXT pUserCtx,
|
|
IN DWORD dwParam,
|
|
IN CONST BYTE *pbData,
|
|
IN DWORD dwFlags,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pUserCtx->pvLocalUserContext;
|
|
PINCACHE_PINS Pins;
|
|
PFN_VERIFYPIN_CALLBACK pfnVerify = VerifyPinCallback;
|
|
VERIFY_PIN_CALLBACK_DATA CallbackCtx;
|
|
DWORD iChar = 0;
|
|
LPSTR szPin = NULL;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalSetProvParam);
|
|
|
|
memset(&Pins, 0, sizeof(Pins));
|
|
memset(&CallbackCtx, 0, sizeof(CallbackCtx));
|
|
|
|
switch (dwParam)
|
|
{
|
|
case PP_KEYEXCHANGE_PIN:
|
|
case PP_SIGNATURE_PIN:
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = CheckForVerifyContext(pUserCtx, FALSE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = PinStringToBytesA(
|
|
(LPSTR) pbData,
|
|
&Pins.cbCurrentPin,
|
|
&Pins.pbCurrentPin);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = BeginCardCapiCall(pUserCtx);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
// Remove any existing cached pin, just in case
|
|
CspRemoveCachedPin(
|
|
pLocalUserCtx->pCardState, wszCARD_USER_USER);
|
|
|
|
CallbackCtx.pUserCtx = pUserCtx;
|
|
CallbackCtx.wszUserId = wszCARD_USER_USER;
|
|
|
|
dwSts = PinCacheAdd(
|
|
&pLocalUserCtx->pCardState->hPinCache,
|
|
&Pins,
|
|
pfnVerify,
|
|
(PVOID) &CallbackCtx);
|
|
|
|
// We're now authenticated to the card if the pin was correct. Make
|
|
// sure we deauthenticate below.
|
|
if (ERROR_SUCCESS == dwSts)
|
|
pLocalUserCtx->pCardState->fAuthenticated = TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
break;
|
|
}
|
|
|
|
Ret:
|
|
EndCardCapiCall(pUserCtx);
|
|
|
|
if (Pins.pbCurrentPin)
|
|
CspFreeH(Pins.pbCurrentPin);
|
|
|
|
LOG_END_CRYPTOAPI(LocalSetProvParam, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalGetProvParam
|
|
//
|
|
DWORD WINAPI
|
|
LocalGetProvParam(
|
|
IN PUSER_CONTEXT pUserContext,
|
|
IN DWORD dwParam,
|
|
OUT PBYTE pbData,
|
|
IN OUT PDWORD pcbDataLen,
|
|
IN DWORD dwFlags,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pUserContext->pvLocalUserContext;
|
|
BYTE cContainers = 0;
|
|
LPWSTR mwszContainers = NULL;
|
|
DWORD cbContainers = 0;
|
|
DWORD cchContainers = 0;
|
|
DWORD cbCurrent = 0;
|
|
BOOL fTransacted = FALSE;
|
|
PROV_ENUMALGS *pEnumAlgs = NULL;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalGetProvParam);
|
|
|
|
switch (dwParam)
|
|
{
|
|
case PP_ENUMALGS_EX:
|
|
case PP_ENUMALGS:
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
// Build the list of supported algorithms if we haven't done so already
|
|
// for this context.
|
|
if (NULL == pLocalUserCtx->pSupportedAlgs)
|
|
{
|
|
dwSts = BuildSupportedAlgorithmsList(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
}
|
|
|
|
// Reset the enumeration if requested.
|
|
if (CRYPT_FIRST == dwFlags)
|
|
pLocalUserCtx->pCurrentAlg = pLocalUserCtx->pSupportedAlgs;
|
|
|
|
// Is the enumeration already done?
|
|
if (NULL == pLocalUserCtx->pCurrentAlg)
|
|
{
|
|
dwSts = ERROR_NO_MORE_ITEMS;
|
|
goto Ret;
|
|
}
|
|
|
|
cbCurrent = (PP_ENUMALGS_EX == dwParam) ?
|
|
sizeof(PROV_ENUMALGS_EX) :
|
|
sizeof(PROV_ENUMALGS);
|
|
|
|
// Check the size of the caller's buffer or if caller is merely
|
|
// requesting size info.
|
|
if (NULL == pbData || *pcbDataLen < cbCurrent)
|
|
{
|
|
*pcbDataLen = cbCurrent;
|
|
|
|
if (NULL != pbData)
|
|
dwSts = ERROR_MORE_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbDataLen = cbCurrent;
|
|
|
|
if (PP_ENUMALGS_EX == dwParam)
|
|
{
|
|
memcpy(pbData, &pLocalUserCtx->pCurrentAlg->EnumalgsEx, cbCurrent);
|
|
}
|
|
else
|
|
{
|
|
// Have to do a member-wise copy of the PROV_ENUMALGS struct since
|
|
// the list we maintain is PROV_ENUMALGS_EX.
|
|
|
|
pEnumAlgs = (PROV_ENUMALGS *) pbData;
|
|
|
|
pEnumAlgs->aiAlgid =
|
|
pLocalUserCtx->pCurrentAlg->EnumalgsEx.aiAlgid;
|
|
pEnumAlgs->dwBitLen =
|
|
pLocalUserCtx->pCurrentAlg->EnumalgsEx.dwDefaultLen;
|
|
pEnumAlgs->dwNameLen =
|
|
pLocalUserCtx->pCurrentAlg->EnumalgsEx.dwNameLen;
|
|
|
|
memcpy(
|
|
pEnumAlgs->szName,
|
|
pLocalUserCtx->pCurrentAlg->EnumalgsEx.szName,
|
|
pEnumAlgs->dwNameLen);
|
|
}
|
|
|
|
pLocalUserCtx->pCurrentAlg = pLocalUserCtx->pCurrentAlg->pNext;
|
|
|
|
break;
|
|
|
|
case PP_ENUMCONTAINERS:
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = CheckForVerifyContext(pUserContext, TRUE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (NULL == pLocalUserCtx->mszEnumContainers ||
|
|
CRYPT_FIRST == dwFlags)
|
|
{
|
|
//
|
|
// We need to build a new list of containers on this card if we
|
|
// haven't already done so, or if the caller is starting a new
|
|
// container enumeration.
|
|
//
|
|
|
|
if (NULL != pLocalUserCtx->mszEnumContainers)
|
|
{
|
|
CspFreeH(pLocalUserCtx->mszEnumContainers);
|
|
pLocalUserCtx->mszEnumContainers = NULL;
|
|
pLocalUserCtx->mszCurrentEnumContainer = NULL;
|
|
}
|
|
|
|
dwSts = BeginCardCapiCall(pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
fTransacted = TRUE;
|
|
|
|
dwSts = ContainerMapEnumContainers(
|
|
pLocalUserCtx->pCardState,
|
|
&cContainers,
|
|
&mwszContainers);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
cchContainers = CountCharsInMultiSz(mwszContainers);
|
|
|
|
cbContainers = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
mwszContainers,
|
|
cchContainers,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (0 == cbContainers)
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pLocalUserCtx->mszEnumContainers = (LPSTR) CspAllocH(cbContainers);
|
|
|
|
LOG_CHECK_ALLOC(pLocalUserCtx->mszEnumContainers);
|
|
|
|
cbContainers = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
mwszContainers,
|
|
cchContainers,
|
|
pLocalUserCtx->mszEnumContainers,
|
|
cbContainers,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (0 == cbContainers)
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pLocalUserCtx->mszCurrentEnumContainer =
|
|
pLocalUserCtx->mszEnumContainers;
|
|
}
|
|
|
|
if (NULL == pLocalUserCtx->mszCurrentEnumContainer ||
|
|
'\0' == pLocalUserCtx->mszCurrentEnumContainer[0])
|
|
{
|
|
dwSts = ERROR_NO_MORE_ITEMS;
|
|
goto Ret;
|
|
}
|
|
|
|
cbCurrent = (strlen(
|
|
pLocalUserCtx->mszCurrentEnumContainer) + 1) * sizeof(CHAR);
|
|
|
|
if (NULL == pbData || *pcbDataLen < cbCurrent)
|
|
{
|
|
*pcbDataLen = cbCurrent;
|
|
|
|
if (NULL != pbData)
|
|
dwSts = ERROR_MORE_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbDataLen = cbCurrent;
|
|
|
|
memcpy(
|
|
pbData,
|
|
(PBYTE) pLocalUserCtx->mszCurrentEnumContainer,
|
|
cbCurrent);
|
|
|
|
((PBYTE) pLocalUserCtx->mszCurrentEnumContainer) += cbCurrent;
|
|
|
|
break;
|
|
|
|
default:
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
break;
|
|
}
|
|
|
|
Ret:
|
|
|
|
if (fTransacted)
|
|
EndCardCapiCall(pUserContext);
|
|
|
|
LOG_END_CRYPTOAPI(LocalGetProvParam, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
|
|
//
|
|
// Function: LocalExportKey
|
|
//
|
|
DWORD WINAPI
|
|
LocalExportKey(
|
|
IN PKEY_CONTEXT pKeyCtx,
|
|
IN PKEY_CONTEXT pPubKeyCtx,
|
|
IN DWORD dwBlobType,
|
|
IN DWORD dwFlags,
|
|
OUT LPBYTE pbData,
|
|
IN OUT LPDWORD pcbDataLen,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocalUserCtx =
|
|
(PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
|
|
CONTAINER_INFO ContainerInfo;
|
|
DWORD cbKey = 0;
|
|
PBYTE pbKey = 0;
|
|
PLOCAL_KEY_CONTEXT pLocalKeyCtx = NULL;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalExportKey);
|
|
|
|
memset(&ContainerInfo, 0, sizeof(ContainerInfo));
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
|
|
switch (dwBlobType)
|
|
{
|
|
case PRIVATEKEYBLOB:
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
if (NULL != pKeyCtx->pvLocalKeyContext)
|
|
{
|
|
pLocalKeyCtx = (PLOCAL_KEY_CONTEXT) pKeyCtx->pvLocalKeyContext;
|
|
|
|
if (NULL != pLocalKeyCtx->pbArchivablePrivateKey)
|
|
{
|
|
if ( *pcbDataLen < pLocalKeyCtx->cbArchivablePrivateKey ||
|
|
NULL == pbData)
|
|
{
|
|
*pcbDataLen = pLocalKeyCtx->cbArchivablePrivateKey;
|
|
|
|
if (NULL != pbData)
|
|
dwSts = ERROR_MORE_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbDataLen = pLocalKeyCtx->cbArchivablePrivateKey;
|
|
|
|
memcpy(
|
|
pbData,
|
|
pLocalKeyCtx->pbArchivablePrivateKey,
|
|
pLocalKeyCtx->cbArchivablePrivateKey);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwSts = (DWORD) NTE_BAD_TYPE;
|
|
break;
|
|
|
|
case PUBLICKEYBLOB:
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspGetContainerInfo(
|
|
pLocalUserCtx->pCardState,
|
|
pLocalUserCtx->bContainerIndex,
|
|
0,
|
|
&ContainerInfo);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
switch (pKeyCtx->Algid)
|
|
{
|
|
case AT_SIGNATURE:
|
|
cbKey = ContainerInfo.cbSigPublicKey;
|
|
pbKey = ContainerInfo.pbSigPublicKey;
|
|
break;
|
|
|
|
case AT_KEYEXCHANGE:
|
|
cbKey = ContainerInfo.cbKeyExPublicKey;
|
|
pbKey = ContainerInfo.pbKeyExPublicKey;
|
|
break;
|
|
|
|
default:
|
|
dwSts = (DWORD) NTE_BAD_KEY;
|
|
goto Ret;
|
|
}
|
|
|
|
if (*pcbDataLen < cbKey || NULL == pbData)
|
|
{
|
|
*pcbDataLen = cbKey;
|
|
|
|
if (NULL != pbData)
|
|
dwSts = ERROR_MORE_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
*pcbDataLen = cbKey;
|
|
|
|
memcpy(pbData, pbKey, cbKey);
|
|
break;
|
|
}
|
|
|
|
Ret:
|
|
EndCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
CleanupContainerInfo(&ContainerInfo);
|
|
|
|
LOG_END_CRYPTOAPI(LocalExportKey, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalImportKey
|
|
//
|
|
DWORD WINAPI
|
|
LocalImportKey(
|
|
IN PKEY_CONTEXT pKeyContext,
|
|
IN PBYTE pbData,
|
|
IN DWORD cbDataLen,
|
|
IN PKEY_CONTEXT pPubKey,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
BLOBHEADER *pBlobHeader = (BLOBHEADER *) pbData;
|
|
PBYTE pbDecrypted = NULL;
|
|
DWORD cbDecrypted = 0;
|
|
CARD_PRIVATE_KEY_DECRYPT_INFO DecryptInfo;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pKeyContext->pUserContext->pvLocalUserContext;
|
|
PBYTE pbPlaintextBlob = NULL;
|
|
DWORD cbPlaintextBlob = 0;
|
|
|
|
memset(&DecryptInfo, 0, sizeof(DecryptInfo));
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalImportKey);
|
|
|
|
switch (pBlobHeader->bType)
|
|
{
|
|
case SIMPLEBLOB:
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
// Only allow Key Exchange type keys to decrypt other keys
|
|
if (AT_SIGNATURE == pPubKey->Algid)
|
|
{
|
|
dwSts = (DWORD) NTE_BAD_TYPE;
|
|
goto Ret;
|
|
}
|
|
|
|
if (CALG_RSA_KEYX != *(ALG_ID *) (pbData + sizeof(BLOBHEADER)))
|
|
{
|
|
dwSts = (DWORD) NTE_BAD_ALGID;
|
|
goto Ret;
|
|
}
|
|
|
|
if (pPubKey->pUserContext != pKeyContext->pUserContext)
|
|
{
|
|
dwSts = (DWORD) NTE_BAD_UID;
|
|
goto Ret;
|
|
}
|
|
|
|
dwSts = CheckForVerifyContext(pKeyContext->pUserContext, FALSE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Decrypt a session key blob using the private key.
|
|
//
|
|
|
|
dwSts = BeginCardCapiCall(pKeyContext->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspAuthenticateUser(pKeyContext->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
DecryptInfo.cbData = cbDataLen - sizeof(BLOBHEADER) - sizeof(ALG_ID);
|
|
DecryptInfo.dwKeySpec = AT_KEYEXCHANGE;
|
|
DecryptInfo.dwVersion = CARD_PRIVATE_KEY_DECRYPT_INFO_CURRENT_VERSION;
|
|
DecryptInfo.pbData = pbData + sizeof(BLOBHEADER) + sizeof(ALG_ID);
|
|
DecryptInfo.bContainerIndex = pLocal->bContainerIndex;
|
|
|
|
dwSts = CspPrivateKeyDecrypt(
|
|
pLocal->pCardState,
|
|
&DecryptInfo);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = VerifyPKCS2Padding(
|
|
DecryptInfo.pbData,
|
|
DecryptInfo.cbData,
|
|
&pbDecrypted,
|
|
&cbDecrypted);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Now we can build a PLAINTEXTKEYBLOB with the decrypted session key
|
|
// and import it into the helper CSP.
|
|
//
|
|
|
|
cbPlaintextBlob = sizeof(BLOBHEADER) + sizeof(DWORD) + cbDecrypted;
|
|
|
|
pbPlaintextBlob = CspAllocH(cbPlaintextBlob);
|
|
|
|
LOG_CHECK_ALLOC(pbPlaintextBlob);
|
|
|
|
((BLOBHEADER *) pbPlaintextBlob)->aiKeyAlg = pBlobHeader->aiKeyAlg;
|
|
((BLOBHEADER *) pbPlaintextBlob)->bType = PLAINTEXTKEYBLOB;
|
|
((BLOBHEADER *) pbPlaintextBlob)->bVersion = CUR_BLOB_VERSION;
|
|
|
|
*(DWORD *) (pbPlaintextBlob + sizeof(BLOBHEADER)) = cbDecrypted;
|
|
|
|
memcpy(
|
|
pbPlaintextBlob + sizeof(BLOBHEADER) + sizeof(DWORD),
|
|
pbDecrypted,
|
|
cbDecrypted);
|
|
|
|
if (! CryptImportKey(
|
|
pKeyContext->pUserContext->hSupportProv,
|
|
pbPlaintextBlob,
|
|
cbPlaintextBlob,
|
|
0,
|
|
pKeyContext->dwFlags,
|
|
&pKeyContext->hSupportKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pKeyContext->Algid = pBlobHeader->aiKeyAlg;
|
|
pKeyContext->cKeyBits = cbDecrypted * 8;
|
|
|
|
break;
|
|
|
|
case PRIVATEKEYBLOB:
|
|
|
|
// We don't allow importing privatekey blobs into the smartcard
|
|
// CSP, and it doesn't make sense to use the helper CSP for this,
|
|
// so fail.
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = (DWORD) NTE_BAD_TYPE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// For all other blob types, let the helper CSP take a shot.
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
}
|
|
|
|
|
|
Ret:
|
|
|
|
EndCardCapiCall(pKeyContext->pUserContext);
|
|
|
|
if (pbDecrypted)
|
|
CspFreeH(pbDecrypted);
|
|
if (pbPlaintextBlob)
|
|
CspFreeH(pbPlaintextBlob);
|
|
|
|
LOG_END_CRYPTOAPI(LocalImportKey, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalEncrypt
|
|
//
|
|
DWORD WINAPI
|
|
LocalEncrypt(
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTKEY hKey,
|
|
IN HCRYPTHASH hHash,
|
|
IN BOOL fFinal,
|
|
IN DWORD dwFlags,
|
|
IN OUT LPBYTE pbData,
|
|
IN OUT LPDWORD pcbDataLen,
|
|
IN DWORD cbBufLen)
|
|
{
|
|
*pcbDataLen = 0;
|
|
|
|
//
|
|
// TODO
|
|
//
|
|
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
//
|
|
// Function: LocalDecrypt
|
|
//
|
|
DWORD WINAPI
|
|
LocalDecrypt(
|
|
IN PKEY_CONTEXT pKeyCtx,
|
|
IN PHASH_CONTEXT pHashCtx,
|
|
IN BOOL fFinal,
|
|
IN DWORD dwFlags,
|
|
IN OUT LPBYTE pbData,
|
|
IN OUT LPDWORD pcbDataLen,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PBYTE pbDecrypted = NULL;
|
|
DWORD cbDecrypted = 0;
|
|
CARD_PRIVATE_KEY_DECRYPT_INFO DecryptInfo;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pKeyCtx->pUserContext->pvLocalUserContext;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalDecrypt);
|
|
|
|
memset(&DecryptInfo, 0, sizeof(DecryptInfo));
|
|
|
|
dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, FALSE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (AT_KEYEXCHANGE == pKeyCtx->Algid)
|
|
{
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
}
|
|
else
|
|
{
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
goto Ret;
|
|
}
|
|
|
|
dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = CspAuthenticateUser(pKeyCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
DecryptInfo.cbData = *pcbDataLen;
|
|
DecryptInfo.dwKeySpec = AT_KEYEXCHANGE;
|
|
DecryptInfo.dwVersion = CARD_PRIVATE_KEY_DECRYPT_INFO_CURRENT_VERSION;
|
|
DecryptInfo.pbData = pbData;
|
|
DecryptInfo.bContainerIndex = pLocal->bContainerIndex;
|
|
|
|
dwSts = CspPrivateKeyDecrypt(
|
|
pLocal->pCardState,
|
|
&DecryptInfo);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = VerifyPKCS2Padding(
|
|
DecryptInfo.pbData,
|
|
DecryptInfo.cbData,
|
|
&pbDecrypted,
|
|
&cbDecrypted);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
memcpy(
|
|
pbData,
|
|
pbDecrypted,
|
|
cbDecrypted);
|
|
|
|
*pcbDataLen = cbDecrypted;
|
|
|
|
Ret:
|
|
EndCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (pbDecrypted)
|
|
CspFreeH(pbDecrypted);
|
|
|
|
LOG_END_CRYPTOAPI(LocalDecrypt, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalSignHash
|
|
//
|
|
DWORD WINAPI
|
|
LocalSignHash(
|
|
IN PHASH_CONTEXT pHashCtx,
|
|
IN DWORD dwKeySpec,
|
|
IN DWORD dwFlags,
|
|
OUT LPBYTE pbSignature,
|
|
IN OUT LPDWORD pcbSigLen,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pHashCtx->pUserContext->pvLocalUserContext;
|
|
PBYTE pbHash = NULL;
|
|
PBYTE pbSig = NULL;
|
|
DWORD cbHash = 0;
|
|
DWORD cbPrivateKey = 0;
|
|
ALG_ID aiHash = 0;
|
|
DWORD cbData = 0;
|
|
CARD_PRIVATE_KEY_DECRYPT_INFO DecryptInfo;
|
|
RSAPUBKEY *pPubKey = NULL;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalSignHash);
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = CheckForVerifyContext(pHashCtx->pUserContext, FALSE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
memset(&DecryptInfo, 0, sizeof(DecryptInfo));
|
|
|
|
dwSts = BeginCardCapiCall(pHashCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Get the size of the private key that will be used for signing
|
|
//
|
|
dwSts = GetKeyModulusLength(
|
|
pHashCtx->pUserContext, dwKeySpec, &cbPrivateKey);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (*pcbSigLen < cbPrivateKey || NULL == pbSignature)
|
|
{
|
|
*pcbSigLen = cbPrivateKey;
|
|
|
|
if (NULL != pbSignature)
|
|
dwSts = ERROR_MORE_DATA;
|
|
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Get the hash value we're going to sign
|
|
//
|
|
if (! CryptGetHashParam(
|
|
pHashCtx->hSupportHash,
|
|
HP_HASHVAL,
|
|
NULL,
|
|
&cbHash,
|
|
0))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
pbHash = (PBYTE) CspAllocH(cbHash);
|
|
|
|
LOG_CHECK_ALLOC(pbHash);
|
|
|
|
if (! CryptGetHashParam(
|
|
pHashCtx->hSupportHash,
|
|
HP_HASHVAL,
|
|
pbHash,
|
|
&cbHash,
|
|
0))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Get the algid of this hash so the correct encoding can be applied
|
|
//
|
|
cbData = sizeof(aiHash);
|
|
|
|
if (! CryptGetHashParam(
|
|
pHashCtx->hSupportHash,
|
|
HP_ALGID,
|
|
(PBYTE) &aiHash,
|
|
&cbData,
|
|
0))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Apply PKCS1 encoding to this hash data. It gets padded out to the
|
|
// length of the key modulus. The padded buffer is allocated for us.
|
|
//
|
|
dwSts = ApplyPKCS1SigningFormat(
|
|
aiHash,
|
|
pbHash,
|
|
cbHash,
|
|
0,
|
|
cbPrivateKey,
|
|
&pbSig);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Private key decrypt the formatted data
|
|
//
|
|
dwSts = CspAuthenticateUser(pHashCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
DecryptInfo.cbData = cbPrivateKey;
|
|
DecryptInfo.pbData = pbSig;
|
|
DecryptInfo.dwKeySpec = dwKeySpec;
|
|
DecryptInfo.dwVersion = CARD_PRIVATE_KEY_DECRYPT_INFO_CURRENT_VERSION;
|
|
DecryptInfo.bContainerIndex = pLocal->bContainerIndex;
|
|
|
|
dwSts = CspPrivateKeyDecrypt(
|
|
pLocal->pCardState,
|
|
&DecryptInfo);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Copy the completed signature into the caller's buffer
|
|
//
|
|
memcpy(
|
|
pbSignature,
|
|
pbSig,
|
|
cbPrivateKey);
|
|
|
|
*pcbSigLen = cbPrivateKey;
|
|
|
|
Ret:
|
|
EndCardCapiCall(pHashCtx->pUserContext);
|
|
|
|
if (pbSig)
|
|
CspFreeH(pbSig);
|
|
if (pbHash)
|
|
CspFreeH(pbHash);
|
|
|
|
LOG_END_CRYPTOAPI(LocalSignHash, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalVerifySignature
|
|
//
|
|
DWORD WINAPI
|
|
LocalVerifySignature(
|
|
IN PHASH_CONTEXT pHashCtx,
|
|
IN CONST BYTE *pbSignature,
|
|
IN DWORD cbSigLen,
|
|
IN PKEY_CONTEXT pKeyCtx,
|
|
IN DWORD dwFlags,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
PLOCAL_USER_CONTEXT pLocal =
|
|
(PLOCAL_USER_CONTEXT) pHashCtx->pUserContext->pvLocalUserContext;
|
|
CONTAINER_INFO ContainerInfo;
|
|
HCRYPTKEY hKey = 0;
|
|
BOOL fSignature = (AT_SIGNATURE == pKeyCtx->Algid);
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalVerifySignature);
|
|
|
|
memset(&ContainerInfo, 0, sizeof(ContainerInfo));
|
|
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
|
|
dwSts = CheckForVerifyContext(pHashCtx->pUserContext, FALSE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = BeginCardCapiCall(pHashCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Get the public key
|
|
//
|
|
dwSts = CspGetContainerInfo(
|
|
pLocal->pCardState,
|
|
pLocal->bContainerIndex,
|
|
0,
|
|
&ContainerInfo);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Import the public key into the helper CSP
|
|
//
|
|
if (! CryptImportKey(
|
|
pHashCtx->pUserContext->hSupportProv,
|
|
fSignature ?
|
|
ContainerInfo.pbSigPublicKey :
|
|
ContainerInfo.pbKeyExPublicKey,
|
|
fSignature ?
|
|
ContainerInfo.cbSigPublicKey :
|
|
ContainerInfo.cbKeyExPublicKey,
|
|
0,
|
|
0,
|
|
&hKey))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Use the helper CSP to verify the signature
|
|
//
|
|
if (! CryptVerifySignature(
|
|
pHashCtx->hSupportHash,
|
|
pbSignature,
|
|
cbSigLen,
|
|
hKey,
|
|
NULL,
|
|
dwFlags))
|
|
{
|
|
dwSts = GetLastError();
|
|
goto Ret;
|
|
}
|
|
|
|
Ret:
|
|
EndCardCapiCall(pHashCtx->pUserContext);
|
|
|
|
CleanupContainerInfo(&ContainerInfo);
|
|
|
|
if (hKey)
|
|
CryptDestroyKey(hKey);
|
|
|
|
LOG_END_CRYPTOAPI(LocalVerifySignature, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalGetUserKey
|
|
//
|
|
DWORD WINAPI
|
|
LocalGetUserKey(
|
|
IN PKEY_CONTEXT pKeyCtx,
|
|
OUT PLOCAL_CALL_INFO pLocalCallInfo)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
DWORD cbKey = 0;
|
|
|
|
LOG_BEGIN_CRYPTOAPI(LocalGetUserKey);
|
|
|
|
if (AT_SIGNATURE == pKeyCtx->Algid || AT_KEYEXCHANGE == pKeyCtx->Algid)
|
|
{
|
|
SetLocalCallInfo(pLocalCallInfo, FALSE);
|
|
}
|
|
else
|
|
{
|
|
SetLocalCallInfo(pLocalCallInfo, TRUE);
|
|
goto Ret;
|
|
}
|
|
|
|
dwSts = CheckForVerifyContext(pKeyCtx->pUserContext, TRUE);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = BeginCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
dwSts = GetKeyModulusLength(
|
|
pKeyCtx->pUserContext,
|
|
pKeyCtx->Algid,
|
|
&cbKey);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
if (cbKey)
|
|
{
|
|
pKeyCtx->cKeyBits = cbKey * 8;
|
|
}
|
|
else
|
|
{
|
|
dwSts = (DWORD) NTE_NO_KEY;
|
|
goto Ret;
|
|
}
|
|
|
|
Ret:
|
|
EndCardCapiCall(pKeyCtx->pUserContext);
|
|
|
|
LOG_END_CRYPTOAPI(LocalGetUserKey, dwSts);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalDuplicateKey
|
|
//
|
|
DWORD WINAPI
|
|
LocalDuplicateKey(
|
|
IN HCRYPTPROV hProv,
|
|
IN HCRYPTKEY hKey,
|
|
IN LPDWORD pdwReserved,
|
|
IN DWORD dwFlags,
|
|
OUT HCRYPTKEY *phKey)
|
|
{
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
//
|
|
// Function: UnloadStrings
|
|
//
|
|
void
|
|
UnloadStrings(
|
|
IN PCSP_STRING pStrings,
|
|
IN DWORD cStrings)
|
|
{
|
|
DWORD iString = 0;
|
|
|
|
for ( iString = 0;
|
|
iString < cStrings;
|
|
iString++)
|
|
{
|
|
if (NULL != pStrings[iString].wszString)
|
|
{
|
|
CspFreeH(pStrings[iString].wszString);
|
|
pStrings[iString].wszString = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Function: LoadStrings
|
|
//
|
|
DWORD
|
|
LoadStrings(
|
|
IN HMODULE hMod,
|
|
IN PCSP_STRING pStrings,
|
|
IN DWORD cStrings)
|
|
{
|
|
DWORD dwSts = ERROR_INTERNAL_ERROR;
|
|
DWORD cch;
|
|
WCHAR wsz[MAX_PATH];
|
|
DWORD iString = 0;
|
|
|
|
for ( iString = 0;
|
|
iString < cStrings;
|
|
iString++)
|
|
{
|
|
cch = LoadStringW(
|
|
hMod,
|
|
pStrings[iString].dwResource,
|
|
wsz,
|
|
sizeof(wsz) / sizeof(wsz[0]));
|
|
|
|
if (0 == cch)
|
|
{
|
|
dwSts = GetLastError();
|
|
goto ErrorExit;
|
|
}
|
|
|
|
pStrings[iString].wszString = (LPWSTR) CspAllocH(sizeof(WCHAR) * (cch + 1));
|
|
|
|
if (NULL == pStrings[iString].wszString)
|
|
{
|
|
dwSts = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
wcscpy(
|
|
pStrings[iString].wszString,
|
|
wsz);
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
ErrorExit:
|
|
|
|
UnloadStrings(pStrings, cStrings);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Function: LocalDllInitialize
|
|
//
|
|
BOOL WINAPI LocalDllInitialize(
|
|
IN PVOID hmod,
|
|
IN ULONG Reason,
|
|
IN PCONTEXT Context)
|
|
{
|
|
DWORD dwLen = 0;
|
|
static BOOL fLoadedStrings = FALSE;
|
|
static BOOL fInitializedCspState = FALSE;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
switch (Reason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
// load strings
|
|
if (ERROR_SUCCESS != LoadStrings(
|
|
hmod,
|
|
g_Strings,
|
|
sizeof(g_Strings) / sizeof(g_Strings[0])))
|
|
goto Cleanup;
|
|
|
|
fLoadedStrings = TRUE;
|
|
|
|
// Initialize global CSP data for this process
|
|
if (ERROR_SUCCESS != InitializeCspState(hmod))
|
|
goto Cleanup;
|
|
|
|
fInitializedCspState = TRUE;
|
|
|
|
CspInitializeDebug();
|
|
|
|
fSuccess = TRUE;
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
CspUnloadDebug();
|
|
|
|
fSuccess = TRUE;
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
return fSuccess;
|
|
|
|
Cleanup:
|
|
|
|
if (fLoadedStrings)
|
|
{
|
|
UnloadStrings(
|
|
g_Strings,
|
|
sizeof(g_Strings) / sizeof(g_Strings[0]));
|
|
|
|
fLoadedStrings = FALSE;
|
|
}
|
|
|
|
if (fInitializedCspState)
|
|
{
|
|
DeleteCspState();
|
|
fInitializedCspState = FALSE;
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Function: LocalDllRegisterServer
|
|
//
|
|
DWORD WINAPI LocalDllRegisterServer(void)
|
|
{
|
|
HKEY hKey = 0;
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
|
|
dwSts = RegOpenProviderKey(&hKey, KEY_ALL_ACCESS);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
//
|
|
// Add CSP default configuration
|
|
//
|
|
dwSts = RegConfigAddEntries(hKey);
|
|
|
|
if (ERROR_SUCCESS != dwSts)
|
|
goto Ret;
|
|
|
|
Ret:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return dwSts;
|
|
}
|
|
|
|
//
|
|
// Declaration of the LOCAL_CSP_INFO structure required by the
|
|
// CSP lib.
|
|
//
|
|
LOCAL_CSP_INFO LocalCspInfo =
|
|
{
|
|
|
|
LocalAcquireContext, //pfnLocalAcquireContext;
|
|
LocalReleaseContext, //pfnLocalReleaseContext;
|
|
LocalGenKey, //pfnLocalGenKey;
|
|
NULL, //pfnLocalDeriveKey;
|
|
LocalDestroyKey, //pfnLocalDestroyKey;
|
|
LocalSetKeyParam, //pfnLocalSetKeyParam;
|
|
LocalGetKeyParam, //pfnLocalGetKeyParam;
|
|
LocalSetProvParam, //pfnLocalSetProvParam;
|
|
LocalGetProvParam, //pfnLocalGetProvParam;
|
|
NULL, //pfnLocalSetHashParam;
|
|
NULL, //pfnLocalGetHashParam;
|
|
LocalExportKey, //pfnLocalExportKey;
|
|
LocalImportKey, //pfnLocalImportKey;
|
|
NULL, //pfnLocalEncrypt;
|
|
LocalDecrypt, //pfnLocalDecrypt;
|
|
NULL, //pfnLocalCreateHash;
|
|
NULL, //pfnLocalHashData;
|
|
NULL, //pfnLocalHashSessionKey;
|
|
LocalSignHash, //pfnLocalSignHash;
|
|
NULL, //pfnLocalDestroyHash;
|
|
LocalVerifySignature, //pfnLocalVerifySignature;
|
|
NULL, //pfnLocalGenRandom;
|
|
LocalGetUserKey, //pfnLocalGetUserKey;
|
|
NULL, //pfnLocalDuplicateHash;
|
|
NULL, //pfnLocalDuplicateKey;
|
|
|
|
LocalDllInitialize, //pfnLocalDllInitialize;
|
|
LocalDllRegisterServer, //pfnLocalDllRegisterServer;
|
|
NULL, //pfnLocalDllUnregisterServer;
|
|
|
|
MS_SCARD_PROV_W, //wszProviderName;
|
|
PROV_RSA_FULL, //dwProviderType;
|
|
CRYPT_IMPL_REMOVABLE,
|
|
|
|
MS_STRONG_PROV, //wszSupportProviderName;
|
|
PROV_RSA_FULL //dwSupportProviderType;
|
|
|
|
};
|