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