Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1662 lines
41 KiB

// wfscproto - Prototyping code for the Windows for Smart Card Card Module
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <crypt.h>
#include <windows.h>
#include "cardmod.h"
#include "wpscproxy.h"
#include <malloc.h>
#include <stdio.h>
#include <rsa.h>
#include <stdlib.h>
#include "carddbg.h"
//
// Need to define the dsys debug symbols since we're linking directly to the
// proxy lib which requires them.
//
DEFINE_DEBUG2(Cardmod)
#define SC_FAILED(X) (0 != (X))
#define SCW_CALL(X) { \
if ((status = X) != SCW_S_OK) { \
dwError = (DWORD) status; \
goto Ret; \
}}
//
// Using Crypto API, the RSA public exponent is always 0x10001, which can
// be represented in three bytes.
//
#define cbCAPI_PUBLIC_EXPONENT 3
#define wszTEST_CARD_NAME L"SCWUnnamed"
#define wszDEFAULT_ACL_FILE L"/s/a/uw"
#define wszKEY_ACL_FILE L"/s/a/ux"
#define wszNEW_FILE L"/dan"
#define wszRSA_KEY_FILE L"/CK0"
//
// 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
#define PIN_UNBLOCK_P2 0x00
#define PIN_RETRY_COUNTER_CLA 0x00
#define PIN_RETRY_COUNTER_INS 0x50
#define PIN_RETRY_COUNTER_P1 0x00
#define PIN_RETRY_COUNTER_P2 0x00
SCARDHANDLE g_hWfscHandle = 0;
#define ScwAuthenticateName(X, Y, Z) (hScwAuthenticateName(g_hWfscHandle, X, Y, Z))
#define ScwDeauthenticateName(X) (hScwDeauthenticateName(g_hWfscHandle, X))
#define ScwCreateFile(X, Y, Z) (hScwCreateFile(g_hWfscHandle, X, Y, Z))
#define ScwCloseFile(X) (hScwCloseFile(g_hWfscHandle, X))
#define ScwWriteFile(X, Y, Z, A) (hScwWriteFile(g_hWfscHandle, X, Y, Z, A))
#define ScwWriteFile32(X, Y, Z, A) (hScwWriteFile32(g_hWfscHandle, X, Y, Z, A))
#define ScwEnumFile(X, Y, Z, A) (hScwEnumFile(g_hWfscHandle, X, Y, Z, A))
#define ScwGetFileLength(X, Y) (hScwGetFileLength(g_hWfscHandle, X, Y))
#define ScwReadFile32(X, Y, Z, A) (hScwReadFile32(g_hWfscHandle, X, Y, Z, A))
#define ScwAttachToCard(X, Y) (hScwAttachToCard(X, Y, &g_hWfscHandle))
#define ScwCryptoInitialize(X, Y) (hScwCryptoInitialize(g_hWfscHandle, X, Y))
#define ScwCryptoAction(X, Y, Z, A) (hScwCryptoAction(g_hWfscHandle, X, Y, Z, A))
#define ScwDetachFromCard() (hScwDetachFromCard(g_hWfscHandle))
#define ScwDeleteFile(X) (hScwDeleteFile(g_hWfscHandle, X))
#define ScwExecute(A, B, C, D, E, F) (hScwExecute(g_hWfscHandle, A, B, C, D, E, F))
#define ScwSetFilePointer(A, B, C) (hScwSetFilePointer(g_hWfscHandle, A, B, C))
//
// Required for linking to rsa32
//
unsigned int
RSA32API
NewGenRandom(
IN OUT unsigned char **ppbRandSeed /*unused*/,
IN unsigned long *pcbRandSeed /*unused*/,
IN OUT unsigned char *pbBuffer,
IN unsigned long dwLength
)
{
return (unsigned int)RtlGenRandom( pbBuffer, dwLength );
}
void MyRngFunc(
IN PVOID pvInfo,
IN OUT unsigned char **ppbRandSeed /*unused*/,
IN unsigned long *pcbRandSeed /*unused*/,
IN OUT unsigned char *pbBuffer,
IN unsigned long dwLength)
{
NewGenRandom(ppbRandSeed, pcbRandSeed, pbBuffer, dwLength);
}
typedef struct _Principal
{
BYTE rgbPin[4];
LPWSTR pwszUser;
} Principal;
Principal Principals [] = {
{ { 0x00, 0x00, 0x00, 0x00 }, L"Everyone" },
{ { 0x00, 0x00, 0x00, 0x00 }, L"user" },
{ { 0x01, 0x02, 0x03, 0x04 }, L"admin" }
};
#define PRINCIPAL_USER 1
#define PRINCIPAL_ADMIN 2
BYTE rgbUserNewPin [] = {
0x01, 0x01, 0x01, 0x01
};
DWORD Authenticate(
DWORD dwId)
{
return (DWORD) ScwAuthenticateName(
Principals[dwId].pwszUser,
Principals[dwId].rgbPin,
sizeof(Principals[dwId].rgbPin));
}
DWORD Deauthenticate(
DWORD dwId)
{
return (DWORD) ScwDeauthenticateName(Principals[dwId].pwszUser);
}
#define CROW 16
void PrintBytes(LPWSTR pwszHdr, BYTE *pb, DWORD cbSize)
{
ULONG cb, i;
if (cbSize == 0) {
wprintf(L"%s NO Value Bytes\n", pwszHdr);
return;
}
if (NULL != pwszHdr)
wprintf(L"%s\n", pwszHdr);
while (cbSize > 0)
{
wprintf(L" ");
cb = min(CROW, cbSize);
cbSize -= cb;
for (i = 0; i<cb; i++)
wprintf(L" %02X", pb[i]);
for (i = cb; i<CROW; i++)
wprintf(L" ");
wprintf(L" '");
for (i = 0; i<cb; i++)
if (pb[i] >= 0x20 && pb[i] <= 0x7f)
wprintf(L"%c", pb[i]);
else
wprintf(L".");
pb += cb;
wprintf(L"'\n");
}
}
void I_DebugPrintBytes(LPWSTR pwszHdr, BYTE *pb, DWORD cbSize)
{
PrintBytes(pwszHdr, pb, cbSize);
}
DWORD WriteKeyToCard(
IN LPWSTR pwszKeyFile,
IN LPWSTR pwszAclFile,
IN PBYTE pbKey,
IN DWORD cbKey)
{
HFILE hFile = 0;
DWORD cbCheck = 0;
SCODE status = 0;
DWORD dwError = 0;
PrintBytes(L"Key file to write to card", pbKey, cbKey);
//
// Write the private key to the card
//
status = Authenticate(PRINCIPAL_USER);
if (SCW_S_OK != status)
{
dwError = (DWORD) status;
goto Ret;
}
// Delete the key if it already exists
status = ScwCreateFile(pwszKeyFile, NULL, &hFile);
if (SCW_S_OK == status)
{
SCW_CALL(ScwCloseFile(hFile));
hFile = 0;
SCW_CALL(ScwDeleteFile(pwszKeyFile));
}
SCW_CALL(ScwCreateFile(pwszKeyFile, pwszAclFile, &hFile));
SCW_CALL(ScwWriteFile32(hFile, pbKey, cbKey, &cbCheck));
if (cbKey != cbCheck)
{
printf(
"ERROR - expected to write %d key bytes, but only wrote %d\n",
cbKey,
cbCheck);
dwError = -1;
goto Ret;
}
Ret:
if (hFile)
ScwCloseFile(hFile);
return dwError;
}
//
// Generates a new RSA key using rsa32 (BSafe) primitives, then writes
// the key to the card in the card's key format.
//
DWORD GenKeyOnCardWithRsa32(
IN LPWSTR pwszKeyFile,
IN LPWSTR pwszAclFile,
IN DWORD cKeySizeBits)
{
DWORD dwError = ERROR_SUCCESS;
DWORD cbPublic = 0;
DWORD cbPrivate = 0;
DWORD cLocalBits = cKeySizeBits;
BSAFE_PUB_KEY *pPub = NULL;
BSAFE_PRV_KEY *pPrv = NULL;
BSAFE_OTHER_INFO OtherInfo;
DWORD cbTmpLen = 0;
DWORD cbHalfTmpLen = 0;
DWORD cbHalfModLen = 0;
BYTE rgbCardKey [1000];
DWORD cbKey = 0;
PBYTE pbKey = NULL;
DWORD cBitlenBytes = cKeySizeBits / 8;
PBYTE pbIn = NULL;
memset(&OtherInfo, 0, sizeof(OtherInfo));
OtherInfo.pFuncRNG = MyRngFunc;
//
// Figure out how big the key buffers need to be
//
if (! BSafeComputeKeySizes(&cbPublic, &cbPrivate, &cLocalBits))
{
dwError = ERROR_INTERNAL_ERROR;
goto Ret;
}
//
// Alloc the key buffers
//
pPub = (BSAFE_PUB_KEY *) malloc(cbPublic);
if (NULL == pPub)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
pPrv = (BSAFE_PRV_KEY *) malloc(cbPrivate);
if (NULL == pPrv)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
//
// Generate the key pair
//
if (!BSafeMakeKeyPairEx2(
&OtherInfo, pPub, pPrv, cKeySizeBits, 0x3))
{
dwError = ERROR_INTERNAL_ERROR;
goto Ret;
}
//
// Copy the private key out of the BSafe format into the card format
//
// This code is copied from rsaenh.dll sources
//
cbHalfModLen = (pPrv->bitlen + 15) / 16;
// figure out the number of overflow bytes which are in the private
// key structure
cbTmpLen = (sizeof(DWORD) * 2)
- (((pPrv->bitlen + 7) / 8) % (sizeof(DWORD) * 2));
if ((sizeof(DWORD) * 2) != cbTmpLen)
cbTmpLen += sizeof(DWORD) * 2;
cbHalfTmpLen = cbTmpLen / 2;
pbKey = rgbCardKey;
// Key mode
pbKey[cbKey] = MODE_RSA_SIGN;
cbKey++;
// size of public exponent
pbKey[cbKey] = 1;
cbKey++;
// public exponent
pbKey[cbKey] = 0x3;
cbKey++;
// RSA key length
pbKey[cbKey] = (BYTE) cBitlenBytes;
cbKey++;
pbIn = (PBYTE) pPrv + sizeof(BSAFE_PRV_KEY);
// Public modulus
memcpy(pbKey + cbKey, pbIn, cBitlenBytes);
pbIn += cBitlenBytes + cbTmpLen;
cbKey += cBitlenBytes;
// Fast-forward to the end of the private key structure to grab the
// private exponent.
pbIn += 5 * (cbHalfModLen + cbHalfTmpLen);
memcpy(pbKey + cbKey, pbIn, cBitlenBytes);
cbKey += cBitlenBytes;
dwError = WriteKeyToCard(
pwszKeyFile, pwszAclFile, rgbCardKey, cbKey);
Ret:
if (pPub)
free(pPub);
if (pPrv)
free(pPrv);
return dwError;
}
//
// Generates a new RSA key using Crypto API, then exports the key and
// writes it to the card. The key is stored in a format that allows
// the use of Chinese Remainder Theorem parameters for faster RSA perf.
//
DWORD GenKeyOnCardCRT(
IN LPWSTR pwszKeyFile,
IN LPWSTR pwszAclFile,
IN DWORD cKeySizeBits)
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
BYTE rgbCapiKey [1000];
BYTE rgbCardKey [1000];
DWORD dwError = ERROR_SUCCESS;
DWORD cbCapiKey = 0;
BLOBHEADER *pBlobHeader = NULL;
RSAPUBKEY *pPubKey = NULL;
BYTE *pbKey = NULL;
DWORD cbKey = 0;
DWORD cBitlenBytes = 0;
if (! CryptAcquireContext(
&hProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
dwError = GetLastError();
goto Ret;
}
if (! CryptGenKey(
hProv, AT_KEYEXCHANGE, (cKeySizeBits << 16) | CRYPT_EXPORTABLE, &hKey))
{
dwError = GetLastError();
goto Ret;
}
cbCapiKey = sizeof(rgbCapiKey);
if (! CryptExportKey(
hKey, 0, PRIVATEKEYBLOB, 0, rgbCapiKey, &cbCapiKey))
{
dwError = GetLastError();
goto Ret;
}
pBlobHeader = (BLOBHEADER *) rgbCapiKey;
pPubKey = (RSAPUBKEY *) (rgbCapiKey + sizeof(BLOBHEADER));
cBitlenBytes = pPubKey->bitlen / 8;
pbKey = rgbCardKey;
//
// Build the private key in the card's format
//
// Key mode
pbKey[cbKey] = MODE_RSA_SIGN;
cbKey++;
// size of public exponent
pbKey[cbKey] = cbCAPI_PUBLIC_EXPONENT;
cbKey++;
// public exponent
memcpy(
pbKey + cbKey,
(PBYTE) &pPubKey->pubexp,
cbCAPI_PUBLIC_EXPONENT);
cbKey += cbCAPI_PUBLIC_EXPONENT;
// RSA key length
pbKey[cbKey] = (BYTE) cBitlenBytes;
cbKey++;
// public key
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
cBitlenBytes);
cbKey += cBitlenBytes;
// prime 1
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
cBitlenBytes,
cBitlenBytes / 2);
cbKey += cBitlenBytes / 2;
// prime 2
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
(3 * cBitlenBytes / 2),
cBitlenBytes / 2);
cbKey += cBitlenBytes / 2;
// Exp1 (D mod (P-1)) (m/2 bytes)
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
2 * cBitlenBytes,
cBitlenBytes / 2);
cbKey += cBitlenBytes / 2;
// Exp2 (D mod (Q-1)) (m/2 bytes)
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
(5 * cBitlenBytes / 2),
cBitlenBytes / 2);
cbKey += cBitlenBytes / 2;
// Coef ((Q^(-1)) mod p) (m/2 bytes)
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
3 * cBitlenBytes,
cBitlenBytes / 2);
cbKey += cBitlenBytes / 2;
// private exponent
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
(7 * cBitlenBytes / 2),
cBitlenBytes);
cbKey += cBitlenBytes;
dwError = WriteKeyToCard(
pwszKeyFile, pwszAclFile, rgbCardKey, cbKey);
Ret:
if (hKey)
CryptDestroyKey(hKey);
if (hProv)
CryptReleaseContext(hProv, 0);
return dwError;
}
//
// Generates a new RSA key in Crypto API (in software), then exports the
// key and writes it to the card in a format usable by the card's RSA
// engine.
//
DWORD GenKeyOnCardWithCapi(
IN LPWSTR pwszKeyFile,
IN LPWSTR pwszAclFile,
IN DWORD cKeySizeBits)
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
BYTE rgbCapiKey [1000];
BYTE rgbCardKey [1000];
DWORD dwError = ERROR_SUCCESS;
DWORD cbCapiKey = 0;
BLOBHEADER *pBlobHeader = NULL;
RSAPUBKEY *pPubKey = NULL;
BYTE *pbKey = NULL;
DWORD cbKey = 0;
DWORD cBitlenBytes = 0;
if (! CryptAcquireContext(
&hProv, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
dwError = GetLastError();
goto Ret;
}
if (! CryptGenKey(
hProv, AT_KEYEXCHANGE, (cKeySizeBits << 16) | CRYPT_EXPORTABLE, &hKey))
{
dwError = GetLastError();
goto Ret;
}
cbCapiKey = sizeof(rgbCapiKey);
if (! CryptExportKey(
hKey, 0, PRIVATEKEYBLOB, 0, rgbCapiKey, &cbCapiKey))
{
dwError = GetLastError();
goto Ret;
}
pBlobHeader = (BLOBHEADER *) rgbCapiKey;
pPubKey = (RSAPUBKEY *) (rgbCapiKey + sizeof(BLOBHEADER));
cBitlenBytes = pPubKey->bitlen / 8;
pbKey = rgbCardKey;
//
// Build the private key in the card's format
//
// Key mode
pbKey[cbKey] = MODE_RSA_SIGN;
cbKey++;
// size of public exponent
pbKey[cbKey] = cbCAPI_PUBLIC_EXPONENT;
cbKey++;
// public exponent
memcpy(
pbKey + cbKey,
(PBYTE) &pPubKey->pubexp,
cbCAPI_PUBLIC_EXPONENT);
cbKey += cbCAPI_PUBLIC_EXPONENT;
// RSA key length
pbKey[cbKey] = (BYTE) cBitlenBytes;
cbKey++;
// public key
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY),
cBitlenBytes);
cbKey += cBitlenBytes;
// private exponent
memcpy(
pbKey + cbKey,
rgbCapiKey + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
(7 * cBitlenBytes / 2),
cBitlenBytes);
cbKey += cBitlenBytes;
dwError = WriteKeyToCard(
pwszKeyFile, pwszAclFile, rgbCardKey, cbKey);
Ret:
if (hKey)
CryptDestroyKey(hKey);
if (hProv)
CryptReleaseContext(hProv, 0);
return dwError;
}
DWORD SetupRsaKeyOnCardSimulator(
IN LPWSTR pwszKeyFile,
IN LPWSTR pwszAclFile,
IN BOOL fUseSimulator)
{
FILE *fh = NULL;
UINT16 NLen, D1Len, DLen;
BYTE buffer[1000];
DWORD dwError = ERROR_SUCCESS;
SCODE status = 0;
HFILE hFile = 0;
TCOUNT bytecheck = 0;
BOOL fReAuthenticated = FALSE;
status = ScwCreateFile(pwszKeyFile, NULL, &hFile);
if (SCW_S_OK == status)
{
// Key file already exists, so we're done
status = ScwCloseFile(hFile);
return (DWORD) status;
}
fh=fopen("SimKeys.RSA", "rb");
if (NULL == fh)
{
dwError = ERROR_FILE_NOT_FOUND;
goto Ret;
}
dwError = Authenticate(PRINCIPAL_USER);
if (ERROR_SUCCESS != dwError)
goto Ret;
fReAuthenticated = TRUE;
status = ScwCreateFile(pwszKeyFile, pwszAclFile, &hFile);
if (SC_FAILED(status))
{
dwError = (DWORD) status;
goto Ret;
}
buffer[0]=0; //mode=0
ScwWriteFile(hFile, buffer, 1, &bytecheck);
NLen = (UINT16) fgetc(fh);
buffer[0]=(BYTE) NLen;
NLen += 0x14;
ScwWriteFile(hFile, buffer, 1, &bytecheck);
DLen = (UINT16) fgetc(fh);
buffer[0]=(BYTE) DLen;
ScwWriteFile(hFile, buffer, 1, &bytecheck);
D1Len = (UINT16) fgetc(fh);
buffer[0]=(BYTE) D1Len;
ScwWriteFile(hFile, buffer, 1, &bytecheck);
DLen=DLen*256+D1Len+0x14;
//write the keys to file
while(NLen>0) {
buffer[0] = (BYTE) fgetc(fh);
buffer[1] = (BYTE) fgetc(fh);
ScwWriteFile(hFile, buffer, 2, &bytecheck);
NLen-=2;
}
while(DLen>0) {
buffer[0] = (BYTE) fgetc(fh);
buffer[1] = (BYTE) fgetc(fh);
ScwWriteFile(hFile, buffer, 2, &bytecheck);
DLen-=2;
}
Ret:
if (fh)
fclose(fh);
if (hFile)
ScwCloseFile(hFile);
if (fReAuthenticated)
Deauthenticate(PRINCIPAL_USER);
return dwError;
}
DWORD DisplayFileContents(
IN LPWSTR pwszFileName)
{
HFILE hFile = 0;
SCODE status = 0;
DWORD dwError = 0;
PBYTE pbContents = NULL;
DWORD cbContents = 0;
DWORD cbActual = 0;
status = ScwCreateFile(
pwszFileName, NULL, &hFile);
if (SC_FAILED(status))
goto Ret;
status = ScwGetFileLength(
hFile, (TOFFSET *) &cbContents);
if (SC_FAILED(status))
goto Ret;
pbContents = (PBYTE) malloc(cbContents);
if (NULL == pbContents)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
status = ScwReadFile32(
hFile, pbContents, cbContents, &cbActual);
if (SC_FAILED(status))
goto Ret;
PrintBytes(pwszFileName, pbContents, cbActual);
Ret:
if (SCW_S_OK != status)
dwError = (DWORD) status;
if (hFile)
ScwCloseFile(hFile);
if (pbContents)
free(pbContents);
return dwError;
}
DWORD EnumFilesInDirectory(
IN LPWSTR pwszBaseDir,
IN LPWSTR pwszCurrent)
{
SCODE status = 0;
DWORD dwError = 0;
BOOL fFirst = TRUE;
UINT16 EnumState = 0;
WCHAR rgwsz[64];
WCHAR rgwszDir[64];
if ( L'/' != pwszCurrent[0] &&
0 != wcscmp(L"/", pwszBaseDir))
swprintf(
rgwszDir, L"%s/%s", pwszBaseDir, pwszCurrent);
else
swprintf(
rgwszDir, L"%s%s", pwszBaseDir, pwszCurrent);
EnumState = 0;
status = ScwEnumFile(rgwszDir, &EnumState, rgwsz, sizeof(rgwsz) / sizeof(WCHAR));
switch (status)
{
case SCW_S_OK:
// pwszDir is indeed a directory. Keep enumerating.
wprintf(L"%s - DIR\n", rgwszDir);
do
{
dwError = EnumFilesInDirectory(rgwszDir, rgwsz);
}
while (
SCW_S_OK == dwError &&
SCW_S_OK == (status = ScwEnumFile(
rgwszDir, &EnumState, rgwsz, sizeof(rgwsz) / sizeof(WCHAR))));
break;
case SCW_E_NOMOREFILES:
// Empty directory
wprintf(L"%s - DIR\n", rgwszDir);
status = SCW_S_OK;
break;
case SCW_E_BADDIR:
// pwszDir is not a directory. Stop.
wprintf(L"%s - FILE\n", rgwszDir);
DisplayFileContents(rgwszDir);
status = SCW_S_OK;
break;
case SCW_E_NOTAUTHORIZED:
// Not authenticated. Stop with error.
wprintf(L"%s - NOT AUTHORIZED\n", rgwszDir);
break;
case SCW_E_FILENOTFOUND:
// What the hell does this mean?
wprintf(L"%s - FILE NOT FOUND\n", rgwszDir);
status = SCW_S_OK;
break;
default:
// Other error. We're done.
dwError = (DWORD) status;
break;
}
return dwError;
}
//
// Resets the user's pin using the VB applet on the card
//
DWORD TestPinUnblock(
IN PBYTE pbNewPin,
IN DWORD cbNewPin)
{
ISO_HEADER IsoHeader;
BYTE rgbDataIn [256];
UINT16 wStatusWord = 0;
TCOUNT cbDataIn = 0;
BYTE cbUser = (BYTE) ((wcslen(L"user") + 1) * sizeof(WCHAR));
SCODE status = 0;
memset(&IsoHeader, 0, sizeof(IsoHeader));
memset(rgbDataIn, 0, sizeof(rgbDataIn));
// Setup User Name TLV
rgbDataIn[cbDataIn] = 0;
cbDataIn++;
rgbDataIn[cbDataIn] = cbUser;
cbDataIn++;
memcpy(rgbDataIn + cbDataIn, (PBYTE) L"user", cbUser);
cbDataIn += cbUser;
// Setup New Pin TLV
rgbDataIn[cbDataIn] = 2;
cbDataIn++;
rgbDataIn[cbDataIn] = (BYTE) cbNewPin;
cbDataIn++;
memcpy(rgbDataIn + cbDataIn, pbNewPin, cbNewPin);
cbDataIn += (TCOUNT) cbNewPin;
// Build the command
IsoHeader.INS = PIN_UNBLOCK_INS;
IsoHeader.CLA = PIN_UNBLOCK_CLA;
IsoHeader.P1 = PIN_UNBLOCK_P1;
IsoHeader.P2 = PIN_UNBLOCK_P2;
//
// Send the pin change command to the card
//
status = ScwExecute(
&IsoHeader,
rgbDataIn,
cbDataIn,
NULL,
NULL,
&wStatusWord);
if (SCW_S_OK == status)
{
// Reminder: Status words returned by this RTE app are in the form:
// 9000 -> Success
// 6Fyy -> An API failed with return code yy
// 6Ezz -> An exception was raised (zz is the err number)
switch (wStatusWord >> 8)
{
case 0x90:
printf("Pin unblock was successful\n");
break;
case 0x6F:
case 0x6E:
// Make it a 32 bits error code so the message can be retrieved from
// scwapi.dll
status = 0x80000000L | (BYTE) wStatusWord;
break;
default:
printf(
"ERROR: unexpected status word received from card, %04X\n",
wStatusWord);
status = (SCODE) SCARD_F_INTERNAL_ERROR;
break;
}
}
return status;
}
//
// Changes the user's pin using the VB applet on the card
//
DWORD TestPinChange(
IN PBYTE pbCurrentPin,
IN DWORD cbCurrentPin,
IN PBYTE pbNewPin,
IN DWORD cbNewPin)
{
ISO_HEADER IsoHeader;
BYTE rgbDataIn [256];
UINT16 wStatusWord = 0;
TCOUNT cbDataIn = 0;
BYTE cbUser = (BYTE) ((wcslen(L"user") + 1) * sizeof(WCHAR));
SCODE status = 0;
memset(&IsoHeader, 0, sizeof(IsoHeader));
memset(rgbDataIn, 0, sizeof(rgbDataIn));
// Setup User Name TLV
rgbDataIn[cbDataIn] = 0;
cbDataIn++;
rgbDataIn[cbDataIn] = cbUser;
cbDataIn++;
memcpy(rgbDataIn + cbDataIn, (PBYTE) L"user", cbUser);
cbDataIn += cbUser;
// Setup Current Pin TLV
rgbDataIn[cbDataIn] = 1;
cbDataIn++;
rgbDataIn[cbDataIn] = (BYTE) cbCurrentPin;
cbDataIn++;
memcpy(rgbDataIn + cbDataIn, pbCurrentPin, cbCurrentPin);
cbDataIn += (TCOUNT) cbCurrentPin;
// Setup New Pin TLV
rgbDataIn[cbDataIn] = 2;
cbDataIn++;
rgbDataIn[cbDataIn] = (BYTE) cbNewPin;
cbDataIn++;
memcpy(rgbDataIn + cbDataIn, pbNewPin, cbNewPin);
cbDataIn += (TCOUNT) 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 = ScwExecute(
&IsoHeader,
rgbDataIn,
cbDataIn,
NULL,
NULL,
&wStatusWord);
if (SCW_S_OK == status)
{
// Reminder: Status words returned by this RTE app are in the form:
// 9000 -> Success
// 6Fyy -> An API failed with return code yy
// 6Ezz -> An exception was raised (zz is the err number)
switch (wStatusWord >> 8)
{
case 0x90:
printf("Pin was changed successfully\n");
break;
case 0x6F:
case 0x6E:
// Make it a 32 bits error code so the message can be retrieved from
// scwapi.dll
status = 0x80000000L | (BYTE) wStatusWord;
break;
default:
printf(
"ERROR: unexpected status word received from card, %04X\n",
wStatusWord);
status = (SCODE) SCARD_F_INTERNAL_ERROR;
break;
}
}
return status;
}
//
// Retrieves the number of attempts remaining on the specified principal's
// pin from the card, via the Pin Retry Counter applet.
//
DWORD TestPinRetryCounter(
IN LPWSTR wszUserName)
{
ISO_HEADER IsoHeader;
BYTE rgbDataIn [256];
UINT16 wStatusWord = 0;
TCOUNT cbDataIn = (TCOUNT) ((wcslen(wszUserName) + 1) * sizeof(WCHAR));
SCODE status = 0;
memset(&IsoHeader, 0, sizeof(IsoHeader));
memset(rgbDataIn, 0, sizeof(rgbDataIn));
// Setup the user name that we'll send to the card
memcpy(rgbDataIn, (PBYTE) wszUserName, cbDataIn);
// Setup the command
IsoHeader.CLA = PIN_RETRY_COUNTER_CLA;
IsoHeader.INS = PIN_RETRY_COUNTER_INS;
IsoHeader.P1 = PIN_RETRY_COUNTER_P1;
IsoHeader.P2 = PIN_RETRY_COUNTER_P2;
//
// Call the retry counter applet on the card
//
status = ScwExecute(
&IsoHeader,
rgbDataIn,
cbDataIn,
NULL,
NULL,
&wStatusWord);
if (SCW_S_OK == status)
{
// Reminder: Status words returned by this RTE app are in the form:
// 9000 -> Success
// 6Fyy -> An API failed with return code yy
// 6Ezz -> An exception was raised (zz is the err number)
switch (wStatusWord >> 8)
{
case 0x90:
wprintf(
L"Current pin attempts remaining for %s: %02X\n",
wszUserName,
(BYTE) wStatusWord);
break;
case 0x6F:
case 0x6E:
// Make it a 32 bits error code so the message can be retrieved from
// scwapi.dll
status = 0x80000000L | (BYTE) wStatusWord;
break;
default:
printf(
"ERROR: unexpected status word received from card, %04X\n",
wStatusWord);
status = (SCODE) SCARD_F_INTERNAL_ERROR;
break;
}
}
return status;
}
DWORD UpdateT1Atr(void)
{
SCODE status = 0;
DWORD cbFile = 0;
DWORD cbRead = 0;
BYTE rgbAtr [36];
HFILE hFile = 0;
BYTE rgbNewAtr [36];
/*
BYTE rgbNewAtr2 [] = {
0x11, 0x00,
0x9C, 0x13, 0x81, 0x31, 0x20, 0x55, 0x42,
0x61, 0x73, 0x65, 0x43, 0x53, 0x50, 0x2D, 0x54,
0x31, 0x2D, 0x31, 0x6B
};
*/
BYTE rgbNewAtr2 [] = {
0x11, 0x00,
0xDC, 0x13, 0x0A, 0x81, 0x31, 0x20, 0x55, 0x42,
0x61, 0x73, 0x65, 0x43, 0x53, 0x50, 0x2D, 0x54,
0x31, 0x2D, 0x31, 0x21
};
//
// Get the current ATR and display it
//
status = ScwCreateFile(
L"/T0",
NULL,
&hFile);
if (SCW_S_OK != status)
goto Ret;
status = ScwWriteFile32(
hFile, rgbNewAtr2, sizeof(rgbNewAtr2), &cbRead);
if (SCW_S_OK != status)
goto Ret;
/*
status = ScwGetFileLength(
hFile, (TOFFSET *) &cbFile);
if (SCW_S_OK != status)
goto Ret;
if (cbFile > sizeof(rgbAtr))
{
status = (SCODE) SCARD_F_INTERNAL_ERROR;
goto Ret;
}
status = ScwReadFile32(
hFile, rgbAtr, cbFile, &cbRead);
if (SCW_S_OK != status)
goto Ret;
if (cbFile != cbRead)
{
status = (SCODE) SCARD_W_EOF;
goto Ret;
}
PrintBytes(L"Current ATR", rgbAtr + 2, cbFile - 2);
if (rgbAtr[2] & 0x10)
{
printf("Upgrade not necessary\n");
goto Ret;
}
//
// Build the new high data rate T1 ATR, display it, and write
// it to the card.
//
rgbNewAtr[0] = rgbAtr[0];
rgbNewAtr[1] = rgbAtr[1];
rgbNewAtr[2] = rgbAtr[2] | 0x10;
rgbNewAtr[3] = 0x12;
memcpy(rgbNewAtr + 4, rgbAtr + 3, cbFile - 3);
rgbNewAtr[cbFile] ^= 0x02;
status = ScwSetFilePointer(hFile, 0, FILE_BEGIN);
if (SCW_S_OK != status)
goto Ret;
status = ScwWriteFile32(
hFile, rgbNewAtr, cbFile + 1, &cbRead);
if (SCW_S_OK != status)
goto Ret;
if (cbRead != cbFile + 1)
{
status = (SCODE) SCARD_W_EOF;
goto Ret;
}
PrintBytes(L"New ATR", rgbNewAtr + 2, cbRead - 2);
*/
Ret:
if (hFile)
ScwCloseFile(hFile);
return (DWORD) status;
}
void ShowHelp(void)
{
printf("wfscproto <options>\n");
printf(" Options:\n");
printf(" -a : Update the ATR for a T=1 card\n");
printf(" -g : Generate a new private key on the card\n");
printf(" -k [bits] : Key size in bits (default is 512)\n");
printf(" -c : Use Crypto API to generate key (default is to use rsa32.lib directly)\n");
printf(" -t : Use Crypto API to generate key with CRT parameters\n");
printf(" -e : Enumerate all directories and files on card\n");
printf(" -p : Pin change\n");
printf(" -u : Pin unblock\n");
printf(" -r : Query pin retry counter\n");
}
int __cdecl main(int argc, char* argv[])
{
SCODE status = 0;
BOOL fSuccess = FALSE;
HFILE hFile = 0;
BYTE rgb[65];
BYTE rgbData[1024];
BYTE rgbResult[1024];
DWORD cb = 0;
DWORD dw = 0;
UINT16 EnumState = 0;
WCHAR rgwsz[64];
PBYTE pb = NULL;
TCOUNT tcount = 0;
DWORD dwError = 0;
SCARDCONTEXT hSCardContext = 0;
SCARDHANDLE hSCardHandle = 0;
LPSTR mszReaders = NULL;
DWORD cchReaders = SCARD_AUTOALLOCATE;
DWORD dwActiveProtocol = 0;
BOOL fAuthenticatedUser = FALSE;
BOOL fAuthenticatedAdmin = FALSE;
BOOL fUseSimulator = FALSE;
BOOL fEnumFiles = FALSE;
BOOL fGenKey = FALSE;
DWORD dwState = 0;
BYTE rgbAtr [32];
DWORD cbAtr = sizeof(rgbAtr);
DWORD fUseCapi = FALSE;
DWORD cKeyBits = 512;
BOOL fShowHelp = FALSE;
BOOL fPinChange = FALSE;
BOOL fPinUnblock = FALSE;
BOOL fGetPinRetryCounter = FALSE;
BOOL fGenKeyCRT = FALSE;
BOOL fUpdateT1Atr = FALSE;
memset(rgbData, 0, sizeof(rgbData));
memset(rgbResult, 0, sizeof(rgbResult));
while (--argc>0)
{
if (**++argv == '-')
{
switch(argv[0][1])
{
case 'a':
fUpdateT1Atr = TRUE;
break;
case 'c':
fUseCapi = TRUE;
break;
case 'k':
--argc;
++argv;
cKeyBits = atoi(*argv);
break;
case 'g':
fGenKey = TRUE;
break;
case 'e':
fEnumFiles = TRUE;
break;
case 'p':
fPinChange = TRUE;
break;
case 'u':
fPinUnblock = TRUE;
break;
case 'r':
fGetPinRetryCounter = TRUE;
break;
case 't':
fGenKeyCRT = TRUE;
break;
case '?':
fShowHelp = TRUE;
goto Ret;
default:
fShowHelp = TRUE;
goto Ret;
}
}
else
goto Ret;
}
//
// Attach to the card
//
if (fUseSimulator)
{
// For connecting to the simulator
status = ScwAttachToCard(NULL_TX, wszTEST_CARD_NAME);
if (SC_FAILED(status))
goto Ret;
}
else
{
status = SCardEstablishContext(
SCARD_SCOPE_USER, NULL, NULL, &hSCardContext);
if (SC_FAILED(status))
goto Ret;
status = SCardListReadersA(
hSCardContext, NULL, (LPSTR) (&mszReaders), &cchReaders);
if (SC_FAILED(status) || NULL == mszReaders)
goto Ret;
status = SCardConnectA(
hSCardContext,
mszReaders,
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 | SCARD_PROTOCOL_DEFAULT,
&hSCardHandle,
&dwActiveProtocol);
if (SC_FAILED(status))
goto Ret;
if (mszReaders)
{
SCardFreeMemory(hSCardContext, mszReaders);
mszReaders = NULL;
}
cchReaders = SCARD_AUTOALLOCATE;
status = SCardStatusA(
hSCardHandle,
(LPSTR) (&mszReaders),
&cchReaders,
&dwState,
&dwActiveProtocol,
rgbAtr,
&cbAtr);
if (SC_FAILED(status))
goto Ret;
status = ScwAttachToCard(
hSCardHandle, NULL);
if (SC_FAILED(status))
goto Ret;
}
status = Authenticate(PRINCIPAL_USER);
if (SC_FAILED(status))
goto Ret;
fAuthenticatedUser = TRUE;
if (fUpdateT1Atr)
{
dwError = UpdateT1Atr();
if (ERROR_SUCCESS != dwError)
goto Ret;
}
//
// Enumerate all files
//
if (fEnumFiles)
{
status = (DWORD) EnumFilesInDirectory(L"", L"/");
if (SC_FAILED(status))
goto Ret;
}
//
// RSA Operation
//
if (fGenKey)
{
if (fUseSimulator)
{
dwError = SetupRsaKeyOnCardSimulator(
wszRSA_KEY_FILE, wszKEY_ACL_FILE, fUseSimulator);
if (ERROR_SUCCESS != dwError)
goto Ret;
}
else
{
printf(
"Using %s to generate %d bit key\n",
fUseCapi ? "Crypto API" : "rsa32.lib",
cKeyBits);
if (FALSE == fUseCapi)
dwError = GenKeyOnCardWithRsa32(
wszRSA_KEY_FILE, wszKEY_ACL_FILE, cKeyBits);
else
dwError = GenKeyOnCardWithCapi(
wszRSA_KEY_FILE, wszKEY_ACL_FILE, cKeyBits);
if (ERROR_SUCCESS != dwError)
goto Ret;
}
// Initialize
pb = rgb;
*pb++ = 0x00; // Tag
cb = (wcslen(wszRSA_KEY_FILE) + 1) * sizeof(WCHAR);
*pb++ = (BYTE) (1 + cb + 2);
// Length
// Number of following bytes:
// filename len, filename + NULL, key data offset
*pb++ = (BYTE) cb / sizeof(WCHAR); // Value
wcscpy((LPWSTR) pb, wszRSA_KEY_FILE);
pb += cb;
*(WORD*)pb = 0x0000;
status = ScwCryptoInitialize(
CM_RSA | CM_KEY_INFILE,
rgb);
if (SC_FAILED(status))
goto Ret;
// RSA Sign
memset(rgbData, 0, sizeof(rgbData));
for (dw = 0; dw < 16; dw++)
rgbData[dw] = (BYTE) dw;
PrintBytes(L"Plaintext", rgbData, 16);
tcount = (TCOUNT) (cKeyBits / 8);
status = ScwCryptoAction(
rgbData,
16,
rgbResult,
&tcount);
if (SC_FAILED(status))
goto Ret;
PrintBytes(L"Ciphertext", rgbResult, tcount);
}
if (fGenKeyCRT)
{
printf(
"Using Crypto API to generate %d bit key with CRT params\n",
cKeyBits);
dwError = GenKeyOnCardCRT(
wszRSA_KEY_FILE, wszKEY_ACL_FILE, cKeyBits);
if (ERROR_SUCCESS != dwError)
goto Ret;
// Initialize
pb = rgb;
*pb++ = 0x00; // Tag
cb = (wcslen(wszRSA_KEY_FILE) + 1) * sizeof(WCHAR);
*pb++ = (BYTE) (1 + cb + 2);
// Length
// Number of following bytes:
// filename len, filename + NULL, key data offset
*pb++ = (BYTE) cb / sizeof(WCHAR); // Value
wcscpy((LPWSTR) pb, wszRSA_KEY_FILE);
pb += cb;
*(WORD*)pb = 0x0000;
status = ScwCryptoInitialize(
CM_RSA_CRT | CM_KEY_INFILE,
rgb);
if (SC_FAILED(status))
goto Ret;
// RSA Sign
memset(rgbData, 0, sizeof(rgbData));
for (dw = 0; dw < 16; dw++)
rgbData[dw] = (BYTE) dw;
PrintBytes(L"Plaintext", rgbData, 16);
tcount = (TCOUNT) (cKeyBits / 8);
status = ScwCryptoAction(
rgbData,
16,
rgbResult,
&tcount);
if (SC_FAILED(status))
goto Ret;
PrintBytes(L"Ciphertext", rgbResult, tcount);
}
if (fPinChange)
{
//
// Test the on-card pin change applet
//
if (fAuthenticatedUser)
{
status = (DWORD) Deauthenticate(PRINCIPAL_USER);
if (SC_FAILED(status))
goto Ret;
fAuthenticatedUser = FALSE;
}
status = (DWORD) TestPinChange(
Principals[PRINCIPAL_USER].rgbPin,
sizeof(Principals[PRINCIPAL_USER].rgbPin),
rgbUserNewPin,
sizeof(rgbUserNewPin));
if (SC_FAILED(status))
goto Ret;
// Now change the pin back
status = (DWORD) TestPinChange(
rgbUserNewPin,
sizeof(rgbUserNewPin),
Principals[PRINCIPAL_USER].rgbPin,
sizeof(Principals[PRINCIPAL_USER].rgbPin));
if (SC_FAILED(status))
goto Ret;
}
if (fPinUnblock)
{
//
// Test the on-card pin unblock applet
//
// Need to authenticate the Admin first
if (fAuthenticatedUser)
{
status = (DWORD) Deauthenticate(PRINCIPAL_USER);
if (SC_FAILED(status))
goto Ret;
fAuthenticatedUser = FALSE;
}
status = (DWORD) Authenticate(PRINCIPAL_ADMIN);
if (SC_FAILED(status))
goto Ret;
fAuthenticatedAdmin = TRUE;
status = (DWORD) TestPinUnblock(
rgbUserNewPin,
sizeof(rgbUserNewPin));
if (SC_FAILED(status))
goto Ret;
// Now change the User pin back to its original value
status = (DWORD) Deauthenticate(PRINCIPAL_ADMIN);
if (SC_FAILED(status))
goto Ret;
fAuthenticatedAdmin = FALSE;
status = (DWORD) TestPinChange(
rgbUserNewPin,
sizeof(rgbUserNewPin),
Principals[PRINCIPAL_USER].rgbPin,
sizeof(Principals[PRINCIPAL_USER].rgbPin));
if (SC_FAILED(status))
goto Ret;
}
if (fGetPinRetryCounter)
{
//
// Test the on-card pin retry counter applet
//
status = (DWORD) TestPinRetryCounter(
Principals[PRINCIPAL_USER].pwszUser);
if (SC_FAILED(status))
goto Ret;
}
fSuccess = TRUE;
Ret:
if (! fSuccess)
{
if (fShowHelp)
ShowHelp();
else
printf("ERROR: 0x%x\n", status);
}
else
printf("Success\n");
if (fAuthenticatedAdmin)
Deauthenticate(PRINCIPAL_ADMIN);
if (fAuthenticatedUser)
Deauthenticate(PRINCIPAL_USER);
ScwDetachFromCard();
if (mszReaders)
status = SCardFreeMemory(hSCardContext, mszReaders);
if (hSCardHandle)
status = SCardDisconnect(hSCardHandle, SCARD_RESET_CARD);
if (hSCardContext)
status = SCardReleaseContext(hSCardContext);
return 0;
}