LudovicRousseau / pyscard

pyscard smartcard library for python
http://pyscard.sourceforge.net/
GNU Lesser General Public License v2.1
386 stars 111 forks source link

CCID Escape command illegal function (Windows 7) #19

Closed iomode closed 8 years ago

iomode commented 8 years ago

OS: Windows 7 SP1 64-bit Python: 2.7.11 Pyscard: 1.9.2

I have a problem sending an CCID Escape command via pyscard to my CCID Reader. When I execute the code snippet I get: scard.error: Failed to control: Illegal function.

I wrote the same sequence in C using the original API and it works without problems. Is it possible that pyscard does not support Escape commands?

#! /usr/bin/env python

from smartcard.scard import *

hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_SYSTEM)
if hresult != SCARD_S_SUCCESS:
    raise error, 'Failed to establish context: ' + SCardGetErrorMessage(hresult)

hresult, readers = SCardListReaders(hcontext, [])
if hresult != SCARD_S_SUCCESS:
    raise error(
        'Failed to list readers: ' + \
        SCardGetErrorMessage(hresult))
if len(readers) < 1:
    raise Exception('No smart card readers')
print('PCSC Readers:', readers)

hresult, hcard, dwActiveProtocol = SCardConnect(
    hcontext, readers[0], SCARD_SHARE_DIRECT, 0)
if hresult != SCARD_S_SUCCESS:
    raise error, 'Failed to control: ' + SCardGetErrorMessage(hresult)

CMD = [0xA0, 0x00]
IOCTL_CCID_ESCAPE = SCARD_CTL_CODE(3500)

hresult, response = SCardControl(hcard, IOCTL_CCID_ESCAPE, CMD)
if hresult != SCARD_S_SUCCESS:
    raise error, 'Failed to control: ' + SCardGetErrorMessage(hresult)

print(response)
print "Done"
LudovicRousseau commented 8 years ago

PySCard does support Escape commands. What is the value of hresult?

iomode commented 8 years ago

print hex(hresult)

0x1L

LudovicRousseau commented 8 years ago

I have no idea what could be wrong. Can you debug on your side? You could start by tracing the PC/SC calls done by your C application and your Python application. Maybe using ScardSpy https://www.idrix.fr/Root/content/category/7/25/48/

iomode commented 8 years ago

This are my results: python script:

2016-02-25 10:43:13.883 (Thread = 0x00000470) - SCardConnectA( hContext = 0xCD010000, szReader = "MYREADER 0", dwShareMode = 0x00000003, dwPreferredProtocols = 0x00000000 ):
2016-02-25 10:43:13.883 (Thread = 0x00000470) - SCardConnectA Handle   = 0xEA010000

2016-02-25 10:43:13.883 (Thread = 0x00000470) - SCardControl( hCard = 0xEA010000 on reader "MYREADER 0", dwControlCode = 0x003136B0, lpOutBuffer = 0x02782F80, nOutBufferSize = 65548, lpBytesReturned = 0x005BF5D0 ):
 Input command = 
  A0 BE
2016-02-25 10:43:13.884 (Thread = 0x00000470) - SCardControl Failed. Error 0x00000001
 Duration = 1 ms

c++ programm (compiled with visual studio 2013):

2016-02-25 10:43:09.736 (Thread = 0x00000188) - SCardConnectA( hContext = 0xCD010000, szReader = "MYREADER 0", dwShareMode = 0x00000003, dwPreferredProtocols = 0x00000000 ):
2016-02-25 10:43:09.736 (Thread = 0x00000188) - SCardConnectW Returned Handle   = 0xEA010000

2016-02-25 10:43:09.737 (Thread = 0x00000188) - SCardControl( hCard = 0xEA010000 on reader "MYREADER 0", dwControlCode = 0x003136B0, lpOutBuffer = 0x0034F9F8, nOutBufferSize = 256, lpBytesReturned = 0x0034F9EC ):
 Input command = 
  A0 BE
2016-02-25 10:43:09.739 (Thread = 0x00000188) - SCardControl Response   = 
  90 00
 Duration = 2 ms

2016-02-25 10:43:09.739 (Thread = 0x00000188) - SCardDisconnect( hCard = 0xEA010000 on reader "MYREADER 0", dwDisposition = 0x00000000):
2016-02-25 10:43:09.739 (Thread = 0x00000188) - SCardDisconnect Success

My C++ programm:

#include "stdafx.h"
#include <windows.h>
#include <winscard.h>
#include <iostream>
#include <WinBase.h>
#include <string>

#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(3500)
using namespace std;

int main(int argc, char * argv[])
{
    const BYTE ESCAPE_COMMAND_TEST[] = { 0xA0, 0xBE };
    SCARDCONTEXT hContext;
    SCARDHANDLE hCard;
    DWORD dwProtocol;
    BYTE abResponse[256];
    DWORD dwRespLen = NULL;
    LONG rc = 0;
    LPTSTR          pmszReaders = NULL;
    LPTSTR          pReader;
    LPTSTR          pfirstReader = NULL;
    LONG            lReturn, lReturn2;
    DWORD           cch = SCARD_AUTOALLOCATE;

    /* Instanciate the winscard.dll library */
    rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
    if (rc != SCARD_S_SUCCESS) {
        cout << "Could not get context! (SCardEstablishContext)" << endl;
        return -1;
    }

    // Retrieve the list the readers.
    lReturn = SCardListReaders(hContext,
        SCARD_DEFAULT_READERS,
        (LPTSTR)&pmszReaders,
        &cch);

    switch (lReturn)
    {
    case SCARD_E_NO_READERS_AVAILABLE:
        cout << "No readers connected! (SCARD_E_NO_READERS_AVAILABLE)" << endl;
        return -2;
        break;

    case SCARD_S_SUCCESS:
    {
        // Do something with the multi string of readers.
        // Output the values.
        // A double-null terminates the list of values.
        pReader = pmszReaders;
        while ('\0' != *pReader)
        {
            // Display the value.
            printf("Reader found: '%S'\n", pReader);
            if (pfirstReader == NULL)
                pfirstReader = pReader;
            // Advance to the next value.
            pReader = pReader + wcslen((wchar_t *)pReader) + 1;
        }

        rc = SCardConnect(hContext, pfirstReader, SCARD_SHARE_DIRECT, 0, &hCard, &dwProtocol);
        if (rc != SCARD_S_SUCCESS) {
            cout << "Could not connect to reader! (SCardConnect)" << endl;
            return -3;
        }

        std::cout << "Successfully connected to reader!" << std::endl;

        rc = SCardControl(hCard, IOCTL_CCID_ESCAPE, ESCAPE_COMMAND_TEST, sizeof(ESCAPE_COMMAND_TEST), abResponse, sizeof(abResponse), &dwRespLen);
        if (rc != SCARD_S_SUCCESS) {
            cout << "Control command sending failed (SCardControl)!" << endl;
            exit(-4);
        }

        SCardDisconnect(hCard, SCARD_LEAVE_CARD);
        // Free the memory.
        lReturn2 = SCardFreeMemory(hContext,
            pfirstReader);
        if (SCARD_S_SUCCESS != lReturn2)
            printf("Failed SCardFreeMemory\n");
        SCardReleaseContext(hContext);
        std::cout << "Reader successfully disconnected." << std::endl;
    }
    break;
    default:
        printf("Failed SCardListReaders\n");
        return -3;
        break;
    }
    return 0;
}
LudovicRousseau commented 8 years ago

Thanks. One difference is the size of the pbRecvBuffer buffer. Can you change your C++ code and use:

BYTE abResponse[65548];

What is the ScardSpy result?

iomode commented 8 years ago

I think we found the problem. abResponse[65548] fails the same way as python. abResponse[65544] is the biggest working size. Maybe this should better not exceed 2^16 (65536)?

LudovicRousseau commented 8 years ago

Argh! Stupid Windows.

Can you try to rebuild pyscard with the following patch:

**--- /var/folders/5h/3d1x67_x5g30t36wypgxpmpc0000gn/T//pXYc2b_scard.i    2016-02-25 14:10:13.000000000 +0100
+++ smartcard/scard/scard.i 2016-02-25 14:10:07.000000000 +0100
@@ -152,7 +152,7 @@ Inc., 51 Franklin St, Fifth Floor, Bosto
 #else // !PCSCLITE
 // SCARD_CTL_CODE defined in WinSmCrd.h included by Win32 winscard.h
 // MAX_BUFFER_SIZE_EXTENDED is pcsc-lite specific
-#define MAX_BUFFER_SIZE_EXTENDED    (4 + 3 + (1<<16) + 3 + 2)
+#define MAX_BUFFER_SIZE_EXTENDED    (4 + 3 + (1<<16) + 3 + 2) -4
 #endif //PCSCLITE

 #include "pcsctypes.h"

and test again your Python script?

iomode commented 8 years ago

It works! Thank you for your awesome support.

I can now send any escape command without problems. Btw. did this bug only affect the escape command?

LudovicRousseau commented 8 years ago

You can check that SCardTransmit() is working but I guess it is (or I would have received bug reports :-)

LudovicRousseau commented 8 years ago

Bug fixed with https://github.com/LudovicRousseau/pyscard/commit/160456fc2677f3a10262466420cfba94d60d42ef

fmoghaddampoor commented 8 years ago

Hi guys Well these days Im trying to design a software which use smart card readers, I am using ACR1252u and I have discovered how to buzz my smart card reader if a tag or card is on the reader. but still wondering how can I do this without the card on the reader. the code which works for when the card is on the reader is below:

retCode = Card.SCardConnect(hContext, readername, Card.SCARD_SHARE_SHARED, Card.SCARD_PROTOCOL_T0 | Card.SCARD_PROTOCOL_T1, ref hCard, ref Protocol);

Byte[] setBuzzerLoud = new Byte[6];
setBuzzerLoud[0] = 0xE0;
setBuzzerLoud[1] = 0x00;
setBuzzerLoud[2] = 0x00;
setBuzzerLoud[3] = 0x21;
setBuzzerLoud[4] = 0x01;
setBuzzerLoud[5] = 0x77;
uint pcBytesReturned = 0;
Byte[] RecieveBuff = new Byte[64];
uint controlcode = 3225264;
int status = Card.SCardControl(hCard, controlcode, ref setBuzzerLoud[0], 6, ref RecieveBuff[0], RecieveBuff.Length, ref pcBytesReturned);

MessageBox.Show(status.ToString());

The problem is when hcard is on the reader the status which is the error shows 6. which means wrong handle!. But why buzzing a reader is connected to if the card is over the reader? is there anyway to turn this over? cause after this I want to turn on LEDs while the card is not over the reader- Guys plz if anyone have solved this problem tell us.

LudovicRousseau commented 8 years ago

@fmoghaddampoor please open a new issue for new problems.