def test_03(self, llc): """Version handling""" bt_record = ndef.BluetoothEasyPairingRecord('01:02:03:04:05:06') bt_record.name = 'carrier-1' client = handover_connect(llc, self.options) try: info("send handover request message with version 1.2") hr_record = ndef.HandoverRequestRecord('1.2', os.urandom(2)) hr_record.add_alternative_carrier('active', bt_record.name) handover_send(client, [hr_record, bt_record]) records = handover_recv(client, timeout=3.0) if records[0].version_string != "1.2": raise TestFail("handover select message version is not 1.2") info("received handover select message version 1.2") finally: client.close() client = handover_connect(llc, self.options) try: info("send handover request message with version 1.1") hr_record = ndef.HandoverRequestRecord('1.1', os.urandom(2)) hr_record.add_alternative_carrier('active', bt_record.name) handover_send(client, [hr_record, bt_record]) records = handover_recv(client, timeout=3.0) if records[0].version_string != "1.2": raise TestFail("handover select message version is not 1.2") info("received handover select message version 1.2") finally: client.close() client = handover_connect(llc, self.options) try: info("send handover request message with version 1.15") hr_record = ndef.HandoverRequestRecord('1.15', os.urandom(2)) hr_record.add_alternative_carrier('active', bt_record.name) handover_send(client, [hr_record, bt_record]) records = handover_recv(client, timeout=3.0) if records[0].version_string != "1.2": raise TestFail("handover select message version is not 1.2") info("received handover select message version 1.2") finally: client.close() client = handover_connect(llc, self.options) try: info("send handover request message with version 15.0") hr_record = ndef.HandoverRequestRecord('15.0', os.urandom(2)) hr_record.add_alternative_carrier('active', bt_record.name) handover_send(client, [hr_record, bt_record]) records = handover_recv(client, timeout=3.0) if records[0].version_string != "1.2": raise TestFail("handover select message version is not 1.2") info("received handover select message version 1.2") finally: client.close()
def test_08(self, llc): """Skip meaningless records""" client = handover_connect(llc, self.options) try: bt_record = ndef.BluetoothEasyPairingRecord("01:02:03:04:05:06") bt_record.name = "carrier-1" bt_record.device_name = "Handover Test Client" bt_record.device_class = 0x10010C bt_record.add_service_class(0x1105) bt_record.add_service_class(0x1106) hr_record = ndef.HandoverRequestRecord("1.2", os.urandom(2)) hr_record.add_alternative_carrier("active", bt_record.name) handover_send(client, [hr_record, ndef.TextRecord("X"), bt_record]) records = handover_recv(client, timeout=3.0) info("received {}".format(records[0].type)) hs_record, bt_record = records if len(hs_record.alternative_carriers) != 1: raise TestFail("one selected carrier is expected") if bt_record.type != "application/vnd.bluetooth.ep.oob": raise TestFail("a Bluetooth carrier is expected") finally: client.close()
def test_02(self, llc): """Empty carrier list""" client = handover_connect(llc, self.options) try: hr_record = ndef.HandoverRequestRecord("1.2", os.urandom(2)) handover_send(client, [hr_record]) records = handover_recv(client, timeout=3.0) if len(records[0].alternative_carriers) > 0: raise TestFail("handover select message returned carriers") finally: client.close()
def test_07(self, llc): """Two handover requests""" client = handover_connect(llc, self.options) try: unknown_carrier = "urn:nfc:ext:nfcpy.org:unknown-carrier-type" records = [ ndef.HandoverRequestRecord("1.2", os.urandom(2)), ndef.Record(unknown_carrier, "unknown-carrier") ] records[0].add_alternative_carrier("active", records[1].name) info("request carrier {}".format(records[1].type)) handover_send(client, records) records = handover_recv(client, timeout=3.0) info("received {}".format(records[0].type)) if records[0].version_info.major != 1: raise TestFail("handover major version is not 1") if len(records[0].alternative_carriers) != 0: raise TestFail("an empty carrier selection is expected first") bt_record = ndef.BluetoothEasyPairingRecord("01:02:03:04:05:06") bt_record.name = "carrier-1" bt_record.device_name = "Handover Test Client" bt_record.device_class = 0x10010C bt_record.add_service_class(0x1105) bt_record.add_service_class(0x1106) hr_record = ndef.HandoverRequestRecord("1.2", os.urandom(2)) hr_record.add_alternative_carrier("active", bt_record.name) info("propose carrier {}".format(bt_record.type)) handover_send(client, [hr_record, bt_record]) records = handover_recv(client, timeout=3.0) info("received {}".format(records[0].type)) finally: client.close()
def test_05(self, llc): """Bluetooth secure pairing""" client = handover_connect(llc, self.options) try: bt_record = ndef.BluetoothEasyPairingRecord("01:02:03:04:05:06") bt_record.name = "carrier-1" bt_record.device_name = "Handover Test Client" bt_record.device_class = 0x10010C bt_record.add_service_class(0x1105) bt_record.add_service_class(0x1106) bt_record.simple_pairing_hash_256 = \ 0x1234567890ABCDEF1234567890ABCDEF bt_record.simple_pairing_randomizer_256 = \ 0x010203040506070809000A0B0C0D0E0F hr_record = ndef.HandoverRequestRecord("1.2", os.urandom(2)) hr_record.add_alternative_carrier("active", bt_record.name) handover_send(client, [hr_record, bt_record]) records = handover_recv(client, timeout=3.0) info("received {}".format(records[0].type)) hs_record, bt_record = records if len(hs_record.alternative_carriers) != 1: raise TestFail("one selected carrier is expected") if bt_record.type != "application/vnd.bluetooth.ep.oob": raise TestFail("a Bluetooth carrier is expected") if bt_record.device_name is None: if self.options.relax: log.warning("no local device name attribute") else: raise TestFail("no local device name attribute") if bt_record.device_name == "": raise TestFail("empty local device name attribute") if bt_record.device_class is None: log.warning("there is no class of device attribute") if len(bt_record.service_class_list) == 0: log.warning("there are no service class UUIDs") if bt_record.simple_pairing_hash_256 is None: if self.options.relax: log.warning("ssp hash required for secure pairing") else: raise TestFail("ssp hash required for secure pairing") if bt_record.simple_pairing_randomizer_256 is None: if self.options.relax: log.warning("ssp rand required for secure pairing") else: raise TestFail("ssp rand required for secure pairing") finally: client.close()
def test_06(self, llc): """Unknown carrier type""" client = handover_connect(llc, self.options) try: unknown_carrier = "urn:nfc:ext:nfcpy.org:unknown-carrier-type" records = [ ndef.HandoverRequestRecord("1.2", os.urandom(2)), ndef.Record(unknown_carrier, "unknown-carrier") ] records[0].add_alternative_carrier("active", records[1].name) handover_send(client, records) records = handover_recv(client, timeout=3.0) info("received {}".format(records[0].type)) if records[0].version_info.major != 1: raise TestFail("handover major version is not 1") if len(records[0].alternative_carriers) != 0: raise TestFail("an empty carrier selection is expected") finally: client.close()
def dpp_handover_client(llc): uri = wpas_get_nfc_uri(start_listen=False) uri = ndef.UriRecord(uri) print("NFC URI record for DPP: " + str(uri)) carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data) hr = ndef.HandoverRequestRecord(version="1.4", crn=os.urandom(2)) hr.add_alternative_carrier('active', carrier.name) message = [hr, carrier] print("NFC Handover Request message for DPP: " + str(message)) client = nfc.handover.HandoverClient(llc) try: summary("Trying to initiate NFC connection handover") client.connect() summary("Connected for handover") except nfc.llcp.ConnectRefused: summary("Handover connection refused") client.close() return except Exception as e: summary("Other exception: " + str(e)) client.close() return summary("Sending handover request") if not client.send_records(message): summary("Failed to send handover request") client.close() return summary("Receiving handover response") message = client.recv_records(timeout=3.0) if message is None: summary("No response received") client.close() return print("Received message: " + str(message)) if len(message) < 1 or \ not isinstance(message[0], ndef.HandoverSelectRecord): summary("Response was not Hs - received: " + message.type) client.close() return print("Received message") print("alternative carriers: " + str(message[0].alternative_carriers)) dpp_found = False for carrier in message: if isinstance(carrier, ndef.HandoverSelectRecord): continue print("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.dpp": if len(carrier.data) == 0 or carrier.data[0] != 0: print("URI Identifier Code 'None' not seen") continue print("DPP carrier type match - send to wpa_supplicant") dpp_found = True uri = carrier.data[1:].decode("utf-8") print("DPP URI: " + uri) res = wpas_report_handover_sel(uri) if res is None or "FAIL" in res: summary("DPP handover report rejected") break success_report("DPP handover reported successfully (initiator)") print("peer_id=" + res) peer_id = int(res) # TODO: Single Configurator instance wpas = wpas_connect() if wpas is None: break res = wpas.request("DPP_CONFIGURATOR_ADD") if "FAIL" in res: print("Failed to initiate Configurator") break conf_id = int(res) global own_id print("Initiate DPP authentication") cmd = "DPP_AUTH_INIT peer=%d own=%d conf=sta-dpp configurator=%d" % ( peer_id, own_id, conf_id) res = wpas.request(cmd) if "FAIL" in res: print("Failed to initiate DPP authentication") break if not dpp_found: print( "DPP carrier not seen in response - allow peer to initiate a new handover with different parameters" ) client.close() print("Returning from dpp_handover_client") return print("Remove peer") client.close() print("Done with handover") global only_one if only_one: print("only_one -> stop loop") global continue_loop continue_loop = False global no_wait if no_wait: print("Trying to exit..") global terminate_now terminate_now = True print("Returning from dpp_handover_client")
def dpp_handover_client(llc): uri = wpas_get_nfc_uri(start_listen=False) if uri is None: summary("Cannot start handover client - no bootstrap URI available") return uri = ndef.UriRecord(uri) summary("NFC URI record for DPP: " + str(uri)) carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data) crn = os.urandom(2) hr = ndef.HandoverRequestRecord(version="1.4", crn=crn) hr.add_alternative_carrier('active', carrier.name) message = [hr, carrier] summary("NFC Handover Request message for DPP: " + str(message)) global peer_crn if peer_crn is not None: summary( "NFC handover request from peer was already received - do not send own" ) return client = nfc.handover.HandoverClient(llc) try: summary("Trying to initiate NFC connection handover") client.connect() summary("Connected for handover") except nfc.llcp.ConnectRefused: summary("Handover connection refused") client.close() return except Exception as e: summary("Other exception: " + str(e)) client.close() return if peer_crn is not None: summary( "NFC handover request from peer was already received - do not send own" ) client.close() return summary("Sending handover request") global my_crn, my_crn_ready, hs_sent my_crn_ready = True if not client.send_records(message): my_crn_ready = False summary("Failed to send handover request") client.close() return my_crn, = struct.unpack('>H', crn) summary("Receiving handover response") try: message = client.recv_records(timeout=3.0) except Exception as e: # This is fine if we are the handover selector if hs_sent: summary( "Client receive failed as expected since I'm the handover server: %s" % str(e)) else: summary("Client receive failed: %s" % str(e)) message = None if message is None: if hs_sent: summary( "No response received as expected since I'm the handover server" ) else: summary("No response received") client.close() return summary("Received message: " + str(message)) if len(message) < 1 or \ not isinstance(message[0], ndef.HandoverSelectRecord): summary("Response was not Hs - received: " + message.type) client.close() return summary("Received handover select message") summary("alternative carriers: " + str(message[0].alternative_carriers)) dpp_found = False for carrier in message: if isinstance(carrier, ndef.HandoverSelectRecord): continue summary("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.dpp": if len(carrier.data) == 0 or carrier.data[0] != 0: summary("URI Identifier Code 'None' not seen") continue summary("DPP carrier type match - send to wpa_supplicant") dpp_found = True uri = carrier.data[1:].decode("utf-8") summary("DPP URI: " + uri) res = wpas_report_handover_sel(uri) if res is None or "FAIL" in res: summary("DPP handover report rejected") break success_report("DPP handover reported successfully (initiator)") summary("peer_id=" + res) peer_id = int(res) wpas = wpas_connect() if wpas is None: break global enrollee_only global config_params if enrollee_only: extra = " role=enrollee" elif config_params: extra = " role=configurator " + config_params else: # TODO: Single Configurator instance res = wpas.request("DPP_CONFIGURATOR_ADD") if "FAIL" in res: summary("Failed to initiate Configurator") break conf_id = int(res) extra = " conf=sta-dpp configurator=%d" % conf_id global own_id summary("Initiate DPP authentication") cmd = "DPP_AUTH_INIT peer=%d own=%d" % (peer_id, own_id) cmd += extra res = wpas.request(cmd) if "FAIL" in res: summary("Failed to initiate DPP authentication") break if not dpp_found: summary( "DPP carrier not seen in response - allow peer to initiate a new handover with different parameters" ) client.close() summary("Returning from dpp_handover_client") return summary("Remove peer") client.close() summary("Done with handover") global only_one if only_one: print("only_one -> stop loop") global continue_loop continue_loop = False global no_wait if no_wait: print("Trying to exit..") global terminate_now terminate_now = True summary("Returning from dpp_handover_client")
assert record.alternative_carriers[0].carrier_power_state == 'active' assert record.alternative_carriers[0].carrier_data_reference == 'wifi' assert record.alternative_carriers[0].auxiliary_data_reference[0] == 'a1' assert record.alternative_carriers[0].auxiliary_data_reference[1] == 'a2' assert record.alternative_carriers[1].carrier_power_state == 'inactive' assert record.alternative_carriers[1].carrier_data_reference == 'bt31' assert record.alternative_carriers[1].auxiliary_data_reference[0] == 'a3' assert len(record.unknown_records) == 1 assert record.unknown_records[0].type == 'text/plain' assert record.unknown_records[0].name == 'txt' assert record.unknown_records[0].data == b'Hello' handover_request_messages = [ ('d102014872 11', [ndef.HandoverRequestRecord('1.1')]), ('91020a487211 d10204616301013100 5a030201612f62310001', [ndef.HandoverRequestRecord('1.1', None, (1, '1')), ndef.Record('a/b', '1', b'\x00\x01')]), ('d10208487212 d1020263721234', [ndef.HandoverRequestRecord('1.2', 0x1234)]), ('910211487212 91020263721234 510204616301013100 5a030201612f62310001', [ndef.HandoverRequestRecord('1.2', 0x1234, (1, '1')), ndef.Record('a/b', '1', b'\x00\x01')]), ('910211487212 91020263721234 510204616301013100 590205014863310203612f62', [ndef.HandoverRequestRecord('1.2', 0x1234, (1, '1')), ndef.HandoverCarrierRecord('a/b', None, '1')]), ] class TestHandoverRequestMessage:
def run_dpp_handover_client(handover, alt=False): chan_override = None if alt: chan_override = handover.altchanlist handover.alt_proposal_used = True global test_uri, test_alt_uri if test_uri: summary("TEST MODE: Using specified URI (alt=%s)" % str(alt)) uri = test_alt_uri if alt else test_uri else: uri = wpas_get_nfc_uri(start_listen=False, chan_override=chan_override) if uri is None: summary("Cannot start handover client - no bootstrap URI available", color=C_RED) return handover.my_uri = uri uri = ndef.UriRecord(uri) summary("NFC URI record for DPP: " + str(uri)) carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data) global test_crn if test_crn: prev, = struct.unpack('>H', test_crn) summary("TEST MODE: Use specified crn %d" % prev) crn = test_crn test_crn = struct.pack('>H', prev + 0x10) else: crn = os.urandom(2) hr = ndef.HandoverRequestRecord(version="1.4", crn=crn) hr.add_alternative_carrier('active', carrier.name) message = [hr, carrier] summary("NFC Handover Request message for DPP: " + str(message)) if handover.peer_crn is not None and not alt: summary("NFC handover request from peer was already received - do not send own") return if handover.client: summary("Use already started handover client") client = handover.client else: summary("Start handover client") client = HandoverClient(handover, handover.llc) try: summary("Trying to initiate NFC connection handover") client.connect() summary("Connected for handover") except nfc.llcp.ConnectRefused: summary("Handover connection refused") client.close() return except Exception as e: summary("Other exception: " + str(e)) client.close() return handover.client = client if handover.peer_crn is not None and not alt: summary("NFC handover request from peer was already received - do not send own") return summary("Sending handover request") handover.my_crn_ready = True if not client.send_records(message): handover.my_crn_ready = False summary("Failed to send handover request", color=C_RED) run_client_alt(handover, alt) return handover.my_crn, = struct.unpack('>H', crn) summary("Receiving handover response") try: start = time.time() message = client.recv_records(timeout=3.0) end = time.time() summary("Received {} record(s) in {} seconds".format(len(message) if message is not None else -1, end - start)) except Exception as e: # This is fine if we are the handover selector if handover.hs_sent: summary("Client receive failed as expected since I'm the handover server: %s" % str(e)) elif handover.alt_proposal_used and not alt: summary("Client received failed for initial proposal as expected since alternative proposal was also used: %s" % str(e)) else: summary("Client receive failed: %s" % str(e), color=C_RED) message = None if message is None: if handover.hs_sent: summary("No response received as expected since I'm the handover server") elif handover.alt_proposal_used and not alt: summary("No response received for initial proposal as expected since alternative proposal was also used") elif handover.try_own and not alt: summary("No response received for initial proposal as expected since alternative proposal will also be sent") else: summary("No response received", color=C_RED) run_client_alt(handover, alt) return summary("Received message: " + str(message)) if len(message) < 1 or \ not isinstance(message[0], ndef.HandoverSelectRecord): summary("Response was not Hs - received: " + message.type) return summary("Received handover select message") summary("alternative carriers: " + str(message[0].alternative_carriers)) if handover.i_m_selector: summary("Ignore the received select since I'm the handover selector") run_client_alt(handover, alt) return if handover.alt_proposal_used and not alt: summary("Ignore received handover select for the initial proposal since alternative proposal was sent") client.close() return dpp_found = False for carrier in message: if isinstance(carrier, ndef.HandoverSelectRecord): continue summary("Remote carrier type: " + carrier.type) if carrier.type == "application/vnd.wfa.dpp": if len(carrier.data) == 0 or carrier.data[0] != 0: summary("URI Identifier Code 'None' not seen", color=C_RED) continue summary("DPP carrier type match - send to wpa_supplicant") dpp_found = True uri = carrier.data[1:].decode("utf-8") summary("DPP URI: " + uri) handover.peer_uri = uri if test_uri: summary("TEST MODE: Fake processing") break res = wpas_report_handover_sel(uri) if res is None or "FAIL" in res: summary("DPP handover report rejected", color=C_RED) break success_report("DPP handover reported successfully (initiator)") summary("peer_id=" + res) peer_id = int(res) wpas = wpas_connect() if wpas is None: break global enrollee_only global config_params if enrollee_only: extra = " role=enrollee" elif config_params: extra = " role=configurator " + config_params else: # TODO: Single Configurator instance res = wpas.request("DPP_CONFIGURATOR_ADD") if "FAIL" in res: summary("Failed to initiate Configurator", color=C_RED) break conf_id = int(res) extra = " conf=sta-dpp configurator=%d" % conf_id global own_id summary("Initiate DPP authentication") cmd = "DPP_AUTH_INIT peer=%d own=%d" % (peer_id, own_id) cmd += extra res = wpas.request(cmd) if "FAIL" in res: summary("Failed to initiate DPP authentication", color=C_RED) break if not dpp_found and handover.no_alt_proposal: summary("DPP carrier not seen in response - do not allow alternative proposal anymore") elif not dpp_found: summary("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters") handover.alt_proposal = True handover.my_crn_ready = False handover.my_crn = None handover.peer_crn = None handover.hs_sent = False summary("Returning from dpp_handover_client") return summary("Remove peer") handover.close() summary("Done with handover") global only_one if only_one: print("only_one -> stop loop") global continue_loop continue_loop = False global no_wait if no_wait or only_one: summary("Trying to exit..") global terminate_now terminate_now = True summary("Returning from dpp_handover_client")