| | |
| | | # -*- coding: utf-8 -*-
|
| | | from __future__ import print_function
|
| | |
|
| | | import smartcard.CardRequest
|
| | | import smartcard.CardConnectionObserver
|
| | | import smartcard.ExclusiveTransmitCardConnection
|
| | | import smartcard.pcsc.PCSCPart10
|
| | | |
| | | from pyasn1.type import univ |
| | | from pyasn1.codec.ber import decoder |
| | | import subprocess |
| | |
|
| | | from smartcard.util import toHexString, toASCIIBytes, toBytes, toASCIIString
|
| | |
|
| | |
| | | report = 0
|
| | | def __init__(self, level, message):
|
| | | if level >= SCardDebug.report:
|
| | | print(message)
|
| | | print message |
| | |
|
| | | class SCardConnectionObserver(smartcard.CardConnectionObserver.CardConnectionObserver):
|
| | | def update( self, cardconnection, ccevent ):
|
| | |
| | | MSB = 0x80
|
| | | CONSTRUCTED = 0x20
|
| | |
|
| | | debug = True
|
| | | |
| | | tags = {
|
| | | 0x02: ["Integer", ""],
|
| | | 0x03: ["Bit string", ""],
|
| | | 0x04: ["Octet string", ""],
|
| | | 0x05: ["Null", ""],
|
| | | 0x06: ["Object identifier", ""],
|
| | | 0x42: ["Issuer Identification Number (IIN)", "The number that identifies the major industry and the card issuer and that forms the first part of the Primary Account Number (PAN)"],
|
| | | 0x4F: ["Application Identifier (AID) - card", "Identifies the application as described in ISO/IEC 7816-5"],
|
| | | 0x50: ["Application Label", "Mnemonic associated with the AID according to ISO/IEC 7816-5"],
|
| | |
| | | if tag == 0x9f8004:
|
| | | tag = 0x9f80
|
| | | data.append(0x04)
|
| | | if SCardTLV.debug:
|
| | | print('Got tag: ' + toHexString(tag))
|
| | |
|
| | | length = data.pop()
|
| | | if length == 0x80:
|
| | |
| | | if constructed:
|
| | | read = SCardTLV.decode(read)
|
| | |
|
| | | if tag in ret:
|
| | | ret[tag].push(read)
|
| | | else:
|
| | | ret[tag] = [ read ]
|
| | | ret[tag] = read |
| | |
|
| | | return ret
|
| | |
|
| | | @staticmethod
|
| | | def displayTag(data, intend=""):
|
| | | if data[0] in SCardTLV.tags:
|
| | | print(intend + SCardTLV.tags[data[0]][0] + " [" + hex(data[0]) + "], length "+str(data[1]))
|
| | | print intend + SCardTLV.tags[data[0]][0] + " [" + hex(data[0]) + "], length "+str(data[1]) |
| | | else:
|
| | | print(intend + "UNKNOWN TAG [" + hex(data[0]) + "], length "+str(data[1]))
|
| | | print intend + "UNKNOWN TAG [" + hex(data[0]) + "], length "+str(data[1]) |
| | |
|
| | | @staticmethod
|
| | | def display(data, intend="", singleline = None):
|
| | | for tag, value in data.items():
|
| | | if tag in SCardTLV.tags:
|
| | | print(intend + SCardTLV.tags[tag][0] + " [" + hex(tag) + "]:")
|
| | | print intend + SCardTLV.tags[tag][0] + " [" + hex(tag) + "]:" |
| | | else:
|
| | | print(intend + "UNKNOWN TAG [" + hex(tag) + "]:")
|
| | | print intend + "UNKNOWN TAG [" + hex(tag) + "]:" |
| | |
|
| | | if tag in SCardTLV.specialTags:
|
| | | value.reverse()
|
| | |
| | | elif isinstance(value, dict):
|
| | | SCardTLV.display(value, intend+"\t")
|
| | | else:
|
| | | print(intend+"\t"+toHexString(value)+" ("+toASCIIString(value)+")")
|
| | | print intend+"\t"+toHexString(value)+" ("+toASCIIString(value)+")" |
| | |
|
| | | class SCardSelectFileBy:
|
| | | MFDFEF = 0x00
|
| | |
| | | self.connection = conn
|
| | |
|
| | | def getFeatures(self):
|
| | | print(smartcard.pcsc.PCSCPart10.getFeatureRequest(self.connection))
|
| | | print smartcard.pcsc.PCSCPart10.getFeatureRequest(self.connection) |
| | |
|
| | | class SCardEMVPINEncode:
|
| | | @staticmethod
|
| | |
| | | exclusive = smartcard.ExclusiveTransmitCardConnection.ExclusiveTransmitCardConnection(serv.connection)
|
| | | exclusive.lock()
|
| | | time.sleep(0.2)
|
| | | print("inserted", toHexString(serv.connection.getATR()))
|
| | | print "inserted", toHexString(serv.connection.getATR()) |
| | |
|
| | | self.service = serv
|
| | | self.connection = serv.connection
|
| | |
| | |
|
| | | def _sendAPDU(self, adpu = []):
|
| | | response, SW1, SW2 = self.exclusive.transmit(adpu)
|
| | | |
| | | if SW1 != 0x90:
|
| | | raise SCardResponseException(SW1, SW2)
|
| | |
|
| | |
| | |
|
| | | return self._sendAPDU(adpu)
|
| | |
|
| | | def GetResponse(self, CLA = 0x00, P1 = 0x00, P2 = 0x00, Le = 0x00): |
| | | return self._sendAPDU([CLA, 0xC0, P1, P2, Le]) |
| | | |
| | | def ReadBinary(self, CLA = 0x00, offset = 0x00, Le = 0x00):
|
| | | try:
|
| | | return self._sendAPDU([CLA, 0xB0, (offset >> 8) & 0x7F, offset & 0xFF, Le])
|
| | |
| | | return self.ReadBinary(CLA, offset, Le = e.SW2)
|
| | | else:
|
| | | raise e
|
| | | |
| | | def ReadBinaryAll(self, CLA = 0x00):
|
| | | data = []
|
| | | while len(data) <= 0x7FFF:
|
| | | try:
|
| | | response, SW1, SW2 = self.ReadBinary(CLA, len(data))
|
| | | data += response
|
| | | except SCardResponseException as e:
|
| | | if e.SW1 == 0x6B:
|
| | | break
|
| | | raise e
|
| | | return data
|
| | |
|
| | | def ReadRecord(self, CLA = 0x00, record = 0x00, identifier = 0x00, Le = 0x00):
|
| | | try:
|
| | |
| | |
|
| | | return self._sendAPDU(adpu)
|
| | |
|
| | | class SCardActions: |
| | | def __init__(self, card): |
| | | self.card = card |
| | | |
| | | def cdRoot(self, CLA = 0x00): |
| | | return self.cd("3F20") |
| | | |
| | | def cdAID(self, AID, CLA = 0x00): |
| | | return self.card.SelectFile(CLA = CLA, by = SCardSelectFileBy.DFname, data = toBytes(AID), Le = 0) |
| | | |
| | | def cd(self, MFEFDF, CLA = 0x00): |
| | | return self.card.SelectFile(CLA = CLA, by = SCardSelectFileBy.MFDFEF, data = toBytes(MFEFDF), Le = 0) |
| | | |
| | | def readBinaryEF(self, EF, blockSize = 4, CLA = 0x00): |
| | | attrs = self.cd(EF, CLA = CLA) |
| | | data = [] |
| | | offset = 0 |
| | | try: |
| | | while True: |
| | | offset = int(len(data) / blockSize) |
| | | result, _, _ = self.card.ReadBinary(offset = offset, CLA = CLA) |
| | | if result == []: |
| | | break |
| | | data = data[0:offset * blockSize] + result |
| | | except SCardResponseException as e: |
| | | if e.SW1 == 0x6B: |
| | | pass |
| | | else: |
| | | raise e |
| | | |
| | | return data |
| | | |
| | | class SCardHandler:
|
| | | @staticmethod
|
| | | def getCard():
|
| | | request = smartcard.CardRequest.CardRequest(newcardonly=True, timeout=None)
|
| | | print("Insert card...")
|
| | | print "Insert card..." |
| | | service = request.waitforcard()
|
| | | print "Card detected..." |
| | | time.sleep(0.5)
|
| | | return SCard(service)
|
| | |
|
| | |
| | | ]
|
| | |
|
| | | def __init__(self, card):
|
| | | self.card = card
|
| | | self.card = SCardActions(card) |
| | |
|
| | | def selectAID(self):
|
| | | #self.card.SelectFile(by = SCardSelectFileBy.MFDFEF, data = toBytes("3F20"))
|
| | | for aid in SCardELS.aids:
|
| | | try:
|
| | | self.card.SelectFile(by = SCardSelectFileBy.DFname, data = toBytes(aid), Le = 0)
|
| | | return True
|
| | | return self.card.cdAID(aid) |
| | | except:
|
| | | pass |
| | | |
| | | raise Exception('ELS AID not available')
|
| | | return False
|
| | |
|
| | | def readCert(self):
|
| | | self.card.SelectFile(by = SCardSelectFileBy.childEF, data = toBytes("0001"), Le = 0)
|
| | | return self.card.ReadBinaryAll()
|
| | | data = self.card.readBinaryEF("0001") |
| | | return data |
| | |
|
| | | def readData(self):
|
| | | self.card.SelectFile(by = SCardSelectFileBy.childEF, data = toBytes("0002"), Le = 0)
|
| | | return self.card.ReadBinaryAll()
|
| | | data = self.card.readBinaryEF("0002") |
| | | return data |
| | |
|
| | | class SCardEMV:
|
| | | aids = [
|
| | |
| | | data, SW1, SW2 = self.card.ReadRecord(record = i, identifier = (sfi << 3) | SCardReadRecordIdentifier.P1isRecordNumber | SCardReadRecordIdentifier.ReadP1)
|
| | | records.append(SCardTLV.decode(data))
|
| | | except SCardResponseException as e:
|
| | | if e.SW1 != 0x6A or e.SW2 != 0x83:
|
| | | if e.SW1 != 0x6A or (e.SW2 != 0x83 and e.SW2 != 0x88): |
| | | raise SCardResponseException(e.SW1, e.SW2)
|
| | |
|
| | | return self.card.SelectFile(by = SCardSelectFileBy.DFname, data = records[0][0x70][0x61][0x4f], Le = 0x00)
|
| | |
| | | data, SW1, SW2 = self.card.ReadRecord(record = i, identifier = (sfi << 3) | SCardReadRecordIdentifier.P1isRecordNumber | SCardReadRecordIdentifier.ReadP1)
|
| | | SCardTLV.display(SCardTLV.decode(data))
|
| | | except SCardResponseException as e:
|
| | | if e.SW1 != 0x6A or e.SW2 != 0x83:
|
| | | if e.SW1 != 0x6A or (e.SW2 != 0x83 and e.SW2 != 0x88): |
| | | raise SCardResponseException(e.SW1, e.SW2)
|
| | |
|
| | | def readData(self):
|
| | |
| | | first = tag >> 8
|
| | | second = tag & 255
|
| | |
|
| | | try: |
| | | data, SW1, SW2 = self.card.GetData(CLA = 0x80, P1 = first, P2 = second)
|
| | | SCardTLV.display(SCardTLV.decode(data))
|
| | | except SCardResponseException as e: |
| | | if e.SW1 != 0x6A or (e.SW2 != 0x83 and e.SW2 != 0x88): |
| | | raise SCardResponseException(e.SW1, e.SW2) |
| | |
|
| | | def PIN(self, data = ""):
|
| | | data, SW1, SW2 = self.card.Verify(codeType = SCardVerifyCodeTypeEMV.plaintext, data = SCardEMVPINEncode.plaintext(data))
|
| | |
|
| | |
|
| | | ELS = 1
|
| | | ELS = 0 |
| | |
|
| | | if ELS:
|
| | | try:
|
| | |
| | | els = SCardELS(card)
|
| | |
|
| | | els.selectAID()
|
| | | SCardTLV.decode(els.readCert())
|
| | | SCardTLV.decode(els.readData())
|
| | | cert = toASCIIString(els.readCert()) |
| | | |
| | | openssl = subprocess.Popen(['openssl', 'x509', '-text', '-noout', '-inform', 'DER'], |
| | | stdin = subprocess.PIPE, stdout = subprocess.PIPE) |
| | | stdout, stderr = openssl.communicate(cert) |
| | | |
| | | print "" |
| | | print stdout |
| | | print "" |
| | | |
| | | data = decoder.decode(toASCIIString(els.readData()))[0] |
| | | data_signatureType = data.getComponentByPosition(0) |
| | | data_signature = data.getComponentByPosition(1) |
| | | assert(data_signatureType.asTuple() == univ.ObjectIdentifier('1.2.840.113549.1.7.2').asTuple()) |
| | | |
| | | data_signature_version = data_signature.getComponentByPosition(0) |
| | | assert(data_signature_version >= 3) |
| | | data_signature_algorithms = data_signature.getComponentByPosition(1) |
| | | data_signature_data = data_signature.getComponentByPosition(2) |
| | | data_signature_info = data_signature.getComponentByPosition(data_signature_version) |
| | | assert(data_signature_info != None) |
| | | |
| | | data_signature_data_type = data_signature_data.getComponentByPosition(0) |
| | | data_signature_data_data = data_signature_data.getComponentByPosition(1) |
| | | assert(data_signature_data_type.asTuple() == univ.ObjectIdentifier('1.2.616.1.101.4.1.1.1').asTuple()) |
| | | |
| | | els = data_signature_data_data.asOctets() |
| | | els = decoder.decode(els)[0] |
| | | els_version = els.getComponentByPosition(0) |
| | | assert(els_version == 1) |
| | | els_serialNumber = els.getComponentByPosition(1) |
| | | els_university = els.getComponentByPosition(2) |
| | | els_surnames = els.getComponentByPosition(3) |
| | | els_surnames_tuple = [str(els_surnames.getComponentByPosition(i)) for i in range(len(els_surnames))] |
| | | els_surnames_printable = ' '.join(els_surnames_tuple) |
| | | els_names = els.getComponentByPosition(4) |
| | | els_names_tuple = [str(els_names.getComponentByPosition(i)) for i in range(len(els_names))] |
| | | els_names_printable = ' '.join(els_names_tuple) |
| | | els_studentNumber = els.getComponentByPosition(5) |
| | | els_editId = els.getComponentByPosition(6) |
| | | els_personalNumber = els.getComponentByPosition(7) |
| | | els_expiry = els.getComponentByPosition(8) |
| | | |
| | | print "Uczelnia: " + els_university |
| | | print "Nazwisko: " + els_surnames_printable |
| | | print "Imię: " + els_names_printable |
| | | print "Album: " + els_studentNumber |
| | | print "PESEL: " + els_personalNumber |
| | | print "Ważność: " + els_expiry |
| | | print "Edycja: " + els_editId |
| | | except (KeyboardInterrupt, SystemExit):
|
| | | pass
|
| | | except:
|