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))
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))
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))
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))
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))
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))
def DisplayPasskey(): return Capture(SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY), SecurityCaptures._extract_passkey)
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)