def test_SCardGetErrorMessage(self): res = SCardGetErrorMessage(SCARD_S_SUCCESS) # do not test on Windows # the error messages are different and localized if get_platform() in ('win32', 'win-amd64'): return expected = "Command successful." self.assertEqual(res, expected) res = SCardGetErrorMessage(SCARD_F_INTERNAL_ERROR) expected = "Internal error." self.assertEqual(res, expected) res = SCardGetErrorMessage(1) expected = "Unknown error: 0x00000001" # macOS bug not yet fixed if get_platform().startswith('macosx-'): version = get_platform() # something like 'macosx-10.14-x86_64' version = version.split('-')[1] # '10.14' major, minor = map(int, version.split('.')) # (10, 14) if major == 10 and minor < 13: expected = "Unkown error: 0x00000001" self.assertEqual(res, expected)
def connect(self, protocol=None, mode=None, disposition=None): '''Disconnect and reconnect in exclusive mode PCSCCardconnections.''' CardConnectionDecorator.connect(self, protocol, mode, disposition) component = self.component while True: if isinstance( component, smartcard.pcsc.PCSCCardConnection.PCSCCardConnection): pcscprotocol = PCSCCardConnection.translateprotocolmask( protocol) if 0 == pcscprotocol: pcscprotocol = component.getProtocol() if component.hcard is not None: hresult = SCardDisconnect(component.hcard, SCARD_LEAVE_CARD) if hresult != 0: raise CardConnectionException( 'Failed to disconnect: ' + SCardGetErrorMessage(hresult)) hresult, component.hcard, dwActiveProtocol = SCardConnect( component.hcontext, str(component.reader), SCARD_SHARE_EXCLUSIVE, pcscprotocol) if hresult != 0: raise CardConnectionException( 'Failed to connect with SCARD_SHARE_EXCLUSIVE' + SCardGetErrorMessage(hresult)) # print('reconnected exclusive') break if hasattr(component, 'component'): component = component.component else: break
def __str__(self): text = super(SmartcardException, self).__str__() if self.hresult != -1: text += ": %s (0x%08X)" % (SCardGetErrorMessage( self.hresult), self.hresult) return text
def updateReadersStateList(self): # If there is no observer remaining, there is no need to update the readers states list if not self.obs: return self.mutex.acquire() hresult, readers_list = SCardListReaders(self.hcontext, []) if hresult != SCARD_S_SUCCESS: raise CardConnectionException('Unable to list readers: ' + SCardGetErrorMessage(hresult)) # Add the reader in the readers state list if it is not present for reader in readers_list: found = False for state in self.readers_state_list: if state[0] == reader: found = True break if not found: self.readers_state_list.append((reader, SCARD_STATE_UNAWARE, [])) # Remove the reader from the readers state list if it is not present in the readers list for state in self.readers_state_list: if state[0] not in readers_list: self.readers_state_list.remove(state) # Use Pnp Notification only if supported if self.isPnpSupported(): self.readers_state_list.append(('\\\\?PnP?\\Notification', SCARD_STATE_UNAWARE, [])) self.mutex.release()
def send_apdu(self, cl, ins, p1, p2, data): apdu = [cl, ins, p1, p2, len(data)] + [byte2int(b) for b in data] hresult, response = SCardTransmit(self._card, self._protocol, apdu) if hresult != SCARD_S_SUCCESS: raise Exception('Failed to transmit: ' + SCardGetErrorMessage(hresult)) status = response[-2] << 8 | response[-1] return b''.join(int2byte(i) for i in response[:-2]), status
def open(self): if self._reader: try: hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: raise Exception('Failed to establish context : ' + SCardGetErrorMessage(hresult)) hresult, hcard, dwActiveProtocol = SCardConnect( hcontext, self._reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) if hresult != SCARD_S_SUCCESS: raise Exception('Unable to connect: ' + SCardGetErrorMessage(hresult)) return LLScardDevice(hcontext, hcard, dwActiveProtocol) except Exception: self._set_status(CardStatus.InUse)
def _list(self): try: hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: raise Exception('Failed to establish context : ' + SCardGetErrorMessage(hresult)) try: hresult, readers = SCardListReaders(hcontext, []) if hresult != SCARD_S_SUCCESS: raise Exception('Failed to list readers: ' + SCardGetErrorMessage(hresult)) return readers finally: hresult = SCardReleaseContext(hcontext) if hresult != SCARD_S_SUCCESS: raise Exception('Failed to release context: ' + SCardGetErrorMessage(hresult)) except: # noqa: E722 return []
def test_SCardGetErrorMessage(self): res = SCardGetErrorMessage(SCARD_S_SUCCESS) # do not test on Windows # the error messages are different and localized if get_platform() in ('win32', 'win-amd64'): return expected = "Command successful." self.assertEqual(res, expected) res = SCardGetErrorMessage(SCARD_F_INTERNAL_ERROR) expected = "Internal error." self.assertEqual(res, expected) res = SCardGetErrorMessage(1) expected = "Unknown error: 0x00000001" # macOS bug not yet fixed macos_bug_expected = "Unkown error: 0x00000001" self.assertIn(res, [expected, macos_bug_expected])
def __str__(self): text = super(SmartcardException, self).__str__() if self.hresult != -1: hresult = self.hresult if hresult < 0: # convert 0x-7FEFFFE3 into 0x8010001D hresult += 0x100000000 text += ": {} (0x{:08X})".format( SCardGetErrorMessage(self.hresult), hresult) return text
def transceive(self, bytes): if not self.card_connection.hcard: raise PCSCNotConnected( "Tried to transit to non-open connection: {}".format( self.card_connection)) protocol = self.card_connection.getProtocol() pcscprotocolheader = translateprotocolheader(protocol) # http://pyscard.sourceforge.net/epydoc/smartcard.scard.scard-module.html#SCardTransmit hresult, response = SCardTransmit(self.card_connection.hcard, pcscprotocolheader, bytes) if hresult != 0: raise CardConnectionException('Failed to transmit with protocol ' + str(pcscprotocolheader) + '. ' + SCardGetErrorMessage(hresult)) return response
def lock(self): '''Lock card with SCardBeginTransaction.''' component = self.component while True: if isinstance( component, smartcard.pcsc.PCSCCardConnection.PCSCCardConnection): hresult = SCardBeginTransaction(component.hcard) if 0 != hresult: raise CardConnectionException( 'Failed to lock with SCardBeginTransaction: ' + SCardGetErrorMessage(hresult)) else: # print('locked') pass break if hasattr(component, 'component'): component = component.component else: break
def unlock(self): '''Unlock card with SCardEndTransaction.''' component = self.component while True: if isinstance( component, smartcard.pcsc.PCSCCardConnection.PCSCCardConnection): hresult = SCardEndTransaction(component.hcard, SCARD_LEAVE_CARD) if 0 != hresult: raise CardConnectionException( 'Failed to unlock with SCardEndTransaction' +\ SCardGetErrorMessage(hresult)) else: #print 'unlocked' pass break if hasattr(component, 'component'): component = component.component else: break
def update(self, observable, actions): addedcards, removedcards = actions for card in addedcards: connection = card.createConnection() connection.connect() # This will log raw card traffic to console connection.addObserver(ConsoleCardConnectionObserver()) comp = connection.component if not comp.hcard: raise Exception( "Tried to transit to non-open connection: {}".format(comp)) protocol = comp.getProtocol() pcscprotocolheader = translateprotocolheader(protocol) # http://pyscard.sourceforge.net/epydoc/smartcard.scard.scard-module.html#SCardTransmit msg = [0xff, 0xca, 0x00, 0x00, 0x04] hresult, response = SCardTransmit(comp.hcard, pcscprotocolheader, msg) if hresult != 0: raise Exception('Failed to transmit with protocol ' + str(pcscprotocolheader) + '. ' + SCardGetErrorMessage(hresult)) resp_bytes = ['{0:02x}'.format(r) for r in response] status = ''.join(resp_bytes[-2:]) if status != '9000': return # raise Exception('Could not read card.') serial = ''.join(resp_bytes[0:4]) self.on_card(serial)
def run(self): """Runs until stopEvent is notified, and notify observers of all card insertion/removal. """ logging.debug("thread running: %d", self.observable.countObservers()) while not self.stopEvent.isSet(): try: added_cards = [] removed_cards = [] # Update the readers state list to add potentially new found readers and delete removed ones self.observable.updateReadersStateList() logging.debug("listening for changes...") hresult, new_readers_state = SCardGetStatusChange( self.observable.hcontext, self.polling_timeout, self.observable.getReadersStateList()) logging.debug("changes acquired!") logging.debug("states: %s", new_readers_state) # Listen only to others result errors if hresult != SCARD_S_SUCCESS and hresult != SCARD_E_UNKNOWN_READER and hresult != SCARD_E_TIMEOUT: if hresult == SCARD_E_CANCELLED: break else: raise CardConnectionException( 'Unable to get status change: ' + SCardGetErrorMessage(hresult)) # Update observable readers state list and search for added or removed cards self.observable.setReadersStateList(new_readers_state) for state in self.observable.getReadersStateList(): reader, event, atr = state if event & SCARD_STATE_CHANGED: # Check if we have a card present and an atr (is mute + atr a thing ?) if (event & SCARD_STATE_PRESENT or event & SCARD_STATE_MUTE) and len(atr) != 0: # If the event is telling that a card is present/mute add it to the cards list card = Card(reader, atr) logging.debug( "card added with atr: %s on reader %s", card.atr, card.reader) added_cards.append(card) self.observable.addCard(reader, atr) # Check if we have a card empty slot and if the card is in the list (change+empty can happen after SCARD_STATE_UNAWARE fo ex.) elif event & SCARD_STATE_EMPTY and reader in self.observable.getCardsList( ).keys(): # If the event is telling that reader is empty remove it from the cards list atr = self.observable.getCardsList().get(reader) card = Card(reader, atr) logging.debug( "card removed with atr: %s on reader %s", card.atr, card.reader) removed_cards.append(card) self.observable.removeCard(reader) elif event & SCARD_STATE_UNKNOWN or event & SCARD_STATE_IGNORE or event & SCARD_STATE_UNAVAILABLE: # If the event is telling that a reader is not available/existing remove the card on it from the cards list if reader in self.observable.cards_list.keys(): logging.debug( "reader removed, card removed with atr: %s on reader %s", card.atr, card.reader) removed_cards.append(card) self.observable.removeCard(reader) # Update observers if we have added or removed cards if added_cards != [] or removed_cards != []: self.observable.setChanged() self.observable.notifyObservers( (added_cards, removed_cards)) except Exception: # FIXME Tighten the exceptions caught by this block traceback.print_exc() self.stopEvent.set()
def transmit_command(command): hresult, response = SCardTransmit(hcard, dwActiveProtocol, command) if hresult != SCARD_S_SUCCESS or response[1] != 0x9F: raise error("Failed to select ARA: " + SCardGetErrorMessage(hresult)) print_hex_response(response)
print("response: " + toHexString(response, HEX)) def transmit_command(command): hresult, response = SCardTransmit(hcard, dwActiveProtocol, command) if hresult != SCARD_S_SUCCESS or response[1] != 0x9F: raise error("Failed to select ARA: " + SCardGetErrorMessage(hresult)) print_hex_response(response) if __name__ == "__main__": try: hresult, hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: raise error( "Failed to establish context : " + SCardGetErrorMessage(hresult) ) print("Context established!") hresult, readers = SCardListReaders(hcontext, []) if hresult != SCARD_S_SUCCESS: raise error("failed to get readers: " + SCardGetErrorMessage(hresult)) print("readers:", readers) if len(readers) < 1: raise error("No smart card readers") # default to select first reader reader = readers[0] print("select reader:", reader)
def readCard(self, dend, msr): """Wait for card insertion and returns a card service.""" AbstractCardRequest.waitforcard(self) cardfound = False data = [] swiped = False # for non infinite timeout, a timer will signal # the end of the time-out by setting the evt event evt = Event() if INFINITE == self.timeout: timertimeout = 1 else: timertimeout = self.timeout timer = Timer( timertimeout, signalEvent, [evt, INFINITE == self.timeout]) # create a dictionary entry for new readers readerstates = {} readernames = self.getReaderNames() for reader in readernames: if not reader in readerstates: readerstates[reader] = (reader, SCARD_STATE_UNAWARE) # remove dictionary entry for readers that disappeared for oldreader in list(readerstates.keys()): if oldreader not in readernames: del readerstates[oldreader] # call SCardGetStatusChange only if we have some readers if {} != readerstates: hresult, newstates = SCardGetStatusChange( self.hcontext, 0, list(readerstates.values())) else: hresult = 0 newstates = [] # we can expect normally time-outs or reader # disappearing just before the call # otherwise, raise execption on error if 0 != hresult and \ SCARD_E_TIMEOUT != hresult and \ SCARD_E_UNKNOWN_READER != hresult: raise CardRequestException( 'Failed to SCardGetStatusChange ' + \ SCardGetErrorMessage(hresult)) # in case of timeout or reader disappearing, # the content of the states is useless # in which case we clear the changed bit if SCARD_E_TIMEOUT == hresult or SCARD_E_UNKNOWN_READER == hresult: for state in newstates: state[1] = state[1] & (0xFFFFFFFF ^ SCARD_STATE_CHANGED) # update readerstate for state in newstates: readername, eventstate, atr = state readerstates[readername] = (readername, eventstate) # if a new card is not requested, just return the first available if not self.newcardonly: for state in newstates: readername, eventstate, atr = state if eventstate & SCARD_STATE_PRESENT: reader = PCSCReader(readername) if self.cardType.matches(atr, reader): if self.cardServiceClass.supports('dummy'): cardfound = True return self.cardservice(reader) while not evt.isSet() and not cardfound: sleep(self.pollinginterval) # PCSC refresh rate # create a dictionary entry for new readers readernames = self.getReaderNames() for reader in readernames: if not reader in readerstates: readerstates[reader] = (reader, SCARD_STATE_UNAWARE) # remove dictionary entry for readers that disappeared for oldreader in list(readerstates.keys()): if oldreader not in readernames: del readerstates[oldreader] # wait for card insertion if {} != readerstates: hresult, newstates = SCardGetStatusChange( self.hcontext, 0, list(readerstates.values())) else: hresult = SCARD_E_TIMEOUT newstates = [] # msr-read card intermezzo if not self.msr_active: try: if swiped: return msr.process_data(data) data += msr.device.read(dend.bEndpointAddress, dend.wMaxPacketSize, 5) if len(data) >= 537: swiped = True except usb.core.USBError as e: if e.args == ('Operation timed out',): print('Invalid swipe, discarding %s bytes of data', len(data)) data = [] continue # time-out if SCARD_E_TIMEOUT == hresult: if evt.isSet(): raise CardRequestTimeoutException() # reader vanished before or during the call elif SCARD_E_UNKNOWN_READER == hresult: pass # some error happened elif 0 != hresult: timer.cancel() raise CardRequestException( 'Failed to get status change ' + \ SCardGetErrorMessage(hresult)) # something changed! else: # check if we have to return a match, i.e. # if no new card in inserted and there is a card found # or if a new card is requested, and there is a change+present for state in newstates: readername, eventstate, atr = state r, oldstate = readerstates[readername] # the status can change on a card already inserted, e.g. # unpowered, in use, ... # if a new card is requested, clear the state changed bit # if the card was already inserted and is still inserted if self.newcardonly: if oldstate & SCARD_STATE_PRESENT and \ eventstate & \ (SCARD_STATE_CHANGED | SCARD_STATE_PRESENT): eventstate = eventstate & \ (0xFFFFFFFF ^ SCARD_STATE_CHANGED) if (self.newcardonly and \ eventstate & SCARD_STATE_PRESENT and \ eventstate & SCARD_STATE_CHANGED) or \ (not self.newcardonly and \ eventstate & SCARD_STATE_PRESENT): reader = PCSCReader(readername) if self.cardType.matches(atr, reader): if self.cardServiceClass.supports('dummy'): cardfound = True # timer.cancel() return self.cardservice(reader) # update state dictionary readerstates[readername] = (readername, eventstate) if evt.isSet(): raise CardRequestTimeoutException()
def check(hresult, op_des, printManualy=-1): if hresult != SCARD_S_SUCCESS: raise Exception('Failed to {0}: {1}\nhresult = {2}'.format( op_des, SCardGetErrorMessage(hresult), hresult)) elif (DEBUG_PRINT and type(printManualy) == int) or printManualy: print('Success to ' + op_des)
def getReaders(self): if self.hcontext is None: self.__establishContext() hresult, readers_list = SCardListReaders(self.hcontext, []) if hresult != SCARD_S_SUCCESS: raise CardConnectionException('Unable to list readers: ' + SCardGetErrorMessage(hresult))
def run(self): """Runs until stopEvent is notified, and notify observers of all reader insertion/removal. """ logging.debug("thread running: %d", self.observable.countObservers()) while not self.stopEvent.isSet(): try: added_readers = [] removed_readers = [] # Update the readers state list to add potentially new found readers and delete removed ones self.observable.updateReadersStateList() logging.debug("listening for changes...") hresult, new_readers_state = SCardGetStatusChange(self.observable.hcontext, self.polling_timeout, self.observable.getReadersStateList()) logging.debug("changes acquired!") logging.debug("states: %s", new_readers_state) # Listen only to others result errors if hresult != SCARD_S_SUCCESS and hresult != SCARD_E_UNKNOWN_READER and hresult != SCARD_E_TIMEOUT: if hresult == SCARD_E_CANCELLED: break else: raise CardConnectionException('Unable to get status change: ' + SCardGetErrorMessage(hresult)) # Update observable readers state list and search for added or removed cards self.observable.setReadersStateList(new_readers_state) for state in self.observable.getReadersStateList(): reader, event, atr = state if event & SCARD_STATE_CHANGED: if event & SCARD_STATE_UNKNOWN or event & SCARD_STATE_IGNORE or event & SCARD_STATE_UNAVAILABLE: # If the event is telling that a reader is not available/existing remove it from readers list logging.debug("reader removed: %s", reader) removed_readers.append(reader) self.observable.removeReader(reader) elif reader not in self.observable.getReadersList() and not reader == '\\\\?PnP?\\Notification': # If the event is telling that there is change on a reader which is not present in the readers list, add it logging.debug("reader added: %s", reader) added_readers.append(reader) self.observable.addReader(reader) # Update observers if we have added or removed cards if added_readers != [] or removed_readers != []: self.observable.setChanged() self.observable.notifyObservers((added_readers, removed_readers)) except Exception: # FIXME Tighten the exceptions caught by this block traceback.print_exc() self.stopEvent.set()
def __establishContext(self): hresult, self.hcontext = SCardEstablishContext(SCARD_SCOPE_USER) if hresult != SCARD_S_SUCCESS: raise CardConnectionException('Failed to establish context: ' + SCardGetErrorMessage(hresult))
def __releaseContext(self): hresult = SCardReleaseContext(self.hcontext) if hresult != SCARD_S_SUCCESS: raise CardConnectionException('Failed to release context: ' + SCardGetErrorMessage(hresult)) self.hcontext = None