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
예제 #3
0
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()
예제 #4
0
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