Reading data from credit cards and Polish Electronic Student Cards (ELS)
Jacek Kowalski
2015-03-08 7083b9929e5cc163e7cadea10b9ba03a2b23a54c
commit | author | age
7083b9 1 # -*- coding: utf-8 -*-
JK 2 from __future__ import print_function
3
4 import smartcard.CardRequest
5 import smartcard.CardConnectionObserver
6 import smartcard.ExclusiveTransmitCardConnection
7 import smartcard.pcsc.PCSCPart10
8
9 from smartcard.util import toHexString, toASCIIBytes, toBytes, toASCIIString
10
11 import collections, sys, traceback, time
12
13 class SCardDebug:
14     DEBUG = 0
15     WARNING = 1
16     ERROR = 2
17     report = 0
18     def __init__(self, level, message):
19         if level >= SCardDebug.report:
20             print(message)
21
22 class SCardConnectionObserver(smartcard.CardConnectionObserver.CardConnectionObserver):
23     def update( self, cardconnection, ccevent ):
24         if 'connect' == ccevent.type:
25             SCardDebug(SCardDebug.DEBUG, 'connecting to ' + cardconnection.getReader())
26         elif 'disconnect' == ccevent.type:
27             SCardDebug(SCardDebug.DEBUG, 'disconnecting from ' + cardconnection.getReader())
28         elif 'command' == ccevent.type:
29             if isinstance(ccevent.args[0], collections.Sequence):
30                 SCardDebug(SCardDebug.DEBUG, 'send ' + toHexString(ccevent.args[0]))
31         elif 'response' == ccevent.type:
32             if isinstance(ccevent.args[0], collections.Sequence):
33                 SCardDebug(SCardDebug.DEBUG, 'recv ' + toHexString(ccevent.args[0]) + " " + toHexString(ccevent.args[-2:]))
34
35 class SCardInternalException(Exception):
36     SCardEMV_1PAY_Not_Supported = 123514
37     def __init__(self, code, msg):
38         self.code = code
39         self.msg = msg
40     
41     def __str__(self):
42         return "Internal Exception " + self.code + ": " + self.msg
43
44 class SCardResponseException(Exception):
45     errors = {
46         0x6700 : "Wrong Lc",
47         0x6984 : "Referenced data invalidated",
48         0x6A81 : "Function not supported",
49         0x6A82 : "File not found",
50         0x6A86 : "Incorrect parameters P1, P2",
51         0x6A87 : "Lc inconsistent"
52     }
53     def __init__(self, SW1, SW2):
54         self.SW1 = SW1
55         self.SW2 = SW2
56         code = (SW1 << 8) + SW2
57         if code in SCardResponseException.errors:
58             self.msg = SCardResponseException.errors[code]
59         else:
60             self.msg = "Unknown error"
61     def __str__(self):
62         return self.msg
63
64 class SCardTLV:
65     EXTENDED = 0x1F
66     MSB = 0x80
67     CONSTRUCTED = 0x20
68     
69     debug = True
70     
71     tags = {
72         0x02: ["Integer", ""],
73         0x03: ["Bit string", ""],
74         0x04: ["Octet string", ""],
75         0x05: ["Null", ""],
76         0x06: ["Object identifier", ""],
77         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)"],
78         0x4F: ["Application Identifier (AID) - card", "Identifies the application as described in ISO/IEC 7816-5"],
79         0x50: ["Application Label", "Mnemonic associated with the AID according to ISO/IEC 7816-5"],
80         0x57: ["Track 2 Equivalent Data", "Contains the data elements of track 2 according to ISO/IEC 7813, excluding start sentinel, end sentinel, and Longitudinal Redundancy Check (LRC), as follows: Primary Account Number (n, var. up to 19) Field Separator (Hex 'D') (b) Expiration Date (YYMM) (n 4) Service Code (n 3) Discretionary Data (defined by individual payment systems) (n, var.) Pad with one Hex 'F' if needed to ensure whole bytes (b)"],
81         0x5A: ["Application Primary Account Number (PAN)", "Valid cardholder account number"],
82         0x5F20: ["Cardholder Name", "Indicates cardholder name according to ISO 7813"],
83         0x5F24: ["Application Expiration Date", "Date after which application expires"],
84         0x5F25: ["Application Effective Date", "Date from which the application may be used"],
85         0x5F28: ["Issuer Country Code", "Indicates the country of the issuer according to ISO 3166"],
86         0x5F2A: ["Transaction Currency Code", "Indicates the currency code of the transaction according to ISO 4217"],
87         0x5F2D: ["Language Preference", "1-4 languages stored in order of preference, each represented by 2 alphabetical characters according to ISO 639 Note: EMVCo strongly recommends that cards be personalised with data element '5F2D' coded in lowercase, but that terminals accept the data element whether it is coded in upper or lower case."],
88         0x5F30: ["Service Code", "Service code as defined in ISO/IEC 7813 for track 1 and track 2"],
89         0x5F34: ["Application Primary Account Number (PAN) Sequence Number", "Identifies and differentiates cards with the same PAN"],
90         0x5F36: ["Transaction Currency Exponent", "Indicates the implied position of the decimal point from the right of the transaction amount represented according to ISO 4217"],
91         0x5F50: ["Issuer URL", "The URL provides the location of the Issuer's Library Server on the Internet."],
92         0x5F53: ["International Bank Account Number (IBAN)", "Uniquely identifies the account of a customer at a financial institution as defined in ISO 13616."],
93         0x5F54: ["Bank Identifier Code (BIC)", "Uniquely identifies a bank as defined in ISO 9362."],
94         0x5F55: ["Issuer Country Code (alpha2 format)", "Indicates the country of the issuer as defined in ISO 3166 (using a 2 character alphabetic code)"],
95         0x5F56: ["Issuer Country Code (alpha3 format)", "Indicates the country of the issuer as defined in ISO 3166 (using a 3 character alphabetic code)"],
96         0x61: ["Application Template", "Contains one or more data objects relevant to an application directory entry according to ISO/IEC 7816-5"],
97         0x6F: ["File Control Information (FCI) Template", "Identifies the FCI template according to ISO/IEC 7816-4"],
98         0x70: ["EMV Proprietary Template", "Template proprietary to the EMV specification"],
99         0x71: ["Issuer Script Template 1", "Contains proprietary issuer data for transmission to the ICC before the second GENERATE AC command"],
100         0x72: ["Issuer Script Template 2", "Contains proprietary issuer data for transmission to the ICC after the second GENERATE AC command"],
101         0x73: ["Directory Discretionary Template", "Issuer discretionary part of the directory according to ISO/IEC 7816-5"],
102         0x77: ["Response Message Template Format 2", "Contains the data objects (with tags and lengths) returned by the ICC in response to a command"],
103         0x80: ["Response Message Template Format 1", "Contains the data objects (without tags and lengths) returned by the ICC in response to a command"],
104         0x81: ["Amount, Authorised (Binary)", "Authorised amount of the transaction (excluding adjustments)"],
105         0x82: ["Application Interchange Profile", "Indicates the capabilities of the card to support specific functions in the application"],
106         0x83: ["Command Template", "Identifies the data field of a command message"],
107         0x84: ["Dedicated File (DF) Name", "Identifies the name of the DF as described in ISO/IEC 7816-4"],
108         0x86: ["Issuer Script Command", "Contains a command for transmission to the ICC"],
109         0x87: ["Application Priority Indicator", "Indicates the priority of a given application or group of applications in a directory"],
110         0x88: ["Short File Identifier (SFI)", "Identifies the SFI to be used in the commands related to a given AEF or DDF. The SFI data object is a binary field with the three high order bits set to zero."],
111         0x89: ["Authorisation Code", "Value generated by the authorisation authority for an approved transaction"],
112         0x8A: ["Authorisation Response Code", "Code that defines the disposition of a message"],
113         0x8C: ["Card Risk Management Data Object List 1 (CDOL1)", "List of data objects (tag and length) to be passed to the ICC in the first GENERATE AC command"],
114         0x8D: ["Card Risk Management Data Object List 2 (CDOL2)", "List of data objects (tag and length) to be passed to the ICC in the second GENERATE AC command"],
115         0x8E: ["Cardholder Verification Method (CVM) List", "Identifies a method of verification of the cardholder supported by the application"],
116         0x8F: ["Certification Authority Public Key Index", "Identifies the certification authority's public key in conjunction with the RID"],
117         0x90: ["Issuer Public Key Certificate", "Issuer public key certified by a certification authority"],
118         0x91: ["Issuer Authentication Data", "Data sent to the ICC for online issuer authentication"],
119         0x92: ["Issuer Public Key Remainder", "Remaining digits of the Issuer Public Key Modulus"],
120         0x93: ["Signed Static Application Data", "Digital signature on critical application parameters for SDA"],
121         0x94: ["Application File Locator (AFL)", "Indicates the location (SFI, range of records) of the AEFs related to a given application"],
122         0x95: ["Terminal Verification Results", "Status of the different functions as seen from the terminal"],
123         0x97: ["Transaction Certificate Data Object List (TDOL)", "List of data objects (tag and length) to be used by the terminal in generating the TC Hash Value"],
124         0x98: ["Transaction Certificate (TC) Hash Value", "Result of a hash function specified in Book 2, Annex B3.1"],
125         0x99: ["Transaction Personal Identification Number (PIN) Data", "Data entered by the cardholder for the purpose of the PIN verification"],
126         0x9A: ["Transaction Date", "Local date that the transaction was authorised"],
127         0x9B: ["Transaction Status Information", "Indicates the functions performed in a transaction"],
128         0x9C: ["Transaction Type", "Indicates the type of financial transaction, represented by the first two digits of ISO 8583:1987 Processing Code"],
129         0x9D: ["Directory Definition File (DDF) Name", "Identifies the name of a DF associated with a directory"],
130         0x9F01: ["Acquirer Identifier", "Uniquely identifies the acquirer within each payment system"],
131         0x9F02: ["Amount, Authorised (Numeric)", "Authorised amount of the transaction (excluding adjustments)"],
132         0x9F03: ["Amount, Other (Numeric)", "Secondary amount associated with the transaction representing a cashback amount"],
133         0x9F04: ["Amount, Other (Binary)", "Secondary amount associated with the transaction representing a cashback amount"],
134         0x9F05: ["Application Discretionary Data", "Issuer or payment system specified data relating to the application"],
135         0x9F06: ["Application Identifier (AID) - terminal", "Identifies the application as described in ISO/IEC 7816-5"],
136         0x9F07: ["Application Usage Control", "Indicates issuer's specified restrictions on the geographic usage and services allowed for the application"],
137         0x9F08: ["Application Version Number", "Version number assigned by the payment system for the application"],
138         0x9F09: ["Application Version Number", "Version number assigned by the payment system for the application"],
139         0x9F0B: ["Cardholder Name Extended", "Indicates the whole cardholder name when greater than 26 characters using the same coding convention as in ISO 7813"],
140         0x9F0D: ["Issuer Action Code - Default", "Specifies the issuer's conditions that cause a transaction to be rejected if it might have been approved online, but the terminal is unable to process the transaction online"],
141         0x9F0E: ["Issuer Action Code - Denial", "Specifies the issuer's conditions that cause the denial of a transaction without attempt to go online"],
142         0x9F0F: ["Issuer Action Code - Online", "Specifies the issuer's conditions that cause a transaction to be transmitted online"],
143         0x9F10: ["Issuer Application Data", "Contains proprietary application data for transmission to the issuer in an online transaction"],
144         0x9F11: ["Issuer Code Table Index", "Indicates the code table according to ISO/IEC 8859 for displaying the Application Preferred Name"],
145         0x9F12: ["Application Preferred Name", "Preferred mnemonic associated with the AID"],
146         0x9F13: ["Last Online Application Transaction Counter (ATC) Register", "ATC value of the last transaction that went online"],
147         0x9F14: ["Lower Consecutive Offline Limit", "Issuer-specified preference for the maximum number of consecutive offline transactions for this ICC application allowed in a terminal with online capability"],
148         0x9F15: ["Merchant Category Code", "Classifies the type of business being done by the merchant, represented according to ISO 8583:1993 for Card Acceptor Business Code"],
149         0x9F16: ["Merchant Identifier", "When concatenated with the Acquirer Identifier, uniquely identifies a given merchant"],
150         0x9F17: ["Personal Identification Number (PIN) Try Counter", "Number of PIN tries remaining"],
151         0x9F18: ["Issuer Script Identifier", "Identification of the Issuer Script"],
152         0x9F1A: ["Terminal Country Code", "Indicates the country of the terminal, represented according to ISO 3166"],
153         0x9F1B: ["Terminal Floor Limit", "Indicates the floor limit in the terminal in conjunction with the AID"],
154         0x9F1C: ["Terminal Identification", "Designates the unique location of a terminal at a merchant"],
155         0x9F1D: ["Terminal Risk Management Data", "Application-specific value used by the card for risk management purposes"],
156         0x9F1E: ["Interface Device (IFD) Serial Number", "Unique and permanent serial number assigned to the IFD by the manufacturer"],
157         0x9F1F: ["Track 1 Discretionary Data", "Discretionary part of track 1 according to ISO/IEC 7813"],
158         0x9F20: ["Track 2 Discretionary Data", "Discretionary part of track 2 according to ISO/IEC 7813"],
159         0x9F21: ["Transaction Time", "Local time that the transaction was authorised"],
160         0x9F22: ["Certification Authority Public Key Index", "Identifies the certification authority's public key in conjunction with the RID"],
161         0x9F23: ["Upper Consecutive Offline Limit", "Issuer-specified preference for the maximum number of consecutive offline transactions for this ICC application allowed in a terminal without online capability"],
162         0x9F26: ["Application Cryptogram", "Cryptogram returned by the ICC in response of the GENERATE AC command"],
163         0x9F27: ["Cryptogram Information Data", "Indicates the type of cryptogram and the actions to be performed by the terminal"],
164         0x9F2D: ["Integrated Circuit Card (ICC) PIN Encipherment Public Key Certificate", "ICC PIN Encipherment Public Key certified by the issuer"],
165         0x9F2E: ["Integrated Circuit Card (ICC) PIN Encipherment Public Key Exponent", "ICC PIN Encipherment Public Key Exponent used for PIN encipherment"],
166         0x9F2F: ["Integrated Circuit Card (ICC) PIN Encipherment Public Key Remainder", "Remaining digits of the ICC PIN Encipherment Public Key Modulus"],
167         0x9F32: ["Issuer Public Key Exponent", "Issuer public key exponent used for theverification of the Signed Static Application Data and the ICC Public Key Certificate"],
168         0x9F33: ["Terminal Capabilities", "Indicates the card data input, CVM, and security capabilities of the terminal"],
169         0x9F34: ["Cardholder Verification Method (CVM) Results", "Indicates the results of the last CVM performed"],
170         0x9F35: ["Terminal Type", "Indicates the environment of the terminal, its communications capability, and its operational control"],
171         0x9F36: ["Application Transaction Counter (ATC)", "Counter maintained by the application in the ICC (incrementing the ATC is managed by the ICC)"],
172         0x9F37: ["Unpredictable Number", "Value to provide variability and uniqueness to the generation of a cryptogram"],
173         0x9F38: ["Processing Options Data Object List (PDOL)", "Contains a list of terminal resident data objects (tags and lengths) needed by the ICC in processing the GET PROCESSING OPTIONS command"],
174         0x9F39: ["Point-of-Service (POS) Entry Mode", "Indicates the method by which the PAN was entered, according to the first two digits of the ISO 8583:1987 POS Entry Mode"],
175         0x9F3A: ["Amount, Reference Currency", "Authorised amount expressed in the reference currency"],
176         0x9F3B: ["Application Reference Currency", "1-4 currency codes used between the terminal and the ICC when the Transaction Currency Code is different from the Application Currency Code; each code is 3 digits according to ISO 4217"],
177         0x9F3C: ["Transaction Reference Currency Code", "Code defining the common currency used by the terminal in case the Transaction Currency Code is different from theApplication Currency Code"],
178         0x9F3D: ["Transaction Reference Currency Exponent", "Indicates the implied position of the decimal point from the right of the transaction amount, with the Transaction Reference Currency Code represented according to ISO 4217"],
179         0x9F40: ["Additional Terminal Capabilities", "Indicates the data input and output capabilities of the terminal"],
180         0x9F41: ["Transaction Sequence Counter", "Counter maintained by the terminal that is incremented by one for each transaction"],
181         0x9F42: ["Application Currency Code", "Indicates the currency in which the account is managed according to ISO 4217"],
182         0x9F43: ["Application Reference Currency Exponent", "Indicates the implied position of the decimal point from the right of the amount, for each of the 1-4 reference currencies represented according to ISO 4217"],
183         0x9F44: ["Application Currency Exponent", "Indicates the implied position of the decimal point from the right of the amount represented according to ISO 4217"],
184         0x9F45: ["Data Authentication Code", "An issuer assigned value that is retained by the terminal during the verification process of the Signed Static Application Data"],
185         0x9F46: ["Integrated Circuit Card (ICC) Public Key Certificate", "ICC Public Key certified by the issuer"],
186         0x9F47: ["Integrated Circuit Card (ICC) Public Key Exponent", "ICC Public Key Exponent used for the verification of the Signed Dynamic Application Data"],
187         0x9F48: ["Integrated Circuit Card (ICC) Public Key Remainder", "Remaining digits of the ICC Public Key Modulus"],
188         0x9F49: ["Dynamic Data Authentication Data Object List (DDOL)", "List of data objects (tag and length) to be passed to the ICC in the INTERNAL AUTHENTICATE command"],
189         0x9F4A: ["Static Data Authentication Tag List", "List of tags of primitive data objects defined in this specification whose value fields are to be included in the Signed Static or Dynamic Application Data"],
190         0x9F4B: ["Signed Dynamic Application Data", "Digital signature on critical application parameters for DDA or CDA"],
191         0x9F4C: ["ICC Dynamic Number", "Time-variant number generated by the ICC, to be captured by the terminal"],
192         0x9F4D: ["Log Entry", "Provides the SFI of the Transaction Log file and its number of records"],
193         0x9F4E: ["Merchant Name and Location", "Indicates the name and location of the merchant"],
194         0x9F4F: ["Log Format", "List (in tag and length format) of data objects representing the logged data elements that are passed to the terminal when a transaction  log record is read"],
195         0xA5: ["File Control Information (FCI) Proprietary Template", "Identifies the data object proprietary to this specification in the FCI template according to ISO/IEC 7816-4"],
196         0xBF0C: ["File Control Information (FCI) Issuer Discretionary Data", "Issuer discretionary part of the FCI"],
197     }
198     
199     specialTags = {
200         0x8C: 1,
201         0x8D: 1,
202         0x9F38: 1,
203         0x9F4F: 1,
204     }
205     
206     @staticmethod
207     def decodeTag(data):
208         tag = data.pop()
209         constructed = (tag & SCardTLV.CONSTRUCTED != 0x00)
210         
211         if tag & SCardTLV.EXTENDED == SCardTLV.EXTENDED:
212             tag = (tag << 8) | data.pop()
213             while tag & SCardTLV.MSB != 0x00:
214                 tag = (tag << 8) | data.pop()
215         if tag == 0x9f8004:
216             tag = 0x9f80
217             data.append(0x04)
218         if SCardTLV.debug:
219             print('Got tag: ' + toHexString(tag))
220         
221         length = data.pop()
222         if length == 0x80:
223             length = -1
224         elif length & SCardTLV.MSB != 0x00:
225             toread = length ^ SCardTLV.MSB
226             length = 0
227             for i in range(toread):
228                 length = (length << 8) | data.pop()
229         
230         return [tag, length, constructed]
231     
232     @staticmethod
233     def decode(data):
234         if isinstance(data, basestring):
235             data = toASCIIBytes(data)
236         
237         data.reverse()
238         
239         ret = {}
240         
241         while len(data) > 0:
242             [tag, length, constructed] = SCardTLV.decodeTag(data)
243             
244             if length == -1:
245                 length = rsearch(data, [0, 0])
246             
247             read = data[-length:]
248             read.reverse()
249             data[-length:] = []
250             
251             if constructed:
252                 read = SCardTLV.decode(read)
253             
254             if tag in ret:
255                 ret[tag].push(read)
256             else:
257                 ret[tag] = [ read ]
258         
259         return ret
260     
261     @staticmethod
262     def displayTag(data, intend=""):
263         if data[0] in SCardTLV.tags:
264             print(intend + SCardTLV.tags[data[0]][0] + " [" + hex(data[0]) + "], length "+str(data[1]))
265         else:
266             print(intend + "UNKNOWN TAG [" + hex(data[0]) + "], length "+str(data[1]))
267     
268     @staticmethod
269     def display(data, intend="", singleline = None):
270         for tag, value in data.items():
271             if tag in SCardTLV.tags:
272                 print(intend + SCardTLV.tags[tag][0] + " [" + hex(tag) + "]:")
273             else:
274                 print(intend + "UNKNOWN TAG [" + hex(tag) + "]:")
275             
276             if tag in SCardTLV.specialTags:
277                 value.reverse()
278                 while len(value) > 0:
279                     SCardTLV.displayTag(SCardTLV.decodeTag(value), intend+"\t")
280             elif isinstance(value, dict):
281                 SCardTLV.display(value, intend+"\t")
282             else:
283                 print(intend+"\t"+toHexString(value)+" ("+toASCIIString(value)+")")
284
285 class SCardSelectFileBy:
286     MFDFEF = 0x00
287     childDF = 0x01
288     childEF = 0x02
289     parentDF = 0x03
290     DFname = 0x04
291     fromMF = 0x08
292     fromDF = 0x09
293
294 class SCardSelectFileRecord:
295     first = 0x00
296     last = 0x01
297     next = 0x02
298     previous = 0x03
299     
300     FCI = 0x00
301     FCP = 0x04
302     FMD = 0x08
303
304 class SCardReadRecordIdentifier:
305     P1isRecordNumber = 0x04
306     ReadP1 = 0x00
307     ReadP1toLast = 0x01
308     ReadLasttoP1 = 0x02
309     
310     P1isRecordIdentifier = 0x00
311     ReadFirstOccurrence = 0x00
312     ReadLastOccurrence = 0x01
313     ReadNextOccurrence = 0x02
314     ReadPreviousOccurrence = 0x03
315
316 class SCardVerifyCodeType:
317     general = 0x00
318     specific = 0x80
319
320 class SCardVerifyCodeTypeEMV:
321     plaintext = 0x80
322     enciphered = 0x88
323
324 class SCardReader:
325     GET_FIRMWARE_VERSION = 0x2078
326     DISPLAY_LCD_MESSAGE = 0x2079
327     READ_KEY = 0x2080
328     
329     def __init__(self, conn):
330         self.connection = conn
331     
332     def getFeatures(self):
333         print(smartcard.pcsc.PCSCPart10.getFeatureRequest(self.connection))
334
335 class SCardEMVPINEncode:
336     @staticmethod
337     def plaintext(digits = ""):
338         if not isinstance(digits, str):
339             raise Exception("PIN must be passed as a string.")
340         
341         if len(digits) > 12:
342             raise Exception("PIN must not be longer than 12 digits.")
343         
344         for i in digits:
345             if not i.isdigit():
346                 raise Exception('PIN must have digits only!')
347         
348         digits = [int(i) for i in digits]
349         digits.reverse()
350         
351         send = []
352         send.append(0x20 | len(digits))
353         
354         while len(digits) > 0:
355             first = digits.pop()
356             if len(digits) > 0:
357                 second = digits.pop()
358             else:
359                 second = 0xf
360             
361             send.append(first << 4 | second)
362         
363         while len(send) < 8:
364             send.append(0xff)
365         
366         return send
367
368 class SCardSecurePIN:
369     bmFormatStringBits = 0x00
370     bmFormatStringBytes = 0x80
371     
372     bmFormatStringPINPositionMask = 0b01111000
373     
374     bmFormatStringJustifyLeft = 0x00
375     bmFormatStringJustifyRight = 0x04
376     
377     bmFormatStringBinary = 0x00
378     bmFormatStringBCD = 0x01
379     bmFormatStringASCII = 0x02
380     
381     def __init__(self, conn):
382         self.connection = conn
383     
384     # TODO: Implement various hardware pin-entry options
385
386 class SCard:
387     def __init__(self, serv):
388         observer = SCardConnectionObserver()
389         serv.connection.addObserver(observer)
390         serv.connection.connect(protocol = smartcard.CardConnection.CardConnection.T0_protocol|smartcard.CardConnection.CardConnection.T1_protocol)
391         exclusive = smartcard.ExclusiveTransmitCardConnection.ExclusiveTransmitCardConnection(serv.connection)
392         exclusive.lock()
393         time.sleep(0.2)
394         print("inserted", toHexString(serv.connection.getATR()))
395         
396         self.service = serv
397         self.connection = serv.connection
398         self.exclusive = exclusive
399         self.observer = observer
400     
401     def __del__(self):
402         self.exclusive.unlock()
403         self.connection.deleteObserver(self.observer)
404     
405     def _sendAPDU(self, adpu = []):
406         response, SW1, SW2 = self.exclusive.transmit(adpu)
407         if SW1 != 0x90:
408             raise SCardResponseException(SW1, SW2)
409         
410         return response, SW1, SW2
411     
412     def GetData(self, CLA = 0x00, P1 = 0x00, P2 = 0x00, Le = 0x00):
413         try:
414             return self._sendAPDU([CLA, 0xCA, P1, P2, Le])
415         except SCardResponseException as e:
416             if e.SW1 == 0x6C:
417                 return self.GetData(CLA, P1, P2, Le = e.SW2)
418             else:
419                 raise e
420     
421     def GetProcessingOption(self, CLA = 0x80, TLV = None):
422         adpu = [CLA, 0xA8, 0x00, 0x00]
423         
424         adpu.append(len(TLV))
425         adpu.extend(TLV)
426         
427         adpu.append(0x00)
428         
429         return self._sendAPDU(adpu)
430     
431     def ReadBinary(self, CLA = 0x00, offset = 0x00, Le = 0x00):
432         try:
433             return self._sendAPDU([CLA, 0xB0, (offset >> 8) & 0x7F, offset & 0xFF, Le])
434         except SCardResponseException as e:
435             if e.SW1 == 0x6C:
436                 return self.ReadBinary(CLA, offset, Le = e.SW2)
437             else:
438                 raise e
439     
440     def ReadBinaryAll(self, CLA = 0x00):
441         data = []
442         while len(data) <= 0x7FFF:
443             try:
444                 response, SW1, SW2 = self.ReadBinary(CLA, len(data))
445                 data += response
446             except SCardResponseException as e:
447                 if e.SW1 == 0x6B:
448                     break
449                 raise e
450         return data
451     
452     def ReadRecord(self, CLA = 0x00, record = 0x00, identifier = 0x00, Le = 0x00):
453         try:
454             return self._sendAPDU([CLA, 0xB2, record, identifier, Le])
455         except SCardResponseException as e:
456             if e.SW1 == 0x6C:
457                 return self.ReadRecord(CLA, record, identifier, Le = e.SW2)
458             else:
459                 raise e
460     
461     def SelectFile(self, CLA = 0x00, by = 0x00, record = 0x00, data = None, Le = None):
462         adpu = [CLA, 0xA4, by, record]
463         
464         if isinstance(data, basestring):
465             data = toASCIIBytes(data)
466         
467         if isinstance(data, list):
468             adpu.append(len(data))
469             adpu.extend(data)
470         
471         if Le != None:
472             adpu.append(Le)
473         
474         return self._sendAPDU(adpu)
475     
476     def Verify(self, CLA=0x00, P1 = 0x00, codeType = 0x00, data = None):
477         adpu = [CLA, 0x20, P1, codeType]
478         
479         if isinstance(data, basestring):
480             data = toASCIIBytes(data)
481         
482         if isinstance(data, list):
483             adpu.append(len(data))
484             adpu.extend(data)
485         
486         return self._sendAPDU(adpu)
487
488 class SCardHandler:
489     @staticmethod
490     def getCard():
491         request = smartcard.CardRequest.CardRequest(newcardonly=True, timeout=None)
492         print("Insert card...")
493         service = request.waitforcard()
494         time.sleep(0.5)
495         return SCard(service)
496
497 class SCardELS:
498     aids = [
499         "D6160000300101"
500     ]
501     
502     def __init__(self, card):
503         self.card = card
504     
505     def selectAID(self):
506         #self.card.SelectFile(by = SCardSelectFileBy.MFDFEF, data = toBytes("3F20"))
507         for aid in SCardELS.aids:
508             try:
509                 self.card.SelectFile(by = SCardSelectFileBy.DFname, data = toBytes(aid), Le = 0)
510                 return True
511             except:
512                 raise Exception('ELS AID not available')
513         return False
514     
515     def readCert(self):
516         self.card.SelectFile(by = SCardSelectFileBy.childEF, data = toBytes("0001"), Le = 0)
517         return self.card.ReadBinaryAll()
518     
519     def readData(self):
520         self.card.SelectFile(by = SCardSelectFileBy.childEF, data = toBytes("0002"), Le = 0)
521         return self.card.ReadBinaryAll()
522
523 class SCardEMV:
524     aids = [
525         "A0000000031010",
526         "A0000000032010",
527         "A0000000032020",
528         "A0000000038010",
529         "A0000000041010",
530         "A0000000049999",
531         "A0000000043060",
532         "A0000000046000",
533         "A0000000050001",
534         "A0000000050002",
535         "A00000002501",
536         "A0000005241010",
537         "A0000001523010",
538         "A0000002771010",
539         "A00000006510",
540         "A0000000291010",
541         "A0000001211010",
542         "A0000001410001",
543         "A0000001544442",
544         "A0000003591010028001"
545     ]
546     
547     def __init__(self, card):
548         self.card = card
549     
550     def selectRoot(self):
551         self.card.SelectFile(by = SCardSelectFileBy.MFDFEF, data = toBytes("3F20"))
552     
553     def selectAIDby1PAY(self):
554         try:
555             SCardDebug(SCardDebug.DEBUG, "Trying 1PAY.SYS.DDF01...")
556             data, SW1, SW2 = self.card.SelectFile(by = SCardSelectFileBy.DFname, data = "1PAY.SYS.DDF01", Le = 0x00)
557             SCardDebug(SCardDebug.DEBUG, "... success")
558             
559             fileControl = SCardTLV.decode(data)
560             SCardTLV.display(fileControl);
561             
562             records = []
563             sfi = fileControl[0x6F][0xA5][0x88][0]
564             
565             try:
566                 for i in range(1, 255):
567                     data, SW1, SW2 = self.card.ReadRecord(record = i, identifier = (sfi << 3) | SCardReadRecordIdentifier.P1isRecordNumber | SCardReadRecordIdentifier.ReadP1)
568                     records.append(SCardTLV.decode(data))
569             except SCardResponseException as e:
570                 if e.SW1 != 0x6A or e.SW2 != 0x83:
571                     raise SCardResponseException(e.SW1, e.SW2)
572             
573             return self.card.SelectFile(by = SCardSelectFileBy.DFname, data = records[0][0x70][0x61][0x4f], Le = 0x00)
574         except SCardResponseException:
575             SCardDebug(SCardDebug.DEBUG, "1PAY.SYS.DDF01 not supported, skipping...")
576             raise SCardInternalException(SCardInternalException.SCardEMV_1PAY_Not_Supported, "1PAY.SYS.DDF01 not supported")
577     
578     def selectAIDbruteforce(self):
579         for i in SCardEMV.aids:
580             aid = toBytes(i)
581             try:
582                 SCardDebug(SCardDebug.DEBUG, "Trying AID " + i + "...")
583                 out = self.card.SelectFile(by = SCardSelectFileBy.DFname, data = aid, Le = 0x00)
584                 SCardDebug(SCardDebug.DEBUG, "... supported")
585                 return out
586             except SCardResponseException:
587                 SCardDebug(SCardDebug.DEBUG, "... not supported")
588         raise Exception("Cannot select EMV AID")
589     
590     def selectAID(self):
591         #try:
592             #self.selectRoot()
593             #out = self.selectAIDby1PAY()
594         #except SCardInternalException:
595             try:
596                 #self.selectRoot()
597                 out = self.selectAIDbruteforce()
598             except SCardInternalException:
599                 raise Exception("Cannot select EMV AID")
600         
601             return SCardTLV.decode(out[0])
602     
603     def getPDOL(self, AIDdata):
604         PDOL = []
605         if 0x6F in AIDdata:
606             if 0xA5 in AIDdata[0x6F]:
607                 if 0x9F38 in AIDdata[0x6F][0xA5]:
608                     PDOL = emv.decodePDOL(AIDdata[0x6F][0xA5][0x9F38])
609         
610         return PDOL
611     
612     def decodePDOL(self, PDOL=[]):
613         if len(PDOL) == 0:
614             return []
615         
616         PDOL = PDOL[:]
617         PDOL.reverse()
618         
619         tags = []
620         while len(PDOL) > 0:
621             tags.append(SCardTLV.decodeTag(PDOL)[0:2])
622         
623         return tags
624     
625     def getProcessingOptions(self, decodedPDOL=None):
626         toSend = []
627         knownTags = {
628             #0x9F1A: [0x06, 0x16]
629         }
630         
631         for tag in decodedPDOL:
632             temporary = [0]*tag[1]
633             if tag[0] in knownTags:
634                 temporary[0:len(knownTags[tag[0]])] = knownTags[tag[0]]
635                 temporary = temporary[0:tag[1]]
636             toSend += temporary
637         
638         toSend = [0x83, len(toSend)] + toSend
639         
640         SCardDebug(SCardDebug.DEBUG, "Getting processing options...")
641         out = self.card.GetProcessingOption(TLV = toSend)
642         return SCardTLV.decode(out[0])
643     
644     def readRecords(self, sfi = 0x01):
645         try:
646             for i in range(1, 255):
647                 data, SW1, SW2 = self.card.ReadRecord(record = i, identifier = (sfi << 3) | SCardReadRecordIdentifier.P1isRecordNumber | SCardReadRecordIdentifier.ReadP1)
648                 SCardTLV.display(SCardTLV.decode(data))
649         except SCardResponseException as e:
650             if e.SW1 != 0x6A or e.SW2 != 0x83:
651                 raise SCardResponseException(e.SW1, e.SW2)
652     
653     def readData(self):
654         tags = [
655             0x9F36,
656             0x9F17,
657             0x9F13,
658             0x9F4F
659         ]
660         
661         for tag in tags:
662             first = tag >> 8
663             second = tag & 255
664             
665             data, SW1, SW2 = self.card.GetData(CLA = 0x80, P1 = first, P2 = second)
666             SCardTLV.display(SCardTLV.decode(data))
667     
668     def PIN(self, data = ""):
669         data, SW1, SW2 = self.card.Verify(codeType = SCardVerifyCodeTypeEMV.plaintext, data = SCardEMVPINEncode.plaintext(data))
670
671
672 ELS = 1
673
674 if ELS:
675     try:
676         cards = SCardHandler()
677         card = cards.getCard()
678         els = SCardELS(card)
679         
680         els.selectAID()
681         SCardTLV.decode(els.readCert())
682         SCardTLV.decode(els.readData())
683     except (KeyboardInterrupt, SystemExit):
684         pass
685     except:
686         traceback.print_exc(file=sys.stdout)
687 else:
688     try:
689         """
690         card = SCardHandler.getCard()
691         reader = SCardReader(card.connection)
692         reader.getFeatures()
693         """
694         
695         cards = SCardHandler()
696         card = cards.getCard()
697         emv = SCardEMV(card)
698         
699         AIDdata = emv.selectAID()
700         SCardTLV.display(AIDdata)
701         
702         PDOL = emv.getPDOL(AIDdata)
703         procOpts = emv.getProcessingOptions(PDOL);
704         SCardTLV.display(procOpts)
705         
706         sfi = 0x01
707         
708         if 0x77 in procOpts:
709             sfi = (procOpts[0x77][0x94][0] >> 3)
710         
711         emv.readRecords(sfi)
712         emv.readData()
713     except (KeyboardInterrupt, SystemExit):
714         pass
715     except:
716         traceback.print_exc(file=sys.stdout)