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