• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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