Skip to content

Commit

Permalink
SCardTransmit() may return SCARD_E_INSUFFICIENT_BUFFER
Browse files Browse the repository at this point in the history
SCardTransmit() now correctly returns SCARD_E_INSUFFICIENT_BUFFER when
pcbRecvLength is not big enough to receive the card response.

The APDU is succesfully exchanged with the card but the card response is
lost since the client application buffer is not large enough to receive
it.

Before this patch an error was reported in the CCID driver and the
application got a SCARD_E_NOT_TRANSACTED error instead.

Now the expected size is available in pcbRecvLength for the application
to adapt its buffer size and, possibly, recall SCardTransmit().

Thanks to Mironenko for the bug report
LudovicRousseau/CCID#5
  • Loading branch information
Ludovic Rousseau committed May 29, 2015
1 parent e2752b7 commit 8eb9ea1
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 2 deletions.
86 changes: 86 additions & 0 deletions UnitaryTests/BufferOverflow2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* MUSCLE SmartCard Development ( http:https://pcsclite.alioth.debian.org/pcsclite.html )
*
* Copyright (C) 2009
* Ludovic Rousseau <[email protected]>
*/
#include <stdio.h>
#include <string.h>

#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif

#define GREEN "\33[32m"
#define BRIGHT_RED "\33[01;31m"
#define NORMAL "\33[0m"

int main(void)
{
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
DWORD dwActiveProtocol;
LONG rv;
char mszReaders[1024];
DWORD dwReaders = sizeof(mszReaders);
SCARD_IO_REQUEST ioRecvPci = *SCARD_PCI_T0; /* use a default value */
unsigned char bSendBuffer[MAX_BUFFER_SIZE];
unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
DWORD send_length, length;

rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
printf("SCardEstablishContext %lX\n", rv);

rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
printf("SCardListReaders %lX\n", rv);

rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard,
&dwActiveProtocol);
printf("SCardConnect %lX\n", rv);

send_length = 5;
/* GET RANDOM for a GPK card */
memcpy(bSendBuffer, "\x80\x84\x00\x00\x20", send_length);

/* expected size is 0x20 + 2 = 34 bytes */
length = 30;
rv = SCardTransmit(hCard, SCARD_PCI_T0, bSendBuffer, send_length,
&ioRecvPci, bRecvBuffer, &length);
if (SCARD_E_INSUFFICIENT_BUFFER == rv)
{
printf(GREEN "test PASS. Insufficient buffer is expected\n" NORMAL);
}
else
{
printf(BRIGHT_RED "test FAIL\n" NORMAL);
}
printf("SCardTransmit %lX: %s\n", rv, pcsc_stringify_error(rv));
printf("Expected length: %ld\n", length);
if (SCARD_S_SUCCESS == rv)
{
int i;

for (i=0; i<length; i++)
printf("%02X ", bRecvBuffer[i]);
printf("\n");
}

rv = SCardTransmit(hCard, SCARD_PCI_T0, bSendBuffer, send_length,
&ioRecvPci, bRecvBuffer, &length);
printf("SCardTransmit %lX: %s\n", rv, pcsc_stringify_error(rv));
printf("Expected length: %ld\n", length);
if (SCARD_S_SUCCESS == rv)
{
int i;

for (i=0; i<length; i++)
printf("%02X ", bRecvBuffer[i]);
printf("\n");
}

return 0;
}
1 change: 1 addition & 0 deletions UnitaryTests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ LDLIBS := $(PCSC_LDLIBS)

PROGRAMS := SCardBeginTransaction \
BufferOverflow \
BufferOverflow2 \
exec

all: $(PROGRAMS)
Expand Down
2 changes: 1 addition & 1 deletion src/winscard_clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2709,7 +2709,7 @@ static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
*
* @return Error code.
* @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
* @retval SCARD_E_INSUFFICIENT_BUFFER \p cbSendLength or \p cbRecvLength are too big (\ref SCARD_E_INSUFFICIENT_BUFFER)
* @retval SCARD_E_INSUFFICIENT_BUFFER \p cbRecvLength was not large enough for the card response. The expected size is now in \p cbRecvLength (\ref SCARD_E_INSUFFICIENT_BUFFER)
* @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE)
* @retval SCARD_E_INVALID_PARAMETER \p pbSendBuffer or \p pbRecvBuffer or \p pcbRecvLength or \p pioSendPci is null (\ref SCARD_E_INVALID_PARAMETER)
* @retval SCARD_E_INVALID_VALUE Invalid Protocol, reader name, etc (\ref SCARD_E_INVALID_VALUE)
Expand Down
8 changes: 7 additions & 1 deletion src/winscard_svc.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,12 +638,18 @@ static void ContextThread(LPVOID newContext)
ioSendPci.cbPciLength = trStr.ioSendPciLength;
ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
cbRecvLength = trStr.pcbRecvLength;
cbRecvLength = sizeof pbRecvBuffer;

trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
pbRecvBuffer, &cbRecvLength);

if (cbRecvLength > trStr.pcbRecvLength)
/* The client buffer is not large enough.
* The pbRecvBuffer buffer will NOT be sent a few
* lines bellow. So no buffer overflow is expected. */
trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;

trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
trStr.ioSendPciLength = ioSendPci.cbPciLength;
trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
Expand Down

0 comments on commit 8eb9ea1

Please sign in to comment.