1# Copyright (C) 2024 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# Lint as: python3 16 17from binascii import hexlify 18 19_NUM_POLLING_LOOPS = 50 20 21def create_select_apdu(aid_hex): 22 """Creates a select APDU command for the given AID""" 23 aid_bytes = bytearray.fromhex(aid_hex) 24 return bytearray.fromhex("00A40400") + bytearray([len(aid_bytes)]) + aid_bytes 25 26def poll_and_transact(pn532, command_apdus, response_apdus, custom_frame = None): 27 """Polls for an NFC Type-A tag 50 times. If tag is found, performs a transaction. 28 29 :param pn532: PN532 device 30 :param command_apdus: Command APDUs in transaction 31 :param response_apdus: Response APDUs in transaction 32 :param custom_frame: A custom frame to send as part of te polling loop other than pollA(). 33 34 :return: [if tag is found, if transaction was successful] 35 """ 36 transacted = False 37 tag = None 38 for i in range(_NUM_POLLING_LOOPS): 39 tag = pn532.poll_a() 40 if tag is not None: 41 transacted = tag.transact(command_apdus, response_apdus) 42 pn532.mute() 43 break 44 if custom_frame is not None: 45 pn532.send_broadcast(bytearray.fromhex(custom_frame)) 46 pn532.mute() 47 return tag is not None, transacted 48 49def parse_protocol_params(sak, ats): 50 """ 51 Helper function to check whether protocol parameters are properly set. 52 :param sak: SAK byte 53 :param ats: ATS bytearray 54 :return: whether bits are set correctly, message to print 55 """ 56 msg = "" 57 success = True 58 msg += "SAK:\n" 59 if sak & 0x20 != 0: 60 msg += " (OK) ISO-DEP bit (0x20) is set.\n" 61 else: 62 success = False 63 msg += " (FAIL) ISO-DEP bit (0x20) is NOT set.\n" 64 if sak & 0x40 != 0: 65 msg += " (OK) P2P bit (0x40) is set.\n" 66 else: 67 msg += " (WARN) P2P bit (0x40) is NOT set.\n" 68 69 ta_present = False 70 tb_present = False 71 tc_present = False 72 atsIndex = 0 73 if ats[atsIndex] & 0x40 != 0: 74 msg += " (OK) T(C) is present (bit 7 is set).\n" 75 tc_present = True 76 else: 77 success = False 78 msg += " (FAIL) T(C) is not present (bit 7 is NOT set).\n" 79 if ats[atsIndex] and 0x20 != 0: 80 msg += " (OK) T(B) is present (bit 6 is set).\n" 81 tb_present = True 82 else: 83 success = False 84 msg += " (FAIL) T(B) is not present (bit 6 is NOT set).\n" 85 if ats[atsIndex] and 0x10 != 0: 86 msg += " (OK) T(A) is present (bit 5 is set).\n" 87 ta_present = True 88 else: 89 success = False 90 msg += " (FAIL) T(A) is not present (bit 5 is NOT set).\n" 91 fsc = ats[atsIndex] & 0x0F 92 if fsc > 8: 93 success = False 94 msg += " (FAIL) FSC " + str(fsc) + " is > 8\n" 95 elif fsc < 2: 96 msg += " (FAIL EMVCO) FSC " + str(fsc) + " is < 2\n" 97 else: 98 msg += " (OK) FSC = " + str(fsc) + "\n" 99 100 atsIndex += 1 101 if ta_present: 102 msg += " TA: 0x" + str(ats[atsIndex] & 0xff) + "\n" 103 if ats[atsIndex] & 0x80 != 0: 104 msg += " (OK) bit 8 set, indicating only same bit rate divisor.\n" 105 else: 106 msg += " (FAIL EMVCO) bit 8 NOT set, indicating support for asymmetric bit rate divisors. EMVCo requires bit 8 set.\n" 107 if ats[atsIndex] & 0x70 != 0: 108 msg += " (FAIL EMVCO) EMVCo requires bits 7 to 5 set to 0.\n" 109 else: 110 msg += " (OK) bits 7 to 5 indicating only 106 kbit/s L->P supported.\n" 111 if ats[atsIndex] & 0x7 != 0: 112 msg += " (FAIL EMVCO) EMVCo requires bits 3 to 1 set to 0.\n" 113 else: 114 msg += " (OK) bits 3 to 1 indicating only 106 kbit/s P->L supported.\n" 115 atsIndex += 1 116 117 if tb_present: 118 msg += " TB: 0x" + str(ats[3] & 0xFF) + "\n" 119 fwi = (ats[atsIndex] & 0xF0) >> 4 120 if fwi > 8: 121 msg += " (FAIL) FWI=" + str(fwi) + ", should be <= 8\n" 122 elif fwi == 8: 123 msg += " (FAIL EMVCO) FWI=" + str(fwi) + ", EMVCo requires <= 7\n" 124 else: 125 msg += " (OK) FWI=" + str(fwi) + "\n" 126 sfgi = ats[atsIndex] & 0x0F 127 if sfgi > 8: 128 success = False 129 msg += " (FAIL) SFGI=" + str(sfgi) + ", should be <= 8\n" 130 else: 131 msg += " (OK) SFGI=" + str(sfgi) + "\n" 132 atsIndex += 1 133 if tc_present: 134 msg += " TC: 0x" + str(ats[atsIndex] & 0xFF) + "\n" 135 nadSupported = ats[atsIndex] & 0x01 != 0 136 if nadSupported: 137 success = False 138 msg += " (FAIL) NAD bit is not allowed to be set.\n" 139 else: 140 msg += " (OK) NAD bit is not set.\n" 141 atsIndex += 1 142 if atsIndex + 1 < len(ats): 143 bytes_to_copy = len(ats) - atsIndex 144 historical_bytes = bytearray(ats[atsIndex:atsIndex + bytes_to_copy]) 145 msg += "\n(OK) Historical bytes: " + hexlify(historical_bytes).decode() 146 return success, msg 147 148def get_apdus(nfc_emulator, service_name): 149 """ 150 Gets apdus for a given service. 151 :param nfc_emulator: emulator snippet. 152 :param service_name: Service name of APDU sequence to fetch. 153 :return: [command APDU byte array, response APDU byte array] 154 """ 155 command_apdus = nfc_emulator.getCommandApdus(service_name) 156 response_apdus = nfc_emulator.getResponseApdus(service_name) 157 return [bytearray.fromhex(apdu) for apdu in command_apdus], [ 158 (bytearray.fromhex(apdu) if apdu != "*" else apdu) for apdu in response_apdus] 159 160def to_byte_array(apdu_array): 161 return [bytearray.fromhex(apdu) for apdu in apdu_array] 162