def check_fci_9102(buffer):
    tlvs = utils.parse_tlv(buffer)
    sub_tlvs = []
    sub_fci_9102 = []
    for tlv in tlvs:
        for fci_item in fci_9102:
            if tlv.tag == fci_item[0]:
                sub_fci_9102.append(fci_item)
                sub_tlvs.append(tlv)
    # 判断集合中的顺序是否一致
    has_ordered = True
    for index in range(len(sub_fci_9102)):
        if sub_fci_9102[index][0] != sub_tlvs[index].tag or sub_fci_9102[index][1] != sub_tlvs[index].level:
            Log.warn('tag%s is not ordered.',sub_tlvs[index].tag)
            has_ordered = False
    if not has_ordered:
        order_tags = [item[0] for item in sub_fci_9102]
        Log.warn('the minium order list should be %s',str(order_tags))
    # 判断是否缺少必须的tag
    for item in fci_9102:
        if item not in sub_fci_9102:
            if item[2] == TagCondition.M:
                Log.error('FCI 9102 should contains tag%s',item[0])
            elif item[2] == TagCondition.C:
                Log.warn('FCI 9102 recommand that tag%s should be existed.',item[0])
    # 判断是否包含多余的tag
    for item in tlvs:
        if item not in sub_tlvs:
            Log.warn('FCI 9102 should not contains tag%s',item.tag)
Exemple #2
0
 def create_check_aid_case(self, check_aid_list):
     case_node = self.smart_qc.create_case_node('AID检测-非接',
                                                'SSQCaseEx3.dll')
     # <DeviceList>
     device_list_node = self.smart_qc.create_node(case_node, 'DeviceList')
     self.smart_qc.create_device_node(device_list_node, 'PC Twin2')
     # <SpecialInput>
     special_input_node = self.smart_qc.create_node(case_node,
                                                    'SpecialInput')
     # <CardStruct>
     card_struct_node = self.smart_qc.create_node(special_input_node,
                                                  'CardSturct')
     # <MF>
     self.smart_qc.create_node(card_struct_node, 'MF', fid='3F00')
     # <ApduList>
     app_nodes = self.dp_xml_handle.get_child_nodes(
         self.dp_xml_handle.root_element, 'App')
     cur_aids = []
     for app_node in app_nodes:
         aid = self.dp_xml_handle.get_attribute(app_node, 'aid')
         if not aid:
             Log.error(
                 'can not get aid from dp xml, check wether the dp xml is correct.'
             )
             return
         cur_aids.append(aid)
     need_check_aids = []
     for aid in check_aid_list:
         if aid not in cur_aids:
             need_check_aids.append(aid)
     apdu_list_node = self.smart_qc.create_node(card_struct_node,
                                                'ApduList')
     for aid in need_check_aids:
         apdu = '00A40400' + utils.get_strlen(aid) + aid
         self.smart_qc.create_node(apdu_list_node,
                                   'Apdu ',
                                   value=apdu,
                                   sw12="6A82")
     test_process_list_node = self.smart_qc.create_node(
         case_node, 'TestProcessList')
     self.smart_qc.create_node(test_process_list_node,
                               'Card_sturct_test',
                               enable='false')
     self.smart_qc.create_node(test_process_list_node,
                               'Compare_IC_info',
                               enable='false')
     self.smart_qc.create_node(test_process_list_node,
                               'Special_file_test',
                               enable='false')
     self.smart_qc.create_node(test_process_list_node,
                               'Transaction_test',
                               enable='false')
     self.smart_qc.create_node(test_process_list_node,
                               'Check_atr',
                               enable='false')
     self.smart_qc.create_node(test_process_list_node,
                               'ApduList_test',
                               enable='true')
def check_startswith_70(apdu_resps):
    '''
    检测读记录响应数据是否以70模板开头
    '''
    for resp in apdu_resps:
        if helper.case_startswith('70', resp.response) != CR.OK:
            Log.error('read record response not start with template 70')
            return CR.ERROR
    return CR.OK
Exemple #4
0
 def _parse_set_status_cmd(self, req, resp):
     if req[0:6] == '80F080':
         if req[6:8] == '07':
             Log.info('current card lifecycle: OP_INITIALIZE')
         elif req[6:8] == '0F':
             Log.info('current card lifecycle: SECURED')
         else:
             Log.error('Unknown card lifecycle')
         if resp != '9000':
             Log.error('set current lifecyle Failed.')
def check_empty_tag(trans_obj):
    '''
    检测读记录之前的数据是否有空值的现象
    '''
    has_empty_tag = False
    for tag_info in trans_obj.tags_info:
        if not tag_info.value:
            Log.error('tag%s is empty', tag_info.tag)
            has_empty_tag = True
    if has_empty_tag:
        return CR.ERROR
    return CR.OK
Exemple #6
0
 def _filter(self, data):
     if data and data.startswith('APDU'):
         start_index = data.find('[')
         end_index = data.find(']', start_index)
         resp_start_index = data.find('[', end_index)
         resp_end_index = data.find(']', resp_start_index)
         req = data[start_index + 1:end_index]  #取[]中间的APDU指令
         resp = data[resp_start_index + 1:resp_end_index]
         if req[0:4] in ('00A4', '80E2', '80E6', '80D8', '80F0'):
             if not req.endswith('00'):
                 Log.error('data error: %s not end with 00' % data)
             return req[0:-2], resp
     return '', ''
Exemple #7
0
 def _comapre_dgi_list(self, mock_cps, prod_cps):
     Log.info('===================== Check DGI List =====================')
     mock_cps_dgis = [item.name for item in mock_cps.dgi_list]
     prod_cps_dgis = [item.name for item in prod_cps.dgi_list]
     for mock_cps_dgi_name in mock_cps_dgis:
         if mock_cps_dgi_name not in prod_cps_dgis:
             Log.error('should perso DGI %s in product environment',
                       mock_cps_dgi_name)
     for prod_cps_dgi_name in prod_cps_dgis:
         if prod_cps_dgi_name not in mock_cps_dgis:
             Log.error('should NOT perso DGI %s in product environment',
                       prod_cps_dgi_name)
     Log.info("\nmock dgi list:%s\n", mock_cps_dgis)
     Log.info('prod dgi list:%s\n', str(prod_cps_dgis))
Exemple #8
0
 def _parse_install_cmd(self, data, resp):
     if data.startswith('80E60C00'):
         data = data[10:]  # 去掉命令头及长度部分
         data, pkg = self._get_install_param(data)
         data, applet = self._get_install_param(data)
         data, inst = self._get_install_param(data)
         data, priviliage = self._get_install_param(data)
         token, param = self._get_install_param(data)
         if resp != '6101':
             Log.error('Install Instance:%s Failed.', inst)
         else:
             Log.info('Install Instance:%s', inst)
         Log.info('Package:%s', pkg)
         Log.info('Applet:%s', applet)
         Log.info('Priviliage:%s', priviliage)
         Log.info('Install param:%s', param)
         Log.info('Token:%s\n', token)
Exemple #9
0
 def read_record(self,tag94):
     '''
     读记录数据
     '''
     resps = []
     afls = utils.parse_afl(tag94)
     for afl in afls:
         Log.info('read record: %02X%02X',afl.sfi,afl.record_no)
         resp = apdu.read_record(afl.sfi,afl.record_no)
         if resp.sw != 0x9000:
             Log.error('read record wrong')
             return resps
         tools.output_apdu_info(resp)
         resps.append(resp)
         if afl.is_static_sign_data:
             self.sig_data += utils.remove_template70(resp.response)
     return resps
Exemple #10
0
def split_rsa(xml, goldpac_dgi_list, is_second_app):
    rule_file_handle = RuleXml(xml.file_name)
    _, key = rule_file_handle.get_decrypted_attribute('RSA')
    sddf_tag = ''
    _, sddf_tag, _ = rule_file_handle.get_tag_link_attribute(
        'EMVDataName', 'Icc_KeyPair')
    if is_second_app:
        sddf_tag = sddf_tag[0:4] + get_second_app_index() + sddf_tag[5:8]
    else:
        sddf_tag = sddf_tag[0:4] + get_first_app_index() + sddf_tag[5:8]
    encrypted_data = get_goldpac_data(goldpac_dgi_list, sddf_tag,
                                      is_second_app)
    if encrypted_data is None:
        Log.error('无法获取RSA数据[tag' + sddf_tag + ']缺少数据')
    decrypted_data = algorithm.des3_ecb_decrypt(key, encrypted_data)
    if len(decrypted_data) <= 2 or decrypted_data[0:2] != '30':
        Log.error('RSA解密失败')
        return None
    decrypted_data = decrypted_data[2:]
    _, decrypted_data = get_rsa_dgi_len(decrypted_data)
    dgi_list = []
    for i in range(9):
        decrypted_data = decrypted_data[2:]  #remove flag '02'
        dgi_len, decrypted_data = get_rsa_dgi_len(decrypted_data)
        dgi_data = get_rsa_dgi_value(decrypted_data, dgi_len)
        decrypted_data = decrypted_data[dgi_len:]
        dgi = Dgi()
        if is_second_app:
            dgi.name = '_2'
        if i == 4:
            dgi.name = '8205' + dgi.name
        elif i == 5:
            dgi.name = '8204' + dgi.name
        elif i == 6:
            dgi.name = '8203' + dgi.name
        elif i == 7:
            dgi.name = '8202' + dgi.name
        elif i == 8:
            dgi.name = '8201' + dgi.name
        else:
            continue
        dgi.add_tag_value(dgi.name[0:4], dgi_data)
        dgi_list.append(dgi)
        Log.info(dgi.name[0:4] + '=' + dgi_data)
    return dgi_list
def check_duplicate_tag(trans_obj):
    '''
    检测GPO和读记录数据中是否有重复tag出现
    '''
    tags = []
    has_duplicate = False
    for tag_info in trans_obj.tags_info:
        if tag_info.step in (PROCESS_STEP.GPO, PROCESS_STEP.READ_RECORD):
            tags.append(tag_info.tag)
    tag_counts = len(tags)
    for current in range(tag_counts):
        for index in range(current + 1, tag_counts):
            if tags[current] == tags[index]:
                Log.error('tag%s has duplicated', tags[current])
                has_duplicate = True
    if has_duplicate:
        return CR.ERROR
    return CR.OK
Exemple #12
0
def check_tag_len(trans_obj):
    has_error = False
    for tag_info in trans_obj.tags_info:
        tag_len = len(tag_info.value) // 2
        len_type, lens = get_tag_len(tag_info.tag, trans_obj.aid)
        if len_type == LenType.Range:
            if tag_len < lens[0] or tag_len > lens[1]:
                Log.error(
                    'tag%s length is not correct, should be in range%d-%d. current len: %d',
                    tag_info.tag, lens[0], lens[1], tag_len)
                has_error = True
        elif len_type == LenType.Fixed:
            if tag_len not in lens:
                Log.error(
                    'tag%s length is not correct, should be any of %s. current len: %d',
                    tag_info.tag, str(lens), tag_len)
                has_error = True
    if has_error:
        return CR.ERROR
    return CR.OK
Exemple #13
0
 def first_gac_cda(self):
     tag8C = self.get_tag(PROCESS_STEP.READ_RECORD, '8C')
     if not tag8C:
         Log.error('first gac cda faild since tag8C is tempty')
         return False
     tls = utils.parse_tl(tag8C)
     data = ''
     self.unpredicatble_number = ''
     for tl in tls:
         data += terminal.get_terminal(tl.tag, tl.len)
         if tl.tag == '9F37':
             self.unpredicatble_number = terminal.get_terminal(
                 tl.tag, tl.len)
     resp = super().gac(Crypto_Type.TC_CDA, data)
     if resp.sw != 0x9000:
         Log.error('send first gac command failed. SW:%04X', resp.sw)
         return
     tlvs = utils.parse_tlv(resp.response)
     tools.output_apdu_info(resp)
     self.store_tag_group(PROCESS_STEP.FIRST_GAC, tlvs)
Exemple #14
0
def get_pse_and_ppse_dgi_list(sddf_dgi_list):
    global _aid_list_info
    pse_dgi_list = []
    ppse_dgi_list = []
    pse_index, _ = _aid_list_info.get(
        '315041592E5359532E4444463031',
        ('F', ''))  #_aid_list_info['315041592E5359532E4444463031']
    ppse_index, _ = _aid_list_info.get(
        '325041592E5359532E4444463031',
        ('F', ''))  #_aid_list_info['325041592E5359532E4444463031']
    if pse_index == 'F':
        Log.error('无法获取PSE DGI相关列表')
    if ppse_index == 'F':
        Log.error('无法获取PPSE DGI相关列表')
    for dgi in sddf_dgi_list:
        if dgi[4] == pse_index:
            pse_dgi_list.append(dgi)
        elif dgi[4] == ppse_index:
            ppse_dgi_list.append(dgi)
    return pse_dgi_list, ppse_dgi_list
Exemple #15
0
def _parse_tlv(dgi_name, data):
    dgi = Dgi()
    data = utils.remove_dgi(data, dgi_name)
    int_dgi = utils.str_to_int(dgi_name)
    if int_dgi < 0x0B01:
        if data[0:2] != '70':
            Log.error('数据有误,小于0B01的DGI应包含70模板')
            return None
        data = utils.remove_template70(data)
    if not utils.is_rsa(dgi_name) and utils.is_tlv(data):
        tlvs = utils.parse_tlv(data)
        if len(tlvs) > 0 and tlvs[0].is_template is True:
            value = utils.assemble_tlv(tlvs[0].tag, tlvs[0].value)
            dgi.add_tag_value(dgi_name, value)
        else:
            for tlv in tlvs:
                value = utils.assemble_tlv(tlv.tag, tlv.value)
                dgi.add_tag_value(tlv.tag, value)
    else:
        dgi.add_tag_value(dgi_name, data)
    return dgi
Exemple #16
0
 def issuer_auth(self):
     tag9F26 = self.get_tag(PROCESS_STEP.FIRST_GAC, '9F26')
     if not self.cvn:
         Log.error('can not get CVN, check tag9F10 wether existed.')
         return
     if self.cvn == '0A':  # CVN10处理流程
         arc = '3030'
         key = self.key_ac
         if self.key_flag == App_Master_Key.MDK:
             tag5A = self.get_tag(PROCESS_STEP.READ_RECORD, '5A')
             tag5F34 = self.get_tag(PROCESS_STEP.READ_RECORD, '5F34')
             key = auth.gen_udk(key, tag5A, tag5F34)
         arpc = auth.gen_arpc_by_des3(key, tag9F26, arc)
         resp = apdu.external_auth(arpc, arc)
         if resp.sw == 0x9000:
             return True
     elif self.cvn == '12':  # CVN18处理流程
         csu = '00820000'
         self.divert_key()  #需要使用AC session key
         arpc = auth.gen_arpc_by_mac(self.session_key_ac, tag9F26, csu)
         terminal.set_terminal('91', arpc + csu)
         return True
     return False
Exemple #17
0
 def gen_9F4B(self,ddol):
     '''
     发送内部认证命令,卡片生成tag9F4B动态签名数据
     '''
     resp = apdu.internal_auth(ddol)
     if resp.sw != 0x9000:
         Log.error('SW: %0X',resp.sw)
         Log.error('send internal authentication apdu command failed whereby dda/cda failed')
         return ''
     tlvs = utils.parse_tlv(resp.response)
     if not tlvs:
         Log.error('response: %s',resp.response)
         Log.error('internal authentication response data can not be breaked up to tlv format')
         return ''
     # 返回的APDU可能是模板77或者80
     if resp.response.startswith('77'):
         if len(tlvs) != 2:
             Log.error('response: %s',resp.response)
             Log.error('internal authentication response data is not correct')
             return ''
         return tlvs[1].value
     elif resp.response.startswith('80'):
         return tlvs[0].value
     else:
         Log.error('response: %s',resp.response)
         Log.error('internal authentication response data is not startwith 70/80')
     return ''
Exemple #18
0
 def do_cda(self):
     tag8C = self.get_tag(PROCESS_STEP.READ_RECORD,'8C')
     tag9F47 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F47')
     tag9F4B = self.get_tag(PROCESS_STEP.FIRST_GAC,'9F4B')
     if not tag8C:
         Log.error('tag8C: %s',tag8C)
         Log.error('require tag8C failed whereby dda failed')
         return False
     if not tag9F47:
         Log.error('tag9F47: %s',tag9F47)
         Log.error('require tag9F47 failed whereby dda failed')
         return False
     if not tag9F4B:
         Log.error('tag9F4B: %s',tag9F4B)
         Log.error('require tag9F4B failed whereby dda failed')
         return False
     issuer_pub_key = self._get_issuer_pub_key()
     if not issuer_pub_key:
         Log.error('get issuer public key failed where by cda failed.')
         return False
     icc_pub_key = self._get_icc_pub_key(issuer_pub_key)
     if not icc_pub_key:
         Log.error('get icc public key failed where by cda failed.')
         return False
     sig_data = self.unpredicatble_number
     if not auth.validate_9F4B(icc_pub_key,tag9F47,sig_data,tag9F4B):
         Log.error('icc public key: %s',icc_pub_key)
         Log.error('tag9F47: %s',tag9F47)
         Log.error('tag9F4B: %s',tag9F4B)
         Log.error('validate tag9F4B failed whereby cda failed')
         return False
     Log.info('cda authentication sucess.')
     return True
Exemple #19
0
 def do_dda(self,fDDA=False):
     tag9F47 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F47')
     if not tag9F47:
         Log.error('tag9F47: %s',tag9F47)
         Log.error('require tag9F47 failed whereby dda failed')
         return False
     tag9F4B = ''
     ddol = ''
     if fDDA:
         tag9F4B = self.get_tag(PROCESS_STEP.GPO,'9F4B')
         tag9F69 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F69')
         if not tag9F69:
             Log.error('tag9F69: %s',tag9F69)
             Log.error('require tag9F69 failed whereby dda failed')
             return False
         # 这里无需再判断终端数据是否存在,在GPO阶段已经验证过
         tag9F37 = terminal.get_terminal('9F37')
         tag9F02 = terminal.get_terminal('9F02')
         tag5F2A = terminal.get_terminal('5F2A')
         # 这里默认使用ddol代替fDDA的签名数据
         # 签名使用的tag9F36自动包含在了tag9F4B恢复数据中,这里无需重复包含
         ddol = tag9F37 + tag9F02 + tag5F2A + tag9F69 
     else:
         tag9F49 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F49')
         if not tag9F49:
             Log.error('tag9F49: %s',tag9F49)
             Log.error('require tag9F49 failed whereby dda failed')
             return False
         ddol = tools.assemble_dol(tag9F49)
         if not ddol:
             Log.error('tag9F49: %s',tag9F49)
             Log.error('can not get terminal ddol data whereby dda failed')
             return False
         tag9F4B = self.gen_9F4B(ddol)
     if not tag9F4B:
         Log.error('can not get tag9F4B data whereby dda failed')
         return False
     issuer_pub_key = self._get_issuer_pub_key()
     if not issuer_pub_key:
         Log.error('get issuer public key failed where by dda failed.')
         return False
     icc_pub_key = self._get_icc_pub_key(issuer_pub_key)
     if not icc_pub_key:
         Log.error('get icc public key failed where by dda failed.')
         return False
     if not auth.validate_9F4B(icc_pub_key,tag9F47,ddol,tag9F4B):
         Log.error('icc public key: %s',icc_pub_key)
         Log.error('tag9F47: %s',tag9F47)
         Log.error('sig data: %s',ddol)
         Log.error('tag9F4B: %s',tag9F4B)
         Log.error('validate tag9F4B failed whereby dda failed')
         return False
     Log.info('dda authentication sucess.')
     return True
Exemple #20
0
 def _get_icc_pub_key(self,issuer_pub_key):
     icc_pub_key = ''
     tag9F32 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F32')
     tag9F46 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F46')
     tag9F48 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F48')
     tag9F47 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F47')
     tag5A = self.get_tag(PROCESS_STEP.READ_RECORD,'5A')
     tag5F24 = self.get_tag(PROCESS_STEP.READ_RECORD,'5F24')
     
     if not tag9F46:
         Log.error('tag9F46: %s',tag9F46)
         Log.error('require tag9F46 failed whereby dda failed')
         return icc_pub_key
     if not tag9F47:
         Log.error('tag9F47: %s',tag9F47)
         Log.error('require tag9F47 failed whereby dda failed')
         return icc_pub_key
     if not tag5A:
         Log.error('tag5A: %s',tag5A)
         Log.error('require tag5A failed whereby dda failed')
         return icc_pub_key
     if not tag5F24:
         Log.error('tag5F24: %s',tag5F24)
         Log.error('require tag5F24 failed whereby dda failed')
         return icc_pub_key
     if not tag9F32:
         Log.error('tag9F32: %s',tag9F32)
         Log.info('require tag9F32 failed whereby dda failed')
         return issuer_pub_key
     tag9F4A = self.get_tag(PROCESS_STEP.READ_RECORD,'9F4A')
     if tag9F4A:
         tag82 = self.get_tag(PROCESS_STEP.GPO,'82')
         if not tag82:
             Log.error('require tag82 failed whereby dda failed')
             return icc_pub_key
         self.sig_data += tag82
     icc_pub_key = auth.get_icc_pub_key(issuer_pub_key,tag9F32,tag9F46,tag9F48,tag9F47,self.sig_data,tag5A,tag5F24)
     if not icc_pub_key:
         Log.error('issuer public key: %s',issuer_pub_key)
         Log.error('tag9F32: %s',tag9F32)
         Log.error('tag9F46: %s',tag9F46)
         Log.error('tag9F47: %s',tag9F47)
         Log.error('sig data: %s',self.sig_data)
         Log.error('tag5A: %s',tag5A)
         Log.error('tag5F24: %s',tag5F24)
         Log.error('can not get icc public key whereby dda failed')
         return ''
     return icc_pub_key
Exemple #21
0
 def _get_issuer_pub_key(self):
     '''
     恢复发卡行公钥
     '''
     issuer_pub_key = ''
     tag84 = self.get_tag(PROCESS_STEP.SELECT,'84')
     tag8F = self.get_tag(PROCESS_STEP.READ_RECORD,'8F')
     tag90 = self.get_tag(PROCESS_STEP.READ_RECORD,'90')
     tag92 = self.get_tag(PROCESS_STEP.READ_RECORD,'92')
     tag9F32 = self.get_tag(PROCESS_STEP.READ_RECORD,'9F32')
     tag5A = self.get_tag(PROCESS_STEP.READ_RECORD,'5A')
     tag5F24 = self.get_tag(PROCESS_STEP.READ_RECORD,'5F24')
     if not tag84 or len(tag84) < 10:
         Log.error('tag84: %s',tag84)
         Log.error('tag84 is empty or length less than 10 bytes whereby dda failed')
         return issuer_pub_key
     if not tag8F:
         Log.error('tag8F: %s',tag8F)
         Log.info('require tag8F failed whereby dda failed')
         return issuer_pub_key
     if not tag90:
         Log.error('tag90: %s',tag90)
         Log.info('require tag90 failed whereby dda failed')
         return issuer_pub_key
     if not tag9F32:
         Log.error('tag9F32: %s',tag9F32)
         Log.info('require tag9F32 failed whereby dda failed')
         return issuer_pub_key
     if not tag5A:
         Log.error('tag5A: %s',tag5A)
         Log.info('require tag5A failed whereby dda failed')
         return issuer_pub_key
     if not tag5F24:
         Log.error('tag5F24: %s',tag5F24)
         Log.info('require tag5F24 failed whereby dda failed')
         return issuer_pub_key
     # 验证tag90,获取发卡行公钥
     # 获取CA 公钥及CA指数
     ca_pub_key,ca_exp = auth.get_ca_pub_key(tag84[0:10],tag8F)
     if not ca_pub_key or not ca_exp:
         Log.error('rid: %s index: %s ',tag84[0:10],tag8F)
         Log.error('can not get ca public key, make sure this root ca existed, please check pcsc.db file')
         return issuer_pub_key
     issuer_pub_key = auth.get_issuer_pub_key(ca_pub_key,ca_exp,tag90,tag92,tag9F32,tag5A,tag5F24)
     if not issuer_pub_key:
         Log.error('CA public key: %s',ca_pub_key)
         Log.error('CA exp: %s',ca_exp)
         Log.error('tag90: %s',tag90)
         Log.error('tag92: %s',tag92)
         Log.error('tag9F32: %s',tag9F32)
         Log.error('tag5A: %s',tag5A)
         Log.error('tag5F24: %s',tag5F24)
         Log.info('can not get issuer public key whereby dda failed')
         return ''
     return issuer_pub_key
Exemple #22
0
def get_icc_pub_key(issuer_pub_key,tag9F32,tag9F46,tag9F48,tag9F47,sig_data,tag5A,tag5F24):
    '''
    获取IC卡公钥
    '''
    icc_pub_key = ''
    recovery_data = gen_recovery_data(issuer_pub_key,tag9F32,tag9F46)
    if not recovery_data:
        Log.error('can not require recovery data through public cert tag90')
        return icc_pub_key
    Log.info('icc recovery data: %s',recovery_data)
    if recovery_data[0:4] != '6A04' or recovery_data[-2:] != 'BC':
        Log.error('recovery data format incorrect, it should start with 6A02 and end with BC')
        return icc_pub_key
    pan = recovery_data[4:24].replace('F','')
    if len(pan) < 16 or tag5A.replace('F','') != pan:
        Log.error('PAN: %s',pan)
        Log.error('tag5A: %s',tag5A)
        Log.error('pan required from recovery data is not accord with tag5A')
        return icc_pub_key
    expiry_date = int(recovery_data[26:28] + recovery_data[24:26])
    now = int(time.strftime('%y%m'))
    if expiry_date < now:
        Log.warn('expiry date: %s',recovery_data[26:28] + recovery_data[24:26])
        Log.warn('icc cert has been overdue')
    if expiry_date < int(tag5F24[0:4]):
        Log.warn('expiry date: %s',recovery_data[26:28] + recovery_data[24:26])
        Log.warn('tag5F24: %s',tag5F24)
        Log.warn('icc cert overdue earlier than application expiry date')
    if recovery_data[34:38] != '0101':
        Log.error('hash algo flag: %s',recovery_data[34:36])
        Log.error('ipk algo flag: %s',recovery_data[36:38])
    hash_input = recovery_data[2:-42] + tag9F48 + tag9F47 + sig_data
    hash_cert = recovery_data[-42:-2]
    hash_output = algorithm.gen_hash(hash_input)
    if hash_cert != hash_output:
        Log.error('hash input: %s',hash_input)
        Log.error('hash: %s',hash_output)
        Log.error('hash cert: %s',hash_cert)
        Log.error('hash compared failed whereby gen icc recovery data failed ')
        return icc_pub_key
    icc_cert_len = int(recovery_data[38:40],16) * 2
    if icc_cert_len <= len(issuer_pub_key) - 84:
        icc_pub_key = recovery_data[42:42 + icc_cert_len]
    else:
        icc_pub_key = recovery_data[42:-42] + tag9F48
    Log.info('icc pub key: %s',icc_pub_key)
    return icc_pub_key
Exemple #23
0
    def gen_cps(self,
                session_key=None,
                second_session_key=None,
                delete80_list=[]):
        cps = Cps()
        start_perso = False  # 个人化起始行
        app_type = None  # 个人化应用类型
        prevous_req = ''  #保存上一次的数据,对于一条超长数据,需要使用两条store data指令
        prevous_req_len = 0  #
        is_jetco_app = False  #判断是否有jetco应用
        parse_perso_complete = False  #是否已经完成个人化
        has_check_status = False  #是否有检测卡片状态
        has_check_kmc = False  # 是否有检测修改过卡片KMC
        if not delete80_list:
            delete80_list = ['8201', '8202', '8203', '8204', '8205']
        while not self.log_handle.EOF:
            is_encrypted = False
            data = self.log_handle.read_line()  #每次读取一行数据进行分析
            req, resp = self._filter(data)  #过滤非指定的APDU信息,返回请求和响应数据
            if req.startswith('80E60C00'):  #解析安装参数信息
                Log.info(
                    '===================== Check Install Param ====================='
                )
                self._parse_install_cmd(req, resp)
            if req.startswith('00A40400') and not req.startswith(
                    '00A4040008A000000003000000'):
                start_perso = True  #从此行开始认定个人化开始
            if start_perso:
                if req.startswith('00A404000E315041592E5359532E4444463031'):
                    app_type = 'PSE'  #说明接下来是个人化PSE
                    continue
                elif req.startswith('00A404000E325041592E5359532E4444463031'):
                    app_type = 'PPSE'  #接下来个人化PPSE
                    continue
                elif req.startswith('00A40400'):  #应用
                    app_type = 'APP'
                    if req.startswith('00A4040009A00000047400000001'):
                        app_type = "JETCO"
                        is_jetco_app = True  # 这里判断,是因为表示是双应用数据
                    continue
                if app_type:
                    if req.startswith('80E2') and req[4:6] in (
                            '00', '60', '80', 'E0'):  #处理store data 数据
                        if resp != '9000':
                            Log.error('perso error: [APDU: %s][%s]', req, resp)
                            continue
                        #判断是否为加密数据
                        if req[4:6] in ('60', 'E0'):
                            is_encrypted = True
                        # 判断是否已经解析完个人化数据,接下来要判断卡片安全状态和修改KMC
                        if req[4:6] in ('80', 'E0') and app_type == 'APP':
                            parse_perso_complete = True
                        req = req[10:]  # 去掉命令头及长度
                        # 处理仅一条APDU指令发送store data的情况
                        if not prevous_req:
                            dgi_name = req[0:4]  # DGI名称
                            if is_jetco_app:  #默认Jetco为第二应用
                                dgi_name += '_2'
                            req = req[4:]  # 去掉DGI名称

                            # 去掉DGI后面跟随的长度
                            data_len = 0
                            if req[0:4] == 'FF00':
                                data_len = int(req[4:6], 16)
                                req = req[6:]
                            else:
                                data_len = int(req[0:2], 16)
                                req = req[2:]

                            # 如果长度和后面的数据不一致,则说明分两条APDU发送
                            if data_len * 2 != len(req):
                                prevous_req = req
                                prevous_req_len = data_len
                                continue
                        else:  # 处理需要两条APDU指令发送的情况
                            req = prevous_req + req
                            if prevous_req_len * 2 != len(req):
                                Log.error("data len error")
                                return None
                            prevous_req = ''
                            prevous_req_len = 0
                        dgi = None
                        if is_jetco_app:
                            dgi = self.parse_store_data(
                                app_type, dgi_name, req, second_session_key,
                                is_encrypted, delete80_list)
                        else:
                            dgi = self.parse_store_data(
                                app_type, dgi_name, req, session_key,
                                is_encrypted, delete80_list)
                        cps.add_dgi(dgi)
            if parse_perso_complete:
                if req.startswith('80F080'):  # 检测卡片是否设置为安全状态
                    Log.info(
                        '===================== Check Card Status ====================='
                    )
                    has_check_status = True
                    self._parse_set_status_cmd(req, resp)
                if req.startswith('80D8'):  # 检测卡片是否修改KMC
                    Log.info(
                        '===================== Check KMC ====================='
                    )
                    has_check_kmc = True
                    self._parse_modify_kmc(req, resp)
        if not has_check_status:
            Log.info(
                '===================== Check Card Status ====================='
            )
            Log.error('Not set card status during perso card.\n')
        if not has_check_kmc:
            Log.info('===================== Check KMC =====================')
            Log.error('Not modify kmc during perso card.\n')
        return cps
Exemple #24
0
 def _parse_modify_kmc(self, req, resp):
     if req[0:4] == '80D8' and resp == '610A':
         Log.info('Check Modify KMC Sucess.')
     else:
         Log.error('Check Modify KMC Failed.')
Exemple #25
0
 def compare_cps(self, product_cps, mock_cps, ignore_list=[]):
     self._comapre_dgi_list(mock_cps, product_cps)
     self._display_dki(product_cps)
     self._display_key_info(product_cps)
     mock_dgis = mock_cps.get_all_dgis()
     if not ignore_list:
         # 涉及KMS相关的值,不比较
         ignore_list = [
             '8F', '90', '92', '9F32', '9F46', '9F48', '93', '8201', '8202',
             '8203', '8204', '8205', '8000', '9000', 'A006', 'A016', '8400',
             '8401', '8001', '9001', 'B010', 'B023'
         ]
     Log.info('===================== Compare Data =====================')
     has_err = False
     for mock_dgi in mock_dgis:
         Log.info(
             '===================== compare dgi %s =====================',
             mock_dgi.name)
         product_dgi = product_cps.get_dgi(mock_dgi.name)
         if not product_dgi:
             Log.error('cannot find DGI %s in product enviromnent' %
                       mock_dgi.name)
             has_err = True
             continue
         if product_dgi.name in ('9115', '9116', '9117'):
             product_value = product_dgi.get_value(product_dgi.name)
             mock_value = ''
             for tag, value in mock_dgi.get_all_tags().items():
                 mock_value += value
             if mock_value != product_value:
                 has_err = True
                 Log.error('compare dgi %s failed.' % product_dgi.name)
                 Log.error('Prod_value: %s' % product_value)
                 Log.error('Mock_value: %s\n' % mock_value)
             else:
                 Log.info('compare dgi %s sucess.' % product_dgi.name)
                 Log.info('Prod_value: %s' % product_value)
                 Log.info('Mock_value: %s\n' % mock_value)
         else:
             for tag, value in mock_dgi.get_all_tags().items():
                 if tag in ignore_list:
                     continue
                 product_value = product_dgi.get_value(tag)
                 if product_value != value:
                     has_err = True
                     Log.error('compare tag %s failed.' % tag)
                     Log.error('Prod_value: %s' % product_value)
                     Log.error('Mock_value: %s\n' % value)
                 else:
                     Log.info('compare tag %s sucess.' % tag)
                     Log.info('Prod_value: %s' % product_value)
                     Log.info('Mock_value: %s\n' % value)
     if has_err:
         Log.error('Comapare data failed.')
     else:
         Log.info('Compared data sucess.')
Exemple #26
0
def get_issuer_pub_key(ca_pub_key,ca_exp,tag90,tag92,tag9F32,tag5A,tag5F24):
    '''
    获取发卡行公钥
    '''
    issuer_pub_key = ''
    recovery_data = gen_recovery_data(ca_pub_key,ca_exp,tag90)
    if not recovery_data:
        Log.error('can not require recovery data through public cert tag90')
        return issuer_pub_key
    Log.info('issuer recovery data: %s',recovery_data)
    if recovery_data[0:4] != '6A02' or recovery_data[-2:] != 'BC':
        Log.error('recovery data format incorrect, it should start with 6A02 and end with BC')
        return issuer_pub_key
    issuer_bin = recovery_data[4:12].replace('F','')
    if len(issuer_bin) < 3 or not tag5A.startswith(issuer_bin):
        Log.error('issuer_bin: %s',issuer_bin)
        Log.error('tag5A: %s',tag5A)
        Log.error('issuer_bin required from recovery data is not accord with tag5A')
        return issuer_pub_key
    expiry_date = int(recovery_data[14:16] + recovery_data[12:14])
    now = int(time.strftime('%y%m'))
    if expiry_date < now:
        Log.warn('expiry date: %s',recovery_data[14:16] + recovery_data[12:14])
        Log.warn('issuer cert has been overdue')
    if expiry_date < int(tag5F24[0:4]):
        Log.warn('expiry date: %s',recovery_data[14:16] + recovery_data[12:14])
        Log.warn('tag5F24: %s',tag5F24)
        Log.warn('issuer cert overdue earlier than application expiry date')
    if recovery_data[22:26] != '0101':
        Log.error('hash algo flag: %s',recovery_data[22:24])
        Log.error('ipk algo flag: %s',recovery_data[24:26])
        return issuer_pub_key
    hash_input = recovery_data[2:-42] + tag92 + tag9F32
    hash_cert = recovery_data[-42:-2]
    hash_output = algorithm.gen_hash(hash_input)
    if hash_cert != hash_output:
        Log.error('hash input: %s',hash_input)
        Log.error('hash: %s',hash_output)
        Log.error('hash cert: %s',hash_cert)
        Log.error('hash compared failed whereby gen issuer recovery data failed ')
        return issuer_pub_key
    issuer_cert_len = int(recovery_data[26:28],16) * 2
    if issuer_cert_len <= len(ca_pub_key) - 72:
        issuer_pub_key = recovery_data[30:30 + issuer_cert_len]
    else:
        issuer_pub_key = recovery_data[30:-42] + tag92
    Log.info('issuer pub key: %s',issuer_pub_key)
    return issuer_pub_key
Exemple #27
0
    def create_case(self, configs, check_aid_list=None):
        app_nodes = self.dp_xml_handle.get_child_nodes(
            self.dp_xml_handle.root_element, 'App')
        # handle contact case
        for app_node in app_nodes:
            aid = self.dp_xml_handle.get_attribute(app_node, 'aid')
            if not aid:
                Log.error(
                    'can not get aid from dp xml, check wether the dp xml is correct.'
                )
                return
            app_type = self.dp_xml_handle.get_attribute(app_node, 'type')
            if not app_type:
                Log.warn('can not recognize app type')
                app_type = ''
            app_type += '_conatct_test'
            if aid[:10] not in configs:
                Log.error('can not get configuration of aid %s', aid)
                return
            config = configs[aid[:10]]  # get this aid's configuration
            # create header
            case_node = self._create_header(app_type, aid,
                                            config['contact_device'],
                                            config['contact_dll'],
                                            config['contact_spec'])
            if 'dki_cvn' in config:
                self.smart_qc.create_node(case_node,
                                          'VerifyTag9F10',
                                          pattern=config['dki_cvn'])
            # <CompareData>
            compare_data_node = self.smart_qc.create_node(
                case_node, 'CompareData')
            gpo_node = self.dp_xml_handle.get_node_by_attribute(
                app_node, 'DGI', name=config['gpo_dgi'])
            if not gpo_node:
                Log.error('can not found dgi %s in app node,aid=%s',
                          config['gpo_dgi'], aid)
                return
            afl_node = self.dp_xml_handle.get_node_by_attribute(
                gpo_node, 'Tag', name=config['afl_tag'])
            if not afl_node:
                Log.error('can not found tag %s in dgi %s', config['afl_tag'],
                          config['gpo_dgi'])
                return
            afl_tag = self.dp_xml_handle.get_attribute(afl_node, 'value')
            if not afl_tag:
                Log.error('tag %s is empty', config['afl_tag'])
                return
            dgi_names = self._get_dgis(afl_tag)

            # pse tags
            pse_nodes = self._get_pse_nodes()
            for node in pse_nodes:
                self.create_tag_node('pse', node, compare_data_node,
                                     '315041592E5359532E4444463031')
            fci_node = self.dp_xml_handle.get_node_by_attribute(
                app_node, 'DGI', name=config['contact_fci_dgi'])
            if not fci_node:
                Log.error('can not found dgi %s in app node',
                          config['contact_fci_dgi'])
                return
            # app fci tags
            self.create_tag_node(app_type, fci_node, compare_data_node, aid)
            # app gpo tags
            self.create_tag_node(app_type, gpo_node, compare_data_node, aid)
            # app record tags
            for dgi_name in dgi_names:
                node = self.dp_xml_handle.get_node_by_attribute(app_node,
                                                                'DGI',
                                                                name=dgi_name)
                self.create_tag_node(app_type, node, compare_data_node, aid)
            # risk management tags
            internal_dgis = config['risk_dgi_list']
            get_data_tags = [[tag, False] for tag in config['get_data_tags']]

            risk_tags = ''
            for dgi_name in internal_dgis:
                node = self.dp_xml_handle.get_node_by_attribute(app_node,
                                                                'DGI',
                                                                name=dgi_name)
                if node:
                    self.create_tag_node(app_type, node, compare_data_node,
                                         aid, get_data_tags)
            for item in get_data_tags:
                tag = item[0]
                has_check = item[1]
                if not has_check:
                    Log.error(
                        'can not get tag %s in dp xml,check the "get_data_tags" configuration',
                        tag)
                else:
                    if len(tag) == 2:
                        tag = '00' + tag
                    risk_tags += tag + ','
            if not risk_tags:
                Log.error('MustContain node is empty')
                return
            risk_tags = risk_tags[0:-1]
            # <MustConatin>
            self.smart_qc.create_text_node(case_node, 'MustContain', risk_tags)
            # <ShowCardFace>
            self.smart_qc.create_node(case_node, 'ShowCardFace')
        # handle contactless case
        for app_node in app_nodes:
            aid = self.dp_xml_handle.get_attribute(app_node, 'aid')
            if not aid:
                Log.error(
                    'can not get aid from dp xml, check wether the dp xml is correct.'
                )
                return
            if aid in ('315041592E5359532E4444463031',
                       '325041592E5359532E4444463031'):
                continue
            app_type = self.dp_xml_handle.get_attribute(app_node, 'type')
            if not app_type:
                Log.warn('can not recognize app type')
                app_type = ''
            app_type += '_conatctless_test'
            if aid[:10] not in configs:
                Log.error('can not configuration of aid %s', aid)
                return
            config = configs[aid[:10]]  # get this aid's configuration

            # 判断是否有非接数据,并生成非接case
            fci_dgi_node = self.dp_xml_handle.get_node_by_attribute(
                app_node, 'DGI', name=config['contactless_fci_dgi'])
            if fci_dgi_node:
                case_node = self._create_header(app_type, aid,
                                                config['contactless_device'],
                                                config['contactless_dll'],
                                                config['contactless_spec'])
                compare_data_node = self.smart_qc.create_node(
                    case_node, 'CompareData')
                ppse_child_node = self._get_ppse_node()
                self.create_tag_node('ppse', ppse_child_node,
                                     compare_data_node,
                                     '325041592E5359532E4444463031')
                self.create_tag_node(app_type, fci_dgi_node, compare_data_node,
                                     aid)

        # check aid list
        if check_aid_list:
            self.create_check_aid_case(check_aid_list)
Exemple #28
0
def validate_9F4B(icc_pub_key,icc_exp,sig_data,tag9F4B):
    '''
    校验tag9F4B的正确性
    '''
    recovery_data = gen_recovery_data(icc_pub_key,icc_exp,tag9F4B)
    if not recovery_data:
        Log.error('can not require recovery data through public cert tag90')
        return False
    Log.info('tag9F4B recovery data: %s',recovery_data)
    if recovery_data[0:4] not in ('6A05','6A95') or recovery_data[-2:] != 'BC':
        Log.error('recovery data format incorrect, it should start with 6A05/6A95 and end with BC')
        return False
    hash_input = recovery_data[2:-42] + sig_data
    hash_9F4B = recovery_data[-42:-2]
    hash_output = algorithm.gen_hash(hash_input)
    if hash_9F4B != hash_output:
        Log.error('hash in tag9F4B: %s',hash_9F4B)
        Log.error('hash input: %s',hash_input)
        Log.error('hash calc: %s',hash_output)
        Log.error('hash compared failed whereby tag9F4B is not correct ')
        return False
    icc_dynamic_data_len = int(recovery_data[8:10],16) * 2
    tag9F4C = recovery_data[10:10 + icc_dynamic_data_len]
    terminal.set_terminal('9F4C',tag9F4C)
    return True