|
|
// CSmartCard.cpp: implementation of the CSmartCard class.
//
// (c) Copyright Schlumberger Technology Corp., unpublished work, created
// 2000. This computer program includes Confidential, Proprietary
// Information and is a Trade Secret of Schlumberger Technology Corp. All
// use, disclosure, and/or reproduction is prohibited unless authorized
// in writing. All Rights Reserved.
//////////////////////////////////////////////////////////////////////
#include "NoWarning.h"
#include <string>
#include <wtypes.h>
#include <scuOsExc.h>
#include <scuExcHelp.h>
#include <scuArrayP.h>
#include <scuSecureArray.h>
#include "iopExc.h"
#include "SmartCard.h"
#include "LockWrap.h"
using namespace std; using namespace scu;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////// Begin CSmartCard::Exception //////////////////////////
/////////////////////////// LOCAL/HELPER /////////////////////////////////
namespace { using namespace iop;
// Transfer data to/from the card. The data to read/write is
// broken up into cMaxBlock sized chunks when calling rsc's
// (CSmartCard) member procedure pbtm (pointer to member routine)
// to actually do the read/write.
template<class BlockType, class PBlockTransferMember> void TransferData(const WORD wOffset, // file offset to start
const WORD wDataLength, // amount to transfer
BlockType bData, // data buffer to read/write
CSmartCard &rsc, // card object to use
PBlockTransferMember pbtm, // member proc to read/write
WORD cMaxBlock) // max size transfer at once
{ WORD wBytesTransferred = 0; WORD wFullRounds = wDataLength / cMaxBlock;
/////////////////////////////////////////////////
// Transfer maximum bytes at each full round //
/////////////////////////////////////////////////
for (WORD wCurrentRound = 0; wCurrentRound < wFullRounds; wCurrentRound++) { (rsc.*pbtm)(wOffset + wBytesTransferred, bData + wBytesTransferred, cMaxBlock);
wBytesTransferred += cMaxBlock; }
// Transfer any leftovers
BYTE bBytesLeft = wDataLength - wBytesTransferred; if (bBytesLeft != 0) { (rsc.*pbtm)(wOffset + wBytesTransferred, bData + wBytesTransferred, bBytesLeft); } }
scu::CauseCodeDescriptionTable<CSmartCard::CauseCode> ccdt[] = { { CSmartCard::ccAccessConditionsNotMet, TEXT("Access conditions not met.") }, { CSmartCard::ccAlgorithmIdNotSupported, TEXT("The algorithm ID is not supported in the card.") }, { CSmartCard::ccAskRandomNotLastApdu, TEXT("The random number is no longer available. The " "AskRandom APDU must be sent immediately previous " "to this one.") }, { CSmartCard::ccAuthenticationFailed, TEXT("Authentication failed (i.e. CHV or key rejected, or " "wrong cryptogram).") }, { CSmartCard::ccBadFilePath, TEXT("The file path is invalid. Ensure that each file " "name in the path is 4 characters long and is a valid " "representation of the hexadecimal ID.") }, { CSmartCard::ccBadState, TEXT("The Application is not in a state permitting this " "operation.") }, { CSmartCard::ccCannotReadOutsideFileBoundaries, TEXT("Could not read outside the file boundaries.") }, { CSmartCard::ccCannotWriteOutsideFileBoundaries, TEXT("Could not write outside the file boundaries.") }, { CSmartCard::ccCardletNotInRegisteredState, TEXT("Cardlet is not in a registered state. It may be " "blocked or not completely installed.") }, { CSmartCard::ccChvNotInitialized, TEXT("No CHV is initialzed.") }, { CSmartCard::ccChvVerificationFailedMoreAttempts, TEXT("CHV verification was unsuccessful, at least one " "attempt remains.") }, { CSmartCard::ccContradictionWithInvalidationStatus, TEXT("Contradiction with invalidation status occured.") }, { CSmartCard::ccCurrentDirectoryIsNotSelected, TEXT("The current directory is not selected.") }, { CSmartCard::ccDataPossiblyCorrupted, TEXT("Data possibly corrupted.")
}, { CSmartCard::ccDefaultLoaderNotSelected, TEXT("Cardlet is currently selected and install cannot " "run. Default loader application must be selected.") }, { CSmartCard::ccDirectoryNotEmpty, TEXT("This directory still contains other files or " "directories and may not be deleted.") }, { CSmartCard::ccFileAlreadyInvalidated, TEXT("File already invalidated.") }, { CSmartCard::ccFileExists, TEXT("The file ID requested is already in use.") }, { CSmartCard::ccFileIdExistsOrTypeInconsistentOrRecordTooLong, TEXT("Either the file ID already exists in the current " "directory, the file type is inconsisent with the " "command or the record length is too long.") }, { CSmartCard::ccFileIndexDoesNotExist, TEXT("The file index passed does not exist in the current " "directory.") }, { CSmartCard::ccFileInvalidated, TEXT("The command attempted to operate on an invalidated " "file.") }, { CSmartCard::ccFileNotFound, TEXT("The file requested for this operation was not " "found.") }, { CSmartCard::ccFileNotFoundOrNoMoreFilesInDf, TEXT("The file specified was not found or no more files in " "the current DF.") }, { CSmartCard::ccFileTypeInvalid, TEXT("File type is invalid.") }, { CSmartCard::ccIncorrectP1P2, TEXT("Incorrect parameter P1 or P2.") }, { CSmartCard::ccIncorrectP3, TEXT("Incorrect P3.") }, { CSmartCard::ccInstallCannotRun, TEXT("Cardlet is currently selected and install cannot " "run. Default loader application must be selected.") }, { CSmartCard::ccInstanceIdInUse, TEXT("Instance ID is being used by another file.") }, { CSmartCard::ccInsufficientSpace, TEXT("Insufficient space available.") }, { CSmartCard::ccInvalidAnswerReceived, TEXT("Invalid answer received from the card.") }, { CSmartCard::ccInvalidKey, TEXT("CHV verification was unsuccessful; at least one " "attempt remains.") }, { CSmartCard::ccInvalidSignature, TEXT("Signature is invalid.") }, { CSmartCard::ccJava, TEXT("Applet exception occured.") }, { CSmartCard::ccKeyBlocked, TEXT("Key is blocked. No attempts remain.") }, { CSmartCard::ccLimitReached, TEXT("Limit has been reached. Additional value would " "exceed the record's limit.") }, { CSmartCard::ccMemoryProblem, TEXT("Memory problem occured.") }, { CSmartCard::ccNoAccess, TEXT("Access conditions not met.") }, { CSmartCard::ccNoEfSelected, TEXT("No elementary file selected.") }, { CSmartCard::ccNoEfExistsOrNoChvKeyDefined, TEXT("No EF exists, or no CHV or key defined.") }, { CSmartCard::ccNoFileSelected, TEXT("No elementary file selected.") }, { CSmartCard::ccNoGetChallengeBefore, TEXT("A Get Challenge was not performed before this " "operation.") }, { CSmartCard::ccOperationNotActivatedForApdu, TEXT("Algorithm is supported, but the operation is not " "activated for this APDU.") }, { CSmartCard::ccOutOfRangeOrRecordNotFound, TEXT("Out of range or record not found.") }, { CSmartCard::ccOutOfSpaceToCreateFile, TEXT("Not enough space is available to create the file.") }, { CSmartCard::ccProgramFileInvalidated, TEXT("Program file invalidated.") }, { CSmartCard::ccRecordInfoIncompatible, TEXT("Record information is incompatible with the file " "size.") }, { CSmartCard::ccRecordLengthTooLong, TEXT("Record length is too long.") }, { CSmartCard::ccRequestedAlgIdMayNotMatchKeyUse, TEXT("The requested algorithm ID may not match the key " "used.") }, { CSmartCard::ccReturnedDataCorrupted, TEXT("Data return from the card is corrupted.") }, { CSmartCard::ccRootDirectoryNotErasable, TEXT("It is not valid to delete the root directory.") }, { CSmartCard::ccTimeOut, TEXT("Time-out occured.") }, { CSmartCard::ccTooMuchDataForProMode, TEXT("Too much data for PRO mode.") }, { CSmartCard::ccUnknownInstructionClass, TEXT("Unknown instruction class.") }, { CSmartCard::ccUnknownInstructionCode, TEXT("Unknown instruction code.") }, { CSmartCard::ccUnknownStatus, TEXT("An unknown error status was returned from the " "card.") }, { CSmartCard::ccUnidentifiedTechnicalProblem, TEXT("Unidentified technical problem.") }, { CSmartCard::ccUpdateImpossible, TEXT("Update is impossible.") }, { CSmartCard::ccVerificationFailed, TEXT("Verification failed.") }, };
} // namespace
namespace iop {
/////////////////////////// PUBLIC /////////////////////////////////
// Types
// C'tors/D'tors
CSmartCard::Exception::Exception(CauseCode cc, ClassByte cb, Instruction ins, StatusWord sw) throw() : scu::Exception(scu::Exception::fcSmartCard), m_cc(cc), m_cb(cb), m_ins(ins), m_sw(sw) {}
CSmartCard::Exception::~Exception() {}
// Operators
// Operations
scu::Exception * CSmartCard::Exception::Clone() const { return new CSmartCard::Exception(*this); }
void CSmartCard::Exception::Raise() const { throw *this; }
// Access
CSmartCard::Exception::CauseCode CSmartCard::Exception::Cause() const throw() { return m_cc; }
CSmartCard::ClassByte CSmartCard::Exception::Class() const throw() { return m_cb; }
char const * CSmartCard::Exception::Description() const { return scu::FindDescription(Cause(), ccdt, sizeof ccdt / sizeof *ccdt); }
CSmartCard::Exception::ErrorCode CSmartCard::Exception::Error() const throw() { return m_cc; }
CSmartCard::Instruction CSmartCard::Exception::Ins() const throw() { return m_ins; }
CSmartCard::StatusWord CSmartCard::Exception::Status() const throw() { return m_sw; }
// Predicates
// Static Variables
/////////////////////////// PROTECTED /////////////////////////////////
// C'tors/D'tors
// Operators
// Operations
// Access
// Predicates
// Static Variables
/////////////////////////// PRIVATE /////////////////////////////////
// C'tors/D'tors
// Operators
// Operations
// Access
// Predicates
// Static Variables
///////////////////// End CSmartCard::Exception ///////////////////////////
CSmartCard::CSmartCard(const SCARDHANDLE hCardHandle, const char* szReaderName, const SCARDCONTEXT hContext, const DWORD dwMode) : m_hCard(hCardHandle), m_hContext(hContext), m_CurrentDirectory(), m_CurrentFile(), m_dwShareMode(dwMode), m_fSupportLogout(false), m_IOPLock(szReaderName), m_vecEvents(), m_dwEventCounter(0), m_cResponseAvailable(0), m_sCardName(), m_fDirty(false) { m_IOPLock.Init(this); ResetSelect(); }
CSmartCard::~CSmartCard() { try { while(m_vecEvents.size()) { delete *(m_vecEvents.begin()); m_vecEvents.erase(m_vecEvents.begin()); }
// Disconnect the card.
if (m_hCard) SCardDisconnect(m_hCard, SCARD_LEAVE_CARD); } catch(...) {}
}
void CSmartCard::ReConnect() {
DWORD dwProtocol;
HRESULT hr = SCardReconnect(m_hCard, m_dwShareMode, SCARD_PROTOCOL_T0, SCARD_LEAVE_CARD, &dwProtocol); if (hr != SCARD_S_SUCCESS) throw scu::OsException(hr);
}
void CSmartCard::ResetCard() { //*
CLockWrap wrap(&m_IOPLock);
ResetSelect();
HRESULT hResult;
hResult = SCardBeginTransaction(m_hCard);
// We don't apply full logic to handle error detection since
// this was done in the CLockWrap constructor.
if (hResult != SCARD_S_SUCCESS) throw scu::OsException(hResult);
hResult = SCardEndTransaction(m_hCard,SCARD_RESET_CARD); if (hResult != SCARD_S_SUCCESS) throw scu::OsException(hResult); //*/
}
char const * CSmartCard::getCardName() const { return m_sCardName.c_str(); }
void CSmartCard::setCardName(char const *szName) { m_sCardName = string(szName); }
void CSmartCard::SendCardAPDU(const BYTE bCLA, const BYTE bINS, const BYTE bP1, const BYTE bP2, const BYTE bLengthIn, const BYTE* bDataIn, const BYTE bLengthOut, BYTE* bDataOut) { CLockWrap wrap(&m_IOPLock); HRESULT hResult; DWORD dwRecvLength; SecureArray<BYTE> bSW(2); StatusWord sw;
//////////////////
// Build APDU //
//////////////////
SecureArray<BYTE> aabInput(5 + bLengthIn); SecureArray<BYTE> aabOutput;
aabInput[0] = bCLA; aabInput[1] = bINS; aabInput[2] = bP1; aabInput[3] = bP2; aabInput[4] = bLengthIn;
///////////////////////////
// Is data being sent? //
///////////////////////////
if (bLengthIn) { memcpy(&aabInput[5], bDataIn, bLengthIn); dwRecvLength = bSW.size();
hResult = SCardTransmit(m_hCard, SCARD_PCI_T0, aabInput.data(), aabInput.size(), NULL, bSW.data(), &dwRecvLength);
if (hResult != SCARD_S_SUCCESS) { DWORD dwState; DWORD dwProtocol; SecureArray<BYTE> bATR(cMaxAtrLength); DWORD dwATRLen = bATR.size(); DWORD dwReaderNameLen = 0;
HRESULT hr = SCardStatus(m_hCard, NULL, &dwReaderNameLen, &dwState, &dwProtocol, bATR.data(), &dwATRLen); if (hr == SCARD_W_RESET_CARD) { ResetSelect(); ReConnect(); } else throw scu::OsException(hr);
hr=SCardTransmit(m_hCard, SCARD_PCI_T0, aabInput.data(), aabInput.size(), NULL, bSW.data(), &dwRecvLength); if (hr != SCARD_S_SUCCESS) throw scu::OsException(hr); }
//////////////////////////////////////////////////////////////////////////////////
// Rebuffer information so registered functions may not alter data in the IOP //
//////////////////////////////////////////////////////////////////////////////////
SecureArray<BYTE> aabSendData(aabInput);
SecureArray<BYTE> bReceiveData(bSW);
///////////////////////////////////////
// Fire event for information sent //
///////////////////////////////////////
FireEvents(0, aabSendData.size(), aabSendData.data()); FireEvents(1, bReceiveData.size(), bReceiveData.data());
sw = (bSW[0] * 256) + bSW[1];
ProcessReturnStatus(bCLA, bINS, sw);
//////////////////////////////////
// Should we expect data back? //
//////////////////////////////////
if (bLengthOut) { if (ResponseLengthAvailable()) GetResponse(bCLA, bLengthOut, bDataOut); else throw iop::Exception(iop::ccNoResponseAvailable); } } //////////////////////////////
// Data is NOT being sent //
//////////////////////////////
else { aabInput[4] = bLengthOut; dwRecvLength = bLengthOut + 2; aabOutput = SecureArray<BYTE>(dwRecvLength); aabOutput = 0; // zero out the data buffer
hResult = SCardTransmit(m_hCard, SCARD_PCI_T0, aabInput.data(), 5, NULL, aabOutput.data(), &dwRecvLength);
/////////////////////////////////////////////
// if card has been reset, then reconnect //
/////////////////////////////////////////////
if (hResult != SCARD_S_SUCCESS) { DWORD dwState; DWORD dwProtocol; SecureArray<BYTE> bATR(cMaxAtrLength); DWORD dwATRLen = bATR.size(); DWORD dwReaderNameLen = 0;
HRESULT hr = SCardStatus(m_hCard, NULL, &dwReaderNameLen, &dwState, &dwProtocol, bATR.data(), &dwATRLen); if (hr == SCARD_W_RESET_CARD) { ResetSelect(); ReConnect(); } else throw scu::OsException(hResult);
hr=SCardTransmit(m_hCard, SCARD_PCI_T0, aabInput.data(), 5, NULL, aabOutput.data(), &dwRecvLength); if (hr != SCARD_S_SUCCESS) throw scu::OsException(hResult);
} //////////////////////////////////////////////////////////////////////////////////
// Rebuffer information so registered functions may not alter data in the IOP //
//////////////////////////////////////////////////////////////////////////////////
SecureArray<BYTE> bSendData(aabInput.data(),5); SecureArray<BYTE> aabReceiveData(aabOutput.data(),dwRecvLength);
////////////////////////////////////////////////////
// Fire event for information sent and received //
////////////////////////////////////////////////////
FireEvents(0, bSendData.size(), bSendData.data()); FireEvents(1, aabReceiveData.size(), aabReceiveData.data());
sw = (aabOutput[dwRecvLength - 2] * 256) + aabOutput[dwRecvLength - 1];
ProcessReturnStatus(bCLA, bINS, sw);
memcpy(bDataOut, aabOutput.data(), bLengthOut); } }
void CSmartCard::RequireSelect() { if ((m_CurrentDirectory.IsEmpty()) || (m_CurrentFile.IsEmpty())) throw iop::Exception(iop::ccNoFileSelected); }
void CSmartCard::GetResponse(ClassByte cb, BYTE bDataLength, BYTE *bDataOut) { // TO DO: lock redundant??? Wouldn't GetResponse always be called
// by a routine that establishes a lock?
CLockWrap wrap(&m_IOPLock);
if (0 == ResponseLengthAvailable()) throw iop::Exception(iop::ccNoResponseAvailable);
struct Command // T=0 command bytes
{ ClassByte m_cb; Instruction m_ins; BYTE m_bP1; BYTE m_bP2; BYTE m_bP3; } cmnd = { cb, insGetResponse, 0x00, 0x00, bDataLength }; DWORD dwRecvLength = bDataLength + sizeof StatusWord; BYTE bOutput[cMaxGetResponseLength];
memset(bOutput, 0, sizeof bOutput);
HRESULT hr = SCardTransmit(m_hCard, SCARD_PCI_T0, reinterpret_cast<LPCBYTE>(&cmnd), sizeof cmnd, NULL, bOutput, &dwRecvLength);
if (hr != SCARD_S_SUCCESS) throw scu::OsException(hr);
//////////////////////////////////////////////////////////////////////////////////
// Rebuffer information so registered functions may not alter data in the IOP //
//////////////////////////////////////////////////////////////////////////////////
BYTE bSendData[sizeof cmnd]; memcpy(static_cast<void *>(bSendData), static_cast<void const *>(&cmnd), sizeof cmnd); scu::AutoArrayPtr<BYTE> aabReceiveData(new BYTE[dwRecvLength/*bDataLength + 2*/]); memcpy((void*)aabReceiveData.Get(), (void*)bOutput, dwRecvLength/*bDataLength + 2*/);
////////////////////////////////////////////////////
// Fire event for information sent and received //
////////////////////////////////////////////////////
FireEvents(0, sizeof bSendData, bSendData); FireEvents(1, dwRecvLength/*bDataLength + 2*/, aabReceiveData.Get());
//////////////////////////////////////////////////////////
// Set card's status code and map to IOP status codes //
//////////////////////////////////////////////////////////
StatusWord sw = (bOutput[dwRecvLength - sizeof StatusWord]*256) + bOutput[dwRecvLength - (sizeof StatusWord - 1)];
ProcessReturnStatus(cb, insGetResponse, sw);
memcpy(bDataOut, bOutput, bDataLength); }
void CSmartCard::ReadBinary(const WORD wOffset, const WORD wDataLength, BYTE* bData) { CLockWrap wrap(&m_IOPLock);
TransferData(wOffset, wDataLength, bData, *this, &CSmartCard::DoReadBlock, cMaxRwDataBlock);
}
void CSmartCard::WriteBinary(const WORD wOffset, const WORD wDataLength, const BYTE* bData) { CLockWrap wrap(&m_IOPLock);
Dirty(true); //m_apSharedMarker->UpdateMarker(CMarker::WriteMarker);
TransferData(wOffset, wDataLength, bData, *this, &CSmartCard::DoWriteBlock, cMaxRwDataBlock);
}
void CSmartCard::ResetSelect() { m_CurrentDirectory.Clear(); m_CurrentFile.Clear(); }
void CSmartCard::GetCurrentDir(char* CurrentDirectory) { if (!m_CurrentDirectory.IsEmpty()) strcpy(CurrentDirectory,m_CurrentDirectory.GetStringPath().c_str()); else throw iop::Exception(ccInvalidParameter); }
void CSmartCard::GetCurrentFile(char* CurrentFile) { if (!m_CurrentFile.IsEmpty()) strcpy(CurrentFile,m_CurrentFile.GetStringPath().c_str()); else throw iop::Exception(ccInvalidParameter); }
DWORD CSmartCard::RegisterEvent(void (*FireEvent)(void *pToCard, int iEventCode, DWORD dwLen, BYTE* bData), void *pToCard) { EventInfo *Event = new EventInfo; Event->dwHandle = ++m_dwEventCounter; Event->FireEvent = FireEvent; Event->pToCard = pToCard;
m_vecEvents.push_back(Event);
return m_dwEventCounter; }
bool CSmartCard::UnregisterEvent(DWORD dwHandle) { vector<EventInfo*>::iterator iter;
for(iter = m_vecEvents.begin(); iter != m_vecEvents.end(); iter++) { if ((*iter)->dwHandle == dwHandle) break; }
if (iter == m_vecEvents.end()) return false;
delete (*iter); m_vecEvents.erase(iter);
return true; }
bool CSmartCard::HasProperty(WORD wPropNumber) { if (wPropNumber > 512) return false;
////////////////////////////////////
// Open path to registered keys //
////////////////////////////////////
HKEY hkCardKey; HKEY hkTestKey; char szCardPath[] = "SOFTWARE\\Schlumberger\\Smart Cards and Terminals\\Smart Cards";
RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCardPath, NULL, KEY_READ, &hkCardKey);
//////////////////////////////////////////////
// Enumerate subkeys to find an ATR match //
//////////////////////////////////////////////
FILETIME fileTime; char szATR[] = "ATR"; char szMask[] = "ATR Mask"; char szProperties[] = "Properties"; char sBuffer[1024]; BYTE bATR[cMaxAtrLength]; BYTE bATRtest[cMaxAtrLength]; BYTE bMask[cMaxAtrLength]; BYTE bProperties[512]; BYTE bATRLength = sizeof bATR / sizeof *bATR; DWORD dwBufferSize = sizeof(sBuffer); DWORD dwATRSize = sizeof bATR / sizeof *bATR; DWORD dwMaskSize = sizeof bMask / sizeof *bMask; DWORD dwPropSize = sizeof(bProperties); DWORD index = 0;
getATR(bATR, bATRLength);
LONG iRetVal = RegEnumKeyEx(hkCardKey, index, sBuffer, &dwBufferSize, NULL, NULL, NULL, &fileTime); while (iRetVal == ERROR_SUCCESS) { RegOpenKeyEx(hkCardKey, sBuffer, NULL, KEY_READ, &hkTestKey);
RegQueryValueEx(hkTestKey, szATR, NULL, NULL, bATRtest, &dwATRSize); RegQueryValueEx(hkTestKey, szMask, NULL, NULL, bMask, &dwMaskSize);
if (dwATRSize == bATRLength) { scu::AutoArrayPtr<BYTE> aabMaskedATR(new BYTE[dwATRSize]); for (DWORD count = 0; count < dwATRSize; count++) aabMaskedATR[count] = bATR[count] & bMask[count];
if (!memcmp(aabMaskedATR.Get(), bATRtest, dwATRSize)) break; }
index++; dwBufferSize = sizeof(sBuffer); dwATRSize = cMaxAtrLength; dwMaskSize = cMaxAtrLength; RegCloseKey(hkTestKey); iRetVal = RegEnumKeyEx(hkCardKey, index, sBuffer, &dwBufferSize, NULL, NULL, NULL, &fileTime); }
// if loop was broken, iRetVal is still ERROR_SUCCESS, and type holds correct card to use
if (iRetVal == ERROR_SUCCESS) { RegQueryValueEx(hkTestKey, szProperties, NULL, NULL, bProperties, &dwPropSize);
return (bProperties[(wPropNumber - 1) / 8] & (1 << ((wPropNumber - 1) % 8))) ? true : false; } // loop wasn't broken, i.e., ATR not found
else return false; }
void CSmartCard::getATR(BYTE* bATR, BYTE& iATRLength) { DWORD dwProtocol; LPDWORD pcchReaderLen = 0; DWORD dwState; BYTE bMyATR[cMaxAtrLength]; DWORD dwAtrLen = sizeof bMyATR / sizeof *bMyATR;
HRESULT hr = SCardStatus(m_hCard, NULL, pcchReaderLen, &dwState, &dwProtocol, bMyATR, &dwAtrLen);
if (hr == SCARD_W_RESET_CARD) { ResetSelect(); ReConnect(); hr = SCardStatus(m_hCard, NULL, pcchReaderLen, &dwState, &dwProtocol, bMyATR, &dwAtrLen); } if (hr != SCARD_S_SUCCESS) throw scu::OsException(hr);
if ((BYTE)dwAtrLen > iATRLength) throw iop::Exception(ccInvalidParameter);
memcpy(bATR, bMyATR, dwAtrLen); iATRLength = (BYTE)dwAtrLen; }
void CSmartCard::FireEvents(int iEventCode, DWORD dwLength, BYTE *bsData) { vector<EventInfo*>::iterator iter;
for (iter = m_vecEvents.begin(); iter != m_vecEvents.end(); iter++) { EventInfo* pEvent = *iter;
pEvent->FireEvent(pEvent->pToCard, iEventCode, dwLength, bsData); } }
BYTE CSmartCard::FormatPath(char *szOutputPath, const char *szInputPath) { bool fResult = true; BYTE bIndex = 0; BYTE bFileCount = 1; // always allocate memory for at least 1 token
BYTE bFileIDLength = 0; BYTE bPathLength = strlen(szInputPath); WORD wFileHexID; char szPad[] = "0"; char *cTestChar; char *szHexID;
//////////////////////////////////////////////
// Count number of tokens in desired path //
//////////////////////////////////////////////
for (bIndex = 0; bIndex < bPathLength - 1; bIndex++) { if (szInputPath[bIndex] == '/' && szInputPath[bIndex + 1] != '/') bFileCount++; }
// Check path size
if (bFileCount * 5 + 1 > cMaxPathLength) throw iop::Exception(iop::ccFilePathTooLong);
scu::AutoArrayPtr<char> aaszPathIn(new char[bPathLength + 1]); memset((void*)aaszPathIn.Get(), 0, bPathLength + 1); memset((void*)szOutputPath, 0, bFileCount * 5 + 1); strcpy(aaszPathIn.Get(), szInputPath);
iop::CauseCode cc; szHexID = strtok(aaszPathIn.Get(), "/"); for (bFileCount = 0; szHexID; bFileCount++, szHexID = strtok(NULL, "/")) { /////////////////////////////////////////////////////////
// File ID is too large -- greater than 4 characters //
/////////////////////////////////////////////////////////
if (strlen(szHexID) > 4) { fResult = false; cc = iop::ccFileIdTooLarge; break; }
wFileHexID = (WORD)strtoul(szHexID, &cTestChar, 16); /////////////////////////////////////////////////////
// File ID was not in hexadecimal representation //
/////////////////////////////////////////////////////
if (*cTestChar != NULL) { fResult = false; cc = iop::ccFileIdNotHex; break; }
szOutputPath[bFileCount * 5] = '/'; /////////////////////////////////////////////////////////////////
// Pad file ID and put formatted file ID into formatted path //
/////////////////////////////////////////////////////////////////
for (bFileIDLength = strlen(szHexID); bFileIDLength < 4; bFileIDLength++) strcat((szOutputPath + (bFileCount * 5) + (4 - bFileIDLength)), szPad);
strcpy((szOutputPath + (bFileCount * 5) + (5 - strlen(szHexID))), szHexID); }
///////////////////////////////////////////
// If file ID formatting fails, throw //
///////////////////////////////////////////
if (!fResult) { // delete [] szOutputPath; // Can not mean to delete this???? HB.
throw iop::Exception(cc); }
_strupr(szOutputPath);
return bFileCount; }
void CSmartCard::GetState(DWORD &rdwState, DWORD &rdwProtocol) { BYTE bATR[cMaxAtrLength]; DWORD dwATRLen = sizeof bATR / sizeof *bATR; DWORD dwReaderNameLen = 0;
HRESULT hr = SCardStatus(m_hCard, 0, &dwReaderNameLen, &rdwState, &rdwProtocol, bATR, &dwATRLen);
if (SCARD_W_RESET_CARD == hr) { ResetSelect(); ReConnect();
// try again...
hr = SCardStatus(m_hCard, 0, &dwReaderNameLen, &rdwState, &rdwProtocol, bATR, &dwATRLen); }
if (SCARD_S_SUCCESS != hr) throw scu::OsException(hr); }
void CSmartCard::DefaultDispatchError(ClassByte cb, Instruction ins, StatusWord sw) const { CauseCode cc; bool fDoThrow = true;
switch (sw) { case 0x6283: cc = ccFileInvalidated; break;
case 0x6581: cc = ccMemoryProblem; break;
case 0x6982: cc = ccNoAccess; break;
case 0x6983: cc = ccKeyBlocked; break;
case 0x6A80: cc = ccFileTypeInvalid; break;
case 0x6A82: cc = ccFileNotFound; break;
case 0x6A84: cc = ccInsufficientSpace; break;
case 0x6B00: cc = ccIncorrectP1P2; break;
case 0x6D00: cc = ccUnknownInstructionCode; break;
case 0x6E00: cc = ccUnknownInstructionClass; break;
case 0x6F00: cc = ccUnidentifiedTechnicalProblem; break;
case 0x90FF: cc = ccTimeOut; break;
case 0x9002: cc = ccInvalidAnswerReceived; break;
default: if (0x67 == HIBYTE(sw)) cc = ccIncorrectP3; else cc = ccUnknownStatus; break; }
if (fDoThrow) throw Exception(cc, cb, ins, sw); }
void CSmartCard::DispatchError(ClassByte cb, Instruction ins, StatusWord sw) const { CauseCode cc; bool fDoThrow = true;
switch (ins) { case insGetResponse: switch (sw) { case 0x6281: cc = ccReturnedDataCorrupted; break;
case 0x6A86: cc = ccIncorrectP1P2; break;
default: if (0x6C == HIBYTE(sw)) cc = ccIncorrectP3; else fDoThrow = false; break; }
default: fDoThrow = false; break; }
if (fDoThrow) throw Exception(cc, cb, ins, sw);
DefaultDispatchError(cb, ins, sw); }
BYTE CSmartCard::ResponseLengthAvailable() const { return m_cResponseAvailable; }
void CSmartCard::ResponseLengthAvailable(BYTE cResponseLength) { m_cResponseAvailable = cResponseLength; }
void CSmartCard::WriteBlock(WORD wOffset, BYTE const *pbBuffer, BYTE cLength) { DoWriteBlock(wOffset, pbBuffer, cLength);
Dirty(true); //m_apSharedMarker->UpdateMarker(CMarker::WriteMarker);
}
void CSmartCard::ProcessReturnStatus(ClassByte cb, Instruction ins, StatusWord sw) { ResponseLengthAvailable(0); if (swSuccess != sw) { if (0x61 == HIBYTE(sw)) ResponseLengthAvailable(LOBYTE(sw)); else DispatchError(cb, ins, sw); } }
bool CSmartCard::Dirty() const { return m_fDirty; }
void CSmartCard::Dirty(bool fDirty) { m_fDirty = fDirty; }
} // namespace iop
|