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.
3053 lines
81 KiB
3053 lines
81 KiB
#include <windows.h>
|
|
#include <psapi.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 "basecsp.h"
|
|
#include "cardmod.h"
|
|
#include "wpscproxy.h"
|
|
#include "marshalpc.h"
|
|
#include <limits.h>
|
|
#include "pincache.h"
|
|
#include <rsa.h>
|
|
#include <carddbg.h>
|
|
#include <stdio.h>
|
|
#include "physfile.h"
|
|
|
|
DWORD I_CardMapErrorCode(IN SCODE status);
|
|
|
|
//
|
|
// Get the number of characters in a Unicode string,
|
|
// NOT including the terminating Null.
|
|
//
|
|
#define WSZ_CHAR_COUNT(x) ((sizeof(x) / sizeof(WCHAR)) - 1)
|
|
|
|
//
|
|
// Macro for testing DWORD return codes. Any return not equal to
|
|
// ERROR_SUCCESS is assumed to mean Failure.
|
|
//
|
|
#define CARDMOD_FAILED(x) (ERROR_SUCCESS != x)
|
|
|
|
//
|
|
// Debug Logging
|
|
//
|
|
// This uses the debug routines from dsysdbg.h
|
|
// Debug output will only be available in chk
|
|
// bits.
|
|
//
|
|
DEFINE_DEBUG2(Cardmod)
|
|
|
|
#define LOG_BEGIN_FUNCTION(x) \
|
|
{ DebugLog((DEB_TRACE_FUNC, "%s: Entering\n", #x)); }
|
|
|
|
#define LOG_END_FUNCTION(x, y) \
|
|
{ DebugLog((DEB_TRACE_FUNC, "%s: Leaving, status: 0x%x\n", #x, y)); }
|
|
|
|
#define LOG_CHECK_ALLOC(x) \
|
|
{ if (NULL == x) { \
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY; \
|
|
DebugLog((DEB_TRACE_MEM, "%s: Allocation failed\n", #x)); \
|
|
goto Ret; \
|
|
} }
|
|
|
|
#define LOG_CHECK_SCW_CALL(x) \
|
|
{ if (ERROR_SUCCESS != (dwError = I_CardMapErrorCode(x))) { \
|
|
DebugLog((DEB_TRACE_FUNC, "%s: failed, status: 0x%x\n", \
|
|
#x, dwError)); \
|
|
goto Ret; \
|
|
} }
|
|
|
|
//
|
|
// Defines for interoperating with Crypto API public keys
|
|
//
|
|
#define cbCAPI_PUBLIC_EXPONENT 3
|
|
#define CAPI_PUBLIC_EXPONENT 0x10001
|
|
|
|
//
|
|
// Define data size used for Admin principal challenge-response authentication
|
|
//
|
|
#define cbCHALLENGE_RESPONSE_DATA 8
|
|
|
|
//
|
|
// Card module applet instruction codes
|
|
//
|
|
#define PIN_CHANGE_CLA 0x00
|
|
#define PIN_CHANGE_INS 0x52
|
|
#define PIN_CHANGE_P1 0x00
|
|
#define PIN_CHANGE_P2 0x00
|
|
|
|
#define PIN_UNBLOCK_CLA 0x00
|
|
#define PIN_UNBLOCK_INS 0x52
|
|
#define PIN_UNBLOCK_P1 0x01
|
|
// PIN_UNBLOCK_P2 is the new max retry count, which can be set by caller
|
|
|
|
#define PIN_RETRY_COUNTER_CLA 0x00
|
|
#define PIN_RETRY_COUNTER_INS 0x50
|
|
#define PIN_RETRY_COUNTER_P1 0x00
|
|
#define PIN_RETRY_COUNTER_P2 0x00
|
|
|
|
//
|
|
// Data Structures used by this module
|
|
//
|
|
|
|
//
|
|
// Type: SUPPORTED_CARD
|
|
//
|
|
#define MAX_SUPPORTED_FILE_LEN 50 // WCHARS
|
|
#define MAX_SUPPORTED_CARD_ATR_LEN 21
|
|
|
|
typedef struct _SUPPORTED_CARD_
|
|
{
|
|
LPWSTR wszCardName;
|
|
BYTE rgbAtr[MAX_SUPPORTED_CARD_ATR_LEN];
|
|
DWORD cbAtr;
|
|
BYTE rgbAtrMask[MAX_SUPPORTED_CARD_ATR_LEN];
|
|
|
|
CARD_CAPABILITIES CardCapabilities;
|
|
CARD_FREE_SPACE_INFO CardFreeSpaceInfo;
|
|
CARD_KEY_SIZES CardKeySizes_KeyEx;
|
|
CARD_KEY_SIZES CardKeySizes_Sig;
|
|
|
|
} SUPPORTED_CARD, *PSUPPORTED_CARD;
|
|
|
|
SUPPORTED_CARD SupportedCards [] =
|
|
{
|
|
//
|
|
// ITG's deployment cards
|
|
//
|
|
|
|
// T=1
|
|
{ L"ITG_MSCSP_V1",
|
|
{ 0x3b, 0x8c, 0x81, 0x31, 0x20, 0x55, 0x49, 0x54,
|
|
0x47, 0x5f, 0x4d, 0x53, 0x43, 0x53, 0x50, 0x5f,
|
|
0x56, 0x31, 0x2a },
|
|
19,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF },
|
|
{ CARD_CAPABILITIES_CURRENT_VERSION, FALSE, FALSE },
|
|
{ CARD_FREE_SPACE_INFO_CURRENT_VERSION, CARD_DATA_VALUE_UNKNOWN, (DWORD) -1, 2 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 }
|
|
},
|
|
|
|
// T=0
|
|
{ L"ITG_MSCSP_V2",
|
|
{ 0x3b, 0xdc, 0x13, 0x00, 0x40, 0x3a, 0x49, 0x54,
|
|
0x47, 0x5f, 0x4d, 0x53, 0x43, 0x53, 0x50, 0x5f,
|
|
0x56, 0x32 },
|
|
18,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF },
|
|
{ CARD_CAPABILITIES_CURRENT_VERSION, FALSE, FALSE },
|
|
{ CARD_FREE_SPACE_INFO_CURRENT_VERSION, CARD_DATA_VALUE_UNKNOWN, (DWORD) -1, 2 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 }
|
|
},
|
|
|
|
//
|
|
// These are Windows for Smart Cards test cards. They do not support
|
|
// on-card key gen.
|
|
//
|
|
|
|
// T=0 Cards
|
|
{ L"BaseCSP-T0-1",
|
|
{ 0x3B, 0xDC, 0x13, 0x00, 0x40, 0x3A, 0x42, 0x61,
|
|
0x73, 0x65, 0x43, 0x53, 0x50, 0x2D, 0x54, 0x30,
|
|
0x2D, 0x31 },
|
|
18,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF },
|
|
{ CARD_CAPABILITIES_CURRENT_VERSION, FALSE, FALSE },
|
|
{ CARD_FREE_SPACE_INFO_CURRENT_VERSION, CARD_DATA_VALUE_UNKNOWN, (DWORD) -1, 2 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 }
|
|
},
|
|
|
|
// T=1 Card, 9600 bps
|
|
{ L"BaseCSP-T1-1",
|
|
{ 0x3B, 0x8C, 0x81, 0x31, 0x20, 0x55, 0x42, 0x61,
|
|
0x73, 0x65, 0x43, 0x53, 0x50, 0x2D, 0x54, 0x31,
|
|
0x2D, 0x31, 0x68 },
|
|
19,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF },
|
|
{ CARD_CAPABILITIES_CURRENT_VERSION, FALSE, FALSE },
|
|
{ CARD_FREE_SPACE_INFO_CURRENT_VERSION, CARD_DATA_VALUE_UNKNOWN, (DWORD) -1, 2 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 }
|
|
},
|
|
|
|
// T=1 Card, 19 kbps
|
|
{ L"BaseCSP-T1-2",
|
|
{ 0x3B, 0xDC, 0x13, 0x0A, 0x81, 0x31, 0x20, 0x55, 0x42, 0x61,
|
|
0x73, 0x65, 0x43, 0x53, 0x50, 0x2D, 0x54, 0x31,
|
|
0x2D, 0x31, 0x21 },
|
|
21,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF },
|
|
{ CARD_CAPABILITIES_CURRENT_VERSION, FALSE, FALSE },
|
|
{ CARD_FREE_SPACE_INFO_CURRENT_VERSION, CARD_DATA_VALUE_UNKNOWN, (DWORD) -1, 2 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 }
|
|
},
|
|
|
|
// T=1 Card, 38 kbps
|
|
{ L"BaseCSP-T1-3",
|
|
{ 0x3B, 0x9C, 0x13, 0x81, 0x31, 0x20, 0x55, 0x42, 0x61,
|
|
0x73, 0x65, 0x43, 0x53, 0x50, 0x2D, 0x54, 0x31,
|
|
0x2D, 0x31, 0x6B },
|
|
20,
|
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF },
|
|
{ CARD_CAPABILITIES_CURRENT_VERSION, FALSE, FALSE },
|
|
{ CARD_FREE_SPACE_INFO_CURRENT_VERSION, CARD_DATA_VALUE_UNKNOWN, (DWORD) -1, 2 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 },
|
|
{ CARD_KEY_SIZES_CURRENT_VERSION, 1024, 1024, 1024, 0 }
|
|
}
|
|
};
|
|
|
|
static WCHAR l_wszImagePath[MAX_PATH];
|
|
|
|
//
|
|
// Type: CARDMOD_CONTEXT
|
|
//
|
|
typedef struct _CARDMOD_CONTEXT
|
|
{
|
|
SCARDHANDLE hWfscCardHandle;
|
|
PSUPPORTED_CARD pSupportedCard;
|
|
|
|
} CARDMOD_CONTEXT, *PCARDMOD_CONTEXT;
|
|
|
|
typedef struct _VERIFY_PIN_CALLBACK_DATA
|
|
{
|
|
LPWSTR wszUserId;
|
|
PCARD_DATA pCardData;
|
|
} VERIFY_PIN_CALLBACK_DATA, *PVERIFY_PIN_CALLBACK_DATA;
|
|
|
|
//
|
|
// Maps status codes returned from the Smart Card for Windows proxy to common
|
|
// Windows status codes.
|
|
//
|
|
DWORD I_CardMapErrorCode(
|
|
IN SCODE status)
|
|
{
|
|
DWORD iMap = 0;
|
|
struct {
|
|
SCODE scode;
|
|
DWORD dwError;
|
|
} ErrorMap [] = {
|
|
{ SCW_S_OK, ERROR_SUCCESS },
|
|
{ SCW_E_FILENOTFOUND, (DWORD) SCARD_E_FILE_NOT_FOUND },
|
|
{ SCW_E_DIRNOTFOUND, (DWORD) SCARD_E_DIR_NOT_FOUND },
|
|
{ SCW_E_PARTITIONFULL, (DWORD) SCARD_E_WRITE_TOO_MANY },
|
|
{ SCW_E_MEMORYFAILURE, ERROR_NOT_ENOUGH_MEMORY },
|
|
{ SCW_E_VMNOMEMORY, ERROR_NOT_ENOUGH_MEMORY },
|
|
{ SCW_E_NOTAUTHENTICATED, (DWORD) SCARD_E_INVALID_CHV },
|
|
{ SCW_E_ALREADYEXISTS, (DWORD) ERROR_FILE_EXISTS }
|
|
};
|
|
|
|
for (iMap = 0; iMap < (sizeof(ErrorMap) / sizeof(ErrorMap[0])); iMap++)
|
|
{
|
|
if (ErrorMap[iMap].scode == status)
|
|
return ErrorMap[iMap].dwError;
|
|
}
|
|
|
|
// Otherwise, best we can do is pass a general error
|
|
DebugLog((
|
|
DEB_WARN,
|
|
"I_CardMapErrorCode could not map error 0x%X\n",
|
|
status));
|
|
|
|
return (DWORD) SCARD_F_INTERNAL_ERROR;
|
|
}
|
|
|
|
//
|
|
// Maps the error code returned by a card applet to a common error code. The
|
|
// status word returned by the applet is first converted into a Windows For
|
|
// Smart Cards error code.
|
|
//
|
|
// Reminder: Status words returned by the RTE apps are in the form:
|
|
// 9000 -> Success
|
|
// 6Fyy -> An API failed with return code yy
|
|
// 6Ezz -> An exception was raised (zz is the err number)
|
|
//
|
|
DWORD I_CardMapExecuteErrorCode(
|
|
IN WORD wStatus)
|
|
{
|
|
SCODE status = 0xC0000000 | (wStatus & 0xFF);
|
|
|
|
if (0x90 == (wStatus >> 8))
|
|
return ERROR_SUCCESS;
|
|
else
|
|
return I_CardMapErrorCode(status);
|
|
}
|
|
|
|
//
|
|
// Creates and writes a new file to the card with the supplied Access Condition
|
|
// and file contents. If fCache is true, the file is cached using the caller's
|
|
// CacheAddFile function.
|
|
//
|
|
DWORD I_CardWriteFile(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszPhysicalFile,
|
|
IN LPWSTR wszAcl,
|
|
IN PBYTE pbData,
|
|
IN DWORD cbData,
|
|
IN BOOL fCache)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
HFILE hFile = 0;
|
|
DWORD cbActual = 0;
|
|
|
|
UNREFERENCED_PARAMETER(fCache);
|
|
|
|
LOG_CHECK_SCW_CALL(hScwCreateFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
wszPhysicalFile,
|
|
wszAcl,
|
|
&hFile));
|
|
|
|
LOG_CHECK_SCW_CALL(hScwWriteFile32(
|
|
pCardmodContext->hWfscCardHandle,
|
|
hFile,
|
|
pbData,
|
|
cbData,
|
|
&cbActual));
|
|
|
|
if (cbActual != cbData)
|
|
{
|
|
dwError = (DWORD) SCARD_W_EOF;
|
|
goto Ret;
|
|
}
|
|
|
|
DebugLog((
|
|
DEB_TRACE,
|
|
"I_CardWriteFile: wrote %S, %d bytes\n",
|
|
wszPhysicalFile,
|
|
cbData));
|
|
|
|
if (fCache)
|
|
{
|
|
dwError = pCardData->pfnCspCacheAddFile(
|
|
pCardData->pvCacheContext,
|
|
wszPhysicalFile,
|
|
0,
|
|
pbData,
|
|
cbData);
|
|
}
|
|
|
|
Ret:
|
|
if (hFile)
|
|
hScwCloseFile(
|
|
pCardmodContext->hWfscCardHandle, hFile);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// If fUseCached is true, first attempts to satisfy the read request
|
|
// via the caller's CacheLookupFile function. Otherwise,
|
|
// reads a file directly from the smart card by first opening the file and
|
|
// determining its size. The file is cached using the caller's CacheAddFile
|
|
// pointer if fCache is true.
|
|
//
|
|
DWORD I_CardReadFile(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszPhysicalFile,
|
|
OUT PBYTE *ppbData,
|
|
OUT DWORD *pcbData,
|
|
IN BOOL fUseCached)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
HFILE hFile = 0;
|
|
DWORD cbActual = 0;
|
|
|
|
if (fUseCached)
|
|
{
|
|
dwError = pCardData->pfnCspCacheLookupFile(
|
|
pCardData->pvCacheContext,
|
|
wszPhysicalFile,
|
|
0,
|
|
ppbData,
|
|
pcbData);
|
|
|
|
switch (dwError)
|
|
{
|
|
case ERROR_NOT_FOUND:
|
|
// A cached copy of the requested file is not available;
|
|
// read it from the card.
|
|
break;
|
|
|
|
case ERROR_SUCCESS:
|
|
// Fall through
|
|
default:
|
|
|
|
// Either we found cached data or an unexpected error occurred.
|
|
// We're done.
|
|
|
|
goto Ret;
|
|
}
|
|
}
|
|
|
|
LOG_CHECK_SCW_CALL(hScwCreateFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
wszPhysicalFile,
|
|
NULL,
|
|
&hFile));
|
|
|
|
LOG_CHECK_SCW_CALL(hScwGetFileLength(
|
|
pCardmodContext->hWfscCardHandle,
|
|
hFile,
|
|
(TOFFSET *) pcbData));
|
|
|
|
*ppbData = (PBYTE) pCardData->pfnCspAlloc(*pcbData);
|
|
|
|
LOG_CHECK_ALLOC(*ppbData);
|
|
|
|
LOG_CHECK_SCW_CALL(hScwReadFile32(
|
|
pCardmodContext->hWfscCardHandle,
|
|
hFile,
|
|
*ppbData,
|
|
*pcbData,
|
|
&cbActual));
|
|
|
|
if (cbActual != *pcbData)
|
|
dwError = (DWORD) SCARD_W_EOF;
|
|
|
|
DebugLog((
|
|
DEB_TRACE,
|
|
"I_CardReadFile: read %S, %d bytes\n",
|
|
wszPhysicalFile,
|
|
*pcbData));
|
|
|
|
if (fUseCached)
|
|
{
|
|
// Cache this file.
|
|
dwError = pCardData->pfnCspCacheAddFile(
|
|
pCardData->pvCacheContext,
|
|
wszPhysicalFile,
|
|
0,
|
|
*ppbData,
|
|
*pcbData);
|
|
}
|
|
|
|
Ret:
|
|
if (hFile)
|
|
hScwCloseFile(
|
|
pCardmodContext->hWfscCardHandle, hFile);
|
|
|
|
if (ERROR_SUCCESS != dwError && *ppbData)
|
|
{
|
|
pCardData->pfnCspFree(*ppbData);
|
|
*ppbData = NULL;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Maps a logical user name to a physical user, or principal, recognized by
|
|
// the card.
|
|
//
|
|
DWORD GetWellKnownUserMapping(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszLogicalUser,
|
|
OUT LPWSTR *ppwszPhysicalUser)
|
|
{
|
|
DWORD dwError = ERROR_NO_SUCH_USER;
|
|
int iUser = 0;
|
|
|
|
static const WCHAR wszAdmin [] = L"admin";
|
|
static const WCHAR wszAnonymous [] = L"anonymous";
|
|
static const WCHAR wszUser [] = L"user";
|
|
|
|
struct {
|
|
LPWSTR wszLogicalUser;
|
|
const WCHAR (*wszPhysicalUser);
|
|
DWORD cchPhysicalUser;
|
|
} UserMap [] = {
|
|
{ wszCARD_USER_ADMIN,
|
|
wszAdmin,
|
|
WSZ_CHAR_COUNT(wszAdmin) },
|
|
{ wszCARD_USER_EVERYONE,
|
|
wszAnonymous,
|
|
WSZ_CHAR_COUNT(wszAnonymous) },
|
|
{ wszCARD_USER_USER,
|
|
wszUser,
|
|
WSZ_CHAR_COUNT(wszUser) }
|
|
};
|
|
|
|
for (iUser = 0; iUser < sizeof(UserMap) / sizeof(UserMap[0]); iUser++)
|
|
{
|
|
if (0 == wcscmp(wszLogicalUser, UserMap[iUser].wszLogicalUser))
|
|
{
|
|
*ppwszPhysicalUser = (LPWSTR) pCardData->pfnCspAlloc(
|
|
sizeof(WCHAR) * (1 + UserMap[iUser].cchPhysicalUser));
|
|
|
|
LOG_CHECK_ALLOC(*ppwszPhysicalUser);
|
|
|
|
wcscpy(
|
|
*ppwszPhysicalUser,
|
|
UserMap[iUser].wszPhysicalUser);
|
|
|
|
dwError = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ret:
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Maps a logical Access Condition to a physical ACL file recognized by the
|
|
// card.
|
|
//
|
|
DWORD GetWellKnownAcMapping(
|
|
IN PCARD_DATA pCardData,
|
|
IN CARD_FILE_ACCESS_CONDITION AccessCondition,
|
|
OUT LPWSTR *ppwszPhysicalAclFile)
|
|
{
|
|
DWORD dwError = ERROR_NOT_FOUND;
|
|
int iAcl = 0;
|
|
|
|
struct {
|
|
CARD_FILE_ACCESS_CONDITION LogicalAc;
|
|
const WCHAR (*wszPhysicalAcl);
|
|
DWORD cchPhysicalAcl;
|
|
} AclMap [] = {
|
|
{ EveryoneReadUserWriteAc,
|
|
wszUserWritePhysicalAcl,
|
|
WSZ_CHAR_COUNT(wszUserWritePhysicalAcl) },
|
|
{ UserWriteExecuteAc,
|
|
wszUserExecutePhysicalAcl,
|
|
WSZ_CHAR_COUNT(wszUserExecutePhysicalAcl) },
|
|
{ EveryoneReadAdminWriteAc,
|
|
wszAdminWritePhysicalAcl,
|
|
WSZ_CHAR_COUNT(wszAdminWritePhysicalAcl) }
|
|
};
|
|
|
|
for (iAcl = 0; iAcl< sizeof(AclMap) / sizeof(AclMap[0]); iAcl++)
|
|
{
|
|
if (AccessCondition == AclMap[iAcl].LogicalAc)
|
|
{
|
|
*ppwszPhysicalAclFile = (LPWSTR) pCardData->pfnCspAlloc(
|
|
(1 + AclMap[iAcl].cchPhysicalAcl) * sizeof(WCHAR));
|
|
|
|
LOG_CHECK_ALLOC(*ppwszPhysicalAclFile);
|
|
|
|
memcpy(
|
|
*ppwszPhysicalAclFile,
|
|
AclMap[iAcl].wszPhysicalAcl,
|
|
(1 + AclMap[iAcl].cchPhysicalAcl) * sizeof(WCHAR));
|
|
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ret:
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Maps a well known logical file or directory name to a physical file
|
|
// or directory.
|
|
//
|
|
DWORD GetWellKnownFileMapping(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszLogicalFileName,
|
|
OUT LPSTR *ppszPhysicalFileName)
|
|
{
|
|
DWORD cbPhysicalFileName = 0;
|
|
int i = 0;
|
|
BOOL fMatched = FALSE;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
DWORD cchLogicalName = 0;
|
|
LPSTR szAnsiExtra = NULL;
|
|
|
|
enum NameType { File, Directory };
|
|
struct {
|
|
LPWSTR wszLogicalName;
|
|
LPSTR szPhysicalName;
|
|
enum NameType type;
|
|
DWORD cbPhysicalName;
|
|
} FileMap [] = {
|
|
//
|
|
// When composing the lookup table, the deepest directory paths
|
|
// must be listed first, so that partial matching will find the
|
|
// longest partial match first.
|
|
//
|
|
{ wszUSER_SIGNATURE_CERT_PREFIX, szPHYSICAL_USER_SIGNATURE_CERT_PREFIX,
|
|
File, cbPHYSICAL_USER_SIGNATURE_CERT_PREFIX },
|
|
{ wszUSER_KEYEXCHANGE_CERT_PREFIX,szPHYSICAL_USER_KEYEXCHANGE_CERT_PREFIX,
|
|
File, cbPHYSICAL_USER_KEYEXCHANGE_CERT_PREFIX },
|
|
{ wszCSP_DATA_DIR_FULL_PATH, szPHYSICAL_CSP_DIR,
|
|
Directory, cbPHYSICAL_CSP_DIR },
|
|
{ wszCACHE_FILE_FULL_PATH, szPHYSICAL_CACHE_FILE,
|
|
File, cbPHYSICAL_CACHE_FILE },
|
|
{ wszCARD_IDENTIFIER_FILE_FULL_PATH,
|
|
szPHYSICAL_CARD_IDENTIFIER,
|
|
File, cbPHYSICAL_CARD_IDENTIFIER },
|
|
{ wszCONTAINER_MAP_FILE_FULL_PATH,
|
|
szPHYSICAL_CONTAINER_MAP_FILE,
|
|
File, cbPHYSICAL_CONTAINER_MAP_FILE },
|
|
{ wszPERSONAL_DATA_FILE_FULL_PATH,
|
|
szPHYSICAL_PERSONAL_DATA_FILE,
|
|
File, cbPHYSICAL_PERSONAL_DATA_FILE }
|
|
};
|
|
|
|
*ppszPhysicalFileName = NULL;
|
|
|
|
// First, look for an exact match.
|
|
for (i = 0; i < sizeof(FileMap) / sizeof(FileMap[0]); i++)
|
|
{
|
|
if (0 == wcscmp(wszLogicalFileName, FileMap[i].wszLogicalName))
|
|
{
|
|
fMatched = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fMatched)
|
|
{
|
|
if (NULL == FileMap[i].szPhysicalName)
|
|
{
|
|
dwError = ERROR_NOT_FOUND;
|
|
goto Ret;
|
|
}
|
|
|
|
cbPhysicalFileName = FileMap[i].cbPhysicalName + sizeof(WCHAR);
|
|
|
|
*ppszPhysicalFileName = (LPSTR) pCardData->pfnCspAlloc(cbPhysicalFileName);
|
|
|
|
LOG_CHECK_ALLOC(*ppszPhysicalFileName);
|
|
|
|
memcpy(
|
|
*ppszPhysicalFileName,
|
|
FileMap[i].szPhysicalName,
|
|
FileMap[i].cbPhysicalName);
|
|
}
|
|
else
|
|
{
|
|
// Have to try for a partial match. Check if the beginning
|
|
// of the logical name matches a known name.
|
|
|
|
for ( i = 0;
|
|
FALSE == fMatched && (i < sizeof(FileMap) / sizeof(FileMap[0]));
|
|
i++)
|
|
{
|
|
if (wszLogicalFileName !=
|
|
wcsstr(wszLogicalFileName, FileMap[i].wszLogicalName))
|
|
continue;
|
|
|
|
//
|
|
// We found a match and it's at the beginning of the string
|
|
//
|
|
|
|
cchLogicalName = (DWORD) wcslen(FileMap[i].wszLogicalName);
|
|
|
|
//
|
|
// Convert the trailing portion of the matched Unicode string
|
|
// to Ansi.
|
|
//
|
|
|
|
dwError = I_CardConvertFileNameToAnsi(
|
|
pCardData,
|
|
wszLogicalFileName + cchLogicalName,
|
|
&szAnsiExtra);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
//
|
|
// Build the fully matched/converted physical file string. The
|
|
// resultant string will have three single-byte NULL chars
|
|
// appended to ensure that the resultant string is a valid,
|
|
// terminated Unicode string.
|
|
//
|
|
|
|
*ppszPhysicalFileName = (LPSTR) pCardData->pfnCspAlloc(
|
|
3 +
|
|
FileMap[i].cbPhysicalName +
|
|
strlen(szAnsiExtra));
|
|
|
|
LOG_CHECK_ALLOC(*ppszPhysicalFileName);
|
|
|
|
memcpy(
|
|
*ppszPhysicalFileName,
|
|
FileMap[i].szPhysicalName,
|
|
FileMap[i].cbPhysicalName);
|
|
|
|
memcpy(
|
|
*ppszPhysicalFileName + FileMap[i].cbPhysicalName,
|
|
szAnsiExtra,
|
|
strlen(szAnsiExtra));
|
|
|
|
fMatched = TRUE;
|
|
}
|
|
}
|
|
|
|
if (FALSE == fMatched)
|
|
dwError = ERROR_NOT_FOUND;
|
|
|
|
Ret:
|
|
|
|
if (NULL != szAnsiExtra)
|
|
pCardData->pfnCspFree(szAnsiExtra);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Converts a Crypto API private key blob to the separate public and private
|
|
// key files that will be written to the card.
|
|
//
|
|
DWORD ConvertPrivateKeyBlobToCardFormat(
|
|
IN PCARD_DATA pCardData,
|
|
IN DWORD dwKeySpec,
|
|
IN PBYTE pbKeyBlob,
|
|
IN DWORD cbKeyBlob,
|
|
OUT PBYTE *ppbCardPrivateKey,
|
|
OUT DWORD *pcbCardPrivateKey,
|
|
OUT PBYTE *ppbCardPublicKey,
|
|
OUT DWORD *pcbCardPublicKey)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
RSAPUBKEY *pPub = NULL;
|
|
DWORD cBitlenBytes = 0;
|
|
DWORD cbKey = 0;
|
|
PBYTE pbKey = NULL;
|
|
|
|
UNREFERENCED_PARAMETER(pCardData);
|
|
UNREFERENCED_PARAMETER(dwKeySpec);
|
|
UNREFERENCED_PARAMETER(cbKeyBlob);
|
|
|
|
*ppbCardPrivateKey = NULL;
|
|
*pcbCardPrivateKey = 0;
|
|
*ppbCardPublicKey = NULL;
|
|
*pcbCardPublicKey = 0;
|
|
|
|
//
|
|
// Setup the public key file
|
|
//
|
|
pPub = (RSAPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER));
|
|
|
|
*pcbCardPublicKey = (pPub->bitlen / 8) + sizeof(RSAPUBKEY);
|
|
|
|
*ppbCardPublicKey = (PBYTE) pCardData->pfnCspAlloc(*pcbCardPublicKey);
|
|
|
|
LOG_CHECK_ALLOC(*ppbCardPublicKey);
|
|
|
|
memcpy(
|
|
*ppbCardPublicKey,
|
|
pPub,
|
|
*pcbCardPublicKey);
|
|
|
|
//
|
|
// Need to change the RSA "magic" field in the Public key blob from
|
|
// "RSA2" to "RSA1" to make this a correct PUBLICKEYBLOB (although we
|
|
// won't add the BLOBHEADER to the front until someone tries to export
|
|
// it from the card).
|
|
//
|
|
memcpy(
|
|
*ppbCardPublicKey,
|
|
(PBYTE) "RSA1",
|
|
4);
|
|
|
|
//
|
|
// Setup the private key file
|
|
//
|
|
|
|
cBitlenBytes = pPub->bitlen / 8;
|
|
|
|
*pcbCardPrivateKey = 1 + 1 + 3 + 1 + 9 * cBitlenBytes / 2;
|
|
|
|
*ppbCardPrivateKey = (PBYTE) pCardData->pfnCspAlloc(*pcbCardPrivateKey);
|
|
|
|
LOG_CHECK_ALLOC(*ppbCardPrivateKey);
|
|
|
|
pbKey = *ppbCardPrivateKey;
|
|
|
|
// Key mode
|
|
pbKey[cbKey] = MODE_RSA_SIGN;
|
|
cbKey++;
|
|
|
|
// size of public exponent
|
|
pbKey[cbKey] = cbCAPI_PUBLIC_EXPONENT;
|
|
cbKey++;
|
|
|
|
DsysAssert(CAPI_PUBLIC_EXPONENT == pPub->pubexp);
|
|
|
|
// public exponent
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
(PBYTE) &pPub->pubexp,
|
|
cbCAPI_PUBLIC_EXPONENT);
|
|
cbKey += cbCAPI_PUBLIC_EXPONENT;
|
|
|
|
// RSA key length
|
|
pbKey[cbKey] = (BYTE) cBitlenBytes;
|
|
cbKey++;
|
|
|
|
// public key
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
|
|
cBitlenBytes);
|
|
cbKey += cBitlenBytes;
|
|
|
|
// prime 1
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
|
cBitlenBytes,
|
|
cBitlenBytes / 2);
|
|
cbKey += cBitlenBytes / 2;
|
|
|
|
// prime 2
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
|
(3 * cBitlenBytes / 2),
|
|
cBitlenBytes / 2);
|
|
cbKey += cBitlenBytes / 2;
|
|
|
|
// Exp1 (D mod (P-1)) (m/2 bytes)
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
|
2 * cBitlenBytes,
|
|
cBitlenBytes / 2);
|
|
cbKey += cBitlenBytes / 2;
|
|
|
|
// Exp2 (D mod (Q-1)) (m/2 bytes)
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
|
(5 * cBitlenBytes / 2),
|
|
cBitlenBytes / 2);
|
|
cbKey += cBitlenBytes / 2;
|
|
|
|
// Coef ((Q^(-1)) mod p) (m/2 bytes)
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
|
3 * cBitlenBytes,
|
|
cBitlenBytes / 2);
|
|
cbKey += cBitlenBytes / 2;
|
|
|
|
// private exponent
|
|
memcpy(
|
|
pbKey + cbKey,
|
|
pbKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
|
|
(7 * cBitlenBytes / 2),
|
|
cBitlenBytes);
|
|
cbKey += cBitlenBytes;
|
|
|
|
DsysAssert(cbKey == *pcbCardPrivateKey);
|
|
|
|
Ret:
|
|
if (ERROR_SUCCESS != dwError)
|
|
{
|
|
if (*ppbCardPublicKey)
|
|
{
|
|
pCardData->pfnCspFree(*ppbCardPublicKey);
|
|
*ppbCardPublicKey = NULL;
|
|
}
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Card Module Exported Functions
|
|
//
|
|
|
|
//
|
|
// Initializes a CARD_DATA context structure for the card identified by Name,
|
|
// ATR, and SCARDHANDLE supplied by the caller.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardAcquireContext(
|
|
IN OUT PCARD_DATA pCardData,
|
|
IN DWORD dwFlags)
|
|
{
|
|
int iSupportedCard = 0;
|
|
BOOL fSupportedCard = FALSE;
|
|
PCARDMOD_CONTEXT pCardmodContext = NULL;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
LOG_BEGIN_FUNCTION(CardAcquireContext);
|
|
|
|
if (0 != dwFlags)
|
|
{
|
|
dwError = (DWORD) NTE_BAD_FLAGS;
|
|
goto Ret;
|
|
}
|
|
|
|
for (
|
|
iSupportedCard = 0;
|
|
iSupportedCard < sizeof(SupportedCards) /
|
|
sizeof(SupportedCards[0]);
|
|
iSupportedCard++)
|
|
{
|
|
if (0 == wcscmp(
|
|
SupportedCards[iSupportedCard].wszCardName,
|
|
pCardData->pwszCardName)
|
|
&&
|
|
SupportedCards[iSupportedCard].cbAtr == pCardData->cbAtr
|
|
&&
|
|
0 == memcmp(
|
|
SupportedCards[iSupportedCard].rgbAtr,
|
|
pCardData->pbAtr,
|
|
SupportedCards[iSupportedCard].cbAtr))
|
|
{
|
|
fSupportedCard = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FALSE == fSupportedCard)
|
|
{
|
|
dwError = (DWORD) SCARD_E_UNKNOWN_CARD;
|
|
goto Ret;
|
|
}
|
|
|
|
pCardData->pfnCardDeleteContext = CardDeleteContext;
|
|
pCardData->pfnCardQueryCapabilities = CardQueryCapabilities;
|
|
pCardData->pfnCardDeleteContainer = CardDeleteContainer;
|
|
pCardData->pfnCardCreateContainer = CardCreateContainer;
|
|
pCardData->pfnCardGetContainerInfo = CardGetContainerInfo;
|
|
pCardData->pfnCardSubmitPin = CardSubmitPin;
|
|
pCardData->pfnCardChangeAuthenticator = CardChangeAuthenticator;
|
|
pCardData->pfnCardGetChallenge = CardGetChallenge;
|
|
pCardData->pfnCardAuthenticateChallenge = CardAuthenticateChallenge;
|
|
pCardData->pfnCardUnblockPin = CardUnblockPin;
|
|
pCardData->pfnCardDeauthenticate = CardDeauthenticate;
|
|
pCardData->pfnCardCreateFile = CardCreateFile;
|
|
pCardData->pfnCardReadFile = CardReadFile;
|
|
pCardData->pfnCardWriteFile = CardWriteFile;
|
|
pCardData->pfnCardDeleteFile = CardDeleteFile;
|
|
pCardData->pfnCardEnumFiles = CardEnumFiles;
|
|
pCardData->pfnCardGetFileInfo = CardGetFileInfo;
|
|
pCardData->pfnCardQueryFreeSpace = CardQueryFreeSpace;
|
|
pCardData->pfnCardPrivateKeyDecrypt = CardPrivateKeyDecrypt;
|
|
pCardData->pfnCardQueryKeySizes = CardQueryKeySizes;
|
|
|
|
pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pfnCspAlloc(sizeof(CARDMOD_CONTEXT));
|
|
|
|
LOG_CHECK_ALLOC(pCardmodContext);
|
|
|
|
LOG_CHECK_SCW_CALL(hScwAttachToCard(
|
|
pCardData->hScard,
|
|
NULL,
|
|
&pCardmodContext->hWfscCardHandle));
|
|
|
|
pCardmodContext->pSupportedCard = SupportedCards + iSupportedCard;
|
|
|
|
pCardData->pvVendorSpecific = (PVOID) pCardmodContext;
|
|
pCardmodContext = NULL;
|
|
|
|
Ret:
|
|
if ( ERROR_SUCCESS != dwError &&
|
|
NULL != pCardmodContext &&
|
|
pCardmodContext->hWfscCardHandle)
|
|
hScwDetachFromCard(pCardmodContext->hWfscCardHandle);
|
|
if (pCardmodContext)
|
|
pCardData->pfnCspFree(pCardmodContext);
|
|
|
|
LOG_END_FUNCTION(CardAcquireContext, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Frees the resources consumed by a CARD_DATA structure.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardDeleteContext(
|
|
OUT PCARD_DATA pCardData)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
LOG_BEGIN_FUNCTION(CardDeleteContext);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
if (pCardmodContext->hWfscCardHandle)
|
|
{
|
|
hScwDetachFromCard(pCardmodContext->hWfscCardHandle);
|
|
pCardmodContext->hWfscCardHandle = 0;
|
|
}
|
|
|
|
if (pCardData->pvVendorSpecific)
|
|
{
|
|
pCardData->pfnCspFree(pCardData->pvVendorSpecific);
|
|
pCardData->pvVendorSpecific = NULL;
|
|
}
|
|
|
|
LOG_END_FUNCTION(CardDeleteContext, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Returns the static capabilities of the target card.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardQueryCapabilities(
|
|
IN PCARD_DATA pCardData,
|
|
IN OUT PCARD_CAPABILITIES pCardCapabilities)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
LOG_BEGIN_FUNCTION(CardQueryCapabilities);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
memcpy(
|
|
pCardCapabilities,
|
|
&pCardmodContext->pSupportedCard->CardCapabilities,
|
|
sizeof(CARD_CAPABILITIES));
|
|
|
|
LOG_END_FUNCTION(CardQueryCapabilities, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// The encoded key filename is one hex byte, such as "FF", which requires
|
|
// two characters.
|
|
//
|
|
#define cchENCODED_KEY_FILENAME 2
|
|
|
|
//
|
|
// Creates the physical filenames used for the key files associated with the
|
|
// specified container.
|
|
//
|
|
DWORD BuildCardKeyFilenames(
|
|
IN PCARD_DATA pCardData,
|
|
IN DWORD dwKeySpec,
|
|
IN BYTE bContainerIndex,
|
|
OUT OPTIONAL LPSTR *pszPrivateFilename,
|
|
OUT OPTIONAL LPSTR *pszPublicFilename)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
DWORD cchFileName = 0;
|
|
DWORD dwIndex = (DWORD) bContainerIndex;
|
|
LPSTR szPrivatePrefix = NULL;
|
|
DWORD cbPrivatePrefix = 0;
|
|
LPSTR szPublicPrefix = NULL;
|
|
DWORD cbPublicPrefix = 0;
|
|
|
|
if (pszPrivateFilename)
|
|
*pszPrivateFilename = NULL;
|
|
if (pszPublicFilename)
|
|
*pszPublicFilename = NULL;
|
|
|
|
switch (dwKeySpec)
|
|
{
|
|
case AT_SIGNATURE:
|
|
szPrivatePrefix = szPHYSICAL_SIGNATURE_PRIVATE_KEY_PREFIX;
|
|
cbPrivatePrefix = cbPHYSICAL_SIGNATURE_PRIVATE_KEY_PREFIX;
|
|
szPublicPrefix = szPHYSICAL_SIGNATURE_PUBLIC_KEY_PREFIX;
|
|
cbPublicPrefix = cbPHYSICAL_SIGNATURE_PUBLIC_KEY_PREFIX;
|
|
break;
|
|
|
|
case AT_KEYEXCHANGE:
|
|
szPrivatePrefix = szPHYSICAL_KEYEXCHANGE_PRIVATE_KEY_PREFIX;
|
|
cbPrivatePrefix = cbPHYSICAL_KEYEXCHANGE_PRIVATE_KEY_PREFIX;
|
|
szPublicPrefix = szPHYSICAL_KEYEXCHANGE_PUBLIC_KEY_PREFIX;
|
|
cbPublicPrefix = cbPHYSICAL_KEYEXCHANGE_PUBLIC_KEY_PREFIX;
|
|
break;
|
|
|
|
default:
|
|
dwError = (DWORD) NTE_BAD_ALGID;
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Build the public key filename
|
|
//
|
|
|
|
if (pszPublicFilename)
|
|
{
|
|
cchFileName = cchENCODED_KEY_FILENAME;
|
|
cchFileName += (cbPublicPrefix / sizeof(CHAR)) + 3;
|
|
|
|
*pszPublicFilename = (LPSTR) pCardData->pfnCspAlloc(
|
|
cchFileName * sizeof(CHAR));
|
|
|
|
LOG_CHECK_ALLOC(*pszPublicFilename);
|
|
|
|
memcpy(*pszPublicFilename, szPublicPrefix, cbPublicPrefix);
|
|
|
|
sprintf(
|
|
*pszPublicFilename + cbPublicPrefix,
|
|
"%d\0\0",
|
|
dwIndex);
|
|
}
|
|
|
|
//
|
|
// Build the private key filename
|
|
//
|
|
|
|
if (pszPrivateFilename)
|
|
{
|
|
cchFileName = cchENCODED_KEY_FILENAME;
|
|
cchFileName += (cbPrivatePrefix / sizeof(CHAR)) + 3;
|
|
|
|
*pszPrivateFilename = (LPSTR) pCardData->pfnCspAlloc(
|
|
cchFileName * sizeof(CHAR));
|
|
|
|
LOG_CHECK_ALLOC(*pszPrivateFilename);
|
|
|
|
memcpy(*pszPrivateFilename, szPrivatePrefix, cbPrivatePrefix);
|
|
|
|
sprintf(
|
|
*pszPrivateFilename + cbPrivatePrefix,
|
|
"%d\0\0",
|
|
dwIndex);
|
|
}
|
|
|
|
Ret:
|
|
if (ERROR_SUCCESS != dwError)
|
|
{
|
|
if (*pszPublicFilename)
|
|
{
|
|
pCardData->pfnCspFree(*pszPublicFilename);
|
|
*pszPublicFilename = NULL;
|
|
}
|
|
|
|
if (*pszPrivateFilename)
|
|
{
|
|
pCardData->pfnCspFree(*pszPrivateFilename);
|
|
*pszPrivateFilename = NULL;
|
|
}
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Deletes the Signature and Key Exchange public and private key files,
|
|
// if present, associated with the specified container.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardDeleteContainer(
|
|
IN PCARD_DATA pCardData,
|
|
IN BYTE bContainerIndex,
|
|
IN DWORD dwReserved)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
LPSTR szPrivateKeyFile = NULL;
|
|
LPSTR szPublicKeyFile = NULL;
|
|
SCODE scode = 0;
|
|
|
|
UNREFERENCED_PARAMETER(dwReserved);
|
|
|
|
LOG_BEGIN_FUNCTION(CardDeleteContainer);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
//
|
|
// Attempt to delete the Signature key files associated with this
|
|
// container, if any.
|
|
//
|
|
dwError = BuildCardKeyFilenames(
|
|
pCardData,
|
|
AT_SIGNATURE,
|
|
bContainerIndex,
|
|
&szPrivateKeyFile,
|
|
&szPublicKeyFile);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
scode = hScwDeleteFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
(LPWSTR) szPrivateKeyFile);
|
|
|
|
if (SCW_E_FILENOTFOUND != scode && SCW_S_OK != scode)
|
|
goto Ret;
|
|
|
|
scode = hScwDeleteFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
(LPWSTR) szPublicKeyFile);
|
|
|
|
if (SCW_E_FILENOTFOUND != scode && SCW_S_OK != scode)
|
|
goto Ret;
|
|
|
|
pCardData->pfnCspFree(szPrivateKeyFile);
|
|
szPrivateKeyFile = NULL;
|
|
pCardData->pfnCspFree(szPublicKeyFile);
|
|
szPublicKeyFile = NULL;
|
|
|
|
//
|
|
// Attempt to delete the Key Exchange key files associated with this
|
|
// container, if any.
|
|
//
|
|
dwError = BuildCardKeyFilenames(
|
|
pCardData,
|
|
AT_KEYEXCHANGE,
|
|
bContainerIndex,
|
|
&szPrivateKeyFile,
|
|
&szPublicKeyFile);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
scode = hScwDeleteFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
(LPWSTR) szPrivateKeyFile);
|
|
|
|
if (SCW_E_FILENOTFOUND != scode && SCW_S_OK != scode)
|
|
goto Ret;
|
|
|
|
scode = hScwDeleteFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
(LPWSTR) szPublicKeyFile);
|
|
|
|
Ret:
|
|
|
|
if (SCW_E_FILENOTFOUND != scode && SCW_S_OK != scode)
|
|
dwError = I_CardMapErrorCode(scode);
|
|
|
|
if (szPrivateKeyFile)
|
|
pCardData->pfnCspFree(szPrivateKeyFile);
|
|
if (szPublicKeyFile)
|
|
pCardData->pfnCspFree(szPublicKeyFile);
|
|
|
|
LOG_END_FUNCTION(CardDeleteContainer, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Writes the private and public key files to the card, supplying the
|
|
// appropriate access conditions.
|
|
//
|
|
DWORD WriteCardKeyFiles(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszPrivateKeyFile,
|
|
IN LPWSTR wszPublicKeyFile,
|
|
IN PBYTE pbPrivateKey,
|
|
IN DWORD cbPrivateKey,
|
|
IN PBYTE pbPublicKey,
|
|
IN DWORD cbPublicKey)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
CARD_FILE_ACCESS_CONDITION Ac;
|
|
LPWSTR wszPrivateAcl = NULL;
|
|
LPWSTR wszPublicAcl = NULL;
|
|
HFILE hFile = 0;
|
|
SCODE scode = 0;
|
|
|
|
memset(&Ac, 0, sizeof(Ac));
|
|
|
|
Ac = UserWriteExecuteAc;
|
|
|
|
dwError = GetWellKnownAcMapping(
|
|
pCardData, Ac, &wszPrivateAcl);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
Ac = EveryoneReadUserWriteAc;
|
|
|
|
dwError = GetWellKnownAcMapping(
|
|
pCardData, Ac, &wszPublicAcl);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
//
|
|
// See if the private key file already exists
|
|
//
|
|
scode = hScwDeleteFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
wszPrivateKeyFile);
|
|
|
|
if (SCW_S_OK != scode && SCW_E_FILENOTFOUND != scode)
|
|
{
|
|
dwError = I_CardMapErrorCode(scode);
|
|
goto Ret;
|
|
}
|
|
|
|
dwError = I_CardWriteFile(
|
|
pCardData,
|
|
wszPrivateKeyFile,
|
|
wszPrivateAcl,
|
|
pbPrivateKey,
|
|
cbPrivateKey,
|
|
FALSE);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
// Done with private key file
|
|
|
|
//
|
|
// See if the public key file already exists
|
|
//
|
|
scode = hScwDeleteFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
wszPublicKeyFile);
|
|
|
|
if (SCW_S_OK != scode && SCW_E_FILENOTFOUND != scode)
|
|
{
|
|
dwError = I_CardMapErrorCode(scode);
|
|
goto Ret;
|
|
}
|
|
|
|
dwError = I_CardWriteFile(
|
|
pCardData,
|
|
wszPublicKeyFile,
|
|
wszPublicAcl,
|
|
pbPublicKey,
|
|
cbPublicKey,
|
|
TRUE);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
// Done with public key file
|
|
|
|
Ret:
|
|
if (wszPrivateAcl)
|
|
pCardData->pfnCspFree(wszPrivateAcl);
|
|
if (wszPublicAcl)
|
|
pCardData->pfnCspFree(wszPublicAcl);
|
|
if (hFile)
|
|
hScwCloseFile(
|
|
pCardmodContext->hWfscCardHandle, hFile);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Writes new keys to the card in a location logically defined by the
|
|
// bContainerIndex container name. If keys are already defined for the
|
|
// specified container, the existing keys are over-written.
|
|
//
|
|
// If dwFlags contains CARD_CREATE_CONTAINER_KEY_GEN, then dwKeySize is the
|
|
// number of bits of the key to be created.
|
|
//
|
|
// If dwFlags contains CARD_CREATE_CONTAINER_KEY_IMPORT, then dwKeySize is
|
|
// the byte length of pbKeyData.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardCreateContainer(
|
|
IN PCARD_DATA pCardData,
|
|
IN BYTE bContainerIndex,
|
|
IN DWORD dwFlags,
|
|
IN DWORD dwKeySpec,
|
|
IN DWORD dwKeySize,
|
|
IN PBYTE pbKeyData)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PBYTE pbPrivateKeyFile = NULL;
|
|
DWORD cbPrivateKeyFile = 0;
|
|
PBYTE pbPublicKeyFile = NULL;
|
|
DWORD cbPublicKeyFile = 0;
|
|
LPSTR szPrivateKeyFile = NULL;
|
|
LPSTR szPublicKeyFile = NULL;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
LOG_BEGIN_FUNCTION(CardCreateContainer);
|
|
|
|
if (CARD_CREATE_CONTAINER_KEY_GEN & dwFlags)
|
|
{
|
|
dwError = (DWORD) SCARD_E_UNSUPPORTED_FEATURE;
|
|
goto Ret;
|
|
}
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
//
|
|
// Setup the key files
|
|
//
|
|
dwError = ConvertPrivateKeyBlobToCardFormat(
|
|
pCardData,
|
|
dwKeySpec,
|
|
pbKeyData,
|
|
dwKeySize,
|
|
&pbPrivateKeyFile,
|
|
&cbPrivateKeyFile,
|
|
&pbPublicKeyFile,
|
|
&cbPublicKeyFile);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
dwError = BuildCardKeyFilenames(
|
|
pCardData,
|
|
dwKeySpec,
|
|
bContainerIndex,
|
|
&szPrivateKeyFile,
|
|
&szPublicKeyFile);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
//
|
|
// Write the actual keys to the card
|
|
//
|
|
dwError = WriteCardKeyFiles(
|
|
pCardData,
|
|
(LPWSTR) szPrivateKeyFile,
|
|
(LPWSTR) szPublicKeyFile,
|
|
pbPrivateKeyFile,
|
|
cbPrivateKeyFile,
|
|
pbPublicKeyFile,
|
|
cbPublicKeyFile);
|
|
|
|
Ret:
|
|
|
|
if (pbPrivateKeyFile)
|
|
{
|
|
RtlSecureZeroMemory(pbPrivateKeyFile, cbPrivateKeyFile);
|
|
pCardData->pfnCspFree(pbPrivateKeyFile);
|
|
}
|
|
if (pbPublicKeyFile)
|
|
pCardData->pfnCspFree(pbPublicKeyFile);
|
|
if (szPrivateKeyFile)
|
|
pCardData->pfnCspFree(szPrivateKeyFile);
|
|
if (szPublicKeyFile)
|
|
pCardData->pfnCspFree(szPublicKeyFile);
|
|
|
|
LOG_END_FUNCTION(CardCreateContainer, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Initializes a CONTAINER_INFO structure for the indicated container,
|
|
// including Signature and Key Exchange Crypto API public key blobs if
|
|
// those keys exist.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardGetContainerInfo(
|
|
IN PCARD_DATA pCardData,
|
|
IN BYTE bContainerIndex,
|
|
IN DWORD dwFlags,
|
|
IN OUT PCONTAINER_INFO pContainerInfo)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
LPSTR szPublicKeyFile = NULL;
|
|
PBYTE pbPublicKey = NULL;
|
|
DWORD cbPublicKey = 0;
|
|
BLOBHEADER *pBlobHeader = NULL;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
LOG_BEGIN_FUNCTION(CardGetContainerInfo);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
//
|
|
// Does this container have a Signature key?
|
|
//
|
|
|
|
dwError = BuildCardKeyFilenames(
|
|
pCardData,
|
|
AT_SIGNATURE,
|
|
bContainerIndex,
|
|
NULL,
|
|
&szPublicKeyFile);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
dwError = I_CardReadFile(
|
|
pCardData,
|
|
(LPWSTR) szPublicKeyFile,
|
|
&pbPublicKey,
|
|
&cbPublicKey,
|
|
TRUE);
|
|
|
|
switch (dwError)
|
|
{
|
|
case SCARD_E_FILE_NOT_FOUND:
|
|
|
|
// There appears to be no Signature key in this container. Continue.
|
|
|
|
break;
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
pContainerInfo->pbSigPublicKey =
|
|
(PBYTE) pCardData->pfnCspAlloc(sizeof(BLOBHEADER) + cbPublicKey);
|
|
|
|
LOG_CHECK_ALLOC(pContainerInfo->pbSigPublicKey);
|
|
|
|
pBlobHeader = (BLOBHEADER *) pContainerInfo->pbSigPublicKey;
|
|
pBlobHeader->bType = PUBLICKEYBLOB;
|
|
pBlobHeader->bVersion = CUR_BLOB_VERSION;
|
|
pBlobHeader->reserved = 0x0000;
|
|
pBlobHeader->aiKeyAlg = CALG_RSA_SIGN;
|
|
|
|
memcpy(
|
|
pContainerInfo->pbSigPublicKey + sizeof(BLOBHEADER),
|
|
pbPublicKey,
|
|
cbPublicKey);
|
|
|
|
pContainerInfo->cbSigPublicKey = sizeof(BLOBHEADER) + cbPublicKey;
|
|
|
|
pCardData->pfnCspFree(szPublicKeyFile);
|
|
szPublicKeyFile = NULL;
|
|
pCardData->pfnCspFree(pbPublicKey);
|
|
pbPublicKey = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unexpected error
|
|
goto Ret;
|
|
}
|
|
|
|
//
|
|
// Does this container have a Key Exchange key?
|
|
//
|
|
|
|
dwError = BuildCardKeyFilenames(
|
|
pCardData,
|
|
AT_KEYEXCHANGE,
|
|
bContainerIndex,
|
|
NULL,
|
|
&szPublicKeyFile);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
dwError = I_CardReadFile(
|
|
pCardData,
|
|
(LPWSTR) szPublicKeyFile,
|
|
&pbPublicKey,
|
|
&cbPublicKey,
|
|
TRUE);
|
|
|
|
switch (dwError)
|
|
{
|
|
case SCARD_E_FILE_NOT_FOUND:
|
|
|
|
// There appears to be no Key Exchange key in this container.
|
|
|
|
break;
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
pContainerInfo->pbKeyExPublicKey =
|
|
(PBYTE) pCardData->pfnCspAlloc(sizeof(BLOBHEADER) + cbPublicKey);
|
|
|
|
LOG_CHECK_ALLOC(pContainerInfo->pbKeyExPublicKey);
|
|
|
|
pBlobHeader = (BLOBHEADER *) pContainerInfo->pbKeyExPublicKey;
|
|
pBlobHeader->bType = PUBLICKEYBLOB;
|
|
pBlobHeader->bVersion = CUR_BLOB_VERSION;
|
|
pBlobHeader->reserved = 0x0000;
|
|
pBlobHeader->aiKeyAlg = CALG_RSA_KEYX;
|
|
|
|
memcpy(
|
|
pContainerInfo->pbKeyExPublicKey + sizeof(BLOBHEADER),
|
|
pbPublicKey,
|
|
cbPublicKey);
|
|
|
|
pContainerInfo->cbKeyExPublicKey = sizeof(BLOBHEADER) + cbPublicKey;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Unexpected error
|
|
goto Ret;
|
|
}
|
|
|
|
// If we got here, then the API has succeeded
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
Ret:
|
|
if (pbPublicKey)
|
|
pCardData->pfnCspFree(pbPublicKey);
|
|
if (szPublicKeyFile)
|
|
pCardData->pfnCspFree(szPublicKeyFile);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
{
|
|
if (NULL != pContainerInfo->pbKeyExPublicKey)
|
|
{
|
|
pCardData->pfnCspFree(pContainerInfo->pbKeyExPublicKey);
|
|
pContainerInfo->pbKeyExPublicKey = NULL;
|
|
}
|
|
|
|
if (NULL != pContainerInfo->pbSigPublicKey)
|
|
{
|
|
pCardData->pfnCspFree(pContainerInfo->pbSigPublicKey);
|
|
pContainerInfo->pbSigPublicKey = NULL;
|
|
}
|
|
}
|
|
|
|
LOG_END_FUNCTION(CardGetContainerInfo, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Queries the number of pin retries available for the specified user, using
|
|
// the pin counter applet.
|
|
//
|
|
DWORD I_CardQueryPinRetries(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszPrincipal,
|
|
OUT PDWORD pcAttemptsRemaining)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
ISO_HEADER IsoHeader;
|
|
UINT16 wStatusWord = 0;
|
|
SCODE status = 0;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
// Build the command
|
|
IsoHeader.INS = PIN_RETRY_COUNTER_INS;
|
|
IsoHeader.CLA = PIN_RETRY_COUNTER_CLA;
|
|
IsoHeader.P1 = PIN_RETRY_COUNTER_P1;
|
|
IsoHeader.P2 = PIN_RETRY_COUNTER_P2;
|
|
|
|
status = hScwExecute(
|
|
pCardmodContext->hWfscCardHandle,
|
|
&IsoHeader,
|
|
(PBYTE) wszPrincipal,
|
|
(TCOUNT) (wcslen(wszPrincipal) + 1) * sizeof(WCHAR),
|
|
NULL,
|
|
NULL,
|
|
&wStatusWord);
|
|
|
|
if (SCW_S_OK == status)
|
|
dwError = I_CardMapExecuteErrorCode(wStatusWord);
|
|
else
|
|
dwError = I_CardMapErrorCode(status);
|
|
|
|
if (ERROR_SUCCESS == dwError)
|
|
*pcAttemptsRemaining = (DWORD) (wStatusWord & 0xFF);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Authenticates the specified logical user name via the specified pin.
|
|
//
|
|
// If pcAttemptsRemaining is non-NULL, and if the authentication fails,
|
|
// that parameter will container the number of authentication attempts
|
|
// remaining before the card is locked.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardSubmitPin(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszUserId,
|
|
IN PBYTE pbPin,
|
|
IN DWORD cbPin,
|
|
OUT OPTIONAL PDWORD pcAttemptsRemaining)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
LPWSTR wszPrincipal = NULL;
|
|
SCODE scode = SCW_S_OK;
|
|
DWORD dwAttempts = 0;
|
|
|
|
LOG_BEGIN_FUNCTION(CardSubmitPin);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
if (NULL != pcAttemptsRemaining)
|
|
*pcAttemptsRemaining = CARD_DATA_VALUE_UNKNOWN;
|
|
|
|
dwError = GetWellKnownUserMapping(
|
|
pCardData, pwszUserId, &wszPrincipal);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
scode = hScwAuthenticateName(
|
|
pCardmodContext->hWfscCardHandle,
|
|
wszPrincipal,
|
|
pbPin,
|
|
(TCOUNT) cbPin);
|
|
|
|
dwError = I_CardMapErrorCode(scode);
|
|
|
|
if (SCARD_E_INVALID_CHV == dwError && NULL != pcAttemptsRemaining)
|
|
{
|
|
// Determine how many more invalid pin presentation attempts can be
|
|
// made before the card is locked.
|
|
|
|
dwError = I_CardQueryPinRetries(
|
|
pCardData,
|
|
wszPrincipal,
|
|
&dwAttempts);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
*pcAttemptsRemaining = dwAttempts;
|
|
dwError = (DWORD) SCARD_E_INVALID_CHV;
|
|
}
|
|
|
|
Ret:
|
|
|
|
if (wszPrincipal)
|
|
pCardData->pfnCspFree(wszPrincipal);
|
|
|
|
LOG_END_FUNCTION(CardSubmitPin, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Changes the pin for the specified logical user.
|
|
//
|
|
// If the authentication using the current pin fails, and if
|
|
// pcAttemptsRemaining is non-NULL, that parameter will be set to the number
|
|
// of authentication attempts remaining before the card is locked.
|
|
//
|
|
DWORD I_CardChangePin(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszPhysicalUser,
|
|
IN PBYTE pbCurrentPin,
|
|
IN DWORD cbCurrentPin,
|
|
IN PBYTE pbNewPin,
|
|
IN DWORD cbNewPin,
|
|
OUT OPTIONAL PDWORD pcAttemptsRemaining)
|
|
{
|
|
ISO_HEADER IsoHeader;
|
|
UINT16 wStatusWord = 0;
|
|
PBYTE pbDataIn = NULL;
|
|
DWORD cbDataIn = 0;
|
|
DWORD cbUser = 0;
|
|
SCODE status = 0;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
DWORD cAttempts = 0;
|
|
|
|
memset(&IsoHeader, 0, sizeof(IsoHeader));
|
|
|
|
if (NULL != pcAttemptsRemaining)
|
|
*pcAttemptsRemaining = CARD_DATA_VALUE_UNKNOWN;
|
|
|
|
//
|
|
// Allocate a command buffer to be transmitted to the card
|
|
//
|
|
|
|
cbUser = (DWORD) (wcslen(wszPhysicalUser) + 1) * sizeof(WCHAR);
|
|
|
|
cbDataIn = 2 + cbUser + 2 + cbCurrentPin + 2 + cbNewPin;
|
|
|
|
pbDataIn = (PBYTE) pCardData->pfnCspAlloc(cbDataIn);
|
|
|
|
LOG_CHECK_ALLOC(pbDataIn);
|
|
|
|
cbDataIn = 0;
|
|
|
|
// Setup User Name TLV
|
|
pbDataIn[cbDataIn] = 0;
|
|
cbDataIn++;
|
|
|
|
pbDataIn[cbDataIn] = (BYTE) cbUser;
|
|
cbDataIn++;
|
|
|
|
memcpy(pbDataIn + cbDataIn, (PBYTE) wszPhysicalUser, cbUser);
|
|
cbDataIn += cbUser;
|
|
|
|
// Setup Current Pin TLV
|
|
pbDataIn[cbDataIn] = 1;
|
|
cbDataIn++;
|
|
|
|
pbDataIn[cbDataIn] = (BYTE) cbCurrentPin;
|
|
cbDataIn++;
|
|
|
|
memcpy(pbDataIn + cbDataIn, pbCurrentPin, cbCurrentPin);
|
|
cbDataIn += cbCurrentPin;
|
|
|
|
// Setup New Pin TLV
|
|
pbDataIn[cbDataIn] = 2;
|
|
cbDataIn++;
|
|
|
|
pbDataIn[cbDataIn] = (BYTE) cbNewPin;
|
|
cbDataIn++;
|
|
|
|
memcpy(pbDataIn + cbDataIn, pbNewPin, cbNewPin);
|
|
cbDataIn += cbNewPin;
|
|
|
|
// Build the command
|
|
IsoHeader.INS = PIN_CHANGE_INS;
|
|
IsoHeader.CLA = PIN_CHANGE_CLA;
|
|
IsoHeader.P1 = PIN_CHANGE_P1;
|
|
IsoHeader.P2 = PIN_CHANGE_P2;
|
|
|
|
//
|
|
// Send the pin change command to the card
|
|
//
|
|
|
|
status = hScwExecute(
|
|
pCardmodContext->hWfscCardHandle,
|
|
&IsoHeader,
|
|
pbDataIn,
|
|
(TCOUNT) cbDataIn,
|
|
NULL,
|
|
NULL,
|
|
&wStatusWord);
|
|
|
|
if (SCW_S_OK == status)
|
|
dwError = I_CardMapExecuteErrorCode(wStatusWord);
|
|
else
|
|
dwError = I_CardMapErrorCode(status);
|
|
|
|
if (SCARD_E_INVALID_CHV == dwError && NULL != pcAttemptsRemaining)
|
|
{
|
|
dwError = I_CardQueryPinRetries(
|
|
pCardData,
|
|
wszPhysicalUser,
|
|
&cAttempts);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
*pcAttemptsRemaining = cAttempts;
|
|
dwError = (DWORD) SCARD_E_INVALID_CHV;
|
|
}
|
|
|
|
Ret:
|
|
|
|
if (pbDataIn)
|
|
pCardData->pfnCspFree(pbDataIn);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Performs the challenge-response using the provided callback
|
|
//
|
|
/*
|
|
DWORD I_CardChallengeResponse(
|
|
IN PCARD_DATA pCardData,
|
|
IN PFN_PIN_CHALLENGE_CALLBACK pfnCallback,
|
|
IN PVOID pvCallbackContext,
|
|
OUT PBYTE *ppbResponse,
|
|
OUT DWORD *pcbResponse)
|
|
{
|
|
PBYTE pbChallenge = NULL;
|
|
DWORD cbChallenge = 0;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
cbChallenge = cbCHALLENGE_RESPONSE_DATA;
|
|
*pcbResponse = cbCHALLENGE_RESPONSE_DATA;
|
|
|
|
pbChallenge = pCardData->pfnCspAlloc(cbChallenge);
|
|
|
|
LOG_CHECK_ALLOC(pbChallenge);
|
|
|
|
*ppbResponse = pCardData->pfnCspAlloc(*pcbResponse);
|
|
|
|
LOG_CHECK_ALLOC(*ppbResponse);
|
|
|
|
LOG_CHECK_SCW_CALL(hScwGenerateRandom(
|
|
pCardmodContext->hWfscCardHandle,
|
|
pbChallenge,
|
|
(TCOUNT) cbChallenge));
|
|
|
|
dwError = pfnCallback(
|
|
pbChallenge,
|
|
cbChallenge,
|
|
*ppbResponse,
|
|
*pcbResponse,
|
|
pvCallbackContext);
|
|
|
|
Ret:
|
|
|
|
if (NULL != pbChallenge)
|
|
pCardData->pfnCspFree(pbChallenge);
|
|
|
|
if (NULL != *ppbResponse && ERROR_SUCCESS != dwError)
|
|
{
|
|
pCardData->pfnCspFree(*ppbResponse);
|
|
*ppbResponse = NULL;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
*/
|
|
|
|
//
|
|
// Calls the pin unblock applet on the card
|
|
//
|
|
DWORD I_CardUnblock(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR wszPhysicalUser,
|
|
IN PBYTE pbNewPin,
|
|
IN DWORD cbNewPin,
|
|
IN DWORD cNewMaxRetries)
|
|
{
|
|
ISO_HEADER IsoHeader;
|
|
UINT16 wStatusWord = 0;
|
|
PBYTE pbDataIn = NULL;
|
|
DWORD cbDataIn = 0;
|
|
DWORD cbUser = 0;
|
|
SCODE status = 0;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
memset(&IsoHeader, 0, sizeof(IsoHeader));
|
|
|
|
//
|
|
// Allocate a command buffer to be transmitted to the card
|
|
//
|
|
|
|
cbUser = (DWORD) (wcslen(wszPhysicalUser) + 1) * sizeof(WCHAR);
|
|
|
|
cbDataIn = 2 + cbUser + 2 + cbNewPin;
|
|
|
|
pbDataIn = (PBYTE) pCardData->pfnCspAlloc(cbDataIn);
|
|
|
|
LOG_CHECK_ALLOC(pbDataIn);
|
|
|
|
cbDataIn = 0;
|
|
|
|
// Setup User Name TLV
|
|
pbDataIn[cbDataIn] = 0;
|
|
cbDataIn++;
|
|
|
|
pbDataIn[cbDataIn] = (BYTE) cbUser;
|
|
cbDataIn++;
|
|
|
|
memcpy(pbDataIn + cbDataIn, (PBYTE) wszPhysicalUser, cbUser);
|
|
cbDataIn += cbUser;
|
|
|
|
// Setup New Pin TLV
|
|
pbDataIn[cbDataIn] = 2;
|
|
cbDataIn++;
|
|
|
|
pbDataIn[cbDataIn] = (BYTE) cbNewPin;
|
|
cbDataIn++;
|
|
|
|
memcpy(pbDataIn + cbDataIn, pbNewPin, cbNewPin);
|
|
cbDataIn += cbNewPin;
|
|
|
|
// Build the command
|
|
IsoHeader.INS = PIN_UNBLOCK_INS;
|
|
IsoHeader.CLA = PIN_UNBLOCK_CLA;
|
|
IsoHeader.P1 = PIN_UNBLOCK_P1;
|
|
IsoHeader.P2 = (BYTE) cNewMaxRetries;
|
|
|
|
//
|
|
// Send the pin change command to the card
|
|
//
|
|
|
|
status = hScwExecute(
|
|
pCardmodContext->hWfscCardHandle,
|
|
&IsoHeader,
|
|
pbDataIn,
|
|
(TCOUNT) cbDataIn,
|
|
NULL,
|
|
NULL,
|
|
&wStatusWord);
|
|
|
|
if (SCW_S_OK == status)
|
|
dwError = I_CardMapExecuteErrorCode(wStatusWord);
|
|
else
|
|
dwError = I_CardMapErrorCode(status);
|
|
|
|
Ret:
|
|
|
|
if (pbDataIn)
|
|
pCardData->pfnCspFree(pbDataIn);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Retrieves cryptographic authentication challenge bytes from the card.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardGetChallenge(
|
|
IN PCARD_DATA pCardData,
|
|
OUT PBYTE *ppbChallengeData,
|
|
OUT PDWORD pcbChallengeData)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
LOG_BEGIN_FUNCTION(CardGetChallenge);
|
|
|
|
*pcbChallengeData = cbCHALLENGE_RESPONSE_DATA;
|
|
|
|
*ppbChallengeData = pCardData->pfnCspAlloc(*pcbChallengeData);
|
|
|
|
LOG_CHECK_ALLOC(*ppbChallengeData);
|
|
|
|
LOG_CHECK_SCW_CALL(hScwGenerateRandom(
|
|
pCardmodContext->hWfscCardHandle,
|
|
*ppbChallengeData,
|
|
(TCOUNT) (*pcbChallengeData)));
|
|
|
|
Ret:
|
|
|
|
if (NULL != *ppbChallengeData && ERROR_SUCCESS != dwError)
|
|
{
|
|
pCardData->pfnCspFree(*ppbChallengeData);
|
|
*ppbChallengeData = NULL;
|
|
}
|
|
|
|
LOG_END_FUNCTION(CardGetChallenge, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//
|
|
// Submits the supplied response bytes to the card, to complete an Admin
|
|
// challenge-response authentication.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardAuthenticateChallenge(
|
|
IN PCARD_DATA pCardData,
|
|
IN PBYTE pbResponseData,
|
|
IN DWORD cbResponseData,
|
|
OUT OPTIONAL PDWORD pcAttemptsRemaining)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
LOG_BEGIN_FUNCTION(CardAuthenticateChallenge);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
//
|
|
// Authenticate the admin
|
|
//
|
|
|
|
dwError = CardSubmitPin(
|
|
pCardData,
|
|
wszCARD_USER_ADMIN,
|
|
pbResponseData,
|
|
cbResponseData,
|
|
pcAttemptsRemaining);
|
|
|
|
LOG_END_FUNCTION(CardAuthenticateChallenge, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Authenticates as Admin using the provided auth material. Then unblocks the
|
|
// specified account and sets the specified new pin and retry count. The Admin
|
|
// is deauthenticated before returning.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardUnblockPin(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszUserId,
|
|
IN PBYTE pbAuthenticationData,
|
|
IN DWORD cbAuthenticationData,
|
|
IN PBYTE pbNewPinData,
|
|
IN DWORD cbNewPinData,
|
|
IN DWORD cRetryCount,
|
|
IN DWORD dwFlags)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
LPWSTR wszPhysicalUser = NULL;
|
|
|
|
LOG_BEGIN_FUNCTION(CardUnblockPin);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
// Verify that admin authentication method flags are valid, although this
|
|
// module will use the auth data the same way in either case.
|
|
if (CARD_UNBLOCK_PIN_PIN != dwFlags &&
|
|
CARD_UNBLOCK_PIN_CHALLENGE_RESPONSE != dwFlags)
|
|
{
|
|
dwError = (DWORD) NTE_BAD_FLAGS;
|
|
goto Ret;
|
|
}
|
|
|
|
// Map the provided logical user name to physical user
|
|
dwError = GetWellKnownUserMapping(
|
|
pCardData,
|
|
pwszUserId,
|
|
&wszPhysicalUser);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
// Authenticate as admin
|
|
dwError = CardSubmitPin(
|
|
pCardData,
|
|
wszCARD_USER_ADMIN,
|
|
pbAuthenticationData,
|
|
cbAuthenticationData,
|
|
NULL);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
// Perform the unblock
|
|
dwError = I_CardUnblock(
|
|
pCardData,
|
|
wszPhysicalUser,
|
|
pbNewPinData,
|
|
cbNewPinData,
|
|
cRetryCount);
|
|
|
|
Ret:
|
|
|
|
if (NULL != wszPhysicalUser)
|
|
pCardData->pfnCspFree(wszPhysicalUser);
|
|
|
|
LOG_END_FUNCTION(CardUnblockPin, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Changes the pin or challenge-response key for the specified account.
|
|
//
|
|
// Updating the retry count via this API is not supported in this
|
|
// implementation.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardChangeAuthenticator(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszUserId,
|
|
IN PBYTE pbCurrentAuthenticator,
|
|
IN DWORD cbCurrentAuthenticator,
|
|
IN PBYTE pbNewAuthenticator,
|
|
IN DWORD cbNewAuthenticator,
|
|
IN DWORD cRetryCount,
|
|
OUT OPTIONAL PDWORD pcAttemptsRemaining)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
LPWSTR wszPhysicalUser = NULL;
|
|
|
|
LOG_BEGIN_FUNCTION(CardChangeAuthenticator);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
if (0 != cRetryCount)
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
goto Ret;
|
|
}
|
|
|
|
// Map the provided logical user name to physical user
|
|
dwError = GetWellKnownUserMapping(
|
|
pCardData,
|
|
pwszUserId,
|
|
&wszPhysicalUser);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
// Change the authenticator (pin or challenge-response key) for the target
|
|
// account.
|
|
dwError = I_CardChangePin(
|
|
pCardData,
|
|
wszPhysicalUser,
|
|
pbCurrentAuthenticator,
|
|
cbCurrentAuthenticator,
|
|
pbNewAuthenticator,
|
|
cbNewAuthenticator,
|
|
pcAttemptsRemaining);
|
|
|
|
Ret:
|
|
|
|
if (NULL != wszPhysicalUser)
|
|
pCardData->pfnCspFree(wszPhysicalUser);
|
|
|
|
LOG_END_FUNCTION(CardChangeAuthenticator, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// De-authenticates the specified logical user.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardDeauthenticate(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszUserId,
|
|
IN DWORD dwFlags)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
LPWSTR wszPhysicalUser = NULL;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
LOG_BEGIN_FUNCTION(CardDeauthenticate);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
dwError = GetWellKnownUserMapping(pCardData, pwszUserId, &wszPhysicalUser);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
LOG_CHECK_SCW_CALL(hScwDeauthenticateName(
|
|
pCardmodContext->hWfscCardHandle,
|
|
wszPhysicalUser));
|
|
|
|
Ret:
|
|
|
|
if (wszPhysicalUser)
|
|
pCardData->pfnCspFree(wszPhysicalUser);
|
|
|
|
LOG_END_FUNCTION(CardDeauthenticate, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//
|
|
// Creates a new file on the card using the specified logical name and Access
|
|
// Condition.
|
|
//
|
|
// If the specified file already exists, ERROR_FILE_EXISTS is returned.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardCreateFile(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszFileName,
|
|
IN CARD_FILE_ACCESS_CONDITION AccessCondition)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
LPSTR szPhysicalFileName = NULL;
|
|
LPWSTR wszPhysicalAcl = NULL;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
HFILE hFile = 0;
|
|
|
|
LOG_BEGIN_FUNCTION(CardCreateFile);
|
|
|
|
if (wcslen(pwszFileName) >
|
|
MAX_SUPPORTED_FILE_LEN)
|
|
{
|
|
dwError = ERROR_FILENAME_EXCED_RANGE;
|
|
goto Ret;
|
|
}
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
dwError = GetWellKnownFileMapping(
|
|
pCardData, pwszFileName, &szPhysicalFileName);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
dwError = GetWellKnownAcMapping(
|
|
pCardData, AccessCondition, &wszPhysicalAcl);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
LOG_CHECK_SCW_CALL(hScwCreateFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
(LPWSTR) szPhysicalFileName,
|
|
wszPhysicalAcl,
|
|
&hFile));
|
|
|
|
Ret:
|
|
if (szPhysicalFileName)
|
|
pCardData->pfnCspFree(szPhysicalFileName);
|
|
if (wszPhysicalAcl)
|
|
pCardData->pfnCspFree(wszPhysicalAcl);
|
|
if (hFile)
|
|
hScwCloseFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
hFile);
|
|
|
|
LOG_END_FUNCTION(CardCreateFile, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//
|
|
// Reads the specified logical file directly from the card (without any
|
|
// caching).
|
|
//
|
|
// If the specified file is not found, returns SCARD_E_FILE_NOT_FOUND.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardReadFile(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszFileName,
|
|
IN DWORD dwFlags,
|
|
OUT PBYTE *ppbData,
|
|
OUT PDWORD pcbData)
|
|
{
|
|
LPSTR szPhysical = NULL;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
LOG_BEGIN_FUNCTION(CardReadFile);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
dwError = GetWellKnownFileMapping(
|
|
pCardData,
|
|
pwszFileName,
|
|
&szPhysical);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
//
|
|
// For any file requested directly by the CSP (or other caller), assume
|
|
// that no cache lookup should be done. That is, assume that the caller
|
|
// is doing its own caching for files that it "owns".
|
|
//
|
|
dwError = I_CardReadFile(
|
|
pCardData,
|
|
(LPWSTR) szPhysical,
|
|
ppbData,
|
|
pcbData,
|
|
FALSE);
|
|
|
|
Ret:
|
|
if (szPhysical)
|
|
pCardData->pfnCspFree(szPhysical);
|
|
|
|
if (CARDMOD_FAILED(dwError) && *ppbData)
|
|
{
|
|
pCardData->pfnCspFree(*ppbData);
|
|
*ppbData = NULL;
|
|
}
|
|
|
|
LOG_END_FUNCTION(CardReadFile, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Writes the specified logical file to the card.
|
|
//
|
|
// If the specified file does not already exist, SCARD_E_FILE_NOT_FOUND
|
|
// is returned.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardWriteFile(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszFileName,
|
|
IN DWORD dwFlags,
|
|
IN PBYTE pbData,
|
|
IN DWORD cbData)
|
|
{
|
|
LPSTR szPhysical = NULL;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
HFILE hFile = 0;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
DWORD cbActual = 0;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
LOG_BEGIN_FUNCTION(CardWriteFile);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
dwError = GetWellKnownFileMapping(
|
|
pCardData, pwszFileName, &szPhysical);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
LOG_CHECK_SCW_CALL(hScwCreateFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
(LPWSTR) szPhysical,
|
|
NULL,
|
|
&hFile));
|
|
|
|
LOG_CHECK_SCW_CALL(hScwWriteFile32(
|
|
pCardmodContext->hWfscCardHandle,
|
|
hFile,
|
|
pbData,
|
|
cbData,
|
|
&cbActual));
|
|
|
|
if (cbActual != cbData)
|
|
{
|
|
dwError = (DWORD) SCARD_W_EOF;
|
|
goto Ret;
|
|
}
|
|
|
|
Ret:
|
|
if (hFile)
|
|
hScwCloseFile(
|
|
pCardmodContext->hWfscCardHandle, hFile);
|
|
if (szPhysical)
|
|
pCardData->pfnCspFree(szPhysical);
|
|
|
|
LOG_END_FUNCTION(CardWriteFile, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Deletes the specified logical file from the card.
|
|
//
|
|
// If the specified files is not found, SCARD_E_FILE_NOT_FOUND is returned.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardDeleteFile(
|
|
IN PCARD_DATA pCardData,
|
|
IN DWORD dwReserved,
|
|
IN LPWSTR pwszFileName)
|
|
{
|
|
LPSTR szPhysical = NULL;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
UNREFERENCED_PARAMETER(dwReserved);
|
|
|
|
LOG_BEGIN_FUNCTION(CardDeleteFile);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
dwError = GetWellKnownFileMapping(
|
|
pCardData, pwszFileName, &szPhysical);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
LOG_CHECK_SCW_CALL(hScwDeleteFile(
|
|
pCardmodContext->hWfscCardHandle, (LPWSTR) szPhysical));
|
|
|
|
Ret:
|
|
|
|
if (szPhysical)
|
|
pCardData->pfnCspFree(szPhysical);
|
|
|
|
LOG_END_FUNCTION(CardDeleteFile, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Enumerates the files present on the card in the logical directory name
|
|
// specified by the caller in the pmwszFileName parameter.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardEnumFiles(
|
|
IN PCARD_DATA pCardData,
|
|
IN DWORD dwFlags,
|
|
IN OUT LPWSTR *pmwszFileName)
|
|
{
|
|
/*
|
|
LPWSTR wszPhysicalDirectory = NULL;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
LPWSTR wszFiles = NULL;
|
|
LPWSTR wsz = NULL;
|
|
DWORD cchFiles = MAX_SUPPORTED_FILE_LEN;
|
|
DWORD cchCurrent = 0;
|
|
UINT16 nEnumCookie = 0;
|
|
SCODE result = 0;
|
|
BOOL fRetrying = FALSE;
|
|
*/
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
//
|
|
// TODO - need to implement reverse file mapping for this function to work
|
|
// correctly.
|
|
//
|
|
|
|
UNREFERENCED_PARAMETER(pCardData);
|
|
UNREFERENCED_PARAMETER(pmwszFileName);
|
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
|
|
/*
|
|
LOG_BEGIN_FUNCTION(CardEnumFiles);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
// Find the physical directory name in which we'll
|
|
// be enumerating.
|
|
|
|
dwError = GetWellKnownFileMapping(
|
|
pCardData, *pmwszFileName, &wszPhysicalDirectory);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
// Now set the CSP's pointer to the logical directory
|
|
// name to NULL to avoid ambiguity, since we'll be re-using the same
|
|
// pointer to return the list of files.
|
|
|
|
*pmwszFileName = NULL;
|
|
|
|
// Allocate space for a multi-string that may or may not be
|
|
// large enough to hold all of the enumerated file names.
|
|
|
|
wszFiles = (LPWSTR) pCardData->pfnCspAlloc(cchFiles * sizeof(WCHAR));
|
|
|
|
LOG_CHECK_ALLOC(wszFiles);
|
|
|
|
#pragma warning(push)
|
|
// Disable warning/error for conditional expression is constant
|
|
#pragma warning(disable:4127)
|
|
|
|
while (TRUE)
|
|
{
|
|
#pragma warning(pop)
|
|
|
|
//
|
|
// The WFSC marshalling code seems to puke if a buffer length of
|
|
// greater than SCHAR_MAX (127) is passed.
|
|
//
|
|
result = hScwEnumFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
wszPhysicalDirectory,
|
|
&nEnumCookie,
|
|
wszFiles + cchCurrent,
|
|
(TCOUNT) min(cchFiles - cchCurrent, MAX_SUPPORTED_FILE_LEN));
|
|
|
|
if (SCW_S_OK == result)
|
|
{
|
|
// Add on the length of the new file plus its terminator
|
|
cchCurrent += (DWORD) wcslen(wszFiles + cchCurrent) + 1;
|
|
|
|
fRetrying = FALSE;
|
|
|
|
// Continue looping
|
|
}
|
|
else if (SCW_E_BUFFERTOOSMALL == result)
|
|
{
|
|
if (fRetrying)
|
|
{
|
|
// We already retried this call once. Give up.
|
|
break;
|
|
}
|
|
|
|
wsz = (LPWSTR) pCardData->pfnCspAlloc((cchCurrent * 2) * sizeof(WCHAR));
|
|
|
|
LOG_CHECK_ALLOC(wsz);
|
|
|
|
memcpy(
|
|
wsz,
|
|
wszFiles,
|
|
cchCurrent);
|
|
|
|
pCardData->pfnCspFree(wszFiles);
|
|
wszFiles = wsz;
|
|
wsz = NULL;
|
|
cchFiles = cchCurrent * 2;
|
|
|
|
fRetrying = TRUE;
|
|
|
|
// Retry the last enum call
|
|
}
|
|
else if (SCW_E_NOMOREFILES == result)
|
|
{
|
|
*pmwszFileName = (LPWSTR) pCardData->pfnCspAlloc(
|
|
(1 + cchCurrent) * sizeof(WCHAR));
|
|
|
|
LOG_CHECK_ALLOC(*pmwszFileName);
|
|
|
|
memcpy(
|
|
*pmwszFileName,
|
|
wszFiles,
|
|
cchCurrent * sizeof(WCHAR));
|
|
|
|
// Make sure the multi-string is terminated by an extra NULL
|
|
(*pmwszFileName)[cchCurrent] = L'\0';
|
|
|
|
// We're done
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Unexpected error. Bail.
|
|
dwError = (DWORD) result;
|
|
goto Ret;
|
|
}
|
|
}
|
|
|
|
Ret:
|
|
|
|
if (wszPhysicalDirectory)
|
|
pCardData->pfnCspFree(wszPhysicalDirectory);
|
|
if (wszFiles)
|
|
pCardData->pfnCspFree(wszFiles);
|
|
if (wsz)
|
|
pCardData->pfnCspFree(wsz);
|
|
|
|
if (ERROR_SUCCESS != dwError && *pmwszFileName)
|
|
{
|
|
pCardData->pfnCspFree(*pmwszFileName);
|
|
*pmwszFileName = NULL;
|
|
}
|
|
|
|
LOG_END_FUNCTION(CardEnumFiles, dwError);
|
|
|
|
return dwError;
|
|
*/
|
|
}
|
|
|
|
//
|
|
// Initializes a CARD_FILE_INFO structure for the specified logical file.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardGetFileInfo(
|
|
IN PCARD_DATA pCardData,
|
|
IN LPWSTR pwszFileName,
|
|
OUT PCARD_FILE_INFO pCardFileInfo)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
LPSTR szPhysical = NULL;
|
|
HFILE hFile = 0;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
TOFFSET nFileLength = 0;
|
|
|
|
LOG_BEGIN_FUNCTION(CardGetFileInfo);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
dwError = GetWellKnownFileMapping(
|
|
pCardData,
|
|
pwszFileName,
|
|
&szPhysical);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
goto Ret;
|
|
|
|
//
|
|
// First, get the length of the file.
|
|
//
|
|
LOG_CHECK_SCW_CALL(hScwCreateFile(
|
|
pCardmodContext->hWfscCardHandle,
|
|
(LPWSTR) szPhysical,
|
|
NULL,
|
|
&hFile));
|
|
|
|
LOG_CHECK_SCW_CALL(hScwGetFileLength(
|
|
pCardmodContext->hWfscCardHandle,
|
|
hFile,
|
|
&nFileLength));
|
|
|
|
pCardFileInfo->cbFileSize = (DWORD) nFileLength;
|
|
|
|
//
|
|
// Next, get ACL info.
|
|
//
|
|
|
|
// TODO
|
|
pCardFileInfo->AccessCondition = InvalidAc;
|
|
|
|
Ret:
|
|
|
|
if (szPhysical)
|
|
pCardData->pfnCspFree(szPhysical);
|
|
if (hFile)
|
|
hScwCloseFile(
|
|
pCardmodContext->hWfscCardHandle, hFile);
|
|
|
|
LOG_END_FUNCTION(CardGetFileInfo, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//
|
|
// Initializes a CARD_FREE_SPACE_INFO structure using static information about
|
|
// the available space on the target card.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardQueryFreeSpace(
|
|
IN PCARD_DATA pCardData,
|
|
IN DWORD dwFlags,
|
|
OUT PCARD_FREE_SPACE_INFO pCardFreeSpaceInfo)
|
|
{
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
UNREFERENCED_PARAMETER(dwFlags);
|
|
|
|
LOG_BEGIN_FUNCTION(CardQueryFreeSpace);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
//
|
|
// Get the base free space information for this card.
|
|
//
|
|
memcpy(
|
|
pCardFreeSpaceInfo,
|
|
&pCardmodContext->pSupportedCard->CardFreeSpaceInfo,
|
|
sizeof(CARD_FREE_SPACE_INFO));
|
|
|
|
LOG_END_FUNCTION(CardQueryFreeSpace, 0);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Performs an RSA decryption using the specified Signature or Key Exchange
|
|
// key on the specified data. The length of the target data must be equal
|
|
// to the length of the public modulus, and pInfo->cbData must be set to
|
|
// that length.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardPrivateKeyDecrypt(
|
|
IN PCARD_DATA pCardData,
|
|
IN OUT PCARD_PRIVATE_KEY_DECRYPT_INFO pInfo)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
LPSTR szPrivateKeyFile = NULL;
|
|
PBYTE pbInit = NULL;
|
|
DWORD cbInit = 0;
|
|
DWORD cbPrivateKeyFile = 0;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
PBYTE pbCiphertext = NULL;
|
|
TCOUNT cbCiphertext = 0;
|
|
|
|
LOG_BEGIN_FUNCTION(CardPrivateKeyDecrypt);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
dwError = BuildCardKeyFilenames(
|
|
pCardData,
|
|
pInfo->dwKeySpec,
|
|
pInfo->bContainerIndex,
|
|
&szPrivateKeyFile,
|
|
NULL);
|
|
|
|
if (CARDMOD_FAILED(dwError))
|
|
goto Ret;
|
|
|
|
//
|
|
// Setup the command to initialize the RSA operation on the card
|
|
//
|
|
|
|
cbPrivateKeyFile = ((DWORD) wcslen(
|
|
(LPWSTR) szPrivateKeyFile) + 1) * sizeof(WCHAR);
|
|
|
|
cbInit = 1 + 1 + 1 + cbPrivateKeyFile + 2;
|
|
|
|
pbInit = (PBYTE) pCardData->pfnCspAlloc(cbInit);
|
|
|
|
LOG_CHECK_ALLOC(pbInit);
|
|
|
|
cbInit = 0;
|
|
|
|
// Tag
|
|
pbInit[cbInit] = 0x00;
|
|
cbInit++;
|
|
|
|
// Length
|
|
// Number of following bytes:
|
|
// filename len, filename + NULL, key data offset
|
|
pbInit[cbInit] = (BYTE) (1 + cbPrivateKeyFile + 2);
|
|
cbInit++;
|
|
|
|
// Value
|
|
pbInit[cbInit] = (BYTE) cbPrivateKeyFile / sizeof(WCHAR);
|
|
cbInit++;
|
|
|
|
memcpy(pbInit + cbInit, (PBYTE) szPrivateKeyFile, cbPrivateKeyFile);
|
|
cbInit += cbPrivateKeyFile;
|
|
|
|
*(UNALIGNED WORD *) (pbInit + cbInit) = 0x0000;
|
|
|
|
LOG_CHECK_SCW_CALL(hScwCryptoInitialize(
|
|
pCardmodContext->hWfscCardHandle,
|
|
CM_RSA_CRT | CM_KEY_INFILE,
|
|
pbInit));
|
|
|
|
//
|
|
// Do the private key decrypt
|
|
//
|
|
|
|
pbCiphertext = (PBYTE) pCardData->pfnCspAlloc(pInfo->cbData);
|
|
|
|
LOG_CHECK_ALLOC(pbCiphertext);
|
|
|
|
cbCiphertext = (TCOUNT) pInfo->cbData;
|
|
|
|
LOG_CHECK_SCW_CALL(hScwCryptoAction(
|
|
pCardmodContext->hWfscCardHandle,
|
|
pInfo->pbData,
|
|
(TCOUNT) pInfo->cbData,
|
|
pbCiphertext,
|
|
&cbCiphertext));
|
|
|
|
if (cbCiphertext != pInfo->cbData)
|
|
{
|
|
dwError = ERROR_INTERNAL_ERROR;
|
|
goto Ret;
|
|
}
|
|
|
|
memcpy(pInfo->pbData, pbCiphertext, cbCiphertext);
|
|
|
|
Ret:
|
|
|
|
if (pbCiphertext)
|
|
pCardData->pfnCspFree(pbCiphertext);
|
|
if (pbInit)
|
|
pCardData->pfnCspFree(pbInit);
|
|
if (szPrivateKeyFile)
|
|
pCardData->pfnCspFree(szPrivateKeyFile);
|
|
|
|
LOG_END_FUNCTION(CardPrivateKeyDecrypt, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Initializes a CARD_KEY_SIZES structure for the specified key type, indicated
|
|
// the key sizes supported by the target card.
|
|
//
|
|
DWORD
|
|
WINAPI
|
|
CardQueryKeySizes(
|
|
IN PCARD_DATA pCardData,
|
|
IN DWORD dwKeySpec,
|
|
IN DWORD dwReserved,
|
|
OUT PCARD_KEY_SIZES pKeySizes)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
PCARDMOD_CONTEXT pCardmodContext =
|
|
(PCARDMOD_CONTEXT) pCardData->pvVendorSpecific;
|
|
|
|
UNREFERENCED_PARAMETER(dwReserved);
|
|
|
|
LOG_BEGIN_FUNCTION(CardQueryKeySizes);
|
|
|
|
ProxyUpdateScardHandle(pCardmodContext->hWfscCardHandle, pCardData->hScard);
|
|
|
|
switch (dwKeySpec)
|
|
{
|
|
case AT_SIGNATURE:
|
|
memcpy(
|
|
pKeySizes,
|
|
&pCardmodContext->pSupportedCard->CardKeySizes_Sig,
|
|
sizeof(CARD_KEY_SIZES));
|
|
|
|
break;
|
|
|
|
case AT_KEYEXCHANGE:
|
|
memcpy(
|
|
pKeySizes,
|
|
&pCardmodContext->pSupportedCard->CardKeySizes_KeyEx,
|
|
sizeof(CARD_KEY_SIZES));
|
|
|
|
break;
|
|
|
|
default:
|
|
dwError = (DWORD) NTE_BAD_ALGID;
|
|
break;
|
|
}
|
|
|
|
LOG_END_FUNCTION(CardQueryKeySizes, dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//
|
|
// Loader callback.
|
|
//
|
|
BOOL WINAPI
|
|
DllInitialize(
|
|
IN PVOID hmod,
|
|
IN ULONG Reason,
|
|
IN PCONTEXT Context) // Unused parameter
|
|
{
|
|
DWORD dwLen = 0;
|
|
|
|
UNREFERENCED_PARAMETER(Context);
|
|
|
|
if (Reason == DLL_PROCESS_ATTACH)
|
|
{
|
|
// Get our image name.
|
|
dwLen = GetModuleBaseName(
|
|
GetCurrentProcess(),
|
|
hmod,
|
|
l_wszImagePath,
|
|
sizeof(l_wszImagePath) / sizeof(l_wszImagePath[0]));
|
|
|
|
if (0 == dwLen)
|
|
return FALSE;
|
|
|
|
DisableThreadLibraryCalls(hmod);
|
|
|
|
#if DBG
|
|
CardmodInitDebug(MyDebugKeys);
|
|
#endif
|
|
}
|
|
else if (Reason == DLL_PROCESS_DETACH)
|
|
{
|
|
// Cleanup
|
|
#if DBG
|
|
CardmodUnloadDebug();
|
|
#endif
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Registers the cards supported by this card module.
|
|
//
|
|
STDAPI
|
|
DllRegisterServer(
|
|
void)
|
|
{
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
DWORD dwSts;
|
|
int iSupportedCard = 0;
|
|
|
|
for (
|
|
iSupportedCard = 0;
|
|
iSupportedCard < sizeof(SupportedCards) /
|
|
sizeof(SupportedCards[0]);
|
|
iSupportedCard++)
|
|
{
|
|
SCardForgetCardType(
|
|
0,
|
|
SupportedCards[iSupportedCard].wszCardName);
|
|
|
|
dwSts = SCardIntroduceCardType(
|
|
0,
|
|
SupportedCards[iSupportedCard].wszCardName,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
SupportedCards[iSupportedCard].rgbAtr,
|
|
SupportedCards[iSupportedCard].rgbAtrMask,
|
|
SupportedCards[iSupportedCard].cbAtr);
|
|
|
|
if (SCARD_S_SUCCESS != dwSts)
|
|
{
|
|
dwReturn = dwSts;
|
|
goto ErrorRet;
|
|
}
|
|
|
|
dwSts = SCardSetCardTypeProviderName(
|
|
0,
|
|
SupportedCards[iSupportedCard].wszCardName,
|
|
SCARD_PROVIDER_CSP,
|
|
MS_SCARD_PROV);
|
|
|
|
if (SCARD_S_SUCCESS != dwSts)
|
|
{
|
|
dwReturn = dwSts;
|
|
goto ErrorRet;
|
|
}
|
|
|
|
dwSts = SCardSetCardTypeProviderName(
|
|
0,
|
|
SupportedCards[iSupportedCard].wszCardName,
|
|
SCARD_PROVIDER_CARD_MODULE,
|
|
l_wszImagePath);
|
|
|
|
if (SCARD_S_SUCCESS != dwSts)
|
|
{
|
|
dwReturn = dwSts;
|
|
goto ErrorRet;
|
|
}
|
|
}
|
|
|
|
ErrorRet:
|
|
return dwReturn;
|
|
}
|
|
|
|
//
|
|
// Deletes the registration of cards supported by this card module.
|
|
//
|
|
STDAPI
|
|
DllUnregisterServer(
|
|
void)
|
|
{
|
|
DWORD dwSts = ERROR_SUCCESS;
|
|
int iSupportedCard = 0;
|
|
|
|
for (
|
|
iSupportedCard = 0;
|
|
iSupportedCard < sizeof(SupportedCards) /
|
|
sizeof(SupportedCards[0]);
|
|
iSupportedCard++)
|
|
{
|
|
dwSts = SCardForgetCardType(
|
|
0,
|
|
SupportedCards[iSupportedCard].wszCardName);
|
|
}
|
|
|
|
return dwSts;
|
|
}
|