def continueTransaction(continue_trans_tag=CONTINUE_TRANS_TAG): log.log('continueTransaction') continue_tpl = (0xE0, continue_trans_tag) conn.send([0xDE, 0xD2, 0x00, 0x00], continue_tpl) while True: status, buf, uns = getAnswer(False) #Don't ignore unsolicited if status != 0x9000: log.logerr('Transaction terminated with status ', hex(status)) return -1, status, buf, uns tlv = TLVParser(buf) #optional E6 (Status) template, reporting why Terminal is in wait state if tlv.tagCount(0xE6) != 0: log.log('transaction in wait state ', TLVParser(buf)) log.log('PIN Entry is being performed, waiting for user input') #handling to allow user to break from PIN entry to continue test print( 'PIN entry modification, press PC key \'A\' to abort, \'B\' to bypass or \'C\' to cancel' ) while True: if kbhit(): key = getch() log.log('key press ', key) if key == 'a' or key == 'A': log.logerr('PIN entry aborting') abortDevice() break if key == 'b' or key == 'B': log.logerr('PIN entry bypassing') verifyPIN(P1=0xFF) break if key == 'c' or key == 'C': log.logerr('PIN entry cancelling') verifyPIN(P1=0x00) break if conn.is_data_avail(): break # Has user attempted PIN entry, proceed to evaluation of results continue else: #Status result if tlv.tagCount(0xE3): log.log('transaction approved') return TRANSACTION_APPROVED, status, buf, uns if tlv.tagCount(0xE4): log.log('online request, transaction must be verified online') return ONLINE_REQUESTED, status, buf, uns if tlv.tagCount(0xE5): log.log('transaction declined') return TRANSACTION_DECLINED, status, buf, uns
def processEMV(tid): #Create localtag for transaction start_trans_tag = [ [(0x9F, 0x02), b'\x00\x00\x00\x00\x50\x00'], [(0x9A), b'\x04\x01\x01'], [(0x9C), b'\x00'], [(0x9F, 0x21), b'\x01\x01\x01'], [(0x9F, 0x41), b'\x00\x01'], [(0x5F, 0x2A), b'\x08\x26'], [(0xDF, 0xA2, 0x18), b'\x00'], [(0xDF, 0xA2, 0x14), b'\x01'], [(0xDF, 0xA2, 0x04), b'\x00'] # Manual app selection!! ] start_templ = (0xE0, start_trans_tag) #Start transaction conn.send([0xDE, 0xD1, 0x00, 0x00], start_templ) while True: #sleep(1) #conn.send([0xD0, 0xFF, 0x00, 0x00]) status, buf, uns = getEMVAnswer() if status != 0x9000: if status == 0x9F28: return processMagstripeFallback(tid) else: log.logerr('Transaction terminated with status ', hex(status)) return -1 if uns and status == 0x9000: tlv = TLVParser(buf) if tlv.tagCount(0xE6) != 0: log.log('Multi application card!') continue else: log.log('Ignoring unsolicited packet ', tlv) continue else: tlv = TLVParser(buf) if tlv.tagCount(0x50) > 1 and tlv.tagCount((0x9F, 0x06)) > 1: # This is app selection stuff appLabels = tlv.getTag(0x50) appAIDs = tlv.getTag((0x9F, 0x06)) log.log('We have ', len(appLabels), ' applications') if len(appLabels) != len(appAIDs): log.logerr('Invalid response: AID count ', len(appAIDs), ' differs from Labels count ', len(appLabels)) exit(-1) for i in range(len(appLabels)): log.log('App ', i + 1, ': AID ', hexlify(appAIDs[i]), ', label ', str(appLabels[i])) sel = -1 while True: #sels = input('Choose one app: ') #try: # sel = int(sels.strip()) #except: # print('invalid entry!!!') #if sel > 0 and sel <= len(appLabels): break #print(' Invalid selection, please pick valid number! ') # Note: The below will work for up to 9 apps... if kbhit(): try: sel = ord(getch()) except: print('invalid key!') #log.log('key press ', sel) if sel > 0x30 and sel <= 0x30 + len(appLabels): sel -= 0x30 # to number (0 .. x) break elif sel == 27: conn.send([0xD0, 0xFF, 0x00, 0x00]) status, buf, uns = getAnswer() log.logerr('Transaction aborted') return -1 print(' Invalid selection, please pick valid number! ') if conn.is_data_avail(): status, buf, uns = getEMVAnswer() if status != 0x9000: log.logerr('Transaction terminated with status ', hex(status)) return -1 break if sel >= 0: sel = sel - 1 log.log('Selected ', sel) app_sel_tags = [[(0x50), bytearray(appLabels[sel])], [(0x9F, 0x06), bytearray(appAIDs[sel])]] app_sel_templ = (0xE0, app_sel_tags) conn.send([0xDE, 0xD2, 0x00, 0x00], app_sel_templ) log.log('App selected, waiting for response...') continue break #Let's check VSP tlv = TLVParser(buf) vspDecrypt(tlv, tid) #print(TLVParser(buf)) #Continue transaction continue_tran_tag = [[(0x9F, 0x02), [0x00, 0x00, 0x00, 0x00, 0x54, 0x00]], [(0x5F, 0x2A), [0x09, 0x78]], [(0xC2), [0x36, 0x35]], [(0xDF, 0xA2, 0x18), [0x00]], [(0xDF, 0xA3, 0x07), [0x03, 0xE8]], [(0xC0), [0x01]], [(0x91), [ 0x37, 0xDD, 0x29, 0x75, 0xC2, 0xB6, 0x68, 0x2D, 0x00, 0x12 ]]] continue_tpl = (0xE0, continue_tran_tag) conn.send([0xDE, 0xD2, 0x00, 0x00], continue_tpl) while True: status, buf, uns = getEMVAnswer() if status != 0x9000: log.logerr('Transaction terminated with status ', hex(status)) return -1 tlv = TLVParser(buf) if uns and status == 0x9000: #print(tlv) if tlv.tagCount(0xE6) != 0: log.log('PIN Entry is being performed, waiting again') print( 'PIN Entry, press \'A\' to abort, \'B\' to bypass or \'C\' to cancel' ) while True: #sleep(1) validKey = False if kbhit(): key = getch() log.log('key press ', key) if key == 'a' or key == 'A': log.logerr('aborting') conn.send([0xD0, 0xFF, 0x00, 0x00]) validKey = True if key == 'b' or key == 'B': log.logerr('bypassing') conn.send([0xDE, 0xD5, 0xFF, 0x01]) validKey = True if key == 'c' or key == 'C': log.logerr('cancelling') conn.send([0xDE, 0xD5, 0x00, 0x00]) validKey = True if validKey: status, buf, uns = getAnswer( stopOnErrors=False ) # Wait for confirmation, then break to wait for response if status == 0x9000: break else: continue else: continue if conn.is_data_avail(): break continue else: log.log('Ignoring unsolicited packet ', tlv) continue else: if tlv.tagCount(0xE3): log.log("Transaction approved offline") return 1 else: if tlv.tagCount(0xE5): log.log("Transaction declined offline") return 2 else: break # If we get here, we received Online Request. Continue with positive response. conn.send([0xDE, 0xD2, 0x00, 0x00]) status, buf, uns = getEMVAnswer( True) # Ignore unsolicited automatically here if status != 0x9000: log.logerr('Online Request has failed', hex(status)) return -1 tlv = TLVParser(buf) if tlv.tagCount(0xE3): log.log("Transaction approved") return 1 if tlv.tagCount(0xE5): log.log("Transaction declined") return 2 return 3
def processTransaction(): req_unsolicited = conn.connect() if req_unsolicited: #Receive unsolicited log.log('Waiting for unsolicited') status, buf, uns = getAnswer(False) log.log('Unsolicited', TLVParser(buf)) #Send reset device conn.send([0xD0, 0x00, 0x00, 0x01]) status, buf, uns = getAnswer() tlv = TLVParser(buf) tid = tlv.getTag((0x9F, 0x1e)) if len(tid): tid = str(tid[0], 'iso8859-1') log.log('Terminal TID: ', tid) else: tid = '' log.logerr('Invalid TID (or cannot determine TID)!') #Send clear display conn.send([0xD2, 0x01, 0x01, 0x01]) status, buf, uns = getAnswer() #Monitor card and keyboard status conn.send([0xD0, 0x60, 0x1D, 0x03]) status, buf, uns = getAnswer(False) ctls = initContactless() if (ctls): # Start Contactless transaction start_ctls_tag = [ [(0x9F, 0x02), b'\x00\x00\x00\x00\x01\x00'], [(0x9A), b'\x12\x01\x01'], [(0x9C), b'\x00'], [(0x9F, 0x21), b'\x01\x01\x01'], # [(0x9F,0x41), b'\x00\x01' ], [(0x5F, 0x2A), b'\x08\x26'], [(0x9F, 0x1A), b'\x08\x26'] ] start_templ = (0xE0, start_ctls_tag) conn.send([0xC0, 0xA0, 0x01, 0x00], start_templ) log.log('Starting Contactless transaction') status, buf, uns = getAnswer() else: promptForCard() log.log('**** WAIT FOR CARD INSERTION / TAP / SWIPE ****') tranType = 0 result = 0 ignoreSwipe = False while True: print( 'Waiting for card event - please tap, insert or swipe. If you wish to perform Manual Entry, press space' ) while True: #sleep(1) if kbhit(): key = getch() log.log('key press ', key) if key == ' ': log.log('manual entry') if ctls: # Cancel Contactless first log.log('Cancelling contactless') conn.send([0xC0, 0xC0, 0x00, 0x00]) status, buf, uns = getAnswer() status, buf, uns = getAnswer( False ) # Ignore unsolicited as the answer WILL BE unsolicited... performManualEntry(tid) break if conn.is_data_avail(): break continue if conn.is_data_avail(): status, buf, uns = getAnswer(False) # Get unsolicited ONLY if uns: # Check for insertion unsolicited message tlv = TLVParser(buf) if tlv.tagCount(0x48): cardState = EMVCardState(tlv) magState = MagstripeCardState(tlv) if ctls and (cardState == EMV_CARD_INSERTED or magState == MAGSTRIPE_TRACKS_AVAILABLE ): # Ignore failed swipes # Cancel Contactless first log.log('Cancelling contactless') conn.send([0xC0, 0xC0, 0x00, 0x00]) status, buf, uns = getAnswer() status, buf, uns = getAnswer( False ) # Ignore unsolicited as the answer WILL BE unsolicited... if cardState == EMV_CARD_INSERTED: log.log("Card inserted, process EMV transaction!") result = processEMV(tid) tranType = 1 break else: if cardState == ERROR_UNKNOWN_CARD: log.log('Unknown card type ') continue if not ignoreSwipe: if magState == ERROR_UNKNOWN_CARD: log.logerr( 'Swipe has failed, there are no tracks!') continue else: if magState == MAGSTRIPE_TRACKS_AVAILABLE: log.log('Card swiped!') vspDecrypt(tlv, tid) S1DecryptData(tlv) tranType = 2 break log.log("Waiting for next occurrance!") continue # Check for unsolicited keyboard status if tlv.tagCount((0xDF, 0xA2, 0x05)): kbd_tag_val = tlv.getTag((0xDF, 0xA2, 0x05), TLVParser.CONVERT_INT)[0] log.log("Keyboard status, keypress ", hex(kbd_tag_val), 'h') continue if tlv.tagCount(0xE3) or tlv.tagCount(0xE5): log.log("Approved contactless EMV transaction!") # todo: vsp decrypt! vspDecrypt(tlv, tid) S1DecryptData(tlv) tranType = 4 break if tlv.tagCount(0xE7): vspDecrypt(tlv, tid) S1DecryptData(tlv) processCtlsContinue() tranType = 3 break if tlv.tagCount(0xE4): vspDecrypt(tlv, tid) S1DecryptData(tlv) processCtlsContinue() tranType = 5 break if status != 0x9000: if status == 0x9F33: # Fallforward to ICC / Swipe promptForCard() # No need to exit the loop - swipe is not active now continue else: if status == 0x9F34: # Fallforward to ICC only promptForCard() # No need to exit the loop - ctls is not active now, but we have to disable swipes ignoreSwipe = True continue log.logerr("Invalid packet detected, ignoring it!") print('E4: ', tlv.tagCount(0xE4)) print(tlv) else: break # After loop if tranType == 1: # If card still inserted, ask for removal conn.send([0xD0, 0x60, 0x01, 0x00]) status, buf, uns = getAnswer(False) # Get unsolicited tlv = TLVParser(buf) if EMVCardState(tlv) == EMV_CARD_INSERTED: log.log("Card inserted, asking to remove it") removeEMVCard() #Reset display - regardless of tx type conn.send([0xD2, 0x01, 0x01, 0x01]) log.log('*** RESET DISPLAY ***') status, buf, uns = getAnswer()
def processEMV(tid): #Create localtag for transaction start_trans_tag = [[(0x9F, 0x02), b'\x00\x00\x00\x10\x04\x00'], [(0x9A), b'\x04\x01\x01'], [(0x9C), b'\x00'], [(0x9F, 0x21), b'\x01\x01\x01'], [(0x9F, 0x41), b'\x00\x01'], [(0x5F, 0x2A), b'\x08\x26'], [(0xDF, 0xA2, 0x18), b'\x00'], [(0xDF, 0xA2, 0x14), b'\x01'], [(0xDF, 0xA2, 0x04), b'\x01']] start_templ = (0xE0, start_trans_tag) #Start transaction conn.send([0xDE, 0xD1, 0x00, 0x00], start_templ) while True: status, buf, uns = getEMVAnswer() if status != 0x9000: if status == 0x9F28: return processMagstripeFallback(tid) else: log.logerr('Transaction terminated with status ', hex(status)) return -1 if uns and status == 0x9000: tlv = TLVParser(buf) if tlv.tagCount(0xE6) != 0: log.log('Multi application card!') continue else: log.log('Ignoring unsolicited packet ', tlv) continue else: break #Let's check VSP tlv = TLVParser(buf) vspDecrypt(tlv, tid) S1DecryptData(tlv) #print(TLVParser(buf)) #Continue transaction continue_tran_tag = [[(0x9F, 0x02), [0x00, 0x00, 0x00, 0x00, 0x54, 0x00]], [(0x5F, 0x2A), [0x09, 0x78]], [(0xC2), [0x30, 0x30]], [(0xDF, 0xA2, 0x18), [0x00]], [(0xDF, 0xA3, 0x07), [0x03, 0xE8]], [(0xC0), [0x01]], [(0x8A), [0x59, 0x32]], [(0x91), [ 0x37, 0xDD, 0x29, 0x75, 0xC2, 0xB6, 0x68, 0x2D, 0x00, 0x12 ]]] continue_tpl = (0xE0, continue_tran_tag) conn.send([0xDE, 0xD2, 0x00, 0x00], continue_tpl) while True: status, buf, uns = getEMVAnswer() if status != 0x9000: log.logerr('Transaction terminated with status ', hex(status)) return -1 tlv = TLVParser(buf) if uns and status == 0x9000: #print(tlv) if tlv.tagCount(0xE6) != 0: log.log('PIN Entry is being performed, waiting again') print( 'PIN Entry, press \'A\' to abort, \'B\' to bypass or \'C\' to cancel' ) while True: #sleep(1) if kbhit(): key = getch() log.log('key press ', key) if key == 'a' or key == 'A': log.logerr('aborting') conn.send([0xD0, 0xFF, 0x00, 0x00]) break if key == 'b' or key == 'B': log.logerr('bypassing') conn.send([0xDE, 0xD5, 0xFF, 0x01]) status, buf, uns = getAnswer( ) # Wait for confirmation, then break to wait for response break if key == 'c' or key == 'C': log.logerr('cancelling') conn.send([0xDE, 0xD5, 0x00, 0x00]) status, buf, uns = getAnswer( ) # Wait for confirmation, then break to wait for response break if conn.is_data_avail(): break continue else: log.log('Ignoring unsolicited packet ', tlv) continue else: if tlv.tagCount(0xE3): log.log("Transaction approved offline") return 1 else: if tlv.tagCount(0xE5): log.log("Transaction declined offline") return 2 else: break # If we get here, we received Online Request. Continue with positive response. conn.send([0xDE, 0xD2, 0x00, 0x00]) status, buf, uns = getEMVAnswer( True) # Ignore unsolicited automatically here if status != 0x9000: log.logerr('Online Request has failed', hex(status)) return -1 tlv = TLVParser(buf) if tlv.tagCount(0xE3): log.log("Transaction approved") return 1 if tlv.tagCount(0xE5): log.log("Transaction declined") return 2 return 3