|
|
#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; }
|