2009/11/23 Ludovic Rousseau <[email protected]>: > 2009/11/23 Martin Paljak <[email protected]>: >> Out of the control codes supported by the CCID ifdhandler, it is somewhat >> premature for these control codes (which, as I understand, do not result in >> card communication, ever): >> IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE and IOCTL_FEATURE_MCT_READERDIRECT (not >> 100% sure as I have not implemented those) >> CM_IOCTL_GET_FEATURE_REQUEST >> IOCTL_FEATURE_IFD_PIN_PROPERTIES >> >> But valid for these (which will do card communication and where card events >> make sense): >> IOCTL_FEATURE_VERIFY_PIN_DIRECT >> IOCTL_FEATURE_MODIFY_PIN_DIRECT >> >> As the card state is checked on pcsc-lite level, it is not OK or even >> possible to check the semantics of the control codes. One way could be >> postponing the check for reader event states after the ifdhandler returns an >> error. > > You would then send a VERIFY_PIN command to a card that has been > reseted or even changed?
That would not be OK, as the card might be swapped to a hostile one. That was the simplest solution I had in mind. > >> So both return codes are valid from SCardControl, but returned at bad times, >> IMO? I could write a patch for this, if this solution is OK. > > What is the problem to have RFCheckReaderEventState() in all cases? > Does the problem happen in practice? The problem lies with mostly SCARD_SHARE_DIRECT mode, which explicitly talks to the reader, not to the card. I made some tests with a pyscard test application, based on the sample_pinpad.py script, which is also attached. Here are the results: Windows: c:\build>c:\Python25\python.exe scardcontrol.py Context established! PCSC Readers: ['OMNIKEY CardMan 3821 0'] Trying to Control reader: OMNIKEY CardMan 3821 0 Enter card and press enter Connected with active protocol 0 Remove card and press enter [6, 4, 0, 49, 48, 12, 7, 4, 0, 49, 48, 16, 10, 4, 0, 49, 48, 8] can do verify pin: 0x0031300C [6, 4, 0, 49, 48, 12, 7, 4, 0, 49, 48, 16, 10, 4, 0, 49, 48, 8] can do modify pin: 0x00313010 Disconnected Released context. press Enter to continue on Linux: $ python scardcontrol_direct.py Context established! PCSC Readers: ['OmniKey CardMan 3821 00 00'] Trying to Control reader: OmniKey CardMan 3821 00 00 Enter card and press enter Connected with active protocol 0 Remove card and press enter Disconnected <class 'scard.error'> SCardControl failed: Card was removed. Released context. So the behavior is different. On Linux I even managed to get a "Card was reset" from the same test case if Firefox was running. So at least direct mode should be fixed (can send a patch). I could not test with any other reader under Windows if the behaviour is uniformly applied on winscard level or it depends on the reader driver, but IMHO, even if the card is removed, those SCardControl commands that do not talk to the card itself could succeed if the card is removed in SCARD_SHARING_SHARE mode. The behaviour of different Windows drivers should be tested to see how it works. The problem occurred with stress-testing OpenSC when I discovered that extensive "playing with the card" (inserting and removing) resulted in some missing pinpad feature detections. The detection logic goes like this: try to connect with direct mode, if it fails with a sharing violation, try to connect in shared mode with any protocol" and then use SCardControl to detect features. Martin
#! /usr/bin/env python """ Sample for python PCSC wrapper module: send a Control Code to a card or reader __author__ = "Ludovic Rousseau" Copyright 2009 Ludovic Rousseau Author: Ludovic Rousseau, mailto:[email protected] This file is part of pyscard. pyscard is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. pyscard is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with pyscard; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ import sys from smartcard.scard import * from smartcard.util import toASCIIBytes def candoverifypin(hCard): FEATURE_VERIFY_PIN_DIRECT = 6 return parse_get_feature_request(hCard, FEATURE_VERIFY_PIN_DIRECT) def candomodifypin(hCard): FEATURE_MODIFY_PIN_DIRECT = 7 return parse_get_feature_request(hCard, FEATURE_MODIFY_PIN_DIRECT) def parse_get_feature_request(hCard, feature): # check the reader can do a verify pin CM_IOCTL_GET_FEATURE_REQUEST = SCARD_CTL_CODE(3400) hresult, response = SCardControl(hcard, CM_IOCTL_GET_FEATURE_REQUEST, []) if hresult!=SCARD_S_SUCCESS: raise error, 'SCardControl failed: ' + SCardGetErrorMessage(hresult) print response while (len(response) > 0): tag = response[0] if (feature == tag): return (((((response[2]<<8) + response[3])<<8) + response[4])<<8) + response[5] response = response[6:] def verifypin(hCard, control=None): if None==control: control = candoverifypin(hCard) if (None == control): raise error, "Not a pinpad" hresult, response = SCardControl(hcard, control, []) if hresult!=SCARD_S_SUCCESS: raise error, 'SCardControl failed: ' + SCardGetErrorMessage(hresult) return hresult, response try: hresult, hcontext = SCardEstablishContext( SCARD_SCOPE_USER ) if hresult!=0: raise error, 'Failed to establish context: ' + SCardGetErrorMessage(hresult) print 'Context established!' try: hresult, readers = SCardListReaders( hcontext, [] ) if hresult!=0: raise error, 'Failed to list readers: ' + SCardGetErrorMessage(hresult) print 'PCSC Readers:', readers if len(readers)<1: raise error, 'No smart card readers' for zreader in readers: print 'Trying to Control reader:', zreader print 'Enter card and press enter' sys.stdin.read(1) try: hresult, hcard, dwActiveProtocol = SCardConnect( #hcontext, zreader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) hcontext, zreader, SCARD_SHARE_DIRECT, 0) if hresult!=0: raise error, 'Unable to connect: ' + SCardGetErrorMessage(hresult) print 'Connected with active protocol', dwActiveProtocol print 'Remove card and press enter' sys.stdin.read(1) try: cmd_verify = candoverifypin(hcard) if (cmd_verify): print "can do verify pin: 0x%08X" % cmd_verify cmd_modify = candomodifypin(hcard) if (cmd_modify): print "can do modify pin: 0x%08X" % cmd_modify # (hresult, response) = verifypin(hcard, cmd_verify) # r = "" # for i in xrange(len(response)): # r += "%c" % response[i] # print 'Control:', r finally: hresult = SCardDisconnect( hcard, SCARD_UNPOWER_CARD ) if hresult!=0: raise error, 'Failed to disconnect: ' + SCardGetErrorMessage(hresult) print 'Disconnected' except error, (message): print error, message finally: hresult = SCardReleaseContext( hcontext ) if hresult!=SCARD_S_SUCCESS: raise error, 'Failed to release context: ' + SCardGetErrorMessage(hresult) print 'Released context.' except: print sys.exc_info()[0], ':', sys.exc_info()[1] if 'win32'==sys.platform: print 'press Enter to continue' sys.stdin.read(1)
_______________________________________________ Muscle mailing list [email protected] http://lists.drizzle.com/mailman/listinfo/muscle
