1# 2# Copyright 2019 - The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import hci_packets as hci 17import smp_packets as smp 18from blueberry.tests.gd.cert.matchers import SecurityMatchers 19from blueberry.tests.gd.cert.metadata import metadata 20from blueberry.tests.gd.cert.py_hci import PyHci 21from blueberry.tests.gd.cert.py_le_security import PyLeSecurity 22from blueberry.tests.gd.cert.truth import assertThat 23from blueberry.tests.gd.cert import gd_base_test 24from datetime import timedelta 25from blueberry.facade import common_pb2 as common 26from blueberry.facade.hci import le_advertising_manager_facade_pb2 as le_advertising_facade 27from blueberry.facade.hci import le_initiator_address_facade_pb2 as le_initiator_address_facade 28from google.protobuf import empty_pb2 as empty_proto 29from blueberry.facade.security.facade_pb2 import BondMsgType 30from blueberry.facade.security.facade_pb2 import OobDataMessage 31from blueberry.facade.security.facade_pb2 import UiCallbackMsg 32from blueberry.facade.security.facade_pb2 import UiCallbackType 33from blueberry.facade.security.facade_pb2 import UiMsgType 34from blueberry.facade.security.facade_pb2 import LeIoCapabilityMessage 35from blueberry.facade.security.facade_pb2 import LeOobDataPresentMessage 36from blueberry.facade.security.facade_pb2 import LeMaximumEncryptionKeySizeMessage 37from mobly import asserts 38from mobly import test_runner 39 40LeIoCapabilities = LeIoCapabilityMessage.LeIoCapabilities 41LeOobDataFlag = LeOobDataPresentMessage.LeOobDataFlag 42 43DISPLAY_ONLY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.DISPLAY_ONLY) 44KEYBOARD_ONLY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.KEYBOARD_ONLY) 45NO_INPUT_NO_OUTPUT = LeIoCapabilityMessage(capabilities=LeIoCapabilities.NO_INPUT_NO_OUTPUT) 46KEYBOARD_DISPLAY = LeIoCapabilityMessage(capabilities=LeIoCapabilities.KEYBOARD_DISPLAY) 47 48OOB_NOT_PRESENT = LeOobDataPresentMessage(data_present=LeOobDataFlag.NOT_PRESENT) 49OOB_PRESENT = LeOobDataPresentMessage(data_present=LeOobDataFlag.PRESENT) 50 51 52class LeSecurityTest(gd_base_test.GdBaseTestClass): 53 54 def setup_class(self): 55 gd_base_test.GdBaseTestClass.setup_class(self, dut_module='SECURITY', cert_module='SECURITY') 56 57 def setup_test(self): 58 asserts.skip("Unhandled race condition - Flaky test") 59 gd_base_test.GdBaseTestClass.setup_test(self) 60 61 self.dut_security = PyLeSecurity(self.dut) 62 self.cert_security = PyLeSecurity(self.cert) 63 self.dut_hci = PyHci(self.dut) 64 65 raw_addr = self.dut.hci_controller.GetMacAddress(empty_proto.Empty()).address 66 67 self.dut_address = common.BluetoothAddressWithType(address=common.BluetoothAddress(address=raw_addr), 68 type=common.PUBLIC_DEVICE_ADDRESS) 69 privacy_policy = le_initiator_address_facade.PrivacyPolicy( 70 address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS, 71 address_with_type=self.dut_address) 72 self.dut.security.SetLeInitiatorAddressPolicy(privacy_policy) 73 self.cert_address = common.BluetoothAddressWithType(address=common.BluetoothAddress( 74 address=self.cert.hci_controller.GetMacAddress(empty_proto.Empty()).address), 75 type=common.PUBLIC_DEVICE_ADDRESS) 76 cert_privacy_policy = le_initiator_address_facade.PrivacyPolicy( 77 address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS, 78 address_with_type=self.cert_address) 79 self.cert.security.SetLeInitiatorAddressPolicy(cert_privacy_policy) 80 81 def teardown_test(self): 82 return # test skipped 83 self.dut_hci.close() 84 self.dut_security.close() 85 self.cert_security.close() 86 gd_base_test.GdBaseTestClass.teardown_test(self) 87 88 def _prepare_cert_for_connection(self): 89 # DUT Advertises 90 gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_CERT'))) 91 gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize()) 92 config = le_advertising_facade.AdvertisingConfig( 93 advertisement=[gap_data], 94 interval_min=512, 95 interval_max=768, 96 advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND, 97 own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS, 98 channel_map=7, 99 filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES) 100 request = le_advertising_facade.CreateAdvertiserRequest(config=config) 101 create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request) 102 103 def _prepare_dut_for_connection(self): 104 # DUT Advertises 105 gap_name = hci.GapData(data_type=hci.GapDataType.COMPLETE_LOCAL_NAME, data=list(bytes(b'Im_The_DUT'))) 106 gap_data = le_advertising_facade.GapDataMsg(data=gap_name.serialize()) 107 config = le_advertising_facade.AdvertisingConfig( 108 advertisement=[gap_data], 109 interval_min=512, 110 interval_max=768, 111 advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND, 112 own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS, 113 channel_map=7, 114 filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES) 115 request = le_advertising_facade.CreateAdvertiserRequest(config=config) 116 create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request) 117 118 @metadata(pts_test_id="SM/MAS/PROT/BV-01-C", pts_test_name="SMP Time Out – IUT Initiator") 119 def test_le_smp_timeout_iut_initiator(self): 120 """ 121 Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator. 122 """ 123 self._prepare_cert_for_connection() 124 self.dut.security.CreateBondLe(self.cert_address) 125 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 126 BondMsgType.DEVICE_BOND_FAILED, self.cert_address), 127 timeout=timedelta(seconds=35)) 128 129 @metadata(pts_test_id="SM/SLA/PROT/BV-02-C", pts_test_name="SMP Time Out – IUT Responder") 130 def test_le_smp_timeout_iut_responder(self): 131 """ 132 Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator. 133 """ 134 self.cert.security.SetLeIoCapability(KEYBOARD_ONLY) 135 self.dut.security.SetLeIoCapability(DISPLAY_ONLY) 136 137 self._prepare_dut_for_connection() 138 139 # 1. Lower Tester transmits Pairing Request. 140 self.cert.security.CreateBondLe(self.dut_address) 141 142 assertThat(self.dut_security.get_ui_stream()).emits(SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, 143 self.cert_address), 144 timeout=timedelta(seconds=35)) 145 146 # 2. IUT responds with Pairing Response. 147 self.dut.security.SendUiCallback( 148 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 149 boolean=True, 150 unique_id=1, 151 address=self.cert_address)) 152 153 # 3. In phase 2, Lower Tester does not issue the expected Pairing Confirm. 154 155 # Here the cert receives DISPLAY_PASSKEY_ENTRY. By not replying to it we make sure Pairing Confirm is never sent 156 assertThat(self.cert_security.get_ui_stream()).emits(SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, 157 self.dut_address), 158 timeout=timedelta(seconds=5)) 159 160 # 4. IUT times out 30 seconds after issued Pairing Response and reports the failure to the Upper Tester. 161 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 162 BondMsgType.DEVICE_BOND_FAILED, self.cert_address), 163 timeout=timedelta(seconds=35)) 164 165 # 5. After additionally (at least) 10 seconds the Lower Tester issues the expected Pairing Confirm. 166 # 6. The IUT closes the connection before receiving the delayed response or does not respond to it when it is received. 167 #TODO: 168 #assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.Disconnect()) 169 170 @metadata(pts_test_id="SM/MAS/JW/BV-01-C", pts_test_name="Just Works IUT Initiator – Success") 171 def test_just_works_iut_initiator(self): 172 """ 173 Verify that the IUT performs the Just Works pairing procedure correctly as central, initiator when both sides do not require MITM protection. 174 """ 175 self._prepare_cert_for_connection() 176 177 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 178 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 179 self.dut_security.SetLeAuthRequirements() 180 181 self.cert.security.SetLeIoCapability(DISPLAY_ONLY) 182 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 183 self.cert_security.SetLeAuthRequirements() 184 185 # 1. IUT transmits Pairing Request command with: 186 # a. IO capability set to any IO capability 187 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 188 # c. AuthReq Bonding Flags set to ‘00’ and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’ 189 self.dut.security.CreateBondLe(self.cert_address) 190 191 assertThat(self.cert_security.get_ui_stream()).emits( 192 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 193 194 # 2. Lower Tester responds with a Pairing Response command, with: 195 # a. IO capability set to “KeyboardDisplay” 196 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 197 # c. AuthReq Bonding Flags set to ‘00’, and the MITM flag set to ‘0’ and all the reserved bits are set to ‘0’ 198 self.cert.security.SendUiCallback( 199 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 200 boolean=True, 201 unique_id=1, 202 address=self.dut_address)) 203 204 # 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. 205 assertThat(self.dut_security.get_bond_stream()).emits( 206 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 207 208 @metadata(pts_test_id="SM/SLA/JW/BV-02-C", pts_test_name="Just Works IUT Responder – Success") 209 def test_just_works_iut_responder(self): 210 """ 211 Verify that the IUT is able to perform the Just Works pairing procedure correctly when acting as peripheral, responder. 212 """ 213 self._prepare_dut_for_connection() 214 215 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 216 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 217 self.dut_security.SetLeAuthRequirements() 218 219 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 220 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 221 self.cert_security.SetLeAuthRequirements() 222 223 # 1. Lower Tester transmits Pairing Request command with: 224 # a. IO capability set to “NoInputNoOutput” 225 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 226 # c. MITM flag set to ‘0’ and all reserved bits are set to ‘0’ 227 self.cert.security.CreateBondLe(self.dut_address) 228 229 assertThat(self.dut_security.get_ui_stream()).emits( 230 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 231 232 # 2. IUT responds with a Pairing Response command, with: 233 # a. IO capability set to any IO capability 234 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 235 self.dut.security.SendUiCallback( 236 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 237 boolean=True, 238 unique_id=1, 239 address=self.cert_address)) 240 241 # IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK. 242 assertThat(self.dut_security.get_bond_stream()).emits( 243 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 244 245 @metadata(pts_test_id="SM/SLA/JW/BI-03-C", 246 pts_test_name="Just Works IUT Responder – Handle AuthReq flag RFU correctly") 247 def test_just_works_iut_responder_auth_req_rfu(self): 248 """ 249 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 peripheral, responder. 250 """ 251 self._prepare_dut_for_connection() 252 253 self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY) 254 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 255 self.dut_security.SetLeAuthRequirements() 256 257 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 258 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 259 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=2) 260 261 # 1. Lower Tester transmits Pairing Request command with: 262 # a. IO Capability set to ”NoInputNoOutput” 263 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 264 # c. MITM set to ‘0’ and all reserved bits are set to ‘1’ 265 self.cert.security.CreateBondLe(self.dut_address) 266 267 assertThat(self.dut_security.get_ui_stream()).emits( 268 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 269 270 # 2. IUT responds with a Pairing Response command, with: 271 # a. IO capability set to any IO capability 272 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 273 # c. All reserved bits are set to ‘0’ 274 self.dut.security.SendUiCallback( 275 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 276 boolean=True, 277 unique_id=1, 278 address=self.cert_address)) 279 280 # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK. 281 assertThat(self.dut_security.get_bond_stream()).emits( 282 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 283 284 @metadata(pts_test_id="SM/MAS/JW/BI-04-C", 285 pts_test_name="Just Works IUT Initiator – Handle AuthReq flag RFU correctly") 286 def test_just_works_iut_initiator_auth_req_rfu(self): 287 """ 288 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 central, initiator. 289 """ 290 self._prepare_cert_for_connection() 291 292 self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY) 293 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 294 self.dut_security.SetLeAuthRequirements() 295 296 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 297 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 298 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3) 299 300 # 1. IUT transmits a Pairing Request command with: 301 # a. IO Capability set to any IO Capability 302 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 303 # 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. 304 self.dut.security.CreateBondLe(self.cert_address) 305 306 assertThat(self.cert_security.get_ui_stream()).emits( 307 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 308 309 # 2. Lower Tester responds with a Pairing Response command, with: 310 # a. IO Capability set to “NoInputNoOutput” 311 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 312 # 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. 313 self.cert.security.SendUiCallback( 314 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 315 boolean=True, 316 unique_id=1, 317 address=self.dut_address)) 318 319 # 3. IUT and Lower Tester perform phase 2 of the just works pairing and establish an encrypted link with the generated STK. 320 assertThat(self.dut_security.get_bond_stream()).emits( 321 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 322 323 @metadata(pts_test_id="SM/MAS/SCJW/BV-01-C", 324 pts_test_name="Just Works, IUT Initiator, Secure Connections – Success") 325 def test_just_works_iut_initiator_secure_connections(self): 326 """ 327 Verify that the IUT supporting LE Secure Connections performs the Just Works or Numeric Comparison pairing procedure correctly as initiator. 328 """ 329 self._prepare_cert_for_connection() 330 331 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 332 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 333 self.dut_security.SetLeAuthRequirements(secure_connections=1) 334 335 self.cert.security.SetLeIoCapability(DISPLAY_ONLY) 336 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 337 self.cert_security.SetLeAuthRequirements(secure_connections=1) 338 339 # 1. IUT transmits Pairing Request command with: 340 # a. IO capability set to any IO capability 341 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 342 # 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’ 343 self.dut.security.CreateBondLe(self.cert_address) 344 345 assertThat(self.cert_security.get_ui_stream()).emits( 346 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 347 348 # 2. Lower Tester responds with a Pairing Response command, with: 349 # a. IO capability set to “KeyboardDisplay” 350 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 351 # 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’ 352 self.cert.security.SendUiCallback( 353 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 354 boolean=True, 355 unique_id=1, 356 address=self.dut_address)) 357 358 # 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. 359 assertThat(self.dut_security.get_bond_stream()).emits( 360 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 361 362 @metadata(pts_test_id="SM/SLA/SCJW/BV-02-C", 363 pts_test_name="Just Works, IUT Responder, Secure Connections – Success") 364 def test_just_works_iut_responder_secure_connections(self): 365 """ 366 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. 367 """ 368 self._prepare_dut_for_connection() 369 370 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 371 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 372 self.dut_security.SetLeAuthRequirements(secure_connections=1) 373 374 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 375 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 376 self.cert_security.SetLeAuthRequirements(secure_connections=1) 377 378 # 1. Lower Tester transmits Pairing Request command with: 379 # a. IO capability set to “NoInputNoOutput” 380 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 381 # 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’ 382 self.cert.security.CreateBondLe(self.dut_address) 383 384 assertThat(self.dut_security.get_ui_stream()).emits( 385 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 386 387 # 2. IUT responds with a Pairing Response command, with: 388 # a. IO capability set to any IO capability 389 # 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’ 390 self.dut.security.SendUiCallback( 391 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 392 boolean=True, 393 unique_id=1, 394 address=self.cert_address)) 395 396 # 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. 397 assertThat(self.dut_security.get_bond_stream()).emits( 398 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 399 400 @metadata(pts_test_id="SM/SLA/SCJW/BV-03-C", 401 pts_test_name="Just Works, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly") 402 def test_just_works_iut_responder_secure_connections_auth_req_rfu(self): 403 """ 404 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 peripheral, responder. 405 """ 406 self._prepare_dut_for_connection() 407 408 self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY) 409 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 410 self.dut_security.SetLeAuthRequirements(secure_connections=1) 411 412 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 413 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 414 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3) 415 416 # 1. Lower Tester transmits Pairing Request command with: 417 # a. IO Capability set to ”NoInputNoOutput” 418 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 419 # c. MITM set to ‘0’ and all reserved bits are set to a random value. 420 self.cert.security.CreateBondLe(self.dut_address) 421 422 assertThat(self.dut_security.get_ui_stream()).emits( 423 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 424 425 # 2. IUT responds with a Pairing Response command, with: 426 # a. IO capability set to any IO capability 427 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 428 # c. All reserved bits are set to ‘0’ 429 self.dut.security.SendUiCallback( 430 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 431 boolean=True, 432 unique_id=1, 433 address=self.cert_address)) 434 435 # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK. 436 assertThat(self.dut_security.get_bond_stream()).emits( 437 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 438 439 @metadata(pts_test_id="SM/MAS/SCJW/BV-04-C", 440 pts_test_name="Just Works, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly") 441 def test_just_works_iut_initiator_secure_connections_auth_req_rfu(self): 442 """ 443 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 central, initiator. 444 """ 445 self._prepare_cert_for_connection() 446 447 self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY) 448 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 449 self.dut_security.SetLeAuthRequirements(secure_connections=1) 450 451 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 452 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 453 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3) 454 455 # 1. IUT transmits a Pairing Request command with: 456 # a. IO Capability set to any IO Capability 457 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 458 # c. All reserved bits are set to ‘0’. 459 self.dut.security.CreateBondLe(self.cert_address) 460 461 assertThat(self.cert_security.get_ui_stream()).emits( 462 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 463 464 # 2. Lower Tester responds with a Pairing Response command, with: 465 # a. IO Capability set to “NoInputNoOutput” 466 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 467 # 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. 468 self.cert.security.SendUiCallback( 469 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 470 boolean=True, 471 unique_id=1, 472 address=self.dut_address)) 473 474 # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK. 475 assertThat(self.dut_security.get_bond_stream()).emits( 476 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 477 478 @metadata(pts_test_id="SM/MAS/EKS/BV-01-C", 479 pts_test_name="IUT initiator, Lower Tester Maximum Encryption Key Size = Min_Encryption_Key_Length") 480 def test_min_encryption_key_size_equal_to_max_iut_initiator(self): 481 """ 482 Verify that the IUT uses correct key size during encryption as initiator. 483 """ 484 self._prepare_cert_for_connection() 485 486 self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY) 487 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 488 self.dut_security.SetLeAuthRequirements(secure_connections=1) 489 self.dut.security.SetLeMaximumEncryptionKeySize( 490 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10)) 491 492 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 493 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 494 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1) 495 self.cert.security.SetLeMaximumEncryptionKeySize( 496 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x07)) 497 498 # 1. IUT transmits a Pairing Request 499 self.dut.security.CreateBondLe(self.cert_address) 500 501 assertThat(self.cert_security.get_ui_stream()).emits( 502 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 503 504 # 2. Lower Tester responds with Pairing Response command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length’. 505 self.cert.security.SendUiCallback( 506 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 507 boolean=True, 508 unique_id=1, 509 address=self.dut_address)) 510 511 # 3. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the key generated in phase 2. 512 assertThat(self.dut_security.get_bond_stream()).emits( 513 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 514 515 @metadata(pts_test_id="SM/SLA/EKS/BV-02-C", 516 pts_test_name="IUT Responder, Lower Tester Maximum Encryption Key Size = Min_Encryption_Key_Length") 517 def test_min_encryption_key_size_equal_to_max_iut_responder(self): 518 """ 519 Verify that the IUT uses correct key size during encryption as responder. 520 """ 521 self._prepare_dut_for_connection() 522 523 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 524 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 525 self.dut_security.SetLeAuthRequirements() 526 self.dut.security.SetLeMaximumEncryptionKeySize( 527 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x07)) 528 529 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 530 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 531 self.cert_security.SetLeAuthRequirements() 532 self.cert.security.SetLeMaximumEncryptionKeySize( 533 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10)) 534 535 # 1. Lower Tester initiates Pairing Request command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length’. 536 self.cert.security.CreateBondLe(self.dut_address) 537 538 assertThat(self.dut_security.get_ui_stream()).emits( 539 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 540 541 # 2. IUT responds with Pairing Response command. 542 self.dut.security.SendUiCallback( 543 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 544 boolean=True, 545 unique_id=1, 546 address=self.cert_address)) 547 548 #3. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the key generated in phase 2. 549 assertThat(self.dut_security.get_bond_stream()).emits( 550 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BONDED, self.cert_address)) 551 552 @metadata(pts_test_id="SM/MAS/EKS/BI-01-C", 553 pts_test_name="IUT initiator, Lower Tester Maximum Encryption Key Size < Min_Encryption_Key_Length") 554 def test_min_encryption_key_size_less_than_min_iut_initiator(self): 555 """ 556 Verify that the IUT checks that the resultant encryption key size is not smaller than the minimum key size. 557 """ 558 self._prepare_cert_for_connection() 559 560 self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY) 561 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 562 self.dut_security.SetLeAuthRequirements(secure_connections=1) 563 self.dut.security.SetLeMaximumEncryptionKeySize( 564 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10)) 565 566 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 567 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 568 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1) 569 self.cert.security.SetLeMaximumEncryptionKeySize( 570 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x06)) 571 572 # 1. IUT transmits a Pairing Request 573 self.dut.security.CreateBondLe(self.cert_address) 574 575 assertThat(self.cert_security.get_ui_stream()).emits( 576 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 577 578 # 2. Lower Tester responds with Pairing Response command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length-1’. 579 self.cert.security.SendUiCallback( 580 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 581 boolean=True, 582 unique_id=1, 583 address=self.dut_address)) 584 585 # 3. IUT transmits the Pairing Failed command. 586 assertThat(self.dut_security.get_bond_stream()).emits( 587 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.cert_address, 588 int(smp.PairingFailedReason.ENCRYPTION_KEY_SIZE))) 589 590 @metadata(pts_test_id="SM/SLA/EKS/BI-02-C", 591 pts_test_name="IUT Responder, Lower Tester Maximum Encryption Key Size < Min_Encryption_Key_Length") 592 def test_min_encryption_key_size_less_than_min_iut_responder(self): 593 """ 594 Verify that the IUT uses correct key size during encryption as responder. 595 """ 596 self._prepare_dut_for_connection() 597 598 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 599 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 600 self.dut_security.SetLeAuthRequirements() 601 self.dut.security.SetLeMaximumEncryptionKeySize( 602 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x06)) 603 604 self.cert.security.SetLeIoCapability(NO_INPUT_NO_OUTPUT) 605 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 606 self.cert_security.SetLeAuthRequirements() 607 self.cert.security.SetLeMaximumEncryptionKeySize( 608 LeMaximumEncryptionKeySizeMessage(maximum_encryption_key_size=0x10)) 609 610 # 1. Lower Tester initiates Pairing Request command with Maximum Encryption Key Size field set to Min_Encryption_Key_Length-1. 611 self.cert.security.CreateBondLe(self.dut_address) 612 613 assertThat(self.dut_security.get_ui_stream()).emits( 614 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 615 616 self.dut.security.SendUiCallback( 617 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 618 boolean=True, 619 unique_id=1, 620 address=self.cert_address)) 621 622 #3. IUT transmits the Pairing Failed command. 623 assertThat(self.cert_security.get_bond_stream()).emits( 624 SecurityMatchers.BondMsg(BondMsgType.DEVICE_BOND_FAILED, self.dut_address, 625 int(smp.PairingFailedReason.ENCRYPTION_KEY_SIZE))) 626 627 @metadata(pts_test_id="SM/MAS/SCPK/BV-01-C", 628 pts_test_name="Passkey Entry, IUT Initiator, Secure Connections – Success") 629 def test_passkey_entry_iut_initiator_secure_connections(self): 630 """ 631 Verify that the IUT supporting LE Secure Connections performs the Passkey Entry pairing procedure correctly as central, initiator. 632 """ 633 self._prepare_cert_for_connection() 634 635 self.dut.security.SetLeIoCapability(DISPLAY_ONLY) 636 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 637 self.dut_security.SetLeAuthRequirements(secure_connections=1) 638 639 self.cert.security.SetLeIoCapability(KEYBOARD_ONLY) 640 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 641 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1) 642 643 # 1. IUT transmits Pairing Request command with: 644 # a. IO capability set to “DisplayOnly” or “KeyboardOnly” 645 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 646 # 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 647 self.dut.security.CreateBondLe(self.cert_address) 648 649 assertThat(self.cert_security.get_ui_stream()).emits( 650 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 651 652 # 2. Lower Tester responds with a Pairing Response command, with: 653 # a. IO capability set to “KeyboardOnly” 654 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 655 # 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. 656 self.cert.security.SendUiCallback( 657 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 658 boolean=True, 659 unique_id=1, 660 address=self.dut_address)) 661 662 assertThat(self.cert_security.get_ui_stream()).emits( 663 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address)) 664 665 # 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. 666 passkey = self.dut_security.wait_for_ui_event_passkey() 667 668 if passkey == 0: 669 print("Passkey did not arrive into test") 670 671 # 4. IUT and Lower Tester use the same 6-digit passkey. 672 self.cert.security.SendUiCallback( 673 UiCallbackMsg(message_type=UiCallbackType.PASSKEY, 674 numeric_value=passkey, 675 unique_id=1, 676 address=self.dut_address)) 677 678 # 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. 679 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 680 BondMsgType.DEVICE_BONDED, self.cert_address), 681 timeout=timedelta(seconds=10)) 682 683 @metadata(pts_test_id="SM/SLA/SCPK/BV-02-C", 684 pts_test_name="Passkey Entry, IUT Responder, Secure Connections – Success") 685 def test_passkey_entry_iut_responder_secure_connections(self): 686 """ 687 Verify that the IUT supporting LE Secure Connections is able to perform the Passkey Entry pairing procedure correctly when acting as peripheral, responder. 688 """ 689 self._prepare_dut_for_connection() 690 691 self.dut.security.SetLeIoCapability(DISPLAY_ONLY) 692 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 693 self.dut_security.SetLeAuthRequirements(secure_connections=1) 694 695 self.cert.security.SetLeIoCapability(KEYBOARD_DISPLAY) 696 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 697 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1) 698 699 # 1. Lower Tester transmits Pairing Request command with: 700 # a. IO capability set to “KeyboardDisplay” 701 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 702 # 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’ 703 self.cert.security.CreateBondLe(self.dut_address) 704 705 assertThat(self.dut_security.get_ui_stream()).emits( 706 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 707 708 # 2. IUT responds with a Pairing Response command, with: 709 # a. IO capability set to “KeyboardOnly” or “KeyboardDisplay” or “DisplayYesNo” or “DisplayOnly” 710 # b. Secure Connections flag set to '1'. Keypress bit is set to '1' if supported by IUT 711 self.dut.security.SendUiCallback( 712 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 713 boolean=True, 714 unique_id=1, 715 address=self.cert_address)) 716 717 # 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 718 passkey = self.dut_security.wait_for_ui_event_passkey() 719 720 if passkey == 0: 721 print("Passkey did not arrive into test") 722 723 assertThat(self.cert_security.get_ui_stream()).emits( 724 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address)) 725 726 # 4. IUT and Lower Tester use the same pre-defined 6-digit passkey. 727 self.cert.security.SendUiCallback( 728 UiCallbackMsg(message_type=UiCallbackType.PASSKEY, 729 numeric_value=passkey, 730 unique_id=1, 731 address=self.dut_address)) 732 733 # 5. IUT and Lower Tester perform phase 2 of the LE pairing and establish an encrypted link with the LTK generated in phase 2. 734 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 735 BondMsgType.DEVICE_BONDED, self.cert_address), 736 timeout=timedelta(seconds=10)) 737 738 @metadata(pts_test_id="SM/SLA/SCPK/BV-03-C", 739 pts_test_name="Passkey Entry, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly") 740 def test_passkey_entry_iut_responder_secure_connections_auth_req_rfu(self): 741 """ 742 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 peripheral, responder. 743 """ 744 self._prepare_dut_for_connection() 745 746 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 747 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 748 self.dut_security.SetLeAuthRequirements(secure_connections=1) 749 750 self.cert.security.SetLeIoCapability(DISPLAY_ONLY) 751 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 752 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3) 753 754 # 1. Lower Tester transmits Pairing Request command with: 755 # a. IO Capability set to ”KeyboardOnly” 756 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 757 # c. MITM set to ‘1’ and all reserved bits are set to a random value 758 self.cert.security.CreateBondLe(self.dut_address) 759 760 assertThat(self.dut_security.get_ui_stream()).emits( 761 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 762 763 # 2. IUT responds with a Pairing Response command, with: 764 # a. IO Capability set to “KeyboardOnly” or “DisplayOnly” 765 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 766 # c. All reserved bits are set to ‘0’ 767 self.dut.security.SendUiCallback( 768 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 769 boolean=True, 770 unique_id=1, 771 address=self.cert_address)) 772 773 passkey = self.cert_security.wait_for_ui_event_passkey() 774 775 if passkey == 0: 776 print("Passkey did not arrive into test") 777 778 assertThat(self.dut_security.get_ui_stream()).emits( 779 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.cert_address)) 780 781 self.dut.security.SendUiCallback( 782 UiCallbackMsg(message_type=UiCallbackType.PASSKEY, 783 numeric_value=passkey, 784 unique_id=1, 785 address=self.cert_address)) 786 787 # 3. IUT and Lower Tester perform phase 2 of the Passkey Entry pairing and establish an encrypted link with the generated LTK. 788 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 789 BondMsgType.DEVICE_BONDED, self.cert_address), 790 timeout=timedelta(seconds=10)) 791 792 @metadata(pts_test_id="SM/MAS/SCPK/BV-04-C", 793 pts_test_name="Passkey Entry, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly") 794 def test_passkey_entry_iut_initiator_secure_connections_auth_req_rfu(self): 795 """ 796 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 central, initiator. 797 """ 798 self._prepare_cert_for_connection() 799 800 self.dut.security.SetLeIoCapability(KEYBOARD_DISPLAY) 801 self.dut.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 802 self.dut_security.SetLeAuthRequirements(secure_connections=1) 803 804 self.cert.security.SetLeIoCapability(KEYBOARD_ONLY) 805 self.cert.security.SetLeOobDataPresent(OOB_NOT_PRESENT) 806 self.cert_security.SetLeAuthRequirements(mitm=1, secure_connections=1, reserved_bits=3) 807 808 # 1. IUT transmits a Pairing Request command with: 809 # a. IO Capability set to “DisplayOnly” or “DisplayYesNo” or “KeyboardOnly” or “KeyboardDisplay” 810 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 811 # c. All reserved bits are set to ‘0’. 812 self.dut.security.CreateBondLe(self.cert_address) 813 814 assertThat(self.cert_security.get_ui_stream()).emits( 815 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 816 817 # 2. Lower Tester responds with a Pairing Response command, with: 818 # a. IO Capability set to “KeyboardOnly” 819 # b. OOB data flag set to 0x00 (OOB Authentication data not present) 820 # 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. 821 self.cert.security.SendUiCallback( 822 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 823 boolean=True, 824 unique_id=1, 825 address=self.dut_address)) 826 827 assertThat(self.cert_security.get_ui_stream()).emits( 828 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PASSKEY_ENTRY, self.dut_address)) 829 830 passkey = self.dut_security.wait_for_ui_event_passkey() 831 832 self.cert.security.SendUiCallback( 833 UiCallbackMsg(message_type=UiCallbackType.PASSKEY, 834 numeric_value=passkey, 835 unique_id=1, 836 address=self.dut_address)) 837 838 # 3. IUT and Lower Tester perform phase 2 of the Just Works pairing and establish an encrypted link with the generated LTK. 839 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 840 BondMsgType.DEVICE_BONDED, self.cert_address), 841 timeout=timedelta(seconds=10)) 842 843 @metadata(pts_test_id="SM/MAS/SCOB/BV-01-C", 844 pts_test_name="Out of Band, IUT Initiator, Secure Connections – Success") 845 def test_out_of_band_iut_initiator_secure_connections(self): 846 """ 847 Verify that the IUT supporting LE Secure Connections performs the Out-of-Band pairing procedure correctly as central, initiator. 848 """ 849 850 oob_combinations = [(OOB_NOT_PRESENT, OOB_PRESENT), (OOB_PRESENT, OOB_NOT_PRESENT), (OOB_PRESENT, OOB_PRESENT)] 851 852 for (dut_oob_flag, cert_oob_flag) in oob_combinations: 853 print("oob flag combination dut: " + str(dut_oob_flag) + ", cert: " + str(cert_oob_flag)) 854 855 self._prepare_cert_for_connection() 856 857 if dut_oob_flag == LeOobDataFlag.PRESENT: 858 oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty()) 859 self.dut.security.SetOutOfBandData( 860 OobDataMessage(address=self.cert_address, 861 confirmation_value=oobdata.confirmation_value, 862 random_value=oobdata.random_value)) 863 864 if cert_oob_flag == LeOobDataFlag.PRESENT: 865 oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty()) 866 self.cert.security.SetOutOfBandData( 867 OobDataMessage(address=self.dut_address, 868 confirmation_value=oobdata.confirmation_value, 869 random_value=oobdata.random_value)) 870 871 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 872 self.dut.security.SetLeOobDataPresent(dut_oob_flag) 873 self.dut_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1) 874 875 self.cert.security.SetLeIoCapability(DISPLAY_ONLY) 876 self.cert.security.SetLeOobDataPresent(cert_oob_flag) 877 self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1) 878 879 # 1. IUT transmits a Pairing Request command with OOB data flag set to either 0x00 or 0x01, and Secure Connections flag set to '1'. 880 self.dut.security.CreateBondLe(self.cert_address) 881 882 assertThat(self.cert_security.get_ui_stream()).emits( 883 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 884 885 # 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. 886 self.cert.security.SendUiCallback( 887 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 888 boolean=True, 889 unique_id=1, 890 address=self.dut_address)) 891 892 # 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. 893 894 # 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. 895 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 896 BondMsgType.DEVICE_BONDED, self.cert_address), 897 timeout=timedelta(seconds=10)) 898 899 assertThat(self.cert_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 900 BondMsgType.DEVICE_BONDED, self.dut_address), 901 timeout=timedelta(seconds=10)) 902 903 self.dut.security.RemoveBond(self.cert_address) 904 self.cert.security.RemoveBond(self.dut_address) 905 906 assertThat(self.dut_security.get_bond_stream()).emits( 907 SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address)) 908 909 self.dut_security.wait_device_disconnect(self.cert_address) 910 self.cert_security.wait_device_disconnect(self.dut_address) 911 912 @metadata(pts_test_id="SM/SLA/SCOB/BV-02-C", 913 pts_test_name="Out of Band, IUT Responder, Secure Connections – Success") 914 def test_out_of_band_iut_responder_secure_connections(self): 915 """ 916 Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure correctly when acting as peripheral, responder. 917 """ 918 919 oob_combinations = [(OOB_NOT_PRESENT, OOB_PRESENT), (OOB_PRESENT, OOB_NOT_PRESENT), (OOB_PRESENT, OOB_PRESENT)] 920 921 for (dut_oob_flag, cert_oob_flag) in oob_combinations: 922 print("oob flag combination dut: " + str(dut_oob_flag) + ", cert: " + str(cert_oob_flag)) 923 924 self._prepare_dut_for_connection() 925 926 if dut_oob_flag == LeOobDataFlag.PRESENT: 927 oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty()) 928 self.dut.security.SetOutOfBandData( 929 OobDataMessage(address=self.cert_address, 930 confirmation_value=oobdata.confirmation_value, 931 random_value=oobdata.random_value)) 932 933 if cert_oob_flag == LeOobDataFlag.PRESENT: 934 oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty()) 935 self.cert.security.SetOutOfBandData( 936 OobDataMessage(address=self.dut_address, 937 confirmation_value=oobdata.confirmation_value, 938 random_value=oobdata.random_value)) 939 940 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 941 self.dut.security.SetLeOobDataPresent(dut_oob_flag) 942 self.dut_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1) 943 944 self.cert.security.SetLeIoCapability(DISPLAY_ONLY) 945 self.cert.security.SetLeOobDataPresent(cert_oob_flag) 946 self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1) 947 948 # 1. Lower Tester transmits a Pairing Request command with OOB data flag set to either 0x00 or 0x01, and Secure Connections flag set to '1'. 949 self.cert.security.CreateBondLe(self.dut_address) 950 951 assertThat(self.dut_security.get_ui_stream()).emits( 952 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 953 954 # 2. IUT responds with a Pairing Response command with Secure Connections flag set to '1' and OOB data flag set to either 0x00 or 0x01. 955 self.dut.security.SendUiCallback( 956 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 957 boolean=True, 958 unique_id=1, 959 address=self.cert_address)) 960 961 # 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. 962 963 # 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. 964 assertThat(self.cert_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 965 BondMsgType.DEVICE_BONDED, self.dut_address), 966 timeout=timedelta(seconds=10)) 967 968 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 969 BondMsgType.DEVICE_BONDED, self.cert_address), 970 timeout=timedelta(seconds=10)) 971 972 self.cert.security.RemoveBond(self.dut_address) 973 self.dut.security.RemoveBond(self.cert_address) 974 975 assertThat(self.dut_security.get_bond_stream()).emits( 976 SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address)) 977 978 self.cert_security.wait_device_disconnect(self.dut_address) 979 self.dut_security.wait_device_disconnect(self.cert_address) 980 981 @metadata(pts_test_id="SM/SLA/SCOB/BV-03-C", 982 pts_test_name="Out of Band, IUT Responder, Secure Connections – Handle AuthReq Flag RFU Correctly") 983 def test_out_of_band_iut_responder_secure_connections_auth_req_rfu(self): 984 """ 985 Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as peripheral, responder. 986 """ 987 988 reserved_bits_combinations = [1, 2, 3] 989 990 for reserved_bits in reserved_bits_combinations: 991 print("reserved bits in cert dut: " + str(reserved_bits)) 992 993 self._prepare_dut_for_connection() 994 995 oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty()) 996 self.dut.security.SetOutOfBandData( 997 OobDataMessage(address=self.cert_address, 998 confirmation_value=oobdata.confirmation_value, 999 random_value=oobdata.random_value)) 1000 1001 oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty()) 1002 self.cert.security.SetOutOfBandData( 1003 OobDataMessage(address=self.dut_address, 1004 confirmation_value=oobdata.confirmation_value, 1005 random_value=oobdata.random_value)) 1006 1007 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 1008 self.dut.security.SetLeOobDataPresent(OOB_PRESENT) 1009 self.dut_security.SetLeAuthRequirements(bond=1, mitm=0, secure_connections=1) 1010 1011 self.cert.security.SetLeIoCapability(DISPLAY_ONLY) 1012 self.cert.security.SetLeOobDataPresent(OOB_PRESENT) 1013 self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1, reserved_bits=reserved_bits) 1014 1015 # 1. Lower Tester transmits Pairing Request command with: 1016 # a. IO Capability set to any IO capability 1017 # b. OOB data flag set to 0x01 (OOB Authentication data from remote device present) 1018 # c. MITM set to ‘0’, Secure Connections flag is set to '1', and all reserved bits are set to a random value. 1019 self.cert.security.CreateBondLe(self.dut_address) 1020 1021 assertThat(self.dut_security.get_ui_stream()).emits( 1022 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.cert_address)) 1023 1024 # 2. IUT responds with a Pairing Response command, with: 1025 # a. IO Capability set to any IO capability 1026 # b. OOB data flag set to 0x01 (OOB Authentication data present) 1027 # c. Secure Connections flag is set to '1', All reserved bits are set to ‘0’ 1028 self.dut.security.SendUiCallback( 1029 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 1030 boolean=True, 1031 unique_id=1, 1032 address=self.cert_address)) 1033 1034 # 3. IUT and Lower Tester perform phase 2 of the OOB authenticated pairing and establish an encrypted link with the generated LTK. 1035 1036 assertThat(self.cert_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 1037 BondMsgType.DEVICE_BONDED, self.dut_address), 1038 timeout=timedelta(seconds=10)) 1039 1040 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 1041 BondMsgType.DEVICE_BONDED, self.cert_address), 1042 timeout=timedelta(seconds=10)) 1043 1044 self.cert.security.RemoveBond(self.dut_address) 1045 self.dut.security.RemoveBond(self.cert_address) 1046 1047 assertThat(self.dut_security.get_bond_stream()).emits( 1048 SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address)) 1049 1050 self.dut_security.wait_device_disconnect(self.cert_address) 1051 self.cert_security.wait_device_disconnect(self.dut_address) 1052 1053 @metadata(pts_test_id="SM/MAS/SCOB/BV-04-C", 1054 pts_test_name="Out of Band, IUT Initiator, Secure Connections – Handle AuthReq Flag RFU Correctly") 1055 def test_out_of_band_iut_initiator_secure_connections_auth_req_rfu(self): 1056 """ 1057 Verify that the IUT supporting LE Secure Connections is able to perform the Out-of-Band pairing procedure when receiving additional bits set in the AuthReq flag. Reserved For Future Use bits are correctly handled when acting as central, initiator. 1058 """ 1059 1060 reserved_bits_combinations = [1, 2, 3] 1061 1062 for reserved_bits in reserved_bits_combinations: 1063 print("reserved bits in cert dut: " + str(reserved_bits)) 1064 1065 self._prepare_cert_for_connection() 1066 1067 oobdata = self.cert.security.GetLeOutOfBandData(empty_proto.Empty()) 1068 self.dut.security.SetOutOfBandData( 1069 OobDataMessage(address=self.cert_address, 1070 confirmation_value=oobdata.confirmation_value, 1071 random_value=oobdata.random_value)) 1072 1073 oobdata = self.dut.security.GetLeOutOfBandData(empty_proto.Empty()) 1074 self.cert.security.SetOutOfBandData( 1075 OobDataMessage(address=self.dut_address, 1076 confirmation_value=oobdata.confirmation_value, 1077 random_value=oobdata.random_value)) 1078 1079 self.dut.security.SetLeIoCapability(KEYBOARD_ONLY) 1080 self.dut.security.SetLeOobDataPresent(OOB_PRESENT) 1081 self.dut_security.SetLeAuthRequirements(bond=1, mitm=0, secure_connections=1, reserved_bits=0) 1082 1083 self.cert.security.SetLeIoCapability(DISPLAY_ONLY) 1084 self.cert.security.SetLeOobDataPresent(OOB_PRESENT) 1085 self.cert_security.SetLeAuthRequirements(bond=1, mitm=1, secure_connections=1, reserved_bits=reserved_bits) 1086 1087 # 1. IUT transmits Pairing Request command with: 1088 # a. IO Capability set to any IO capability 1089 # b. OOB data flag set to 0x01 (OOB Authentication data present) 1090 # c. MITM set to ‘0’, Secure Connections flag is set to '1', and all reserved bits are set to ‘0’ 1091 self.dut.security.CreateBondLe(self.cert_address) 1092 1093 assertThat(self.cert_security.get_ui_stream()).emits( 1094 SecurityMatchers.UiMsg(UiMsgType.DISPLAY_PAIRING_PROMPT, self.dut_address)) 1095 1096 # 2. Lower Tester responds with a Pairing Response command, with: 1097 # a. IO Capability set to any IO capability 1098 # b. OOB data flag set to 0x01 (OOB Authentication data present) 1099 # c. Secure Connections flag is set to '1', and all reserved bits are set to a random value. 1100 self.cert.security.SendUiCallback( 1101 UiCallbackMsg(message_type=UiCallbackType.PAIRING_PROMPT, 1102 boolean=True, 1103 unique_id=1, 1104 address=self.dut_address)) 1105 1106 # 3. IUT and Lower Tester perform phase 2 of the OOB authenticated pairing and establish an encrypted link with the generated LTK. 1107 1108 assertThat(self.dut_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 1109 BondMsgType.DEVICE_BONDED, self.cert_address), 1110 timeout=timedelta(seconds=10)) 1111 1112 assertThat(self.cert_security.get_bond_stream()).emits(SecurityMatchers.BondMsg( 1113 BondMsgType.DEVICE_BONDED, self.dut_address), 1114 timeout=timedelta(seconds=10)) 1115 1116 self.dut.security.RemoveBond(self.cert_address) 1117 self.cert.security.RemoveBond(self.dut_address) 1118 1119 assertThat(self.dut_security.get_bond_stream()).emits( 1120 SecurityMatchers.BondMsg(BondMsgType.DEVICE_UNBONDED, self.cert_address)) 1121 1122 self.dut_security.wait_device_disconnect(self.cert_address) 1123 self.cert_security.wait_device_disconnect(self.dut_address) 1124 1125 1126if __name__ == '__main__': 1127 test_runner.main() 1128