Esempio n. 1
0
    def setup_test(self):
        super().setup_test()

        self.dut_security = PyLeSecurity(self.dut)
        self.cert_security = PyLeSecurity(self.cert)
        self.dut_hci = PyHci(self.dut)

        self.dut_address = common.BluetoothAddressWithType(
            address=common.BluetoothAddress(
                address=bytes(b'DD:05:04:03:02:01')),
            type=common.RANDOM_DEVICE_ADDRESS)
        privacy_policy = le_initiator_address_facade.PrivacyPolicy(
            address_policy=le_initiator_address_facade.AddressPolicy.
            USE_STATIC_ADDRESS,
            address_with_type=self.dut_address)
        self.dut.security.SetLeInitiatorAddressPolicy(privacy_policy)
        self.cert_address = common.BluetoothAddressWithType(
            address=common.BluetoothAddress(
                address=bytes(b'C5:11:FF:AA:33:22')),
            type=common.RANDOM_DEVICE_ADDRESS)
        cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
            address_policy=le_initiator_address_facade.AddressPolicy.
            USE_STATIC_ADDRESS,
            address_with_type=self.cert_address)
        self.cert.security.SetLeInitiatorAddressPolicy(cert_privacy_policy)
Esempio n. 2
0
 def __init__(self, device):
     """
         Don't call super b/c the gRPC stream setup will crash test
     """
     logging.info("Cert: Init")
     self._device = device
     self._device.wait_channel_ready()
     self._hci = PyHci(device)
     self._hci.register_for_events(
         hci_packets.EventCode.ENCRYPTION_CHANGE,
         hci_packets.EventCode.CHANGE_CONNECTION_LINK_KEY_COMPLETE,
         hci_packets.EventCode.CENTRAL_LINK_KEY_COMPLETE,
         hci_packets.EventCode.RETURN_LINK_KEYS,
         hci_packets.EventCode.PIN_CODE_REQUEST,
         hci_packets.EventCode.LINK_KEY_REQUEST,
         hci_packets.EventCode.LINK_KEY_NOTIFICATION,
         hci_packets.EventCode.ENCRYPTION_KEY_REFRESH_COMPLETE,
         hci_packets.EventCode.IO_CAPABILITY_REQUEST,
         hci_packets.EventCode.IO_CAPABILITY_RESPONSE,
         hci_packets.EventCode.REMOTE_OOB_DATA_REQUEST,
         hci_packets.EventCode.SIMPLE_PAIRING_COMPLETE,
         hci_packets.EventCode.USER_PASSKEY_NOTIFICATION,
         hci_packets.EventCode.KEYPRESS_NOTIFICATION,
         hci_packets.EventCode.USER_CONFIRMATION_REQUEST,
         hci_packets.EventCode.USER_PASSKEY_REQUEST,
         hci_packets.EventCode.REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION)
     self._hci_event_stream = self._hci.get_event_stream()
Esempio n. 3
0
 def setup_test(self):
     super().setup_test()
     self.cert_hci = PyHci(self.cert, acl_streaming=True)
     self.cert_hci.send_command(hci_packets.WriteScanEnableBuilder(hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
     self.cert_name = b'Im_A_Cert'
     self.cert_address = self.cert_hci.read_own_address()
     self.cert_name += b'@' + self.cert_address.encode('utf8')
     self.dut_neighbor = PyNeighbor(self.dut)
Esempio n. 4
0
 def __init__(self, device, cert_address, has_security=False):
     self._device = device
     self._cert_address = cert_address
     self._hci = PyHci(device)
     self._l2cap_stream = EventStream(
         self._device.l2cap.FetchL2capData(empty_proto.Empty()))
     self._security_connection_event_stream = EventStream(
         self._device.l2cap.FetchSecurityConnectionEvents(
             empty_proto.Empty()))
     if has_security == False:
         self._hci.register_for_events(
             hci_packets.EventCode.LINK_KEY_REQUEST)
class LeAdvertisingManagerTest(GdBaseTestClass):
    def setup_class(self):
        super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')

    def setup_test(self):
        super().setup_test()
        self.cert_hci = PyHci(self.cert, acl_streaming=True)

    def teardown_test(self):
        self.cert_hci.close()
        super().teardown_test()

    def test_le_ad_scan_dut_advertises(self):
        self.cert_hci.register_for_le_events(
            hci_packets.SubeventCode.ADVERTISING_REPORT,
            hci_packets.SubeventCode.EXTENDED_ADVERTISING_REPORT)

        # CERT Scans
        self.cert_hci.send_command(
            hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
        scan_parameters = hci_packets.PhyScanParameters()
        scan_parameters.le_scan_type = hci_packets.LeScanType.ACTIVE
        scan_parameters.le_scan_interval = 40
        scan_parameters.le_scan_window = 20
        self.cert_hci.send_command(
            hci_packets.LeSetExtendedScanParametersBuilder(
                hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
                hci_packets.LeScanningFilterPolicy.ACCEPT_ALL, 1,
                [scan_parameters]))
        self.cert_hci.send_command(
            hci_packets.LeSetExtendedScanEnableBuilder(
                hci_packets.Enable.ENABLED,
                hci_packets.FilterDuplicates.DISABLED, 0, 0))

        # DUT Advertises
        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_The_DUT'))
        gap_data = le_advertising_facade.GapDataMsg(
            data=bytes(gap_name.Serialize()))
        config = le_advertising_facade.AdvertisingConfig(
            advertisement=[gap_data],
            interval_min=512,
            interval_max=768,
            advertising_type=le_advertising_facade.AdvertisingEventType.
            ADV_IND,
            own_address_type=common.USE_RANDOM_DEVICE_ADDRESS,
            channel_map=7,
            filter_policy=le_advertising_facade.AdvertisingFilterPolicy.
            ALL_DEVICES)
        request = le_advertising_facade.CreateAdvertiserRequest(config=config)

        create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(
            request)

        assertThat(self.cert_hci.get_le_event_stream()).emits(
            lambda packet: b'Im_The_DUT' in packet.payload)

        remove_request = le_advertising_facade.RemoveAdvertiserRequest(
            advertiser_id=create_response.advertiser_id)
        self.dut.hci_le_advertising_manager.RemoveAdvertiser(remove_request)
        self.cert_hci.send_command(
            hci_packets.LeSetScanEnableBuilder(hci_packets.Enable.DISABLED,
                                               hci_packets.Enable.DISABLED))
Esempio n. 6
0
class PyL2cap(Closable):
    def __init__(self, device, cert_address, has_security=False):
        self._device = device
        self._cert_address = cert_address
        self._hci = PyHci(device)
        self._l2cap_stream = EventStream(
            self._device.l2cap.FetchL2capData(empty_proto.Empty()))
        self._security_connection_event_stream = EventStream(
            self._device.l2cap.FetchSecurityConnectionEvents(
                empty_proto.Empty()))
        if has_security == False:
            self._hci.register_for_events(
                hci_packets.EventCode.LINK_KEY_REQUEST)

    def close(self):
        safeClose(self._l2cap_stream)
        safeClose(self._security_connection_event_stream)
        safeClose(self._hci)

    def register_dynamic_channel(
            self,
            psm=0x33,
            mode=l2cap_facade_pb2.RetransmissionFlowControlMode.BASIC):
        self._device.l2cap.SetDynamicChannel(
            l2cap_facade_pb2.SetEnableDynamicChannelRequest(
                psm=psm, retransmission_mode=mode))
        return PyL2capChannel(self._device, psm, self._l2cap_stream)

    def connect_dynamic_channel_to_cert(
            self,
            psm=0x33,
            mode=l2cap_facade_pb2.RetransmissionFlowControlMode.BASIC):
        """
        Send open Dynamic channel request to CERT.
        Get a future for connection result, to be used after CERT accepts request
        """
        self.register_dynamic_channel(psm, mode)
        response_future = self._device.l2cap.OpenChannel.future(
            l2cap_facade_pb2.OpenChannelRequest(psm=psm,
                                                remote=self._cert_address,
                                                mode=mode))

        return _ClassicConnectionResponseFutureWrapper(response_future,
                                                       self._device, psm,
                                                       self._l2cap_stream)

    def get_channel_queue_buffer_size(self):
        return self._device.l2cap.GetChannelQueueDepth(
            empty_proto.Empty()).size

    def initiate_connection_for_security(self):
        """
        Establish an ACL for the specific purpose of pairing devices
        """
        self._device.l2cap.InitiateConnectionForSecurity(self._cert_address)

    def get_security_connection_event_stream(self):
        """
        Stream of Link related events.  Events are returned with an address.
        Events map to the LinkSecurityInterfaceListener callbacks
        """
        return self._security_connection_event_stream

    def security_link_hold(self):
        """
        Holds open the ACL indefinitely allowing for the security handshake
        to take place
        """
        self._device.l2cap.SecurityLinkHold(self._cert_address)

    def security_link_ensure_authenticated(self):
        """
        Triggers authentication process by sending HCI event AUTHENTICATION_REQUESTED
        """
        self._device.l2cap.SecurityLinkEnsureAuthenticated(self._cert_address)

    def security_link_release(self):
        """
        Releases a Held open ACL allowing for the ACL to time out after the default time
        """
        self._device.l2cap.SecurityLinkRelease(self._cert_address)

    def security_link_disconnect(self):
        """
        Immediately release and disconnect ACL
        """
        self._device.l2cap.SecurityLinkDisconnect(self._cert_address)

    def verify_security_connection(self):
        """
        Verify that we get a connection and a link key request
        """
        assertThat(self.get_security_connection_event_stream()).emits(
            lambda event: event.event_type ==
            LinkSecurityInterfaceCallbackEventType.ON_CONNECTED)
        assertThat(self._hci.get_event_stream()).emits(
            HciMatchers.LinkKeyRequest())
 def setup_test(self):
     super().setup_test()
     self.cert_hci = PyHci(self.cert, acl_streaming=True)
     self.dut_acl_manager = PyAclManager(self.dut)
class AclManagerTest(GdBaseTestClass):
    def setup_class(self):
        super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')

    # todo: move into GdBaseTestClass, based on modules inited
    def setup_test(self):
        super().setup_test()
        self.cert_hci = PyHci(self.cert, acl_streaming=True)
        self.dut_acl_manager = PyAclManager(self.dut)

    def teardown_test(self):
        self.cert_hci.close()
        self.dut_acl_manager.close()
        super().teardown_test()

    def test_dut_connects(self):
        self.cert_hci.enable_inquiry_and_page_scan()
        cert_address = self.cert_hci.read_own_address()

        with self.dut_acl_manager.initiate_connection(cert_address) as dut_acl:
            cert_acl = self.cert_hci.accept_connection()
            cert_acl.send_first(
                b'\x26\x00\x07\x00This is just SomeAclData from the Cert')

            dut_acl.wait_for_connection_complete()

            dut_acl.send(
                b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')

            assertThat(cert_acl).emits(
                lambda packet: b'SomeMoreAclData' in packet.data)
            assertThat(dut_acl).emits(
                lambda packet: b'SomeAclData' in packet.payload)

    def test_cert_connects(self):
        dut_address = self.dut.hci_controller.GetMacAddressSimple()
        self.dut.neighbor.EnablePageScan(
            neighbor_facade.EnableMsg(enabled=True))

        self.dut_acl_manager.listen_for_incoming_connections()
        self.cert_hci.initiate_connection(dut_address)

        dut_acl = self.dut_acl_manager.accept_connection()

        cert_acl = self.cert_hci.complete_connection()

        dut_acl.send(
            b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')

        cert_acl.send_first(
            b'\x26\x00\x07\x00This is just SomeAclData from the Cert')

        assertThat(cert_acl).emits(
            lambda packet: b'SomeMoreAclData' in packet.data)
        assertThat(dut_acl).emits(
            lambda packet: b'SomeAclData' in packet.payload)

    def test_recombination_l2cap_packet(self):
        self.cert_hci.enable_inquiry_and_page_scan()
        cert_address = self.cert_hci.read_own_address()

        with self.dut_acl_manager.initiate_connection(cert_address) as dut_acl:
            cert_acl = self.cert_hci.accept_connection()
            cert_acl.send_first(b'\x06\x00\x07\x00Hello')
            cert_acl.send_continuing(b'!')
            cert_acl.send_first(b'\xe8\x03\x07\x00' + b'Hello' * 200)

            dut_acl.wait_for_connection_complete()

            assertThat(dut_acl).emits(
                lambda packet: b'Hello!' in packet.payload,
                lambda packet: b'Hello' * 200 in packet.payload).inOrder()
Esempio n. 9
0
class LeSecurityTest(GdBaseTestClass):
    """
        Collection of tests that each sample results from
        different (unique) combinations of io capabilities, authentication requirements, and oob data.
    """
    def setup_class(self):
        super().setup_class(dut_module='SECURITY', cert_module='SECURITY')

    def setup_test(self):
        super().setup_test()

        self.dut_security = PyLeSecurity(self.dut)
        self.cert_security = PyLeSecurity(self.cert)
        self.dut_hci = PyHci(self.dut)

        self.dut_address = common.BluetoothAddressWithType(
            address=common.BluetoothAddress(
                address=bytes(b'DD:05:04:03:02:01')),
            type=common.RANDOM_DEVICE_ADDRESS)
        privacy_policy = le_initiator_address_facade.PrivacyPolicy(
            address_policy=le_initiator_address_facade.AddressPolicy.
            USE_STATIC_ADDRESS,
            address_with_type=self.dut_address)
        self.dut.security.SetLeInitiatorAddressPolicy(privacy_policy)
        self.cert_address = common.BluetoothAddressWithType(
            address=common.BluetoothAddress(
                address=bytes(b'C5:11:FF:AA:33:22')),
            type=common.RANDOM_DEVICE_ADDRESS)
        cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy(
            address_policy=le_initiator_address_facade.AddressPolicy.
            USE_STATIC_ADDRESS,
            address_with_type=self.cert_address)
        self.cert.security.SetLeInitiatorAddressPolicy(cert_privacy_policy)

    def teardown_test(self):
        self.dut_hci.close()
        self.dut_security.close()
        self.cert_security.close()
        super().teardown_test()

    def _prepare_cert_for_connection(self):
        # DUT Advertises
        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_The_CERT'))
        gap_data = le_advertising_facade.GapDataMsg(
            data=bytes(gap_name.Serialize()))
        config = le_advertising_facade.AdvertisingConfig(
            advertisement=[gap_data],
            interval_min=512,
            interval_max=768,
            event_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
            address_type=common.RANDOM_DEVICE_ADDRESS,
            channel_map=7,
            filter_policy=le_advertising_facade.AdvertisingFilterPolicy.
            ALL_DEVICES)
        request = le_advertising_facade.CreateAdvertiserRequest(config=config)
        create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(
            request)

    def _prepare_dut_for_connection(self):
        # DUT Advertises
        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_The_DUT'))
        gap_data = le_advertising_facade.GapDataMsg(
            data=bytes(gap_name.Serialize()))
        config = le_advertising_facade.AdvertisingConfig(
            advertisement=[gap_data],
            interval_min=512,
            interval_max=768,
            event_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
            address_type=common.RANDOM_DEVICE_ADDRESS,
            channel_map=7,
            filter_policy=le_advertising_facade.AdvertisingFilterPolicy.
            ALL_DEVICES)
        request = le_advertising_facade.CreateAdvertiserRequest(config=config)
        create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(
            request)

    @metadata(pts_test_id="SM/MAS/PROT/BV-01-C",
              pts_test_name="SMP Time Out – IUT Initiator")
    def test_le_smp_timeout_iut_initiator(self):
        """
            Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator.
        """
        self._prepare_cert_for_connection()
        self.dut.security.CreateBondLe(self.cert_address)
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED),
            timeout=timedelta(seconds=35))

    @metadata(pts_test_id="SM/SLA/PROT/BV-02-C",
              pts_test_name="SMP Time Out – IUT Responder")
    def test_le_smp_timeout_iut_responder(self):
        """
            Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator.
        """
        self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.dut.security.SetLeIoCapability(DISPLAY_ONLY)

        self._prepare_dut_for_connection()

        # 1. Lower Tester transmits Pairing Request.
        self.cert.security.CreateBondLe(self.dut_address)

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT),
            timeout=timedelta(seconds=35))

        # 2. IUT responds with Pairing Response.
        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.cert_address))

        # 3. In phase 2, Lower Tester does not issue the expected Pairing Confirm.

        # Here the cert receives DISPLAY_PASSKEY_ENTRY. By not replying to it we make sure Pairing Confirm is never sent
        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY),
            timeout=timedelta(seconds=5))

        # 4. IUT times out 30 seconds after issued Pairing Response and reports the failure to the Upper Tester.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED),
            timeout=timedelta(seconds=35))

        # 5. After additionally (at least) 10 seconds the Lower Tester issues the expected Pairing Confirm.
        # 6. The IUT closes the connection before receiving the delayed response or does not respond to it when it is received.
        #TODO:
        #assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.Disconnect())

    @metadata(pts_test_id="SM/MAS/JW/BV-01-C",
              pts_test_name="Just Works IUT Initiator – Success")
    def test_just_works_iut_initiator(self):
        """
            Verify that the IUT performs the Just Works pairing procedure correctly as master, initiator when both sides do not require MITM protection.
        """
        self._prepare_cert_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements()

        self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements()

        # 1. IUT transmits Pairing Request command with:
        # a. IO capability set to any IO capability
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq Bonding Flags set to ‘00’ and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’
        self.dut.security.CreateBondLe(self.cert_address)

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. Lower Tester responds with a Pairing Response command, with:
        # a. IO capability set to “KeyboardDisplay”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq Bonding Flags set to ‘00’, and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.dut_address))

        # 3. IUT and Lower Tester perform phase 2 of the just works pairing procedure and establish an encrypted link with the key generated in phase 2.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(pts_test_id="SM/SLA/JW/BV-02-C",
              pts_test_name="Just Works IUT Responder – Success")
    def test_just_works_iut_responder(self):
        """
            Verify that the IUT is able to perform the Just Works pairing procedure correctly when acting as slave, responder.
        """
        self._prepare_dut_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements()

        self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements()

        # 1. Lower Tester transmits Pairing Request command with:
        # a. IO capability set to “NoInputNoOutput”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. MITM flag set to ‘0’ and all reserved bits are set to ‘0’
        self.cert.security.CreateBondLe(self.dut_address)

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. IUT responds with a Pairing Response command, with:
        # a. IO capability set to any IO capability
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.cert_address))

        # IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(pts_test_id="SM/SLA/JW/BI-03-C",
              pts_test_name=
              "Just Works IUT Responder – Handle AuthReq flag RFU correctly")
    def test_just_works_iut_responder_auth_req_rfu(self):
        """
            Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as slave, responder.
        """
        self._prepare_dut_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements()

        self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1,
                                                 secure_connections=1,
                                                 reserved_bits=2)

        # 1. Lower Tester transmits Pairing Request command with:
        # a. IO Capability set to ”NoInputNoOutput”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. MITM set to ‘0’ and all reserved bits are set to ‘1’
        self.cert.security.CreateBondLe(self.dut_address)

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. IUT responds with a Pairing Response command, with:
        # a. IO capability set to any IO capability
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. All reserved bits are set to ‘0’
        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.cert_address))

        # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(pts_test_id="SM/MAS/JW/BI-04-C",
              pts_test_name=
              "Just Works IUT Initiator – Handle AuthReq flag RFU correctly")
    def test_just_works_iut_initiator_auth_req_rfu(self):
        """
            Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as master, initiator.
        """
        self._prepare_cert_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements()

        self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1,
                                                 secure_connections=1,
                                                 reserved_bits=3)

        # 1. IUT transmits a Pairing Request command with:
        # a. IO Capability set to any IO Capability
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. All reserved bits are set to ‘0’. For the purposes of this test the Secure Connections bit and the Keypress bits in the AuthReq bonding flag set by the IUT are ignored by the Lower Tester.
        self.dut.security.CreateBondLe(self.cert_address)

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. Lower Tester responds with a Pairing Response command, with:
        # a. IO Capability set to “NoInputNoOutput”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘0’ and all reserved bits are set to ‘1’. The SC and Keypress bits in the AuthReq bonding flag are set to 0 by the Lower Tester for this test.
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.dut_address))

        # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(
        pts_test_id="SM/MAS/SCJW/BV-01-C",
        pts_test_name="Just Works, IUT Initiator, Secure Connections – Success"
    )
    def test_just_works_iut_initiator_secure_connections(self):
        """
            Verify that the IUT supporting LE Secure Connections performs the Just Works or Numeric Comparison pairing procedure correctly as initiator.
        """
        self._prepare_cert_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(secure_connections=1)

        # 1. IUT transmits Pairing Request command with:
        # a. IO capability set to any IO capability
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq Bonding Flags set to ‘00’, the MITM flag set to either ‘0’ for Just Works or '1' for Numeric Comparison, Secure Connections flag set to '1' and all the reserved bits are set to ‘0’
        self.dut.security.CreateBondLe(self.cert_address)

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. Lower Tester responds with a Pairing Response command, with:
        # a. IO capability set to “KeyboardDisplay”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq Bonding Flags set to ‘00’, the MITM flag set to ‘0’, Secure Connections flag set to '1' and all the reserved bits are set to ‘0’
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.dut_address))

        # 3. IUT and Lower Tester perform phase 2 of the Just Works or Numeric Comparison pairing procedure according to the MITM flag and IO capabilities, and establish an encrypted link with the LTK generated in phase 2.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(
        pts_test_id="SM/SLA/SCJW/BV-02-C",
        pts_test_name="Just Works, IUT Responder, Secure Connections – Success"
    )
    def test_just_works_iut_responder_secure_connections(self):
        """
            Verify that the IUT supporting LE Secure Connections is able to perform the Just Works or Numeric Comparison pairing procedure correctly when acting as responder.
        """
        self._prepare_dut_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(secure_connections=1)

        # 1. Lower Tester transmits Pairing Request command with:
        # a. IO capability set to “NoInputNoOutput”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq Bonding Flags set to ‘00’, MITM flag set to ‘0’, Secure Connections flag set to '1' and all reserved bits are set to ‘0’
        self.cert.security.CreateBondLe(self.dut_address)

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. IUT responds with a Pairing Response command, with:
        # a. IO capability set to any IO capability
        # b. AuthReq Bonding Flags set to ‘00’, MITM flag set to either ‘0’ for Just Works or '1' for Numeric Comparison, Secure Connections flag set to '1' and all reserved bits are set to ‘0’
        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.cert_address))

        # 3. UT and Lower Tester perform phase 2 of the Just Works or Numeric Comparison pairing procedure according to the MITM flag and IO capabilities, and establish an encrypted link with the LTK generated in phase 2.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(
        pts_test_id="SM/SLA/SCJW/BV-03-C",
        pts_test_name=
        "Just Works, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly"
    )
    def test_just_works_iut_responder_secure_connections_auth_req_rfu(self):
        """
            Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as slave, responder.
        """
        self._prepare_dut_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1,
                                                 secure_connections=1,
                                                 reserved_bits=3)

        # 1. Lower Tester transmits Pairing Request command with:
        # a. IO Capability set to ”NoInputNoOutput”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. MITM set to ‘0’ and all reserved bits are set to a random value.
        self.cert.security.CreateBondLe(self.dut_address)

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. IUT responds with a Pairing Response command, with:
        # a. IO capability set to any IO capability
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. All reserved bits are set to ‘0’
        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.cert_address))

        # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(
        pts_test_id="SM/MAS/SCJW/BV-04-C",
        pts_test_name=
        "Just Works, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly"
    )
    def test_just_works_iut_initiator_secure_connections_auth_req_rfu(self):
        """
            Verify that the IUT is able to perform the Just Works pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as master, initiator.
        """
        self._prepare_cert_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1,
                                                 secure_connections=1,
                                                 reserved_bits=3)

        # 1. IUT transmits a Pairing Request command with:
        # a. IO Capability set to any IO Capability
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. All reserved bits are set to ‘0’.
        self.dut.security.CreateBondLe(self.cert_address)

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. Lower Tester responds with a Pairing Response command, with:
        # a. IO Capability set to “NoInputNoOutput”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘0’ and all reserved bits are set to a random value.
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.dut_address))

        # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED))

    @metadata(pts_test_id="SM/MAS/SCPK/BV-01-C",
              pts_test_name=
              "Passkey Entry, IUT Initiator, Secure Connections – Success")
    def test_passkey_entry_iut_initiator_secure_connections(self):
        """
            Verify that the IUT supporting LE Secure Connections performs the Passkey Entry pairing procedure correctly as master, initiator.
        """
        self._prepare_cert_for_connection()

        self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)

        # 1. IUT transmits Pairing Request command with:
        # a. IO capability set to “DisplayOnly” or “KeyboardOnly”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq bonding flag set to ‘00’, the MITM flag set to ‘0’ and Secure Connections flag set to '1'. Keypress bit is set to '1' if supported
        self.dut.security.CreateBondLe(self.cert_address)

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. Lower Tester responds with a Pairing Response command, with:
        # a. IO capability set to “KeyboardOnly”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq bonding flag set to ‘00’, the MITM flag set to ‘1’, Secure Connections flag set to '1' and all reserved bits are set to ‘0’. Keypress bit is set to '1' if supported by the IUT.
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.dut_address))

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY))

        # 3. During the phase 2 pairing, the IUT displays the 6-digit passkey while the Lower Tester prompts user to enter the 6-digit passkey. If the IUT’s IO capabilities are “KeyboardOnly” the passkey is not displayed and both IUT and Lower Tester enter the same 6-digit passkey. If Keypress bit is set, pairing keypress notifications are sent by the Lower Tester.
        passkey = self.dut_security.wait_for_ui_event_passkey()

        if passkey == 0:
            print("Passkey did not arrive into test")

        # 4. IUT and Lower Tester use the same 6-digit passkey.
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PASSKEY,
                          numeric_value=passkey,
                          unique_id=1,
                          address=self.dut_address))

        # 5. IUT and Lower Tester perform phase 2 of the Passkey Entry pairing procedure and establish an encrypted link with the LTK generated in phase 2.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED),
            timeout=timedelta(seconds=10))

    @metadata(pts_test_id="SM/SLA/SCPK/BV-02-C",
              pts_test_name=
              "Passkey Entry, IUT Responder, Secure Connections – Success")
    def test_passkey_entry_iut_responder_secure_connections(self):
        """
            Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure correctly when acting as slave, responder.
        """
        self._prepare_dut_for_connection()

        self.dut.security.SetLeIoCapability(DISPLAY_ONLY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(KEYBOARD_DISPLAY)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1)

        # 1. Lower Tester transmits Pairing Request command with:
        # a. IO capability set to “KeyboardDisplay”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’, and the MITM flag set to ‘1’ Secure Connections flag set to '1' and all reserved bits are set to ‘0’
        self.cert.security.CreateBondLe(self.dut_address)

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. IUT responds with a Pairing Response command, with:
        # a. IO capability set to “KeyboardOnly” or “KeyboardDisplay” or “DisplayYesNo” or “DisplayOnly”
        # b. Secure Connections flag set to '1'. Keypress bit is set to '1' if supported by IUT
        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.cert_address))

        # 3. During the phase 2 passkey pairing process, Lower Tester displays the 6-digit passkey while the IUT prompts user to enter the 6-digit passkey. If the IO capabilities of the IUT are “DisplayYesNo” or “DisplayOnly” the IUT displays the 6-digit passkey while the Lower Tester enters the 6-digit passkey. If Keypress bit is set, pairing keypress notifications are send by the IUT
        passkey = self.dut_security.wait_for_ui_event_passkey()

        if passkey == 0:
            print("Passkey did not arrive into test")

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY))

        # 4. IUT and Lower Tester use the same pre-defined 6-digit passkey.
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PASSKEY,
                          numeric_value=passkey,
                          unique_id=1,
                          address=self.dut_address))

        # 5. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the LTK generated in phase 2.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED),
            timeout=timedelta(seconds=10))

    @metadata(
        pts_test_id="SM/SLA/SCPK/BV-03-C",
        pts_test_name=
        "Passkey Entry, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly"
    )
    def test_passkey_entry_iut_responder_secure_connections_auth_req_rfu(self):
        """
            Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as slave, responder.
        """
        self._prepare_dut_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1,
                                                 secure_connections=1,
                                                 reserved_bits=3)

        # 1. Lower Tester transmits Pairing Request command with:
        # a. IO Capability set to ”KeyboardOnly”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. MITM set to ‘1’ and all reserved bits are set to a random value
        self.cert.security.CreateBondLe(self.dut_address)

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. IUT responds with a Pairing Response command, with:
        # a. IO Capability set to “KeyboardOnly” or “DisplayOnly”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. All reserved bits are set to ‘0’
        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.cert_address))

        passkey = self.cert_security.wait_for_ui_event_passkey()

        if passkey == 0:
            print("Passkey did not arrive into test")

        assertThat(self.dut_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY))

        self.dut.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PASSKEY,
                          numeric_value=passkey,
                          unique_id=1,
                          address=self.cert_address))

        # 3. IUT and Lower Tester perform phase 2 of the Passkey Entry pairing and establish an encrypted link with the generated LTK.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED),
            timeout=timedelta(seconds=10))

    @metadata(
        pts_test_id="SM/MAS/SCPK/BV-04-C",
        pts_test_name=
        "Passkey Entry, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly"
    )
    def test_passkey_entry_iut_initiator_secure_connections_auth_req_rfu(self):
        """
            Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as master, initiator.
        """
        self._prepare_cert_for_connection()

        self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY)
        self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.dut_security.SetLeAuthRequirements(secure_connections=1)

        self.cert.security.SetLeIoCapability(KEYBOARD_ONLY)
        self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT)
        self.cert_security.SetLeAuthRequirements(mitm=1,
                                                 secure_connections=1,
                                                 reserved_bits=3)

        # 1. IUT transmits a Pairing Request command with:
        # a. IO Capability set to “DisplayOnly” or “DisplayYesNo” or “KeyboardOnly” or “KeyboardDisplay”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. All reserved bits are set to ‘0’.
        self.dut.security.CreateBondLe(self.cert_address)

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

        # 2. Lower Tester responds with a Pairing Response command, with:
        # a. IO Capability set to “KeyboardOnly”
        # b. OOB data flag set to 0x00 (OOB Authentication data not present)
        # c. AuthReq bonding flag set to the value indicated in the IXIT [7] for ‘Bonding Flags’ and the MITM flag set to ‘1’ and all reserved bits are set to a random value.
        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                          boolean=True,
                          unique_id=1,
                          address=self.dut_address))

        assertThat(self.cert_security.get_ui_stream()).emits(
            SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY))

        passkey = self.dut_security.wait_for_ui_event_passkey()

        self.cert.security.SendUiCallback(
            UiCallbackMsg(message_type=UiCallbackType.PASSKEY,
                          numeric_value=passkey,
                          unique_id=1,
                          address=self.dut_address))

        # 3.    IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK.
        assertThat(self.dut_security.get_bond_stream()).emits(
            SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED),
            timeout=timedelta(seconds=10))

    @metadata(
        pts_test_id="SM/MAS/SCOB/BV-01-C",
        pts_test_name="Out of Band, IUT Initiator, Secure Connections – Success"
    )
    def test_out_of_band_iut_initiator_secure_connections(self):
        """
            Verify that the IUT supporting LE Secure Connections performs the Out-of-Band pairing procedure correctly as master, initiator.
        """

        oob_combinations = [(OOB_NOT_PRESENT, OOB_PRESENT),
                            (OOB_PRESENT, OOB_NOT_PRESENT),
                            (OOB_PRESENT, OOB_PRESENT)]

        for (dut_oob_flag, cert_oob_flag) in oob_combinations:
            print("oob flag combination dut: " + str(dut_oob_flag) +
                  ", cert: " + str(cert_oob_flag))

            self._prepare_cert_for_connection()

            if dut_oob_flag == LeOobDataFlag.PRESENT:
                oobdata = self.cert.security.GetOutOfBandData(
                    empty_proto.Empty())
                self.dut.security.SetOutOfBandData(
                    OobDataMessage(
                        address=self.cert_address,
                        le_sc_confirmation_value=oobdata.
                        le_sc_confirmation_value,
                        le_sc_random_value=oobdata.le_sc_random_value))

            if cert_oob_flag == LeOobDataFlag.PRESENT:
                oobdata = self.dut.security.GetOutOfBandData(
                    empty_proto.Empty())
                self.cert.security.SetOutOfBandData(
                    OobDataMessage(
                        address=self.dut_address,
                        le_sc_confirmation_value=oobdata.
                        le_sc_confirmation_value,
                        le_sc_random_value=oobdata.le_sc_random_value))

            self.dut.security.SetLeIoCapability(KEYBOARD_ONLY)
            self.dut.security.SetLeOobDataPresent(dut_oob_flag)
            self.dut_security.SetLeAuthRequirements(bond=1,
                                                    mitm=1,
                                                    secure_connections=1)

            self.cert.security.SetLeIoCapability(DISPLAY_ONLY)
            self.cert.security.SetLeOobDataPresent(cert_oob_flag)
            self.cert_security.SetLeAuthRequirements(bond=1,
                                                     mitm=1,
                                                     secure_connections=1)

            # 1. IUT transmits a Pairing Request command with OOB data flag set to either 0x00 or 0x01, and Secure Connections flag set to '1'.
            self.dut.security.CreateBondLe(self.cert_address)

            assertThat(self.cert_security.get_ui_stream()).emits(
                SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT))

            # 2. Lower Tester responds with a Pairing Response command with Secure Connections flag set to '1' and OOB data flag set to either 0x00 or 0x01.
            self.cert.security.SendUiCallback(
                UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT,
                              boolean=True,
                              unique_id=1,
                              address=self.dut_address))

            # 3. IUT uses the 128-bit value generated by the Lower Tester as the confirm value. Similarly, the Lower Tester uses the 128-bit value generated by the IUT as the confirm value.

            # 4. IUT and Lower Tester perform phase 2 of the pairing process and establish an encrypted link with an LTK generated using the OOB data in phase 2.
            assertThat(self.dut_security.get_bond_stream()).emits(
                SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED),
                timeout=timedelta(seconds=10))

            assertThat(self.cert_security.get_bond_stream()).emits(
                SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED),
                timeout=timedelta(seconds=10))

            self.dut.security.RemoveBond(self.cert_address)
            self.cert.security.RemoveBond(self.dut_address)

            assertThat(self.dut_security.get_bond_stream()).emits(
                SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED))

            #disconnection should happen after one second timeout, sleep for 2 just to be sure
            #TODO(jpawlowski): wait for disconnection event instead of sleeping.
            time.sleep(2)
Esempio n. 10
0
 def setup_test(self):
     super().setup_test()
     self.dut_hci = PyHci(self.dut, acl_streaming=True)
     self.cert_hal = PyHal(self.cert)
     self.cert_hal.send_hci_command(ResetBuilder())
Esempio n. 11
0
class DirectHciTest(GdBaseTestClass):
    def setup_class(self):
        super().setup_class(dut_module='HCI', cert_module='HAL')

    def setup_test(self):
        super().setup_test()
        self.dut_hci = PyHci(self.dut, acl_streaming=True)
        self.cert_hal = PyHal(self.cert)
        self.cert_hal.send_hci_command(ResetBuilder())

    def teardown_test(self):
        self.dut_hci.close()
        self.cert_hal.close()
        super().teardown_test()

    def enqueue_acl_data(self, handle, pb_flag, b_flag, data):
        acl = AclBuilder(handle, pb_flag, b_flag, RawBuilder(data))
        self.dut.hci.SendAcl(common.Data(payload=bytes(acl.Serialize())))

    def test_local_hci_cmd_and_event(self):
        # Loopback mode responds with ACL and SCO connection complete
        self.dut_hci.register_for_events(EventCode.LOOPBACK_COMMAND)
        self.dut_hci.send_command(
            WriteLoopbackModeBuilder(LoopbackMode.ENABLE_LOCAL))

        self.dut_hci.send_command(ReadLocalNameBuilder())
        assertThat(self.dut_hci.get_event_stream()).emits(
            HciMatchers.LoopbackOf(ReadLocalNameBuilder()))

    def test_inquiry_from_dut(self):
        self.dut_hci.register_for_events(EventCode.INQUIRY_RESULT)

        self.cert_hal.enable_inquiry_and_page_scan()
        lap = Lap()
        lap.lap = 0x33
        self.dut_hci.send_command(InquiryBuilder(lap, 0x30, 0xff))
        assertThat(self.dut_hci.get_event_stream()).emits(
            HciMatchers.EventWithCode(EventCode.INQUIRY_RESULT))

    def test_le_ad_scan_cert_advertises(self):
        self.dut_hci.register_for_le_events(
            SubeventCode.EXTENDED_ADVERTISING_REPORT,
            SubeventCode.ADVERTISING_REPORT)

        # DUT Scans
        self.dut_hci.send_command(
            LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
        phy_scan_params = PhyScanParameters()
        phy_scan_params.le_scan_interval = 6553
        phy_scan_params.le_scan_window = 6553
        phy_scan_params.le_scan_type = LeScanType.ACTIVE

        self.dut_hci.send_command(
            LeSetExtendedScanParametersBuilder(
                OwnAddressType.RANDOM_DEVICE_ADDRESS,
                LeScanningFilterPolicy.ACCEPT_ALL, 1, [phy_scan_params]))
        self.dut_hci.send_command(
            LeSetExtendedScanEnableBuilder(Enable.ENABLED,
                                           FilterDuplicates.DISABLED, 0, 0))

        # CERT Advertises
        advertising_handle = 0
        self.cert_hal.send_hci_command(
            LeSetExtendedAdvertisingLegacyParametersBuilder(
                advertising_handle,
                LegacyAdvertisingProperties.ADV_IND,
                512,
                768,
                7,
                OwnAddressType.RANDOM_DEVICE_ADDRESS,
                PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
                'A6:A5:A4:A3:A2:A1',
                AdvertisingFilterPolicy.ALL_DEVICES,
                0xF7,
                1,  # SID
                Enable.DISABLED  # Scan request notification
            ))

        self.cert_hal.send_hci_command(
            LeSetExtendedAdvertisingRandomAddressBuilder(
                advertising_handle, '0C:05:04:03:02:01'))
        gap_name = GapData()
        gap_name.data_type = GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_A_Cert'))

        self.cert_hal.send_hci_command(
            LeSetExtendedAdvertisingDataBuilder(
                advertising_handle, Operation.COMPLETE_ADVERTISEMENT,
                FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_name]))

        gap_short_name = GapData()
        gap_short_name.data_type = GapDataType.SHORTENED_LOCAL_NAME
        gap_short_name.data = list(bytes(b'Im_A_C'))

        self.cert_hal.send_hci_command(
            LeSetExtendedAdvertisingScanResponseBuilder(
                advertising_handle, Operation.COMPLETE_ADVERTISEMENT,
                FragmentPreference.CONTROLLER_SHOULD_NOT, [gap_short_name]))

        enabled_set = EnabledSet()
        enabled_set.advertising_handle = 0
        enabled_set.duration = 0
        enabled_set.max_extended_advertising_events = 0
        self.cert_hal.send_hci_command(
            LeSetExtendedAdvertisingEnableBuilder(Enable.ENABLED,
                                                  [enabled_set]))

        assertThat(self.dut_hci.get_le_event_stream()).emits(
            lambda packet: b'Im_A_Cert' in packet.payload)

        self.cert_hal.send_hci_command(
            LeSetExtendedAdvertisingEnableBuilder(Enable.DISABLED,
                                                  [enabled_set]))
        self.dut_hci.send_command(
            LeSetExtendedScanEnableBuilder(Enable.DISABLED,
                                           FilterDuplicates.DISABLED, 0, 0))

    def _verify_le_connection_complete(self):
        cert_conn_complete_capture = HalCaptures.LeConnectionCompleteCapture()
        assertThat(self.cert_hal.get_hci_event_stream()).emits(
            cert_conn_complete_capture)
        cert_handle = cert_conn_complete_capture.get().GetConnectionHandle()

        dut_conn_complete_capture = HciCaptures.LeConnectionCompleteCapture()
        assertThat(self.dut_hci.get_le_event_stream()).emits(
            dut_conn_complete_capture)
        dut_handle = dut_conn_complete_capture.get().GetConnectionHandle()

        return (dut_handle, cert_handle)

    @staticmethod
    def _create_phy_scan_params():
        phy_scan_params = LeCreateConnPhyScanParameters()
        phy_scan_params.scan_interval = 0x60
        phy_scan_params.scan_window = 0x30
        phy_scan_params.conn_interval_min = 0x18
        phy_scan_params.conn_interval_max = 0x28
        phy_scan_params.conn_latency = 0
        phy_scan_params.supervision_timeout = 0x1f4
        phy_scan_params.min_ce_length = 0
        phy_scan_params.max_ce_length = 0
        return phy_scan_params

    def test_le_connection_dut_advertises(self):
        self.dut_hci.register_for_le_events(
            SubeventCode.CONNECTION_COMPLETE,
            SubeventCode.ADVERTISING_SET_TERMINATED,
            SubeventCode.ENHANCED_CONNECTION_COMPLETE,
            SubeventCode.READ_REMOTE_FEATURES_COMPLETE)
        # Cert Connects
        self.cert_hal.send_hci_command(
            LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
        phy_scan_params = DirectHciTest._create_phy_scan_params()
        self.cert_hal.send_hci_command(
            LeExtendedCreateConnectionBuilder(
                InitiatorFilterPolicy.USE_PEER_ADDRESS,
                OwnAddressType.RANDOM_DEVICE_ADDRESS,
                AddressType.RANDOM_DEVICE_ADDRESS, '0D:05:04:03:02:01', 1,
                [phy_scan_params]))

        advertisement = self.dut_hci.create_advertisement(
            0, '0D:05:04:03:02:01')
        advertisement.set_data(b'Im_The_DUT')
        advertisement.set_scan_response(b'Im_The_D')
        advertisement.start()

        (dut_handle, cert_handle) = self._verify_le_connection_complete()

        self.dut_hci.send_command(LeReadRemoteFeaturesBuilder(dut_handle))
        assertThat(self.dut_hci.get_le_event_stream()).emits(
            lambda packet: packet.payload[0] == int(
                EventCode.LE_META_EVENT) and packet.payload[2] == int(
                    SubeventCode.READ_REMOTE_FEATURES_COMPLETE))

        # Send ACL Data
        self.enqueue_acl_data(
            dut_handle, PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
            BroadcastFlag.POINT_TO_POINT, bytes(b'Just SomeAclData'))
        self.cert_hal.send_acl_first(cert_handle,
                                     bytes(b'Just SomeMoreAclData'))

        assertThat(
            self.cert_hal.get_acl_stream()).emits(lambda packet: logging.debug(
                packet.payload) or b'SomeAclData' in packet.payload)
        assertThat(self.dut_hci.get_raw_acl_stream()).emits(
            lambda packet: logging.debug(
                packet.payload) or b'SomeMoreAclData' in packet.payload)

    def test_le_connect_list_connection_cert_advertises(self):
        self.dut_hci.register_for_le_events(
            SubeventCode.CONNECTION_COMPLETE,
            SubeventCode.ENHANCED_CONNECTION_COMPLETE)
        # DUT Connects
        self.dut_hci.send_command(
            LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
        self.dut_hci.send_command(
            LeAddDeviceToConnectListBuilder(ConnectListAddressType.RANDOM,
                                            '0C:05:04:03:02:01'))
        phy_scan_params = DirectHciTest._create_phy_scan_params()
        self.dut_hci.send_command(
            LeExtendedCreateConnectionBuilder(
                InitiatorFilterPolicy.USE_CONNECT_LIST,
                OwnAddressType.RANDOM_DEVICE_ADDRESS,
                AddressType.RANDOM_DEVICE_ADDRESS, 'BA:D5:A4:A3:A2:A1', 1,
                [phy_scan_params]))

        advertisement = self.cert_hal.create_advertisement(
            1,
            '0C:05:04:03:02:01',
            min_interval=512,
            max_interval=768,
            peer_address='A6:A5:A4:A3:A2:A1',
            tx_power=0x7f,
            sid=0)
        advertisement.set_data(b'Im_A_Cert')
        advertisement.start()

        # LeConnectionComplete
        self._verify_le_connection_complete()

    def test_connection_dut_connects(self):
        self.dut_hci.send_command(WritePageTimeoutBuilder(0x4000))

        self.cert_hal.enable_inquiry_and_page_scan()
        address = self.cert_hal.read_own_address()

        self.dut_hci.initiate_connection(address)
        cert_acl = self.cert_hal.accept_connection()
        dut_acl = self.dut_hci.complete_connection()

        # Send ACL Data
        dut_acl.send_first(b'Just SomeAclData')
        cert_acl.send_first(b'Just SomeMoreAclData')

        assertThat(self.cert_hal.get_acl_stream()).emits(
            lambda packet: b'SomeAclData' in packet.payload)
        assertThat(self.dut_hci.get_raw_acl_stream()).emits(
            lambda packet: b'SomeMoreAclData' in packet.payload)

    def test_connection_cert_connects(self):
        self.cert_hal.send_hci_command(WritePageTimeoutBuilder(0x4000))

        self.dut_hci.enable_inquiry_and_page_scan()
        address = self.dut_hci.read_own_address()

        self.cert_hal.initiate_connection(address)
        dut_acl = self.dut_hci.accept_connection()
        cert_acl = self.cert_hal.complete_connection()

        # Send ACL Data
        dut_acl.send_first(b'This is just SomeAclData')
        cert_acl.send_first(b'This is just SomeMoreAclData')

        assertThat(self.cert_hal.get_acl_stream()).emits(
            lambda packet: b'SomeAclData' in packet.payload)
        assertThat(self.dut_hci.get_raw_acl_stream()).emits(
            lambda packet: b'SomeMoreAclData' in packet.payload)
Esempio n. 12
0
class DirectHciTest(GdBaseTestClass):
    def setup_class(self):
        super().setup_class(dut_module='HCI', cert_module='HAL')

    def setup_test(self):
        super().setup_test()
        self.dut_hci = PyHci(self.dut, acl_streaming=True)
        self.cert_hal = PyHal(self.cert)
        self.cert_hal.send_hci_command(hci_packets.ResetBuilder().Serialize())

    def teardown_test(self):
        self.dut_hci.close()
        self.cert_hal.close()
        super().teardown_test()

    def send_hal_hci_command(self, command):
        self.cert_hal.send_hci_command(bytes(command.Serialize()))

    def enqueue_acl_data(self, handle, pb_flag, b_flag, acl):
        acl_msg = hci_facade.AclMsg(handle=int(handle),
                                    packet_boundary_flag=int(pb_flag),
                                    broadcast_flag=int(b_flag),
                                    data=acl)
        self.dut.hci.SendAclData(acl_msg)

    def send_hal_acl_data(self, handle, pb_flag, b_flag, acl):
        lower = handle & 0xff
        upper = (handle >> 8) & 0xf
        upper = upper | int(pb_flag) & 0x3
        upper = upper | ((int(b_flag) & 0x3) << 2)
        lower_length = len(acl) & 0xff
        upper_length = (len(acl) & 0xff00) >> 8
        concatenated = bytes([lower, upper, lower_length, upper_length] +
                             list(acl))
        self.cert_hal.send_acl(concatenated)

    def test_local_hci_cmd_and_event(self):
        # Loopback mode responds with ACL and SCO connection complete
        self.dut_hci.register_for_events(
            hci_packets.EventCode.LOOPBACK_COMMAND)

        self.dut_hci.send_command_with_complete(
            hci_packets.WriteLoopbackModeBuilder(
                hci_packets.LoopbackMode.ENABLE_LOCAL))

        cmd2loop = hci_packets.ReadLocalNameBuilder()
        self.dut_hci.send_command_with_complete(cmd2loop)

        looped_bytes = bytes(cmd2loop.Serialize())
        assertThat(self.dut_hci.get_event_stream()).emits(
            lambda packet: looped_bytes in packet.event)

    def test_inquiry_from_dut(self):
        self.dut_hci.register_for_events(hci_packets.EventCode.INQUIRY_RESULT)

        self.send_hal_hci_command(
            hci_packets.WriteScanEnableBuilder(
                hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
        lap = hci_packets.Lap()
        lap.lap = 0x33
        self.dut_hci.send_command_with_status(
            hci_packets.InquiryBuilder(lap, 0x30, 0xff))
        assertThat(self.dut_hci.get_event_stream()).emits(
            HciMatchers.EventWithCode(hci_packets.EventCode.INQUIRY_RESULT))

    def test_le_ad_scan_cert_advertises(self):
        self.dut_hci.register_for_le_events(
            hci_packets.SubeventCode.EXTENDED_ADVERTISING_REPORT)
        self.dut_hci.register_for_le_events(
            hci_packets.SubeventCode.ADVERTISING_REPORT)

        # DUT Scans
        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
        phy_scan_params = hci_packets.PhyScanParameters()
        phy_scan_params.le_scan_interval = 6553
        phy_scan_params.le_scan_window = 6553
        phy_scan_params.le_scan_type = hci_packets.LeScanType.ACTIVE

        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedScanParametersBuilder(
                hci_packets.AddressType.RANDOM_DEVICE_ADDRESS,
                hci_packets.LeSetScanningFilterPolicy.ACCEPT_ALL, 1,
                [phy_scan_params]))
        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedScanEnableBuilder(
                hci_packets.Enable.ENABLED,
                hci_packets.FilterDuplicates.DISABLED, 0, 0))

        # CERT Advertises
        advertising_handle = 0
        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder(
                advertising_handle,
                hci_packets.LegacyAdvertisingProperties.ADV_IND,
                512,
                768,
                7,
                hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
                hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
                'A6:A5:A4:A3:A2:A1',
                hci_packets.AdvertisingFilterPolicy.ALL_DEVICES,
                0xF7,
                1,  # SID
                hci_packets.Enable.DISABLED  # Scan request notification
            ))

        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(
                advertising_handle, '0C:05:04:03:02:01'))
        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_A_Cert!'))  # TODO: Fix and remove !

        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingDataBuilder(
                advertising_handle,
                hci_packets.Operation.COMPLETE_ADVERTISEMENT,
                hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT,
                [gap_name]))

        gap_short_name = hci_packets.GapData()
        gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME
        gap_short_name.data = list(bytes(b'Im_A_C'))

        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingScanResponseBuilder(
                advertising_handle,
                hci_packets.Operation.COMPLETE_ADVERTISEMENT,
                hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT,
                [gap_short_name]))

        enabled_set = hci_packets.EnabledSet()
        enabled_set.advertising_handle = 0
        enabled_set.duration = 0
        enabled_set.max_extended_advertising_events = 0
        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingEnableBuilder(
                hci_packets.Enable.ENABLED, [enabled_set]))

        assertThat(self.dut_hci.get_le_event_stream()).emits(
            lambda packet: b'Im_A_Cert' in packet.event)

        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingEnableBuilder(
                hci_packets.Enable.DISABLED, [enabled_set]))
        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedScanEnableBuilder(
                hci_packets.Enable.DISABLED,
                hci_packets.FilterDuplicates.DISABLED, 0, 0))

    def _verify_le_connection_complete(self):
        cert_conn_complete_capture = HalCaptures.LeConnectionCompleteCapture()
        assertThat(self.cert_hal.get_hci_event_stream()).emits(
            cert_conn_complete_capture)
        cert_handle = cert_conn_complete_capture.get().GetConnectionHandle()

        dut_conn_complete_capture = HciCaptures.LeConnectionCompleteCapture()
        assertThat(self.dut_hci.get_le_event_stream()).emits(
            dut_conn_complete_capture)
        dut_handle = dut_conn_complete_capture.get().GetConnectionHandle()

        return (dut_handle, cert_handle)

    @staticmethod
    def _create_phy_scan_params():
        phy_scan_params = hci_packets.LeCreateConnPhyScanParameters()
        phy_scan_params.scan_interval = 0x60
        phy_scan_params.scan_window = 0x30
        phy_scan_params.conn_interval_min = 0x18
        phy_scan_params.conn_interval_max = 0x28
        phy_scan_params.conn_latency = 0
        phy_scan_params.supervision_timeout = 0x1f4
        phy_scan_params.min_ce_length = 0
        phy_scan_params.max_ce_length = 0
        return phy_scan_params

    def test_le_connection_dut_advertises(self):
        self.dut_hci.register_for_le_events(
            hci_packets.SubeventCode.CONNECTION_COMPLETE)
        # Cert Connects
        self.send_hal_hci_command(
            hci_packets.LeSetRandomAddressBuilder('0C:05:04:03:02:01'))
        phy_scan_params = DirectHciTest._create_phy_scan_params()
        self.send_hal_hci_command(
            hci_packets.LeExtendedCreateConnectionBuilder(
                hci_packets.InitiatorFilterPolicy.USE_PEER_ADDRESS,
                hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
                hci_packets.AddressType.RANDOM_DEVICE_ADDRESS,
                '0D:05:04:03:02:01', 1, [phy_scan_params]))

        # DUT Advertises
        advertising_handle = 0
        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder(
                advertising_handle,
                hci_packets.LegacyAdvertisingProperties.ADV_IND,
                400,
                450,
                7,
                hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
                hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
                '00:00:00:00:00:00',
                hci_packets.AdvertisingFilterPolicy.ALL_DEVICES,
                0xF8,
                1,  #SID
                hci_packets.Enable.DISABLED  # Scan request notification
            ))

        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(
                advertising_handle, '0D:05:04:03:02:01'))

        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_The_DUT!'))  # TODO: Fix and remove !

        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedAdvertisingDataBuilder(
                advertising_handle,
                hci_packets.Operation.COMPLETE_ADVERTISEMENT,
                hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT,
                [gap_name]))

        gap_short_name = hci_packets.GapData()
        gap_short_name.data_type = hci_packets.GapDataType.SHORTENED_LOCAL_NAME
        gap_short_name.data = list(bytes(b'Im_The_D'))

        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedAdvertisingScanResponseBuilder(
                advertising_handle,
                hci_packets.Operation.COMPLETE_ADVERTISEMENT,
                hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT,
                [gap_short_name]))

        enabled_set = hci_packets.EnabledSet()
        enabled_set.advertising_handle = advertising_handle
        enabled_set.duration = 0
        enabled_set.max_extended_advertising_events = 0
        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetExtendedAdvertisingEnableBuilder(
                hci_packets.Enable.ENABLED, [enabled_set]))

        # Check for success of Enable
        assertThat(self.dut_hci.get_event_stream()).emits(
            HciMatchers.CommandComplete(
                hci_packets.OpCode.LE_SET_EXTENDED_ADVERTISING_ENABLE))

        (dut_handle, cert_handle) = self._verify_le_connection_complete()

        # Send ACL Data
        self.enqueue_acl_data(
            dut_handle,
            hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
            hci_packets.BroadcastFlag.POINT_TO_POINT,
            bytes(b'Just SomeAclData'))
        self.send_hal_acl_data(
            cert_handle,
            hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
            hci_packets.BroadcastFlag.POINT_TO_POINT,
            bytes(b'Just SomeMoreAclData'))

        assertThat(
            self.cert_hal.get_acl_stream()).emits(lambda packet: logging.debug(
                packet.payload) or b'SomeAclData' in packet.payload)
        assertThat(self.dut_hci.get_raw_acl_stream()).emits(
            lambda packet: logging.debug(
                packet.data) or b'SomeMoreAclData' in packet.data)

    def test_le_white_list_connection_cert_advertises(self):
        self.dut_hci.register_for_le_events(
            hci_packets.SubeventCode.CONNECTION_COMPLETE)
        # DUT Connects
        self.dut_hci.send_command_with_complete(
            hci_packets.LeSetRandomAddressBuilder('0D:05:04:03:02:01'))
        self.dut_hci.send_command_with_complete(
            hci_packets.LeAddDeviceToWhiteListBuilder(
                hci_packets.WhiteListAddressType.RANDOM, '0C:05:04:03:02:01'))
        phy_scan_params = DirectHciTest._create_phy_scan_params()
        self.dut_hci.send_command_with_status(
            hci_packets.LeExtendedCreateConnectionBuilder(
                hci_packets.InitiatorFilterPolicy.USE_WHITE_LIST,
                hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
                hci_packets.AddressType.RANDOM_DEVICE_ADDRESS,
                'BA:D5:A4:A3:A2:A1', 1, [phy_scan_params]))

        # CERT Advertises
        advertising_handle = 1
        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingLegacyParametersBuilder(
                advertising_handle,
                hci_packets.LegacyAdvertisingProperties.ADV_IND,
                512,
                768,
                7,
                hci_packets.OwnAddressType.RANDOM_DEVICE_ADDRESS,
                hci_packets.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS,
                'A6:A5:A4:A3:A2:A1',
                hci_packets.AdvertisingFilterPolicy.ALL_DEVICES,
                0x7F,
                0,  # SID
                hci_packets.Enable.DISABLED  # Scan request notification
            ))

        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingRandomAddressBuilder(
                advertising_handle, '0C:05:04:03:02:01'))

        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_A_Cert!'))  # TODO: Fix and remove !

        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingDataBuilder(
                advertising_handle,
                hci_packets.Operation.COMPLETE_ADVERTISEMENT,
                hci_packets.FragmentPreference.CONTROLLER_SHOULD_NOT,
                [gap_name]))
        enabled_set = hci_packets.EnabledSet()
        enabled_set.advertising_handle = 1
        enabled_set.duration = 0
        enabled_set.max_extended_advertising_events = 0
        self.send_hal_hci_command(
            hci_packets.LeSetExtendedAdvertisingEnableBuilder(
                hci_packets.Enable.ENABLED, [enabled_set]))

        # LeConnectionComplete
        self._verify_le_connection_complete()

    def _verify_connection_complete(self):
        cert_connection_complete_capture = HalCaptures.ConnectionCompleteCapture(
        )
        assertThat(self.cert_hal.get_hci_event_stream()).emits(
            cert_connection_complete_capture)
        cert_handle = cert_connection_complete_capture.get(
        ).GetConnectionHandle()

        dut_connection_complete_capture = HciCaptures.ConnectionCompleteCapture(
        )
        assertThat(self.dut_hci.get_event_stream()).emits(
            dut_connection_complete_capture)
        dut_handle = dut_connection_complete_capture.get().GetConnectionHandle(
        )

        return (dut_handle, cert_handle)

    def test_connection_dut_connects(self):
        self.dut_hci.send_command_with_complete(
            hci_packets.WritePageTimeoutBuilder(0x4000))

        # CERT Enables scans and gets its address
        self.send_hal_hci_command(hci_packets.ReadBdAddrBuilder())

        cert_read_bd_addr_capture = HalCaptures.ReadBdAddrCompleteCapture()
        assertThat(self.cert_hal.get_hci_event_stream()).emits(
            cert_read_bd_addr_capture)
        address = cert_read_bd_addr_capture.get().GetBdAddr()

        self.send_hal_hci_command(
            hci_packets.WriteScanEnableBuilder(
                hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))

        # DUT Connects
        self.dut_hci.send_command_with_status(
            hci_packets.CreateConnectionBuilder(
                address,
                0xcc18,  # Packet Type
                hci_packets.PageScanRepetitionMode.R0,
                0,
                hci_packets.ClockOffsetValid.INVALID,
                hci_packets.CreateConnectionRoleSwitch.ALLOW_ROLE_SWITCH))

        # Cert Accepts
        connect_request_capture = HalCaptures.ConnectionRequestCapture()
        assertThat(self.cert_hal.get_hci_event_stream()).emits(
            connect_request_capture, timeout=timedelta(seconds=20))
        connection_request = connect_request_capture.get()
        self.send_hal_hci_command(
            hci_packets.AcceptConnectionRequestBuilder(
                connection_request.GetBdAddr(),
                hci_packets.AcceptConnectionRequestRole.REMAIN_SLAVE))

        (dut_handle, cert_handle) = self._verify_connection_complete()

        # Send ACL Data
        self.enqueue_acl_data(
            dut_handle,
            hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
            hci_packets.BroadcastFlag.POINT_TO_POINT,
            bytes(b'Just SomeAclData'))
        self.send_hal_acl_data(
            cert_handle,
            hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
            hci_packets.BroadcastFlag.POINT_TO_POINT,
            bytes(b'Just SomeMoreAclData'))

        assertThat(self.cert_hal.get_acl_stream()).emits(
            lambda packet: b'SomeAclData' in packet.payload)
        assertThat(self.dut_hci.get_raw_acl_stream()).emits(
            lambda packet: b'SomeMoreAclData' in packet.data)

    def test_connection_cert_connects(self):
        self.send_hal_hci_command(hci_packets.WritePageTimeoutBuilder(0x4000))

        # DUT Enables scans and gets its address
        self.dut_hci.send_command_with_complete(
            hci_packets.WriteScanEnableBuilder(
                hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
        self.dut_hci.send_command_with_complete(
            hci_packets.ReadBdAddrBuilder())

        read_bd_addr_capture = HciCaptures.ReadBdAddrCompleteCapture()
        assertThat(self.dut_hci.get_event_stream()).emits(read_bd_addr_capture)
        address = read_bd_addr_capture.get().GetBdAddr()

        # Cert Connects
        self.send_hal_hci_command(
            hci_packets.CreateConnectionBuilder(
                address,
                0xcc18,  # Packet Type
                hci_packets.PageScanRepetitionMode.R0,
                0,
                hci_packets.ClockOffsetValid.INVALID,
                hci_packets.CreateConnectionRoleSwitch.ALLOW_ROLE_SWITCH))

        # DUT Accepts
        connection_request_capture = HciCaptures.ConnectionRequestCapture()
        assertThat(self.dut_hci.get_event_stream()).emits(
            connection_request_capture, timeout=timedelta(seconds=20))
        connection_request = connection_request_capture.get()
        self.dut_hci.send_command_with_status(
            hci_packets.AcceptConnectionRequestBuilder(
                connection_request.GetBdAddr(),
                hci_packets.AcceptConnectionRequestRole.REMAIN_SLAVE))

        (dut_handle, cert_handle) = self._verify_connection_complete()

        # Send ACL Data
        self.enqueue_acl_data(
            dut_handle,
            hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
            hci_packets.BroadcastFlag.POINT_TO_POINT,
            bytes(b'This is just SomeAclData'))
        self.send_hal_acl_data(
            cert_handle,
            hci_packets.PacketBoundaryFlag.FIRST_NON_AUTOMATICALLY_FLUSHABLE,
            hci_packets.BroadcastFlag.POINT_TO_POINT,
            bytes(b'This is just SomeMoreAclData'))

        assertThat(self.cert_hal.get_acl_stream()).emits(
            lambda packet: b'SomeAclData' in packet.payload)
        assertThat(self.dut_hci.get_raw_acl_stream()).emits(
            lambda packet: b'SomeMoreAclData' in packet.data)
Esempio n. 13
0
class AclManagerTest(GdBaseTestClass):
    def setup_class(self):
        super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')

    # todo: move into GdBaseTestClass, based on modules inited
    def setup_test(self):
        super().setup_test()
        self.cert_hci = PyHci(self.cert, acl_streaming=True)
        self.dut_acl_manager = PyAclManager(self.dut)

    def teardown_test(self):
        self.cert_hci.close()
        super().teardown_test()

    def test_dut_connects(self):
        self.cert_hci.enable_inquiry_and_page_scan()
        cert_address = self.cert_hci.read_own_address()

        self.dut_acl_manager.initiate_connection(cert_address)
        cert_acl = self.cert_hci.accept_connection()
        with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
            cert_acl.send_first(
                b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
            dut_acl.send(
                b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')

            assertThat(cert_acl).emits(
                lambda packet: b'SomeMoreAclData' in packet.payload)
            assertThat(dut_acl).emits(
                lambda packet: b'SomeAclData' in packet.payload)

    def test_cert_connects(self):
        dut_address = self.dut.hci_controller.GetMacAddressSimple()
        self.dut.neighbor.EnablePageScan(
            neighbor_facade.EnableMsg(enabled=True))

        self.dut_acl_manager.listen_for_an_incoming_connection()
        self.cert_hci.initiate_connection(dut_address)
        with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
            cert_acl = self.cert_hci.complete_connection()

            dut_acl.send(
                b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')

            cert_acl.send_first(
                b'\x26\x00\x07\x00This is just SomeAclData from the Cert')

            assertThat(cert_acl).emits(
                lambda packet: b'SomeMoreAclData' in packet.payload)
            assertThat(dut_acl).emits(
                lambda packet: b'SomeAclData' in packet.payload)

    def test_reject_broadcast(self):
        dut_address = self.dut.hci_controller.GetMacAddressSimple()
        self.dut.neighbor.EnablePageScan(
            neighbor_facade.EnableMsg(enabled=True))

        self.dut_acl_manager.listen_for_an_incoming_connection()
        self.cert_hci.initiate_connection(dut_address)
        with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
            cert_acl = self.cert_hci.complete_connection()

            cert_acl.send(
                hci_packets.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE,
                hci_packets.BroadcastFlag.ACTIVE_PERIPHERAL_BROADCAST,
                b'\x26\x00\x07\x00This is a Broadcast from the Cert')
            assertThat(dut_acl).emitsNone()

            cert_acl.send(
                hci_packets.PacketBoundaryFlag.FIRST_AUTOMATICALLY_FLUSHABLE,
                hci_packets.BroadcastFlag.POINT_TO_POINT,
                b'\x26\x00\x07\x00This is just SomeAclData from the Cert')
            assertThat(dut_acl).emits(
                lambda packet: b'SomeAclData' in packet.payload)

    def test_cert_connects_disconnects(self):
        dut_address = self.dut.hci_controller.GetMacAddressSimple()
        self.dut.neighbor.EnablePageScan(
            neighbor_facade.EnableMsg(enabled=True))

        self.dut_acl_manager.listen_for_an_incoming_connection()
        self.cert_hci.initiate_connection(dut_address)
        with self.dut_acl_manager.complete_incoming_connection() as dut_acl:
            cert_acl = self.cert_hci.complete_connection()

            dut_acl.send(
                b'\x29\x00\x07\x00This is just SomeMoreAclData from the DUT')

            cert_acl.send_first(
                b'\x26\x00\x07\x00This is just SomeAclData from the Cert')

            assertThat(cert_acl).emits(
                lambda packet: b'SomeMoreAclData' in packet.payload)
            assertThat(dut_acl).emits(
                lambda packet: b'SomeAclData' in packet.payload)

            dut_acl.disconnect(
                hci_packets.DisconnectReason.REMOTE_USER_TERMINATED_CONNECTION)
            dut_acl.wait_for_disconnection_complete()

    def test_recombination_l2cap_packet(self):
        self.cert_hci.enable_inquiry_and_page_scan()
        cert_address = self.cert_hci.read_own_address()

        self.dut_acl_manager.initiate_connection(cert_address)
        cert_acl = self.cert_hci.accept_connection()
        with self.dut_acl_manager.complete_outgoing_connection() as dut_acl:
            cert_acl.send_first(b'\x06\x00\x07\x00Hello')
            cert_acl.send_continuing(b'!')
            cert_acl.send_first(b'\xe8\x03\x07\x00' + b'Hello' * 200)

            assertThat(dut_acl).emits(
                lambda packet: b'Hello!' in packet.payload,
                lambda packet: b'Hello' * 200 in packet.payload).inOrder()
Esempio n. 14
0
class CertSecurity(PySecurity):
    """
        Contain all of the certification stack logic for sending and receiving
        HCI commands following the Classic Pairing flows.
    """
    _io_cap_lookup = {
        IoCapabilities.DISPLAY_ONLY:
        hci_packets.IoCapability.DISPLAY_ONLY,
        IoCapabilities.DISPLAY_YES_NO_IO_CAP:
        hci_packets.IoCapability.DISPLAY_YES_NO,
        IoCapabilities.KEYBOARD_ONLY:
        hci_packets.IoCapability.KEYBOARD_ONLY,
        IoCapabilities.NO_INPUT_NO_OUTPUT:
        hci_packets.IoCapability.NO_INPUT_NO_OUTPUT,
    }

    _auth_req_lookup = {
        AuthenticationRequirements.NO_BONDING:
        hci_packets.AuthenticationRequirements.NO_BONDING,
        AuthenticationRequirements.NO_BONDING_MITM_PROTECTION:
        hci_packets.AuthenticationRequirements.NO_BONDING_MITM_PROTECTION,
        AuthenticationRequirements.DEDICATED_BONDING:
        hci_packets.AuthenticationRequirements.DEDICATED_BONDING,
        AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION:
        hci_packets.AuthenticationRequirements.
        DEDICATED_BONDING_MITM_PROTECTION,
        AuthenticationRequirements.GENERAL_BONDING:
        hci_packets.AuthenticationRequirements.GENERAL_BONDING,
        AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION:
        hci_packets.AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION,
    }

    _oob_present_lookup = {
        OobDataPresent.NOT_PRESENT:
        hci_packets.OobDataPresent.NOT_PRESENT,
        OobDataPresent.P192_PRESENT:
        hci_packets.OobDataPresent.P_192_PRESENT,
        OobDataPresent.P256_PRESENT:
        hci_packets.OobDataPresent.P_256_PRESENT,
        OobDataPresent.P192_AND_256_PRESENT:
        hci_packets.OobDataPresent.P_192_AND_256_PRESENT,
    }

    _hci_event_stream = None
    _io_caps = hci_packets.IoCapability.DISPLAY_ONLY
    _auth_reqs = hci_packets.AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION
    _secure_connections_enabled = False

    _hci = None

    MAX_PIN_LENGTH = 16
    MIN_PIN_LENGTH = 1

    def _enqueue_hci_command(self, command, expect_complete):
        if (expect_complete):
            self._hci.send_command(command)
        else:
            self._hci.send_command(command)

    def __init__(self, device):
        """
            Don't call super b/c the gRPC stream setup will crash test
        """
        logging.info("Cert: Init")
        self._device = device
        self._device.wait_channel_ready()
        self._hci = PyHci(device)
        self._hci.register_for_events(
            hci_packets.EventCode.ENCRYPTION_CHANGE,
            hci_packets.EventCode.CHANGE_CONNECTION_LINK_KEY_COMPLETE,
            hci_packets.EventCode.CENTRAL_LINK_KEY_COMPLETE,
            hci_packets.EventCode.RETURN_LINK_KEYS,
            hci_packets.EventCode.PIN_CODE_REQUEST,
            hci_packets.EventCode.LINK_KEY_REQUEST,
            hci_packets.EventCode.LINK_KEY_NOTIFICATION,
            hci_packets.EventCode.ENCRYPTION_KEY_REFRESH_COMPLETE,
            hci_packets.EventCode.IO_CAPABILITY_REQUEST,
            hci_packets.EventCode.IO_CAPABILITY_RESPONSE,
            hci_packets.EventCode.REMOTE_OOB_DATA_REQUEST,
            hci_packets.EventCode.SIMPLE_PAIRING_COMPLETE,
            hci_packets.EventCode.USER_PASSKEY_NOTIFICATION,
            hci_packets.EventCode.KEYPRESS_NOTIFICATION,
            hci_packets.EventCode.USER_CONFIRMATION_REQUEST,
            hci_packets.EventCode.USER_PASSKEY_REQUEST,
            hci_packets.EventCode.REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION)
        self._hci_event_stream = self._hci.get_event_stream()

    def create_bond(self, address, type):
        """
            Creates a bond from the cert perspective
        """
        logging.info("Cert: Creating bond to '%s' from '%s'" %
                     (str(address), str(self._device.address)))
        # TODO(optedoblivion): Trigger connection to Send AuthenticationRequested

    def remove_bond(self, address, type):
        """
            We store the link key locally in the test and pretend
            So to remove_bond we need to Remove the "stored" data
        """
        pass

    def set_io_capabilities(self, io_capabilities):
        """
            Set the IO Capabilities used for the cert
        """
        logging.info(
            "Cert: setting IO Capabilities data to '%s'" %
            self._io_capabilities_name_lookup.get(io_capabilities, "ERROR"))
        self._io_caps = self._io_cap_lookup.get(
            io_capabilities, hci_packets.IoCapability.DISPLAY_ONLY)

    def set_authentication_requirements(self, auth_reqs):
        """
            Establish authentication requirements for the stack
        """
        logging.info("Cert: setting Authentication Requirements data to '%s'" %
                     self._auth_reqs_name_lookup.get(auth_reqs, "ERROR"))
        self._auth_reqs = self._auth_req_lookup.get(
            auth_reqs, hci_packets.AuthenticationRequirements.GENERAL_BONDING)

    def get_oob_data_from_controller(self, pb_oob_data_type):
        """
            Get the Out-of-band data for SSP pairing

            :param pb_oob_data_type: Type of data needed
            :return: a tuple of bytes (192c,192r,256c,256r) with increasing security; bytes may be all 0s depending on pb_oob_data_type value

        """
        oob_data_type = self._oob_present_lookup[pb_oob_data_type]

        if (oob_data_type == hci_packets.OobDataPresent.NOT_PRESENT):
            logging.warn("No data present, no need to call get_oob_data")
            return ([0 for i in range(0, 16)], [0 for i in range(0, 16)],
                    [0 for i in range(0, 16)], [0 for i in range(0, 16)])

        logging.info("Cert: Requesting OOB data")
        if oob_data_type == hci_packets.OobDataPresent.P_192_PRESENT:
            # If host and controller supports secure connections we always used ReadLocalOobExtendedDataRequest
            if self._secure_connections_enabled:
                logging.info("Cert: Requesting P192 Data; secure connections")
                complete_capture = HciCaptures.ReadLocalOobExtendedDataCompleteCapture(
                )
                self._enqueue_hci_command(
                    hci_packets.ReadLocalOobExtendedDataBuilder(), True)
                logging.info("Cert: Waiting for OOB response from controller")
                assertThat(self._hci_event_stream).emits(complete_capture)
                command_complete = complete_capture.get()
                complete = hci_packets.ReadLocalOobExtendedDataCompleteView(
                    command_complete)
                return (list(complete.GetC192()), list(complete.GetR192()),
                        [0 for i in range(0, 16)], [0 for i in range(0, 16)])
            # else we use ReadLocalDataRequest
            else:
                logging.info(
                    "Cert: Requesting P192 Data; no secure connections")
                complete_capture = HciCaptures.ReadLocalOobDataCompleteCapture(
                )
                self._enqueue_hci_command(
                    hci_packets.ReadLocalOobDataBuilder(), True)
                logging.info("Cert: Waiting for OOB response from controller")
                assertThat(self._hci_event_stream).emits(complete_capture)
                command_complete = complete_capture.get()
                complete = hci_packets.ReadLocalOobDataCompleteView(
                    command_complete)
                return (list(complete.GetC()), list(complete.GetR()),
                        [0 for i in range(0, 16)], [0 for i in range(0, 16)])

        # Must be secure connection compatible to use these
        elif oob_data_type == hci_packets.OobDataPresent.P_256_PRESENT:
            logging.info(
                "Cert: Requesting P256 Extended Data; secure connections")
            complete_capture = HciCaptures.ReadLocalOobExtendedDataCompleteCapture(
            )
            self._enqueue_hci_command(
                hci_packets.ReadLocalOobExtendedDataBuilder(), True)
            logging.info("Cert: Waiting for OOB response from controller")
            assertThat(self._hci_event_stream).emits(complete_capture)
            command_complete = complete_capture.get()
            complete = hci_packets.ReadLocalOobExtendedDataCompleteView(
                command_complete)
            return ([0 for i in range(0, 16)], [0 for i in range(0, 16)],
                    list(complete.GetC256()), list(complete.GetR256()))

        else:  # Both
            logging.info(
                "Cert: Requesting P192 AND P256 Extended Data; secure connections"
            )
            complete_capture = HciCaptures.ReadLocalOobExtendedDataCompleteCapture(
            )
            self._enqueue_hci_command(
                hci_packets.ReadLocalOobExtendedDataBuilder(), True)
            logging.info("Cert: Waiting for OOB response from controller")
            assertThat(self._hci_event_stream).emits(complete_capture)
            command_complete = complete_capture.get()
            complete = hci_packets.ReadLocalOobExtendedDataCompleteView(
                command_complete)
            return (list(complete.GetC192()), list(complete.GetR192()),
                    list(complete.GetC256()), list(complete.GetR256()))

    def input_passkey(self, address, passkey):
        """
            Pretend to answer the pairing dialog as a user
        """
        logging.info("Cert: Waiting for PASSKEY request")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.EventWithCode(
                hci_packets.EventCode.USER_PASSKEY_REQUEST))
        logging.info("Cert: Send user input passkey %d for %s" %
                     (passkey, address))
        peer = address.decode('utf-8')
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.ENTRY_STARTED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.CLEARED), True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ERASED), True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.DIGIT_ENTERED),
            True)
        self._enqueue_hci_command(
            hci_packets.SendKeypressNotificationBuilder(
                peer, hci_packets.KeypressNotificationType.ENTRY_COMPLETED),
            True)
        self._enqueue_hci_command(
            hci_packets.UserPasskeyRequestReplyBuilder(peer, passkey), True)

    def input_pin(self, address, pin):
        """
            Pretend to answer the pairing dialog as a user
        """

        if len(pin) > self.MAX_PIN_LENGTH or len(pin) < self.MIN_PIN_LENGTH:
            raise Exception("Pin code must be within range")

        logging.info("Cert: Waiting for PIN request")
        assertThat(self._hci_event_stream).emits(HciMatchers.PinCodeRequest())
        logging.info("Cert: Send user input PIN %s for %s" %
                     (pin.decode(), address))
        peer = address.decode('utf-8')
        pin_list = list(pin)
        # Pad
        for i in range(self.MAX_PIN_LENGTH - len(pin_list)):
            pin_list.append(0)
        self._enqueue_hci_command(
            hci_packets.PinCodeRequestReplyBuilder(peer, len(pin), pin_list),
            True)

    def __send_ui_callback(self, address, callback_type, b, uid, pin):
        """
            Pretend to answer the pairing dailog as a user
        """
        logging.info("Cert: Send user input callback uid:%d; response: %s" %
                     (uid, b))
        # TODO(optedoblivion): Make callback and set it to the module

    def enable_secure_simple_pairing(self):
        """
            This is called when you want to enable SSP for testing
        """
        logging.info("Cert: Sending WRITE_SIMPLE_PAIRING_MODE [True]")
        self._enqueue_hci_command(
            hci_packets.WriteSimplePairingModeBuilder(
                hci_packets.Enable.ENABLED), True)
        logging.info("Cert: Waiting for controller response")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.CommandComplete(
                hci_packets.OpCode.WRITE_SIMPLE_PAIRING_MODE))

    def enable_secure_connections(self):
        """
            This is called when you want to enable secure connections support
        """
        logging.info(
            "Cert: Sending WRITE_SECURE_CONNECTIONS_HOST_SUPPORT [True]")
        self._enqueue_hci_command(
            hci_packets.WriteSecureConnectionsHostSupportBuilder(
                hci_packets.Enable.ENABLED), True)
        logging.info("Cert: Waiting for controller response")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.CommandComplete(
                hci_packets.OpCode.WRITE_SECURE_CONNECTIONS_HOST_SUPPORT))
        # TODO(optedoblivion): Figure this out and remove (see classic_pairing_handler.cc)
        #self._secure_connections_enabled = True

    def send_io_caps(self, address):
        logging.info("Cert: Waiting for IO_CAPABILITY_REQUEST")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.IoCapabilityRequest())
        logging.info("Cert: Sending IO_CAPABILITY_REQUEST_REPLY")
        oob_data_present = hci_packets.OobDataPresent.NOT_PRESENT
        self._enqueue_hci_command(
            hci_packets.IoCapabilityRequestReplyBuilder(
                address.decode('utf8'), self._io_caps, oob_data_present,
                self._auth_reqs), True)

    def accept_pairing(self, dut_address, reply_boolean):
        """
            Here we handle the pairing events at the HCI level
        """
        logging.info("Cert: Waiting for LINK_KEY_REQUEST")
        assertThat(self._hci_event_stream).emits(HciMatchers.LinkKeyRequest())
        logging.info("Cert: Sending LINK_KEY_REQUEST_NEGATIVE_REPLY")
        self._enqueue_hci_command(
            hci_packets.LinkKeyRequestNegativeReplyBuilder(
                dut_address.decode('utf8')), True)
        self.send_io_caps(dut_address)
        logging.info("Cert: Waiting for USER_CONFIRMATION_REQUEST")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.UserConfirmationRequest())
        logging.info("Cert: Sending Simulated User Response '%s'" %
                     reply_boolean)
        if reply_boolean:
            logging.info("Cert: Sending USER_CONFIRMATION_REQUEST_REPLY")
            self._enqueue_hci_command(
                hci_packets.UserConfirmationRequestReplyBuilder(
                    dut_address.decode('utf8')), True)
            logging.info("Cert: Waiting for SIMPLE_PAIRING_COMPLETE")
            assertThat(self._hci_event_stream).emits(
                HciMatchers.SimplePairingComplete())
            logging.info("Cert: Waiting for LINK_KEY_NOTIFICATION")
            assertThat(self._hci_event_stream).emits(
                HciMatchers.LinkKeyNotification())
        else:
            logging.info(
                "Cert: Sending USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY")
            self._enqueue_hci_command(
                hci_packets.UserConfirmationRequestNegativeReplyBuilder(
                    dut_address.decode('utf8')), True)
            logging.info("Cert: Waiting for SIMPLE_PAIRING_COMPLETE")
            assertThat(self._hci_event_stream).emits(
                HciMatchers.SimplePairingComplete())

    def accept_oob_pairing(self, dut_address):
        logging.info("Cert: Waiting for IO_CAPABILITY_RESPONSE")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.IoCapabilityResponse())
        self.send_io_caps(dut_address)
        logging.info("Cert: Waiting for SIMPLE_PAIRING_COMPLETE")
        ssp_complete_capture = HciCaptures.SimplePairingCompleteCapture()
        assertThat(self._hci_event_stream).emits(ssp_complete_capture)
        ssp_complete = ssp_complete_capture.get()
        logging.info(ssp_complete.GetStatus())
        assertThat(ssp_complete.GetStatus()).isEqualTo(
            hci_packets.ErrorCode.SUCCESS)

    def on_user_input(self, dut_address, reply_boolean, expected_ui_event):
        """
            Cert doesn't need the test to respond to the ui event
            Cert responds in accept pairing
        """
        pass

    def wait_for_bond_event(self, expected_bond_event):
        """
            A bond event will be triggered once the bond process
            is complete.  For the DUT we need to wait for it,
            for Cert it isn't needed.
        """
        pass

    def enforce_security_policy(self, address, type, policy):
        """
            Pass for now
        """
        pass

    def wait_for_enforce_security_event(self, expected_enforce_security_event):
        """
            Cert side needs to pass
        """
        pass

    def wait_for_disconnect_event(self):
        """
            Cert side needs to pass
        """
        logging.info("Cert: Waiting for DISCONNECT_COMPLETE")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.DisconnectionComplete())

    def close(self):
        safeClose(self._hci)
 def setup_test(self):
     super().setup_test()
     self.cert_hci = PyHci(self.cert, acl_streaming=True)
Esempio n. 16
0
class NeighborTest(GdBaseTestClass):
    def setup_class(self):
        super().setup_class(dut_module='HCI_INTERFACES', cert_module='HCI')

    def setup_test(self):
        super().setup_test()
        self.cert_hci = PyHci(self.cert, acl_streaming=True)
        self.cert_hci.send_command_with_complete(
            hci_packets.WriteScanEnableBuilder(
                hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
        self.cert_name = b'Im_A_Cert'
        self.cert_address = self.cert_hci.read_own_address()
        self.cert_name += b'@' + self.cert_address.encode('utf8')
        self.dut_neighbor = PyNeighbor(self.dut)

    def teardown_test(self):
        self.cert_hci.close()
        super().teardown_test()

    def _set_name(self):
        padded_name = self.cert_name
        while len(padded_name) < 248:
            padded_name = padded_name + b'\0'
        self.cert_hci.send_command_with_complete(
            hci_packets.WriteLocalNameBuilder(padded_name))

        assertThat(self.cert_hci.get_event_stream()).emits(
            HciMatchers.CommandComplete(OpCode.WRITE_LOCAL_NAME))

    def test_inquiry_from_dut(self):
        inquiry_msg = neighbor_facade.InquiryMsg(
            inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
            result_mode=neighbor_facade.ResultMode.STANDARD,
            length_1_28s=3,
            max_results=0)
        session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
        self.cert_hci.send_command_with_complete(
            hci_packets.WriteScanEnableBuilder(
                hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
        assertThat(session).emits(NeighborMatchers.InquiryResult(
            self.cert_address),
                                  timeout=timedelta(seconds=10))

    def test_inquiry_rssi_from_dut(self):
        inquiry_msg = neighbor_facade.InquiryMsg(
            inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
            result_mode=neighbor_facade.ResultMode.RSSI,
            length_1_28s=6,
            max_results=0)
        session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
        self.cert_hci.send_command_with_complete(
            hci_packets.WriteScanEnableBuilder(
                hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
        assertThat(session).emits(NeighborMatchers.InquiryResultwithRssi(
            self.cert_address),
                                  timeout=timedelta(seconds=10))

    def test_inquiry_extended_from_dut(self):
        self._set_name()
        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(self.cert_name))
        gap_data = list([gap_name])

        self.cert_hci.send_command_with_complete(
            hci_packets.WriteExtendedInquiryResponseBuilder(
                hci_packets.FecRequired.NOT_REQUIRED, gap_data))
        inquiry_msg = neighbor_facade.InquiryMsg(
            inquiry_mode=neighbor_facade.DiscoverabilityMode.GENERAL,
            result_mode=neighbor_facade.ResultMode.EXTENDED,
            length_1_28s=8,
            max_results=0)
        session = self.dut_neighbor.set_inquiry_mode(inquiry_msg)
        self.cert_hci.send_command_with_complete(
            hci_packets.WriteScanEnableBuilder(
                hci_packets.ScanEnable.INQUIRY_AND_PAGE_SCAN))
        assertThat(session).emits(NeighborMatchers.ExtendedInquiryResult(
            self.cert_address),
                                  timeout=timedelta(seconds=10))

    def test_remote_name(self):
        self._set_name()
        session = self.dut_neighbor.get_remote_name(self.cert_address)
        session.verify_name(self.cert_name)
Esempio n. 17
0
class CertSecurity(PySecurity):
    """
        Contain all of the certification stack logic for sending and receiving
        HCI commands following the Classic Pairing flows.
    """
    _io_cap_lookup = {
        IoCapabilities.DISPLAY_ONLY:
        hci_packets.IoCapability.DISPLAY_ONLY,
        IoCapabilities.DISPLAY_YES_NO_IO_CAP:
        hci_packets.IoCapability.DISPLAY_YES_NO,
        IoCapabilities.KEYBOARD_ONLY:
        hci_packets.IoCapability.KEYBOARD_ONLY,
        IoCapabilities.NO_INPUT_NO_OUTPUT:
        hci_packets.IoCapability.NO_INPUT_NO_OUTPUT,
    }

    _auth_req_lookup = {
        AuthenticationRequirements.NO_BONDING:
        hci_packets.AuthenticationRequirements.NO_BONDING,
        AuthenticationRequirements.NO_BONDING_MITM_PROTECTION:
        hci_packets.AuthenticationRequirements.NO_BONDING_MITM_PROTECTION,
        AuthenticationRequirements.DEDICATED_BONDING:
        hci_packets.AuthenticationRequirements.DEDICATED_BONDING,
        AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION:
        hci_packets.AuthenticationRequirements.
        DEDICATED_BONDING_MITM_PROTECTION,
        AuthenticationRequirements.GENERAL_BONDING:
        hci_packets.AuthenticationRequirements.GENERAL_BONDING,
        AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION:
        hci_packets.AuthenticationRequirements.GENERAL_BONDING_MITM_PROTECTION,
    }

    _oob_present_lookup = {
        OobDataPresent.NOT_PRESENT:
        hci_packets.OobDataPresent.NOT_PRESENT,
        OobDataPresent.P192_PRESENT:
        hci_packets.OobDataPresent.P_192_PRESENT,
        OobDataPresent.P256_PRESENT:
        hci_packets.OobDataPresent.P_256_PRESENT,
        OobDataPresent.P192_AND_256_PRESENT:
        hci_packets.OobDataPresent.P_192_AND_256_PRESENT,
    }

    _hci_event_stream = None
    _io_caps = hci_packets.IoCapability.DISPLAY_ONLY
    _oob_data = hci_packets.OobDataPresent.NOT_PRESENT
    _auth_reqs = hci_packets.AuthenticationRequirements.DEDICATED_BONDING_MITM_PROTECTION

    _hci = None

    def _enqueue_hci_command(self, command, expect_complete):
        if (expect_complete):
            self._hci.send_command_with_complete(command)
        else:
            self._hci.send_command_with_status(command)

    def __init__(self, device):
        """
            Don't call super b/c the gRPC stream setup will crash test
        """
        logging.info("Cert: Init")
        self._device = device
        self._device.wait_channel_ready()
        self._hci = PyHci(device)
        self._hci.register_for_events(
            hci_packets.EventCode.LINK_KEY_REQUEST,
            hci_packets.EventCode.IO_CAPABILITY_REQUEST,
            hci_packets.EventCode.IO_CAPABILITY_RESPONSE,
            hci_packets.EventCode.USER_PASSKEY_NOTIFICATION,
            hci_packets.EventCode.USER_PASSKEY_REQUEST,
            hci_packets.EventCode.USER_CONFIRMATION_REQUEST,
            hci_packets.EventCode.REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION,
            hci_packets.EventCode.LINK_KEY_NOTIFICATION,
            hci_packets.EventCode.SIMPLE_PAIRING_COMPLETE)
        self._hci_event_stream = self._hci.get_event_stream()

    def create_bond(self, address, type):
        """
            Creates a bond from the cert perspective
        """
        logging.info("Cert: Creating bond to '%s' from '%s'" %
                     (str(address), str(self._device.address)))
        # TODO(optedoblivion): Trigger connection to Send AuthenticationRequested

    def remove_bond(self, address, type):
        """
            We store the link key locally in the test and pretend
            So to remove_bond we need to Remove the "stored" data
        """
        pass

    def set_io_capabilities(self, io_capabilities):
        """
            Set the IO Capabilities used for the cert
        """
        logging.info(
            "Cert: setting IO Capabilities data to '%s'" %
            self._io_capabilities_name_lookup.get(io_capabilities, "ERROR"))
        self._io_caps = self._io_cap_lookup.get(
            io_capabilities, hci_packets.IoCapability.DISPLAY_YES_NO)

    def set_authentication_requirements(self, auth_reqs):
        """
            Establish authentication requirements for the stack
        """
        logging.info("Cert: setting Authentication Requirements data to '%s'" %
                     self._auth_reqs_name_lookup.get(auth_reqs, "ERROR"))
        self._auth_reqs = self._auth_req_lookup.get(
            auth_reqs, hci_packets.AuthenticationRequirements.GENERAL_BONDING)

    def set_oob_data(self, data):
        """
            Set the Out-of-band data for SSP pairing
        """
        logging.info("Cert: setting OOB data present to '%s'" % data)
        self._oob_data = self._oob_present_lookup.get(
            data, hci_packets.OobDataPresent.NOT_PRESENT)

    def send_ui_callback(self, address, callback_type, b, uid):
        """
            Pretend to answer the pairing dailog as a user
        """
        logging.info("Cert: Send user input callback uid:%d; response: %s" %
                     (uid, b))
        # TODO(optedoblivion): Make callback and set it to the module

    def enable_secure_simple_pairing(self):
        """
            This is called when you want to enable SSP for testing
        """
        logging.info("Cert: Sending WRITE_SIMPLE_PAIRING_MODE [True]")
        self._enqueue_hci_command(
            hci_packets.WriteSimplePairingModeBuilder(
                hci_packets.Enable.ENABLED), True)
        logging.info("Cert: Waiting for controller response")
        assertThat(self._hci_event_stream).emits(
            lambda msg: b'\x0e\x04\x01\x56\x0c' in msg.event)

    def accept_pairing(self, dut_address, reply_boolean):
        """
            Here we handle the pairing events at the HCI level
        """
        logging.info("Cert: Waiting for LINK_KEY_REQUEST")
        assertThat(self._hci_event_stream).emits(HciMatchers.LinkKeyRequest())
        logging.info("Cert: Sending LINK_KEY_REQUEST_NEGATIVE_REPLY")
        self._enqueue_hci_command(
            hci_packets.LinkKeyRequestNegativeReplyBuilder(
                dut_address.decode('utf8')), True)
        logging.info("Cert: Waiting for IO_CAPABILITY_REQUEST")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.IoCapabilityRequest())
        logging.info("Cert: Sending IO_CAPABILITY_REQUEST_REPLY")
        self._enqueue_hci_command(
            hci_packets.IoCapabilityRequestReplyBuilder(
                dut_address.decode('utf8'), self._io_caps, self._oob_data,
                self._auth_reqs), True)
        logging.info("Cert: Waiting for USER_CONFIRMATION_REQUEST")
        assertThat(self._hci_event_stream).emits(
            HciMatchers.UserConfirmationRequest())
        logging.info("Cert: Sending Simulated User Response '%s'" %
                     reply_boolean)
        if reply_boolean:
            logging.info("Cert: Sending USER_CONFIRMATION_REQUEST_REPLY")
            self._enqueue_hci_command(
                hci_packets.UserConfirmationRequestReplyBuilder(
                    dut_address.decode('utf8')), True)
            logging.info("Cert: Waiting for SIMPLE_PAIRING_COMPLETE")
            assertThat(self._hci_event_stream).emits(
                HciMatchers.SimplePairingComplete())
            logging.info("Cert: Waiting for LINK_KEY_NOTIFICATION")
            assertThat(self._hci_event_stream).emits(
                HciMatchers.LinkKeyNotification())
        else:
            logging.info(
                "Cert: Sending USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY")
            self._enqueue_hci_command(
                hci_packets.UserConfirmationRequestNegativeReplyBuilder(
                    dut_address.decode('utf8')), True)
            logging.info("Cert: Waiting for SIMPLE_PAIRING_COMPLETE")
            assertThat(self._hci_event_stream).emits(
                HciMatchers.SimplePairingComplete())

    def on_user_input(self, dut_address, reply_boolean, expected_ui_event):
        """
            Cert doesn't need the test to respond to the ui event
            Cert responds in accept pairing
        """
        pass

    def wait_for_bond_event(self, expected_bond_event):
        """
            A bond event will be triggered once the bond process
            is complete.  For the DUT we need to wait for it,
            for Cert it isn't needed.
        """
        pass

    def enforce_security_policy(self, address, type, policy):
        """
            Pass for now
        """
        pass

    def wait_for_enforce_security_event(self, expected_enforce_security_event):
        """
            Cert side needs to pass
        """
        pass

    def close(self):
        safeClose(self._hci)
 def setup_test(self):
     super().setup_test()
     self.cert_hci = PyHci(self.cert)
     self.dut_acl_manager = PyAclManager(self.dut)