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