mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2025-11-11 19:08:26 -06:00
682 lines
16 KiB
C++
682 lines
16 KiB
C++
#include "SCardReader.h"
|
|
#include "PCSCException.h"
|
|
|
|
#include <locale>
|
|
|
|
using namespace std;
|
|
|
|
namespace VeraCrypt
|
|
{
|
|
void SCardReader::Init(const wstring& szSCReaderName, const shared_ptr<SCardLoader> scardLoader, const SCARDHANDLE& hCard, const DWORD& dwProtocol, LPCSCARD_IO_REQUEST pIO_Protocol)
|
|
{
|
|
m_szSCReaderName = szSCReaderName;
|
|
if (scardLoader)
|
|
{
|
|
m_scardLoader = scardLoader;
|
|
m_hSCReaderContext = m_scardLoader->GetSCardContext();
|
|
}
|
|
else
|
|
{
|
|
m_scardLoader = NULL;
|
|
m_hSCReaderContext = 0;
|
|
}
|
|
m_hCard = hCard;
|
|
m_dwProtocol = dwProtocol;
|
|
m_pIO_Protocol = pIO_Protocol;
|
|
}
|
|
|
|
SCardReader::SCardReader(const wstring &szName, const shared_ptr<SCardLoader> scardLoader)
|
|
{
|
|
Init(szName, scardLoader, 0, 0, NULL);
|
|
}
|
|
|
|
SCardReader::SCardReader(const SCardReader& other)
|
|
: m_szSCReaderName(other.m_szSCReaderName),
|
|
m_scardLoader(other.m_scardLoader),
|
|
m_hSCReaderContext(other.m_hSCReaderContext),
|
|
m_hCard(other.m_hCard),
|
|
m_dwProtocol(other.m_dwProtocol),
|
|
m_pIO_Protocol(other.m_pIO_Protocol)
|
|
{
|
|
}
|
|
|
|
SCardReader::SCardReader(SCardReader&& other)
|
|
: m_szSCReaderName(other.m_szSCReaderName),
|
|
m_scardLoader(other.m_scardLoader),
|
|
m_hSCReaderContext(other.m_hSCReaderContext),
|
|
m_hCard(other.m_hCard),
|
|
m_dwProtocol(other.m_dwProtocol),
|
|
m_pIO_Protocol(other.m_pIO_Protocol)
|
|
{
|
|
other.Clear();
|
|
}
|
|
|
|
SCardReader& SCardReader::operator=(const SCardReader& other)
|
|
{
|
|
if (this != &other)
|
|
{
|
|
m_szSCReaderName = other.m_szSCReaderName;
|
|
m_scardLoader = other.m_scardLoader;
|
|
m_hSCReaderContext = other.m_hSCReaderContext;
|
|
m_hCard = other.m_hCard;
|
|
m_dwProtocol = other.m_dwProtocol;
|
|
m_pIO_Protocol = other.m_pIO_Protocol;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
SCardReader& SCardReader::operator=(SCardReader&& other)
|
|
{
|
|
if (this != &other)
|
|
{
|
|
m_szSCReaderName = other.m_szSCReaderName;
|
|
m_scardLoader = other.m_scardLoader;
|
|
m_hSCReaderContext = other.m_hSCReaderContext;
|
|
m_hCard = other.m_hCard;
|
|
m_dwProtocol = other.m_dwProtocol;
|
|
m_pIO_Protocol = other.m_pIO_Protocol;
|
|
|
|
other.Clear();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void SCardReader::Clear(void)
|
|
{
|
|
m_szSCReaderName = L"";
|
|
m_scardLoader = NULL;
|
|
m_hSCReaderContext = 0;
|
|
m_hCard = 0;
|
|
m_dwProtocol = 0;
|
|
m_pIO_Protocol = NULL;
|
|
}
|
|
|
|
SCardReader::~SCardReader()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
const wstring SCardReader::GetNameWide() const
|
|
{
|
|
return m_szSCReaderName;
|
|
}
|
|
|
|
const string SCardReader::GetName() const
|
|
{
|
|
string name = "";
|
|
size_t size = wcstombs(NULL, m_szSCReaderName.c_str(), 0) + 1;
|
|
if (size)
|
|
{
|
|
name.resize(size);
|
|
size = wcstombs(&name[0], m_szSCReaderName.c_str(), size);
|
|
if (size)
|
|
{
|
|
name.resize(size);
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
|
|
bool SCardReader::IsCardPresent(vector<byte>& cardAtr)
|
|
{
|
|
LONG lRet = SCARD_S_SUCCESS;
|
|
SCARD_READERSTATE state;
|
|
bool bIsCardPresent = false;
|
|
#ifdef TC_WINDOWS
|
|
wstring readerName = GetNameWide();
|
|
#else
|
|
string readerName = GetName();
|
|
#endif
|
|
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
cardAtr.clear();
|
|
burn(&state, sizeof(SCARD_READERSTATE));
|
|
state.szReader = readerName.c_str();
|
|
|
|
lRet = m_scardLoader->SCardIsValidContext(m_hSCReaderContext);
|
|
if (SCARD_S_SUCCESS != lRet)
|
|
{
|
|
m_scardLoader->SCardReleaseContext(m_hSCReaderContext);
|
|
lRet = m_scardLoader->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &m_hSCReaderContext);
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
throw PCSCException(lRet);
|
|
}
|
|
|
|
lRet = m_scardLoader->SCardGetStatusChange(m_hSCReaderContext, 0, &state, 1);
|
|
if (lRet == SCARD_S_SUCCESS)
|
|
{
|
|
if ((state.dwEventState & SCARD_STATE_PRESENT) == SCARD_STATE_PRESENT && (state.dwEventState & SCARD_STATE_MUTE) == 0)
|
|
{
|
|
cardAtr.resize(state.cbAtr, 0);
|
|
memcpy(cardAtr.data(), state.rgbAtr, state.cbAtr);
|
|
bIsCardPresent = true;
|
|
burn(&state, sizeof(SCARD_READERSTATE));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw PCSCException(lRet);
|
|
}
|
|
|
|
return bIsCardPresent;
|
|
}
|
|
|
|
bool SCardReader::IsCardPresent()
|
|
{
|
|
vector<byte> dummy;
|
|
return IsCardPresent(dummy);
|
|
}
|
|
|
|
LONG SCardReader::CardHandleStatus()
|
|
{
|
|
LONG lRet = SCARD_E_INVALID_HANDLE;
|
|
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
if (m_hCard != 0)
|
|
{
|
|
#ifdef TC_WINDOWS
|
|
wchar_t
|
|
#else
|
|
char
|
|
#endif
|
|
szName[TC_MAX_PATH] = {};
|
|
BYTE pbAtr[36] = {};
|
|
DWORD dwState, dwProtocol, dwNameLen = TC_MAX_PATH, dwAtrLen = 36;
|
|
lRet = m_scardLoader->SCardStatus(m_hCard, szName, &dwNameLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen);
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
void SCardReader::Connect(DWORD dwProtocolToUse, bool& bHasBeenReset, bool resetAfterConnect)
|
|
{
|
|
LONG lRet = SCARD_S_SUCCESS;
|
|
bHasBeenReset = false;
|
|
#ifdef TC_WINDOWS
|
|
wstring readerName = GetNameWide();
|
|
#else
|
|
string readerName = GetName();
|
|
#endif
|
|
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
lRet = m_scardLoader->SCardIsValidContext(m_hSCReaderContext);
|
|
if (SCARD_S_SUCCESS != lRet)
|
|
{
|
|
m_scardLoader->SCardReleaseContext(m_hSCReaderContext);
|
|
lRet = m_scardLoader->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &m_hSCReaderContext);
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
throw PCSCException(lRet);
|
|
}
|
|
|
|
if (m_hCard != 0)
|
|
{
|
|
lRet = CardHandleStatus();
|
|
if (lRet == SCARD_W_RESET_CARD)
|
|
{
|
|
bHasBeenReset = true;
|
|
lRet = m_scardLoader->SCardReconnect(
|
|
m_hCard,
|
|
SCARD_SHARE_SHARED,
|
|
dwProtocolToUse,
|
|
SCARD_LEAVE_CARD,
|
|
&m_dwProtocol);
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
else if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
// Card handle is invalid, disconnect and reconnect.
|
|
Disconnect();
|
|
}
|
|
}
|
|
|
|
if (m_hCard == 0)
|
|
{
|
|
lRet = m_scardLoader->SCardConnect(
|
|
m_hSCReaderContext,
|
|
readerName.c_str(),
|
|
SCARD_SHARE_SHARED,
|
|
dwProtocolToUse,
|
|
&m_hCard,
|
|
&m_dwProtocol);
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
|
|
if (m_pIO_Protocol == NULL)
|
|
{
|
|
if (m_dwProtocol == SCARD_PROTOCOL_T0)
|
|
{
|
|
m_pIO_Protocol = m_scardLoader->scardT0Pci;
|
|
}
|
|
else if (m_dwProtocol == SCARD_PROTOCOL_T1)
|
|
{
|
|
m_pIO_Protocol = m_scardLoader->scardT1Pci;
|
|
}
|
|
else if (m_dwProtocol == SCARD_PROTOCOL_RAW)
|
|
{
|
|
m_pIO_Protocol = m_scardLoader->scardRawPci;
|
|
}
|
|
else
|
|
{
|
|
lRet = SCARD_E_INVALID_PARAMETER;
|
|
Disconnect();
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
|
|
if (resetAfterConnect)
|
|
{
|
|
lRet = m_scardLoader->SCardReconnect(
|
|
m_hCard,
|
|
SCARD_SHARE_SHARED,
|
|
m_dwProtocol,
|
|
SCARD_RESET_CARD,
|
|
&m_dwProtocol);
|
|
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
Disconnect();
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SCardReader::IsConnected()
|
|
{
|
|
return m_hCard != 0;
|
|
}
|
|
|
|
void SCardReader::Disconnect() const
|
|
{
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
if (m_hCard != 0)
|
|
{
|
|
m_scardLoader->SCardDisconnect(m_hCard, SCARD_LEAVE_CARD);
|
|
m_dwProtocol = 0;
|
|
m_hCard = 0;
|
|
m_pIO_Protocol = NULL;
|
|
}
|
|
}
|
|
|
|
LONG SCardReader::SendAPDU(LPCBYTE pbSendBuffer, DWORD cbSendLength, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength, uint16& SW) const
|
|
{
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
LONG lRet = m_scardLoader->SCardTransmit(m_hCard, m_pIO_Protocol, pbSendBuffer, cbSendLength, NULL, pbRecvBuffer, pcbRecvLength);
|
|
|
|
if (SCARD_S_SUCCESS == lRet)
|
|
{
|
|
if (*pcbRecvLength < 2) // must be at least = 2 (SW)
|
|
{
|
|
lRet = SCARD_E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
SW = (pbRecvBuffer[*pcbRecvLength - 2] << 8) | pbRecvBuffer[*pcbRecvLength - 1];
|
|
*pcbRecvLength -= 2;
|
|
}
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
void SCardReader::BeginTransaction()
|
|
{
|
|
LONG lRet = 0;
|
|
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
if (m_hCard != 0)
|
|
{
|
|
#ifndef _DEBUG
|
|
lRet = m_scardLoader->SCardBeginTransaction(m_hCard);
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
throw PCSCException(lRet);
|
|
}
|
|
#else
|
|
lRet = SCARD_S_SUCCESS;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
lRet = SCARD_E_INVALID_HANDLE;
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
|
|
void SCardReader::EndTransaction()
|
|
{
|
|
LONG lRet = 0;
|
|
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
if (m_hCard != 0)
|
|
{
|
|
#ifndef _DEBUG
|
|
lRet = m_scardLoader->SCardEndTransaction(m_hCard, SCARD_LEAVE_CARD);
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
throw PCSCException(lRet);
|
|
}
|
|
#endif
|
|
lRet = SCARD_S_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
lRet = SCARD_E_INVALID_HANDLE;
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
|
|
void SCardReader::ApduProcessData(CommandAPDU commandAPDU, ResponseAPDU& responseAPDU) const
|
|
{
|
|
LONG lRet = 0;
|
|
uint16 SW = 0;
|
|
|
|
uint32 nc = 0, ne = 0;
|
|
|
|
bool expectingResponse = false;
|
|
bool useExtendedAPDU = false;
|
|
|
|
size_t indexOfLe = 0;
|
|
size_t indexOfLcData = 0;
|
|
|
|
vector<byte> pbSendBuffer;
|
|
vector<byte> pbRecvBuffer;
|
|
DWORD cbSendLength = 0;
|
|
DWORD cbRecvLength = 0;
|
|
|
|
responseAPDU.clear();
|
|
|
|
if (!commandAPDU.isValid())
|
|
{
|
|
throw CommandAPDUNotValid(SRC_POS, commandAPDU.getErrorStr());
|
|
}
|
|
|
|
// See whether the CommandAPDU is extended or not
|
|
useExtendedAPDU = commandAPDU.isExtended();
|
|
|
|
// If T != 1, cannot use Extended-APDU
|
|
if (m_dwProtocol != SCARD_PROTOCOL_T1 && useExtendedAPDU)
|
|
{
|
|
throw ExtendedAPDUNotSupported();
|
|
}
|
|
|
|
// Set some needed vars
|
|
nc = commandAPDU.getNc();
|
|
ne = commandAPDU.getNe();
|
|
pbSendBuffer.resize(useExtendedAPDU ? extendedAPDUMaxSendSize : shortAPDUMaxSendSize, 0);
|
|
pbRecvBuffer.resize(useExtendedAPDU ? extendedAPDUMaxRecvSize : shortAPDUMaxRecvSize, 0);
|
|
cbRecvLength = (DWORD)pbRecvBuffer.size();
|
|
|
|
if (nc > (useExtendedAPDU ? extendedAPDUMaxTransSize : shortAPDUMaxTransSize) - 1) // Max = 255 or 65535
|
|
{
|
|
std::string errStr = vformat("Nc > %d", (useExtendedAPDU ? extendedAPDUMaxTransSize : shortAPDUMaxTransSize) - 1);
|
|
throw CommandAPDUNotValid(SRC_POS, commandAPDU.getErrorStr());
|
|
}
|
|
if (ne > (useExtendedAPDU ? extendedAPDUMaxTransSize : shortAPDUMaxTransSize)) // Max = 256 or 65536
|
|
{
|
|
std::string errStr = vformat("Ne > %d", (useExtendedAPDU ? extendedAPDUMaxTransSize : shortAPDUMaxTransSize) - 1);
|
|
throw CommandAPDUNotValid(SRC_POS, commandAPDU.getErrorStr());
|
|
}
|
|
|
|
// Create and populate buffer to send to card
|
|
pbSendBuffer[0] = commandAPDU.getCLA();
|
|
pbSendBuffer[1] = commandAPDU.getINS();
|
|
pbSendBuffer[2] = commandAPDU.getP1();
|
|
pbSendBuffer[3] = commandAPDU.getP2();
|
|
if (nc == 0)
|
|
{
|
|
if (ne == 0)
|
|
{
|
|
// case 1
|
|
cbSendLength = 4;
|
|
}
|
|
else
|
|
{
|
|
expectingResponse = true;
|
|
|
|
// case 2s or 2e
|
|
if (ne <= 256)
|
|
{
|
|
// case 2s
|
|
// 256 is encoded as 0x00
|
|
pbSendBuffer[4] = (BYTE)ne;
|
|
indexOfLe = 4;
|
|
cbSendLength = 4 + 1; // header || Le (1 byte)
|
|
}
|
|
else
|
|
{
|
|
// case 2e
|
|
// 65536 is encoded as 0x00 0x00 0x00
|
|
BYTE l1, l2;
|
|
if (ne == 65536)
|
|
{
|
|
l1 = 0;
|
|
l2 = 0;
|
|
}
|
|
else
|
|
{
|
|
l1 = (BYTE)(ne >> 8);
|
|
l2 = (BYTE)ne;
|
|
}
|
|
pbSendBuffer[4] = 0x00;
|
|
pbSendBuffer[5] = l1;
|
|
pbSendBuffer[6] = l2;
|
|
cbSendLength = 4 + 3; // header || Le (3 bytes)
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ne == 0)
|
|
{
|
|
// case 3s or 3e
|
|
if (nc <= 255)
|
|
{
|
|
// case 3s
|
|
pbSendBuffer[4] = (BYTE)nc;
|
|
indexOfLcData = 5;
|
|
cbSendLength = 4 + 1 + nc; // header || Lc (1 byte) || Data
|
|
memcpy(&pbSendBuffer[indexOfLcData], commandAPDU.getData().data(), nc);
|
|
}
|
|
else
|
|
{
|
|
// case 3e
|
|
pbSendBuffer[4] = 0;
|
|
pbSendBuffer[5] = (BYTE)(nc >> 8);
|
|
pbSendBuffer[6] = (BYTE)nc;
|
|
indexOfLcData = 7;
|
|
cbSendLength = 4 + 3 + nc; // header || Lc (3 bytes) || Data
|
|
memcpy(&pbSendBuffer[indexOfLcData], commandAPDU.getData().data(), nc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
expectingResponse = true;
|
|
|
|
// case 4s or 4e
|
|
if ((nc <= 255) && (ne <= 256))
|
|
{
|
|
// case 4s
|
|
pbSendBuffer[4] = (BYTE)nc;
|
|
indexOfLcData = 5;
|
|
cbSendLength = 4 + 1 + nc + 1; // header || Lc (1 byte) || Data || Le (1 byte)
|
|
memcpy(&pbSendBuffer[indexOfLcData], commandAPDU.getData().data(), nc);
|
|
pbSendBuffer[indexOfLcData + nc] = (ne != 256) ? (BYTE)ne : 0;
|
|
indexOfLe = indexOfLcData + nc;
|
|
}
|
|
else
|
|
{
|
|
// case 4e
|
|
pbSendBuffer[4] = 0;
|
|
pbSendBuffer[5] = (BYTE)(nc >> 8);
|
|
pbSendBuffer[6] = (BYTE)nc;
|
|
indexOfLcData = 7;
|
|
cbSendLength = 4 + 3 + nc + 2; // header || Lc (3 bytes) || Data || Le (2 bytes)
|
|
memcpy(&pbSendBuffer[indexOfLcData], commandAPDU.getData().data(), nc);
|
|
if (ne != 65536)
|
|
{
|
|
size_t leOfs = cbSendLength - 2;
|
|
pbSendBuffer[leOfs] = (BYTE)(ne >> 8);
|
|
pbSendBuffer[leOfs + 1] = (BYTE)ne;
|
|
}// 65536 is 0x00 0x00 and the buffer has already been initialized with 0s
|
|
}
|
|
}
|
|
}
|
|
cbRecvLength = (DWORD)pbRecvBuffer.size();
|
|
lRet = SendAPDU(pbSendBuffer.data(), cbSendLength, pbRecvBuffer.data(), &cbRecvLength, SW);
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
responseAPDU.setSW(SW);
|
|
goto end;
|
|
}
|
|
|
|
// If Expecting Response
|
|
if (expectingResponse)
|
|
{
|
|
// If Short-APDU
|
|
if (!useExtendedAPDU)
|
|
{
|
|
// If SW != 0x9000
|
|
if (SW != SW_NO_ERROR)
|
|
{
|
|
// If SW == 0x6CXX => Le larger than actual available data on ICC, SW2 contains the appropriate value
|
|
if ((BYTE)(SW >> 8) == (BYTE)(SW_CORRECT_LENGTH_00 >> 8)) // 0x6C
|
|
{
|
|
pbSendBuffer[indexOfLe] = (BYTE)(SW & 0x00FF);
|
|
cbRecvLength = (DWORD)pbRecvBuffer.size();
|
|
lRet = SendAPDU(pbSendBuffer.data(), cbSendLength, pbRecvBuffer.data(), &cbRecvLength, SW);
|
|
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
{
|
|
responseAPDU.setSW(SW);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
// If SW != 0x61XX (GET RESPONSE REMAINING BYTES) => there was an unexpected error
|
|
if (SW != SW_NO_ERROR && ((BYTE)(SW >> 8) != (BYTE)(SW_BYTES_REMAINING_00 >> 8))) // 0x61
|
|
{
|
|
responseAPDU.setSW(SW);
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
// Get response data from APDU Response
|
|
// Response might be complete (1 APDU, <= 256 bytes : SW = 0x9000) or needs a Get Response to get the rest (1st APDU, == 256 bytes, SW = 0x61XX)
|
|
if (cbRecvLength)
|
|
responseAPDU.appendData(pbRecvBuffer.data(), cbRecvLength);
|
|
|
|
// Send get response to get the rest as long as we receive SW == 0x61XX
|
|
// In case of PACE, this is never the case
|
|
while ((lRet == SCARD_S_SUCCESS) && ((BYTE)(SW >> 8) == (BYTE)(SW_BYTES_REMAINING_00 >> 8))) // 0x61
|
|
{
|
|
// GET RESPONSE APDU
|
|
pbSendBuffer[0] = commandAPDU.getCLA();
|
|
pbSendBuffer[1] = INS_GET_RESPONSE;
|
|
pbSendBuffer[2] = 0x00;
|
|
pbSendBuffer[3] = 0x00;
|
|
pbSendBuffer[4] = (BYTE)(SW & 0x00FF);
|
|
cbSendLength = 5;
|
|
|
|
cbRecvLength = (DWORD)pbRecvBuffer.size();
|
|
lRet = SendAPDU(pbSendBuffer.data(), cbSendLength, pbRecvBuffer.data(), &cbRecvLength, SW);
|
|
|
|
if (lRet == SCARD_S_SUCCESS)
|
|
{
|
|
if ((SW != SW_NO_ERROR) && ((SW >> 8) != (BYTE)(SW_BYTES_REMAINING_00 >> 8))) // 0x61
|
|
{
|
|
responseAPDU.clear();
|
|
responseAPDU.setSW(SW);
|
|
}
|
|
else
|
|
responseAPDU.appendData(pbRecvBuffer.data(), cbRecvLength);
|
|
}
|
|
}
|
|
}
|
|
// If Extended-APDU (SW = 0x6CXX and SW = 0x61XX are handled by the low-level driver + smart card reader)
|
|
else
|
|
{
|
|
// If SW != 0x9000 => there was an unexpected error
|
|
if (SW != SW_NO_ERROR)
|
|
{
|
|
responseAPDU.setSW(SW);
|
|
goto end;
|
|
}
|
|
|
|
// Response is complete in 1 ResponseAPDU
|
|
if (cbRecvLength)
|
|
responseAPDU.appendData(pbRecvBuffer.data(), cbRecvLength);
|
|
}
|
|
|
|
if (lRet == SCARD_S_SUCCESS)
|
|
{
|
|
responseAPDU.setSW(SW);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
responseAPDU.setSW(SW);
|
|
}
|
|
|
|
end:
|
|
|
|
burn(pbSendBuffer.data(), pbSendBuffer.size());
|
|
burn(pbRecvBuffer.data(), pbRecvBuffer.size());
|
|
|
|
if (lRet != SCARD_S_SUCCESS)
|
|
throw PCSCException(lRet);
|
|
}
|
|
|
|
void SCardReader::GetATRFromHandle(vector<byte>& atrValue)
|
|
{
|
|
vector<byte> pbATR;
|
|
DWORD cByte = 0;
|
|
LONG lRet = 0;
|
|
|
|
atrValue.clear();
|
|
|
|
if (!m_scardLoader)
|
|
throw ScardLibraryInitializationFailed();
|
|
|
|
lRet = m_scardLoader->SCardGetAttrib(m_hCard, SCARD_ATTR_ATR_STRING, NULL, &cByte);
|
|
if (lRet == SCARD_S_SUCCESS)
|
|
{
|
|
pbATR.resize(cByte, 0);
|
|
lRet = m_scardLoader->SCardGetAttrib(m_hCard, SCARD_ATTR_ATR_STRING, pbATR.data(), &cByte);
|
|
|
|
if (lRet == SCARD_S_SUCCESS)
|
|
{
|
|
atrValue = pbATR;
|
|
}
|
|
else
|
|
{
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw PCSCException(lRet);
|
|
}
|
|
}
|
|
}
|
|
|