def retrieve_get_data_items(connection):
    
    item_tags = [
                 
        (0x1F, 0xFF), # APP MENU OPTIONS                 
        (0xFF, 0x20),
                 
        (0x9F, 0x36), # ATC
        (0x9F, 0x13), # last online ATC register
        (0x9F, 0x17), # pin try counter
        (0x9F, 0x4F)  # log format
        
        ]
    
    tlvs = []
    
    for (p1, p2) in item_tags:
        
        tag = '%00X' % p1 + '%00X' % p2                            
        
        ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=GET_DATA.cla, ins=GET_DATA.ins, p1=p1, p2=p2, le=0x00)

        if (len(ret_data) == 0):
            logging.info('%s - sw1:sw2 = %s:%s' % (tag, '%00X' % sw1, '%00X' % sw2))
            continue
        
        tlv = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys())
        
        tlvs.append(tlv)
        
    return tlvs
Beispiel #2
0
def retrieve_get_data_items(connection):

    item_tags = [
        (0x1F, 0xFF),  # APP MENU OPTIONS                 
        (0xFF, 0x20),
        (0x9F, 0x36),  # ATC
        (0x9F, 0x13),  # last online ATC register
        (0x9F, 0x17),  # pin try counter
        (0x9F, 0x4F)  # log format
    ]

    tlvs = []

    for (p1, p2) in item_tags:

        tag = '%00X' % p1 + '%00X' % p2

        ret_data, sw1, sw2 = select_and_requery(connection=connection,
                                                cla=GET_DATA.cla,
                                                ins=GET_DATA.ins,
                                                p1=p1,
                                                p2=p2,
                                                le=0x00)

        if (len(ret_data) == 0):
            #            logging.info('%s - sw1:sw2 = %s:%s' % (tag, '%00X' % sw1, '%00X' % sw2))
            continue

        tlv = tlv_utils.parse_tlv(ret_data,
                                  known_tags=tag_meanings.emv_tags.keys())

        tlvs.append(tlv)

    return tlvs
def select_application_by_aid(connection, aid):
    
    ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=SELECT.cla, ins=SELECT.ins, p1=0x04, p2=0x00, data=aid, le=0x00)        
    
    if (len(ret_data) == 0):
        return None

    if DO_LOG:
        logging.info('\n' + 'SELECT (A)DF BY DF Name / AID')
        logging.info('AID = %s' % bit_tools.byte_list_to_hex_string(aid))
        for x in report_on_reply(sw1, sw2, ret_data):
            logging.info(x)
   
    # Table 45 (EMV 4.2 Book 1) - FCI Returned by ADF Selection
    #
    # FCI Template
    # 6f 17 8407a0000000041010a50c500a4d617374657243617264
        # DF Name = AID
        # 84 07 a0000000041010
        # FCI PROP TEMPLATE
        # a5 0c 500a4d617374657243617264
            # APP LABEL
            # 50 0a 4d617374657243617264   

    tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys())
    
    if DO_LOG:
        logging.info('')
        for line in tlv_tree.report():
            logging.info(line)
            
    return tlv_tree
Beispiel #4
0
def select_application_by_aid(connection, aid):
    
    ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=SELECT.cla, ins=SELECT.ins, p1=0x04, p2=0x00, data=aid, le=0x00)        
    
    if (len(ret_data) == 0):
        return None

    if DO_LOG:
        logging.info('\n' + 'SELECT (A)DF BY DF Name / AID')
        logging.info('AID = %s' % bit_tools.byte_list_to_hex_string(aid))
        for x in report_on_reply(sw1, sw2, ret_data):
            logging.info(x)
   
    # Table 45 (EMV 4.2 Book 1) - FCI Returned by ADF Selection
    #
    # FCI Template
    # 6f 17 8407a0000000041010a50c500a4d617374657243617264
        # DF Name = AID
        # 84 07 a0000000041010
        # FCI PROP TEMPLATE
        # a5 0c 500a4d617374657243617264
            # APP LABEL
            # 50 0a 4d617374657243617264   

    tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys())
    
    if DO_LOG:
        logging.info('')
        for line in tlv_tree.report():
            logging.info(line)
            
    return tlv_tree
Beispiel #5
0
def get_application_ids_from_pse_elementary_dir_file_for_sfi(connection, sfi):
    '''
    returns aids = list of aids
    '''
    aids = []

    # READ RECORD, PASSING IN SFI RETURNED BY PSE SELECTION
    record_number = 0x01

    # REFERENCE CONTROL PARAMETER
    # LSB3 => P1 is a Record Number
    # 5 high order bits used to encode SFI
    ref_control_param = (0x04 | (sfi << 3))

    ret_data, sw1, sw2 = select_and_requery(connection=connection,
                                            cla=READ_RECORD.cla,
                                            ins=READ_RECORD.ins,
                                            p1=record_number,
                                            p2=ref_control_param,
                                            le=0x00)

    #    if DO_LOG:
    #        logging.info('\n' + 'READ RECORD [PASSING IN SHORT FILE IDENTIFIER = SFI]')
    #        for x in report_on_reply(sw1, sw2, ret_data):
    #            logging.info(x)
    #
    # 70 1a 61 18 4f 07 a0 00 00 00 04 10 10 50 0a 4d 61 73 74 65 72 43 61 72 64 87 01 01
    # 70 = [Payment System] Directory
    # 70 1a 61184f07a0000000041010500a4d617374657243617264870101
    # 61 = Directory Entry = ADF or DDF
    # 61 18 4f07a0000000041010500a4d617374657243617264870101
    # 4f = ADF Name = App ID = AID
    # 4f 07 a0000000041010
    # 50 = Application Label
    # 50 0a 4d617374657243617264 [= MasterCard]
    # 87 = Application Priority Indicator
    # 87 01 01

    tlv_tree = tlv_utils.parse_tlv(ret_data,
                                   known_tags=tag_meanings.emv_tags.keys())
    #
    #    if DO_LOG:
    #        logging.info('')
    #        for line in tlv_tree.report():
    #            logging.info(line)
    #
    nodes = tlv_tree.get_nodes_for_qtag('70.61.4F')
    for node in nodes:
        aids.append(node.value_byte_list)

    # TAG 79 => ISO 7816-6, and is part of EMV spec = Nedbank American Express

    return aids
def get_application_ids_from_pse_elementary_dir_file_for_sfi(connection, sfi):
    '''
    returns aids = list of aids
    '''
    aids = []

    # READ RECORD, PASSING IN SFI RETURNED BY PSE SELECTION
    record_number = 0x01    
    
    # REFERENCE CONTROL PARAMETER
    # LSB3 => P1 is a Record Number
    # 5 high order bits used to encode SFI    
    ref_control_param = (0x04 | (sfi << 3))
    
    ret_data, sw1, sw2 = select_and_requery(connection=connection,
                                            cla=READ_RECORD.cla, 
                                            ins=READ_RECORD.ins, 
                                            p1=record_number, 
                                            p2=ref_control_param, 
                                            le=0x00)
        
    if DO_LOG:
        logging.info('\n' + 'READ RECORD [PASSING IN SHORT FILE IDENTIFIER = SFI]')
        for x in report_on_reply(sw1, sw2, ret_data):
            logging.info(x)       
    
    # 70 1a 61 18 4f 07 a0 00 00 00 04 10 10 50 0a 4d 61 73 74 65 72 43 61 72 64 87 01 01
    # 70 = [Payment System] Directory
    # 70 1a 61184f07a0000000041010500a4d617374657243617264870101
    # 61 = Directory Entry = ADF or DDF
    # 61 18 4f07a0000000041010500a4d617374657243617264870101
    # 4f = ADF Name = App ID = AID
    # 4f 07 a0000000041010
    # 50 = Application Label
    # 50 0a 4d617374657243617264 [= MasterCard]
    # 87 = Application Priority Indicator
    # 87 01 01 
    
    tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys())
    
    if DO_LOG:
        logging.info('')
        for line in tlv_tree.report():
            logging.info(line)
    
    nodes = tlv_tree.get_nodes_for_qtag('70.61.4F')
    for node in nodes:
        aids.append(node.value_byte_list)   
    
    # TAG 79 => ISO 7816-6, and is part of EMV spec = Nedbank American Express
    
    return aids
Beispiel #7
0
def read_record_for_sfi(connection, sfi, record_number):
    '''
    returns tlv_tree or None
    '''
    global cardnumber
    tlv_tree = None

    ref_control_param = (sfi << 3) | 0x04

    ret_data, sw1, sw2 = select_and_requery(connection=connection,
                                            cla=READ_RECORD.cla,
                                            ins=READ_RECORD.ins,
                                            p1=record_number,
                                            p2=ref_control_param,
                                            le=0x00)

    #    if DO_LOG:
    #        logging.info('\n' + 'READ RECORD')
    #        for x in report_on_reply(sw1, sw2, ret_data):
    #            logging.info(x)

    tlv_tree = tlv_utils.parse_tlv(ret_data,
                                   known_tags=tag_meanings.emv_tags.keys())

    #    if DO_LOG:
    ##        logging.info('')
    for line in tlv_tree.report():

        if line[0] == '7' and line[1] == '0' and line[2] == '.' and line[
                3] == '5' and line[4] == 'A':
            #            h="h: "
            #            a = line.find(h)
            #            logging.info(a)
            line = line[90:113]
            line = line.replace('.', '')
            cardnumber = line
            # retcardnum(cardnumber)
            logging.info(line)
            break
def read_record_for_sfi(connection, sfi, record_number):
    '''
    returns tlv_tree or None
    '''
    
    tlv_tree = None
    
    ref_control_param = (sfi << 3) | 0x04
            
    ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=READ_RECORD.cla, ins=READ_RECORD.ins, p1=record_number, p2=ref_control_param, le=0x00)
    
    if DO_LOG:
        logging.info('\n' + 'READ RECORD')
        for x in report_on_reply(sw1, sw2, ret_data):
            logging.info(x)
    
    tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys())
    
    if DO_LOG:
        logging.info('')
        for line in tlv_tree.report():
            logging.info(line)
    
    # PARSE DOL FIELDS                    
    for tag_str in tlv_tree.distinct_tag_list():
        if (tag_str in tag_meanings.DOL_TAGS):
            node = tlv_tree.get_nodes_for_tag(tag_str)[0]
            dol_info, repeated_tag_counts = tlv_utils.parse_concatted_dol_list(node.value_byte_list)
            
            if DO_LOG:
                s = 'DOL List: %s - %s' % (tag_str, tag_meanings.emv_tags[tag_str])
                logging.info('-'*len(s))
                logging.info(s)
                logging.info('-'*len(s))
                for dol_tag in dol_info.keys():
                    logging.info('%s - %s - 0x%00X' % (dol_tag, tag_meanings.emv_tags[dol_tag], dol_info[dol_tag]))

    return tlv_tree
Beispiel #9
0
def read_record_for_sfi(connection, sfi, record_number):
    '''
    returns tlv_tree or None
    '''
    
    tlv_tree = None
    
    ref_control_param = (sfi << 3) | 0x04
            
    ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=READ_RECORD.cla, ins=READ_RECORD.ins, p1=record_number, p2=ref_control_param, le=0x00)
    
    if DO_LOG:
        logging.info('\n' + 'READ RECORD')
        for x in report_on_reply(sw1, sw2, ret_data):
            logging.info(x)
    
    tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys())
    
    if DO_LOG:
        logging.info('')
        for line in tlv_tree.report():
            logging.info(line)
    
    # PARSE DOL FIELDS                    
    for tag_str in tlv_tree.distinct_tag_list():
        if (tag_str in tag_meanings.DOL_TAGS):
            node = tlv_tree.get_nodes_for_tag(tag_str)[0]
            dol_info, repeated_tag_counts = tlv_utils.parse_concatted_dol_list(node.value_byte_list)
            
            if DO_LOG:
                s = 'DOL List: %s - %s' % (tag_str, tag_meanings.emv_tags[tag_str])
                logging.info('-'*len(s))
                logging.info(s)
                logging.info('-'*len(s))
                for dol_tag in dol_info.keys():
                    logging.info('%s - %s - 0x%00X' % (dol_tag, tag_meanings.emv_tags[dol_tag], dol_info[dol_tag]))

    return tlv_tree
def get_pse_sfi(connection):
    '''
    attempt to retrieve SFI (Short File Identifier) 
    of the Directory Elementary File 
    of PSE (Payment System Environment)
    
    SUCCESS
    returns (sfi, tlv_tree, report)
    FAILURE
    returns (None, error_message)
    
    refer
    STRUCTURE OF THE PSE = 12.2.2
    APPLICATION SELECTION = EMV 4.2 Book 1 12 - page 135 / 151
    '''

    report = []

    # 3rd LSB bit-flag set => select by name    
    ref_control_param = 0x04
    
    # 00 => first-or-only-occurrence
    # 02 => next occurrence
    select_options = 0x00    
    
    data = [ord(c) for c in PSE_DDF_NAME]
    
    ret_data, sw1, sw2 = select_and_requery(connection=connection, 
        cla=SELECT.cla, ins=SELECT.ins,
        p1=ref_control_param, 
        p2=select_options, 
        data=data, 
        le=0x00)
    
    select_pse_error_tags = {
        '6A81' : 'card blocked, or select command not supported',
        '6A82' : 'no PSE / file not found',
        '6283' : 'PSE is blocked',
        }
    
    report.append('Attempting to Select PSE')
    report.append('DIRECTORY DEFINITION FILE = 1PAY.SYS.DDF01')
    for x in report_on_reply(sw1, sw2, ret_data):
        report.append(x)
    
    hex = '%00X%00X' % (sw1, sw2)
    # NO PSE
    if hex in select_pse_error_tags:
        report.append('Error - %s' % select_pse_error_tags[hex])
    # PSE FOUND
    else:
        # EMV 4.2 Book 1  - 11.3 Select Command-Response APDUs, Table 44
        # FCI Template returned by successful selection of a DDF
        # Response = 6f 19 84 0e 31 50 41 59 2e 53 59 53 2e 44 44 46 30 31 a5 07 88 01 01 9f 11 01 01
        
        # FCI Template
        # 6f 19 840e315041592e5359532e4444463031a5078801019f110101 (length = 50)
            # DF Name
            # 84 0e 315041592e5359532e4444463031
            # FCI Proprietary Template 
            # a5 07 8801019f110101
                # SFI of the Directory Elementary File
                # 88 01 01
                # Issuer Code Table Index
                # 9f11 01 01        
        
        tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys())
       
        report.append('')
        for line in tlv_tree.report():
            report.append(line)    
    
        # '88':'Short File Identifier (SFI)',
        node = tlv_tree.get_nodes_for_qtag('6F.A5.88')[0]
        sfi = node.value_byte_list[0]
        
        report.append('SFI for PSE - %s' % bit_tools.byte_list_to_hex_string([sfi]))
        
        return (sfi, tlv_tree, report)
    
    return (None, select_pse_error_tags[hex], report)
def get_afl_aip_via_processing_options(connection, pdol=None):
    '''
    return afl or None
    
    EMV 4.2 Book 3 - 6.5.8, 6.5.8.4
    - App Interchange Profile
    - Appp File Locator
    
    EMV 4.2 Book 3 5.4 = Data Object List - DOL
    
    ----------------------------------------------------------------------------------------------
    
    [ EMV 4.2 Book 3 - Application Specification - 10.1 Initiate Application Processing ]
    
    The PDOL is a list of tags and lengths of terminal-resident data elements needed by the ICC 
    in processing the GET PROCESSING OPTIONS command. Only data elements having the terminal as 
    the source of the data may be referenced in the PDOL. If the PDOL does not exist, the GET 
    PROCESSING OPTIONS command uses a command data field of '8300', indicating that the length 
    of the value field in the command data is zero.

    There may be some exceptions in the timing for this. For example, these bits could be set to 
    0 at the completion of the previous transaction or prior to application selection of this 
    transaction. The intent here is that the processing steps as described in the Application 
    Specification presume the bits have been initialised to 0.

    If the PDOL exists, the terminal extracts the PDOL from the FCI of the ADF and uses it to 
    create a concatenated list of data elements without tags or lengths. The rules specified 
    in section 5.4 apply to processing of the PDOL. If an amount field (either Amount, Authorised 
    or Amount, Other) is referenced in the PDOL and the terminal is unable to provide the amount 
    at this point in transaction processing, the amount field in the data element list shall be 
    filled with hexadecimal zeroes. The terminal issues the GET PROCESSING OPTIONS command using 
    either the command data field of '8300' (if there was no PDOL in the ICC) or a data object 
    constructed with a tag of '83' and the appropriate length according to BER-TLV encoding rules 
    and a value field that is the concatenated list of data elements resulting from processing the 
    PDOL.
    
    The card returns either:
    - The Application Interchange Profile the Application File Locator (identifying the files and 
    records containing the data to be used for the transaction), and status SW1 SW2 = '9000', or
    - Status SW1 SW2 = '6985' (Conditions of use not satisfied), indicating that the transaction 
    cannot be performed with this application.

    The format of the response message is given in section 6.5.8. If the status words '6985' are 
    returned, the terminal shall eliminate the current application from consideration and return to 
    the Application Selection function to select another application.
    '''    
    
    # APDU = GET PROCESSING OPTIONS
    data = default_dol = [0x83, 0x00] # tag = 83, length = 0
    
    if (pdol != None):
        data = [0x83]        
        
        concatted = []        
        tags_with_length = tlv_utils.parse_concatted_dol_list_to_ordered_list_of_tag_and_length(pdol)
        for (tag, tag_length) in tags_with_length:            
            
            # TERMINAL COUNTRY CODE
            if (tag == '9F1A'): 
                terminal_country_code_ZAR = [0x07, 0x10]
                concatted.extend(terminal_country_code_ZAR)
                
            # '81':'Amount Authorised (Binary)',
            # '9F02':'Amount Authorised (Numeric)',
            # '9F03':'Amount Other (Numeric)',
            # '9F04':'Amount Other (Binary)',
            
            elif (tag in ['81', '9F02', '9F03', '9F04']):
                for i in range(tag_length):
                    concatted.append(0x00)
            
            else:
                msg = '! Unknown PDOL Tag %s' % tag
                logging.info(msg)
                raise Exception(msg)
                    
        data.append(len(concatted))
        data.extend(concatted)    
    
    ret_data, sw1, sw2 = select_and_requery(connection=connection, 
                                            cla=GET_PROCESSING_OPTIONS.cla, 
                                            ins=GET_PROCESSING_OPTIONS.ins, 
                                            p1=0x00, 
                                            p2=0x00, 
                                            data=data, 
                                            le=0x00)
    
    if DO_LOG:
        logging.info('\n' + 'GET PROCESSING OPTIONS - REQUEST PDOL')
        for x in report_on_reply(sw1, sw2, ret_data):
            logging.info(x) 
    
    # 0x77 0x16 0x82 0x02 0x38 0x00 0x94 0x10 0x08 0x01 0x02 0x00 0x10 0x01 0x02 0x00 0x18 0x01 0x02 0x01 0x20 0x01 0x02 0x00
    # 77 = Format 2 Type Response
    # 77 16 82023800941008010200100102001801020120010200
    # 82 = AIP = Application Interchange Profile
    # 82 02 3800
    # 94 = AFL = Application File Locator
    # 94 10 08010200100102001801020120010200
    #
    # AFL = 08 01 02 00 
    #       10 01 02 00
    #       18 01 02 01
    #       20 01 02 00
    #                      SFI 1st Last OMA-Involved
    # 08 = 8  => 00001000 => 1  01   02           00 
    # 10 = 16 => 00010000 => 2  01   02           00 
    # 18 = 24 => 00011000 => 3  01   02           01
    # 20 = 32 => 00100000 => 4  01   02           00
    
    get_proc_options_format_1_tags = ['80']
    get_proc_options_format_2_tags = ['77', '82', '94']
    
    combined_tags = []
    combined_tags.extend(get_proc_options_format_1_tags)
    combined_tags.extend(get_proc_options_format_2_tags)
    
    '''
    hex_string = bit_tools.byte_list_to_hex_string(ret_data)
    file = open('c:/dev/logs/pdol.txt', 'w')
    file.write(hex_string + '\n')
    file.close()
    '''
    
    tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=combined_tags)
    
    afl = None
    
    # FORMAT 1 - Visa
    if (get_proc_options_format_1_tags[0] in tlv_tree.distinct_tag_list()):
        node = tlv_tree.get_nodes_for_qtag('80')[0]
        aip_afl = node.value_byte_list
        aip_length = 2
        aip = aip_afl[0:aip_length]
        afl = aip_afl[aip_length:]     
        
        if DO_LOG:
            logging.info('AIP_AFL = ' + '.'.join(['%02X' % b for b in aip_afl]))
            logging.info('AIP     = ' + '.'.join(['%02X' % b for b in aip]))
            logging.info('AFL     = ' + '.'.join(['%02X' % b for b in afl]))
    
    # FORMAT 2 - MasterCard
    else:
        node = tlv_tree.get_nodes_for_qtag('77.94')[0]
        afl = node.value_byte_list
        node = tlv_tree.get_nodes_for_qtag('77.82')[0]
        aip = node.value_byte_list
    
    if DO_LOG:
        logging.info('')
        for line in tlv_tree.report():
            logging.info(line)
        
    return afl, aip
Beispiel #12
0
def get_pse_sfi(connection):
    '''
    attempt to retrieve SFI (Short File Identifier) 
    of the Directory Elementary File 
    of PSE (Payment System Environment)
    
    SUCCESS
    returns (sfi, tlv_tree, report)
    FAILURE
    returns (None, error_message)
    
    refer
    STRUCTURE OF THE PSE = 12.2.2
    APPLICATION SELECTION = EMV 4.2 Book 1 12 - page 135 / 151
    '''

    report = []

    # 3rd LSB bit-flag set => select by name
    ref_control_param = 0x04

    # 00 => first-or-only-occurrence
    # 02 => next occurrence
    select_options = 0x00

    data = [ord(c) for c in PSE_DDF_NAME]

    ret_data, sw1, sw2 = select_and_requery(connection=connection,
                                            cla=SELECT.cla,
                                            ins=SELECT.ins,
                                            p1=ref_control_param,
                                            p2=select_options,
                                            data=data,
                                            le=0x00)

    select_pse_error_tags = {
        '6A81': 'card blocked, or select command not supported',
        '6A82': 'no PSE / file not found',
        '6283': 'PSE is blocked',
    }

    report.append('Attempting to Select PSE')
    report.append('DIRECTORY DEFINITION FILE = 1PAY.SYS.DDF01')
    for x in report_on_reply(sw1, sw2, ret_data):
        report.append(x)

    hex = '%00X%00X' % (sw1, sw2)
    # NO PSE
    if hex in select_pse_error_tags:
        report.append('Error - %s' % select_pse_error_tags[hex])
    # PSE FOUND
    else:
        # EMV 4.2 Book 1  - 11.3 Select Command-Response APDUs, Table 44
        # FCI Template returned by successful selection of a DDF
        # Response = 6f 19 84 0e 31 50 41 59 2e 53 59 53 2e 44 44 46 30 31 a5 07 88 01 01 9f 11 01 01

        # FCI Template
        # 6f 19 840e315041592e5359532e4444463031a5078801019f110101 (length = 50)
        # DF Name
        # 84 0e 315041592e5359532e4444463031
        # FCI Proprietary Template
        # a5 07 8801019f110101
        # SFI of the Directory Elementary File
        # 88 01 01
        # Issuer Code Table Index
        # 9f11 01 01

        tlv_tree = tlv_utils.parse_tlv(ret_data,
                                       known_tags=tag_meanings.emv_tags.keys())

        report.append('')
        for line in tlv_tree.report():
            report.append(line)

        # '88':'Short File Identifier (SFI)',
        node = tlv_tree.get_nodes_for_qtag('6F.A5.88')[0]
        sfi = node.value_byte_list[0]

        report.append('SFI for PSE - %s' %
                      bit_tools.byte_list_to_hex_string([sfi]))

        return (sfi, tlv_tree, report)

    return (None, select_pse_error_tags[hex], report)
Beispiel #13
0
def get_afl_aip_via_processing_options(connection, pdol=None):
    '''
    return afl or None
    
    EMV 4.2 Book 3 - 6.5.8, 6.5.8.4
    - App Interchange Profile
    - Appp File Locator
    
    EMV 4.2 Book 3 5.4 = Data Object List - DOL
    
    ----------------------------------------------------------------------------------------------
    
    [ EMV 4.2 Book 3 - Application Specification - 10.1 Initiate Application Processing ]
    
    The PDOL is a list of tags and lengths of terminal-resident data elements needed by the ICC 
    in processing the GET PROCESSING OPTIONS command. Only data elements having the terminal as 
    the source of the data may be referenced in the PDOL. If the PDOL does not exist, the GET 
    PROCESSING OPTIONS command uses a command data field of '8300', indicating that the length 
    of the value field in the command data is zero.

    There may be some exceptions in the timing for this. For example, these bits could be set to 
    0 at the completion of the previous transaction or prior to application selection of this 
    transaction. The intent here is that the processing steps as described in the Application 
    Specification presume the bits have been initialised to 0.

    If the PDOL exists, the terminal extracts the PDOL from the FCI of the ADF and uses it to 
    create a concatenated list of data elements without tags or lengths. The rules specified 
    in section 5.4 apply to processing of the PDOL. If an amount field (either Amount, Authorised 
    or Amount, Other) is referenced in the PDOL and the terminal is unable to provide the amount 
    at this point in transaction processing, the amount field in the data element list shall be 
    filled with hexadecimal zeroes. The terminal issues the GET PROCESSING OPTIONS command using 
    either the command data field of '8300' (if there was no PDOL in the ICC) or a data object 
    constructed with a tag of '83' and the appropriate length according to BER-TLV encoding rules 
    and a value field that is the concatenated list of data elements resulting from processing the 
    PDOL.
    
    The card returns either:
    - The Application Interchange Profile the Application File Locator (identifying the files and 
    records containing the data to be used for the transaction), and status SW1 SW2 = '9000', or
    - Status SW1 SW2 = '6985' (Conditions of use not satisfied), indicating that the transaction 
    cannot be performed with this application.

    The format of the response message is given in section 6.5.8. If the status words '6985' are 
    returned, the terminal shall eliminate the current application from consideration and return to 
    the Application Selection function to select another application.
    '''

    # APDU = GET PROCESSING OPTIONS
    data = default_dol = [0x83, 0x00]  # tag = 83, length = 0

    if (pdol != None):
        data = [0x83]

        concatted = []
        tags_with_length = tlv_utils.parse_concatted_dol_list_to_ordered_list_of_tag_and_length(
            pdol)
        for (tag, tag_length) in tags_with_length:

            # TERMINAL COUNTRY CODE
            if (tag == '9F1A'):
                terminal_country_code_ZAR = [0x07, 0x10]
                concatted.extend(terminal_country_code_ZAR)

            # '81':'Amount Authorised (Binary)',
            # '9F02':'Amount Authorised (Numeric)',
            # '9F03':'Amount Other (Numeric)',
            # '9F04':'Amount Other (Binary)',

            elif (tag in ['81', '9F02', '9F03', '9F04']):
                for i in range(tag_length):
                    concatted.append(0x00)

            else:
                msg = '! Unknown PDOL Tag %s' % tag
                logging.info(msg)
                raise Exception(msg)

        data.append(len(concatted))
        data.extend(concatted)

    ret_data, sw1, sw2 = select_and_requery(connection=connection,
                                            cla=GET_PROCESSING_OPTIONS.cla,
                                            ins=GET_PROCESSING_OPTIONS.ins,
                                            p1=0x00,
                                            p2=0x00,
                                            data=data,
                                            le=0x00)

    #    if DO_LOG:
    #        logging.info('\n' + 'GET PROCESSING OPTIONS - REQUEST PDOL')
    #        for x in report_on_reply(sw1, sw2, ret_data):
    #            logging.info(x)

    # 0x77 0x16 0x82 0x02 0x38 0x00 0x94 0x10 0x08 0x01 0x02 0x00 0x10 0x01 0x02 0x00 0x18 0x01 0x02 0x01 0x20 0x01 0x02 0x00
    # 77 = Format 2 Type Response
    # 77 16 82023800941008010200100102001801020120010200
    # 82 = AIP = Application Interchange Profile
    # 82 02 3800
    # 94 = AFL = Application File Locator
    # 94 10 08010200100102001801020120010200
    #
    # AFL = 08 01 02 00
    #       10 01 02 00
    #       18 01 02 01
    #       20 01 02 00
    #                      SFI 1st Last OMA-Involved
    # 08 = 8  => 00001000 => 1  01   02           00
    # 10 = 16 => 00010000 => 2  01   02           00
    # 18 = 24 => 00011000 => 3  01   02           01
    # 20 = 32 => 00100000 => 4  01   02           00

    get_proc_options_format_1_tags = ['80']
    get_proc_options_format_2_tags = ['77', '82', '94']

    combined_tags = []
    combined_tags.extend(get_proc_options_format_1_tags)
    combined_tags.extend(get_proc_options_format_2_tags)
    '''
    hex_string = bit_tools.byte_list_to_hex_string(ret_data)
    file = open('c:/dev/logs/pdol.txt', 'w')
    file.write(hex_string + '\n')
    file.close()
    '''

    tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=combined_tags)

    afl = None

    # FORMAT 1 - Visa
    if (get_proc_options_format_1_tags[0] in tlv_tree.distinct_tag_list()):
        node = tlv_tree.get_nodes_for_qtag('80')[0]
        aip_afl = node.value_byte_list
        aip_length = 2
        aip = aip_afl[0:aip_length]
        afl = aip_afl[aip_length:]

#        if DO_LOG:
#            logging.info('AIP_AFL = ' + '.'.join(['%02X' % b for b in aip_afl]))
#            logging.info('AIP     = ' + '.'.join(['%02X' % b for b in aip]))
#            logging.info('AFL     = ' + '.'.join(['%02X' % b for b in afl]))

# FORMAT 2 - MasterCard
    else:
        node = tlv_tree.get_nodes_for_qtag('77.94')[0]
        afl = node.value_byte_list
        node = tlv_tree.get_nodes_for_qtag('77.82')[0]
        aip = node.value_byte_list


#    if DO_LOG:
#        logging.info('')
#        for line in tlv_tree.report():
#            logging.info(line)
#
    return afl, aip