def second_gac(self): tag8D = self.get_tag(PROCESS_STEP.READ_RECORD, '8D') data = tools.assemble_dol(tag8D) resp = super().gac(Crypto_Type.TC, data) if resp.sw != 0x9000: Log.info('send gac1 failed.') return tlvs = utils.parse_tlv(resp.response) tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.SECOND_GAC, utils.parse_tlv(resp.response)) return resp
def first_gac(self): tag8C = self.get_tag(PROCESS_STEP.READ_RECORD, '8C') data = tools.assemble_dol(tag8C) resp = super().gac(Crypto_Type.ARQC, data) if resp.sw != 0x9000: Log.info('send gac1 failed.') return tlvs = utils.parse_tlv(resp.response) tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.FIRST_GAC, utils.parse_tlv(resp.response)) self.run_case('case_first_gac', 'run_mc', resp) return resp
def _get_pse_tag_list(self): ''' 获取PSE节点中包含的tag标签列表 ''' tlv_list = [] dgi = self.cps.get_dgi('PSE') dgi_0101_tags = utils.parse_tlv(dgi.get_value('0101')) dgi_9102_tags = utils.parse_tlv(dgi.get_value('9102')) for tag in dgi_0101_tags: if tag.is_template is False and tag.len > 0: tlv_list.append(tag) for tag in dgi_9102_tags: if tag.is_template is False and tag.len > 0: tlv_list.append(tag) return tlv_list
def application_selection(self, aid): resp = super().application_selection(aid) tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.SELECT, utils.parse_tlv(resp.response)) # self.run_case('case_application_selection','run_visa',resp) return resp
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)
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 ''
def application_selection(self): resp = super().application_selection('315041592E5359532E4444463031') tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.SELECT, utils.parse_tlv(resp.response)) # self.run_case('case_application_selection',resp) return resp
def _get_aid(self): ''' 根据PSE中的DGI0101分组获取tag4F ''' dgi = self.cps.get_dgi('PSE') dgi_0101_tags = utils.parse_tlv(dgi.get_value('0101')) for tag in dgi_0101_tags: if tag.tag == '4F': return tag.value
def process_dp(dp_file, rule_file): fh = FileHandle(dp_file, 'rb+') fh.read(fh.current_offset, 8596) #reserved dgi_list = get_dgi_list(fh) file_size = fh.file_size cps_list = [] while fh.current_offset < file_size: card_seq = fh.read_int64_reverse(fh.current_offset) card_data_total_len = fh.read_int_reverse(fh.current_offset) cps = Cps() #存储单个卡片数据 cps.dp_file_path = dp_file pse_and_ppse_dgi = [ 'Store_PSE_1', 'Store_PSE_2', 'Store_PPSE', 'DGIF001' ] for dgi_name in dgi_list: dgi = Dgi() #存储单个DGI数据 if dgi_name in pse_and_ppse_dgi: if dgi_name == 'Store_PSE_1': dgi = process_pse_and_ppse(fh, dgi_name, True) else: dgi = process_pse_and_ppse(fh, dgi_name, False) cps.add_dgi(dgi) continue dgi_mark = fh.read_binary(fh.current_offset, 1) #DGI标识 if dgi_mark != '86': return next_len = get_next_len(fh) dgi_seq = fh.read_binary(fh.current_offset, 2) #读取DGI序号 dgi.name = dgi_seq next_len = get_next_len(fh) n_dgi_seq = utils.hex_str_to_int(dgi_seq) if n_dgi_seq <= 0x0B00: #认为是记录 template70 = fh.read_binary(fh.current_offset, 1) if template70 != '70': return next_len = get_next_len(fh) dgi_data = fh.read_binary(fh.current_offset, next_len) if n_dgi_seq <= 0x0B00 or (dgi_seq not in do_not_parse_tlv_list and utils.is_tlv(dgi_data)): tlvs = utils.parse_tlv(dgi_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_seq, 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_seq, dgi_data) cps.add_dgi(dgi) if rule_file is not None: process_rule(rule_file, cps) process_rule_A001(rule_file, cps) process_rule_eps(rule_file, cps) cps_list.append(cps) return cps_list
def read_record(self): resps = None tag94 = self.get_tag(PROCESS_STEP.GPO, '94') if tag94: resps = super().read_record(tag94) for resp in resps: self.store_tag_group(PROCESS_STEP.READ_RECORD, utils.parse_tlv(resp.response)) # self.run_case('case_read_record','run_visa',resps) return resps
def process_dp(dp_file, rule_file): cps_list = [] fh = FileHandle(dp_file, 'rb+') dp_flag = fh.read_binary(fh.current_offset, 7) data_len = utils.hex_str_to_int(fh.read_binary(fh.current_offset, 8)) dgi_count = fh.read_int64(fh.current_offset) dgi_list = [] for i in range(dgi_count): dgi_name_len = fh.read_int(fh.current_offset) dgi_name = fh.read_str(fh.current_offset, dgi_name_len) dgi_list.append(dgi_name) card_seq = fh.read_binary(fh.current_offset, 4) card_data_len = fh.read_int(fh.current_offset) while data_len > fh.current_offset: cps = Cps() cps.dp_file_path = dp_file for item in dgi_list: dgi = Dgi() start_flag = fh.read_binary(fh.current_offset, 1) if start_flag != '86': return cps_list dgi_len = get_len(fh) dgi_name = fh.read_binary(fh.current_offset, 2) dgi.name = dgi_name dgi_data_len = utils.hex_str_to_int( fh.read_binary(fh.current_offset, 1)) n_dgi_seq = utils.hex_str_to_int(dgi_name) if n_dgi_seq <= 0x0B00: #认为是记录 template70 = fh.read_binary(fh.current_offset, 1) if template70 != '70': return cps_list dgi_data_len = get_len(fh) dgi_data = fh.read_binary(fh.current_offset, dgi_data_len) if item[0:3] == 'PSE': dgi = process_pse_and_ppse(dgi_name, dgi_data, 'PSE') elif item[0:4] == 'PPSE': dgi = process_pse_and_ppse(dgi_name, dgi_data, 'PPSE') else: if n_dgi_seq <= 0x0B00 or (utils.is_rsa(dgi_name) is False and utils.is_tlv(dgi_data)): tlvs = utils.parse_tlv(dgi_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, dgi_data) cps.add_dgi(dgi) if rule_file is not None: process_rule(rule_file, cps) cps_list.append(cps) return cps_list
def gpo(self): tag9F38 = self.get_tag(PROCESS_STEP.SELECT, '9F38') data = '' if tag9F38: data = tools.assemble_dol(tag9F38) resp = super().gpo(data) if resp.sw == 0x9000: tools.output_apdu_info(resp) self.store_tag_group(PROCESS_STEP.GPO, utils.parse_tlv(resp.response)) # self.run_case('case_gpo','run_visa',resp) return resp
def gpo(self): tag9F38 = self.get_tag(PROCESS_STEP.SELECT, '9F38') pdol = '' if tag9F38: pdol = tools.assemble_dol(tag9F38) resp = super().gpo(pdol) if resp.sw == 0x9000: tools.output_apdu_info(resp) tlvs = utils.parse_tlv(resp.response) self.store_tag_group(PROCESS_STEP.GPO, tlvs) self.run_case('case_gpo', resp) return resp
def _get_dgi_list(self, tag94): ''' 根据tag94获取对应的DGI分组 ''' dgi_list = [] dgi = self.cps.get_dgi(tag94) tag94 = utils.parse_tlv(dgi.get_value('94')) afls = utils.parse_afl(tag94[0].value) for afl in afls: sfi = utils.int_to_hex_str(afl.sfi) record = utils.int_to_hex_str(afl.record_no) dgi_list.append(sfi + record) return dgi_list
def read_record(self): aids = [] sfi = 1 for record_no in range(1, 5): resp = apdu.read_record(sfi, record_no, (0x9000, 0x6A83)) tools.output_apdu_info(resp) if resp.sw == 0x6A83: break tlvs = utils.parse_tlv(resp.response) for tlv in tlvs: if tlv.tag == '4F': aids.append(tlv.value) return aids
def application_selection(self): aids = [] resp = super().application_selection('325041592E5359532E4444463031') if resp.sw != 0x9000: Log.error('select ppse failed, sw=%0X', resp.sw) return aids tools.output_apdu_info(resp) tlvs = utils.parse_tlv(resp.response) for tlv in tlvs: if tlv.tag == '4F': aids.append(tlv.value) self.store_tag_group(PROCESS_STEP.SELECT, tlvs) # self.run_case('case_application_selection',resp) return aids
def _get_dgi_tags(self, dgi): ''' 获取指定DGI节点下的tag标签列表 ''' tlv_list = [] dgi_tags = self.cps.get_dgi(dgi) if dgi_tags is None: return tlv_list for _, value in dgi_tags.tag_value_dict.items(): tags = utils.parse_tlv(value) for tag in tags: if tag.tag not in no_contain_list and tag.is_template is False: tlv_list.append(tag) return tlv_list
def process_card_data(fh, rule_file): cps = Cps() flag = fh.read_str(fh.current_offset, 6) if flag != '000EMV': return False, cps card_data_len = fh.read_int64(fh.current_offset) app_count = utils.hex_str_to_int(fh.read_binary(fh.current_offset, 1)) for app in range(app_count): aid_len = utils.hex_str_to_int(fh.read_binary(fh.current_offset, 1)) aid = fh.read_binary(fh.current_offset, aid_len) app_data_len = fh.read_int64(fh.current_offset) dgi_list, encrypt_dgi_list = get_dgi_list(fh) Log.info('encrypt dgi list :', encrypt_dgi_list) for item in dgi_list: card_dgi = Dgi() dgi = fh.read_binary(fh.current_offset, 2) dgi_len = utils.hex_str_to_int(fh.read_binary( fh.current_offset, 1)) dgi_data = fh.read_binary(fh.current_offset, dgi_len) n_dgi = utils.hex_str_to_int(dgi) card_dgi.dgi = dgi if dgi == '0098' or dgi == '0099': dgi = process_pse(dgi, dgi_data) elif dgi == '0100': dgi = process_ppse(dgi, dgi_data) else: if n_dgi < 0x0B01: if dgi_data[0:2] != '70': return False, cps if dgi_data[2:4] == '81': dgi_data = dgi_data[6:] else: dgi_data = dgi_data[4:] if utils.is_rsa(dgi) is False and utils.is_tlv(dgi_data): tlvs = utils.parse_tlv(dgi_data) if len(tlvs) > 0 and tlvs[0].is_template is True: value = utils.assemble_tlv(tlvs[0].tag, tlvs[0].value) card_dgi.add_tag_value(dgi, value) else: for tlv in tlvs: value = process_tag_decrypt( rule_file, tlv.tag, tlv.value) value = utils.assemble_tlv(tlv.tag, value) card_dgi.add_tag_value(tlv.tag, value) else: card_dgi.add_tag_value(dgi, dgi_data) cps.add_dgi(card_dgi) return True, cps
def parse_store_data(self, app_type, dgi_name, data, session_key=None, is_encrypted=False, delete80_list=[]): int_dgi_name = int(dgi_name, 16) if is_encrypted and session_key: data = des3_ecb_decrypt(session_key, data) if dgi_name in delete80_list: index = data.rfind('80') if index != -1: data = data[0:index] #对于PSE和PPSE,不解析TLV格式 if app_type in ('PSE', 'PPSE'): dgi = Dgi() dgi.name = app_type if data.startswith('70'): data = data[4:] #去掉70模板 dgi.add_tag_value(dgi_name, data) return dgi else: #规则如下: #1. 小于0x0B00的记录数据需要解析TLV结构 #2. 如果DGI大于0B00,并且该数据可以解析成TLV,则分如下情况 # a. 如果是8000,9000,9102,9103等不需要分析TLV结构的,则不分析 # b. 如果DGI以A,B字母开头(万事达应用),不用做TLV分析 if int_dgi_name <= 0x0B00 \ or (dgi_name not in self.do_not_parse_tlv_list \ and utils.is_tlv(data)\ and not (dgi_name.startswith('A') or dgi_name.startswith('B')) ): if utils.is_tlv(data): tlvs = utils.parse_tlv(data) return self._assemble_dgi(dgi_name, tlvs) else: dgi = Dgi() dgi.name = dgi_name dgi.add_tag_value(dgi_name, data) return dgi else: dgi = Dgi() dgi.name = dgi_name if dgi_name.endswith('_2'): dgi_name = dgi_name[:-2] dgi.add_tag_value(dgi_name, data) return dgi
def first_gac(self): tag8C = self.get_tag(PROCESS_STEP.READ_RECORD, '8C') data = tools.assemble_dol(tag8C) resp = super().gac(Crypto_Type.ARQC, data) if resp.sw != 0x9000: Log.info('send gac1 failed.') return tlvs = utils.parse_tlv(resp.response) if len(tlvs) != 1 and tlvs[0].tag != '80': Log.info('gac1 response data error') data = tlvs[0].value self.store_tag(PROCESS_STEP.FIRST_GAC, '9F27', data[0:2]) self.store_tag(PROCESS_STEP.FIRST_GAC, '9F36', data[2:6]) self.store_tag(PROCESS_STEP.FIRST_GAC, '9F26', data[6:22]) self.store_tag(PROCESS_STEP.FIRST_GAC, '9F10', data[22:]) return resp
def parse_sddf_data(xml, sddf_tag, goldpac_dgi_list=[]): sddf_data = '' for item in goldpac_dgi_list: if item.goldpac_dgi == sddf_tag: sddf_data = item.data dgi = Dgi() node_dgi, value_format = get_tag_link_attribute(xml, sddf_tag) if node_dgi == '' or value_format == '': return None need_remove_template = is_need_delete_template(node_dgi) global _aid_list_info is_second_app = False for _, aid_info in _aid_list_info.items(): if sddf_tag[4] == aid_info[0]: is_second_app = aid_info[1] break if is_second_app: #说明包含双应用 dgi.name = node_dgi + '_2' else: dgi.name = node_dgi if value_format == 'TLV': data = utils.remove_dgi(sddf_data, node_dgi) if need_remove_template: data = utils.remove_template70(data) if utils.str_to_int(node_dgi) > 0xA000 or not utils.is_tlv(data): dgi.add_tag_value(dgi.name, data) else: 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: if tlv.len > 0x7F: value = tlv.tag + '81' + utils.int_to_hex_str( tlv.len) + tlv.value else: value = tlv.tag + utils.int_to_hex_str( tlv.len) + tlv.value dgi.add_tag_value(tlv.tag, value) elif value_format == 'V': dgi.add_tag_value(dgi.name, sddf_data) return dgi
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)
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
def process_assemble_dgi(self, src_dgi, src_tag, format_str): data = "" tag_list = format_str.split(',') for tag in tag_list[::-1]: if '.' not in tag: #说明是模板 data = tag + utils.get_strlen(data) + data else: dst_dgi = tag.split('.')[0] dst_tag = tag.split('.')[1] if dst_dgi == '': data = dst_tag + data elif dst_dgi[len(dst_dgi) - 1] == 'v': dst_dgi = dst_dgi[0:len(dst_dgi) - 1] value = self.cps.get_tag_value(dst_dgi, dst_tag) if not value: print('dgi %s tag %s 不存在' % (dst_dgi, dst_tag)) data = value + data else: value = '' if dst_dgi in ('9102', '9103'): #对于9103,9102需要特殊处理 tlvs = utils.parse_tlv( self.cps.get_tag_value(dst_dgi, dst_dgi)) for tlv in tlvs: if tlv.tag == dst_tag: value = tlv.value break else: value = self.cps.get_tag_value(dst_dgi, dst_tag) if not value: print('dgi %s tag %s 不存在' % (dst_dgi, dst_tag)) tag_len = utils.get_strlen(value) data = dst_tag + tag_len + value + data dgi = Dgi() dgi.name = src_dgi dgi.add_tag_value(src_tag, data) self.cps.add_dgi(dgi) return self.cps
def get_data(self,tags): for tag in tags: resp = apdu.get_data(tag) if resp.sw == 0x9000: tlvs = utils.parse_tlv(resp.response) self.store_tag_group(PROCESS_STEP.GET_DATA,tlvs)