Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f19d869 authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by Myles Watson
Browse files

LE Security cert test SM/SLA/PROT/BV-02-C

Tag: #gd-refactor
Bug: 155399771
Test: cert/run --host
Change-Id: I2a2a5217d897e3e508af824f64bf9af2db3f46db
parent b602606e
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -89,6 +89,10 @@ class HciMatchers(object):
    def SimplePairingComplete():
        return lambda event: HciMatchers.EventWithCode(EventCode.SIMPLE_PAIRING_COMPLETE)

    @staticmethod
    def Disconnect():
        return lambda event: HciMatchers.EventWithCode(EventCode.DISCONNECT)


class NeighborMatchers(object):

+5 −7
Original line number Diff line number Diff line
@@ -46,16 +46,14 @@ class PyLeSecurity(Closable):
        self._ui_event_stream = EventStream(self._device.security.FetchUiEvents(empty_proto.Empty()))
        self._bond_event_stream = EventStream(self._device.security.FetchBondEvents(empty_proto.Empty()))

    def wait_for_bond_event(self, expected_bond_event,
                            timeout=timedelta(seconds=3)):  # =timedelta(seconds=DEFAULT_TIMEOUT_SECONDS)
        """
            A bond event will be triggered once the bond process
            is complete.  For the DUT we need to wait for it,
            for Cert it isn't needed.
        """
    def wait_for_bond_event(self, expected_bond_event, timeout=timedelta(seconds=3)):
        self._bond_event_stream.assert_event_occurs(
            match_fn=lambda event: event.message_type == expected_bond_event, timeout=timeout)

    def wait_for_ui_event(self, expected_ui_event, timeout=timedelta(seconds=3)):
        self._ui_event_stream.assert_event_occurs(
            match_fn=lambda event: event.message_type == expected_ui_event, timeout=timeout)

    def close(self):
        if self._ui_event_stream is not None:
            safeClose(self._ui_event_stream)
+66 −1
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ import time
from bluetooth_packets_python3 import hci_packets
from cert.event_stream import EventStream
from cert.gd_base_test import GdBaseTestClass
from cert.matchers import HciMatchers
from cert.metadata import metadata
from cert.py_hci import PyHci
from cert.py_le_security import PyLeSecurity
from cert.truth import assertThat
from datetime import timedelta
@@ -30,9 +32,12 @@ from neighbor.facade import facade_pb2 as neighbor_facade
from security.cert.cert_security import CertSecurity
from security.facade_pb2 import AuthenticationRequirements
from security.facade_pb2 import BondMsgType
from security.facade_pb2 import IoCapabilities
from security.facade_pb2 import OobDataPresent
from security.facade_pb2 import UiCallbackMsg
from security.facade_pb2 import UiCallbackType
from security.facade_pb2 import UiMsgType
from security.facade_pb2 import LeIoCapabilityMessage
from bluetooth_packets_python3.hci_packets import OpCode


class LeSecurityTest(GdBaseTestClass):
@@ -49,6 +54,7 @@ class LeSecurityTest(GdBaseTestClass):

        self.dut_security = PyLeSecurity(self.dut)
        self.cert_security = PyLeSecurity(self.cert)
        self.dut_hci = PyHci(self.dut)

        self.dut_address = common.BluetoothAddressWithType(
            address=common.BluetoothAddress(address=bytes(b'DD:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
@@ -58,6 +64,7 @@ class LeSecurityTest(GdBaseTestClass):
        self.cert.security.SetLeInitiatorAddress(self.cert_address)

    def teardown_test(self):
        self.dut_hci.close()
        self.dut_security.close()
        self.cert_security.close()
        super().teardown_test()
@@ -82,6 +89,26 @@ class LeSecurityTest(GdBaseTestClass):
        request = le_advertising_facade.CreateAdvertiserRequest(config=config)
        create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request)

    def _prepare_dut_for_connection(self):
        # DUT Advertises
        gap_name = hci_packets.GapData()
        gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME
        gap_name.data = list(bytes(b'Im_The_DUT'))
        gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize()))
        config = le_advertising_facade.AdvertisingConfig(
            advertisement=[gap_data],
            random_address=self.dut_address.address,
            interval_min=512,
            interval_max=768,
            event_type=le_advertising_facade.AdvertisingEventType.ADV_IND,
            address_type=common.RANDOM_DEVICE_ADDRESS,
            peer_address_type=common.PUBLIC_DEVICE_ADDRESS,
            peer_address=common.BluetoothAddress(address=bytes(b'00:00:00:00:00:00')),
            channel_map=7,
            filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES)
        request = le_advertising_facade.CreateAdvertiserRequest(config=config)
        create_response = self.dut.hci_le_advertising_manager.CreateAdvertiser(request)

    @metadata(pts_test_id="SM/MAS/PROT/BV-01-C", pts_test_name="SMP Time Out – IUT Initiator")
    def test_le_smp_timeout_iut_initiator(self):
        """
@@ -91,3 +118,41 @@ class LeSecurityTest(GdBaseTestClass):
        self.dut.security.CreateBondLe(self.cert_address)
        self.dut_security.wait_for_bond_event(
            expected_bond_event=BondMsgType.DEVICE_BOND_FAILED, timeout=timedelta(seconds=35))

    @metadata(pts_test_id="SM/SLA/PROT/BV-02-C", pts_test_name="SMP Time Out – IUT Responder")
    def test_le_smp_timeout_iut_responder(self):
        """
            Verify that the IUT handles the lack of pairing response after 30 seconds when acting as initiator.
        """
        self.cert.security.SetLeIoCapability(
            LeIoCapabilityMessage(capabilities=LeIoCapabilityMessage.LeIoCapabilities.KEYBOARD_ONLY))
        self.dut.security.SetLeIoCapability(
            LeIoCapabilityMessage(capabilities=LeIoCapabilityMessage.LeIoCapabilities.DISPLAY_ONLY))

        self._prepare_dut_for_connection()

        # 1. Lower Tester transmits Pairing Request.
        self.cert.security.CreateBondLe(self.dut_address)

        self.dut_security.wait_for_ui_event(
            expected_ui_event=UiMsgType.DISPLAY_PAIRING_PROMPT, timeout=timedelta(seconds=35))

        # 2. IUT responds with Pairing Response.
        self.dut.security.SendUiCallback(
            UiCallbackMsg(
                message_type=UiCallbackType.PAIRING_PROMPT, boolean=True, unique_id=1, address=self.cert_address))

        # 3. In phase 2, Lower Tester does not issue the expected Pairing Confirm.

        # Here the cert receives DISPLAY_PASSKEY_ENTRY. By not replying to it we make sure Pairing Confirm is never sent
        self.cert_security.wait_for_ui_event(
            expected_ui_event=UiMsgType.DISPLAY_PASSKEY_ENTRY, timeout=timedelta(seconds=5))

        # 4. IUT times out 30 seconds after issued Pairing Response and reports the failure to the Upper Tester.
        self.dut_security.wait_for_bond_event(
            expected_bond_event=BondMsgType.DEVICE_BOND_FAILED, timeout=timedelta(seconds=35))

        # 5. After additionally (at least) 10 seconds the Lower Tester issues the expected Pairing Confirm.
        # 6. The IUT closes the connection before receiving the delayed response or does not respond to it when it is received.
        #TODO:
        #assertThat(self.dut_hci.get_event_stream()).emits(HciMatchers.Disconnect())
+25 −11
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
                                ::google::protobuf::Empty* response) override {
    hci::Address peer;
    ASSERT(hci::Address::FromString(request->address().address().address(), peer));
    hci::AddressType remote_type = hci::AddressType::PUBLIC_DEVICE_ADDRESS;
    hci::AddressType remote_type = static_cast<hci::AddressType>(request->address().type());

    switch (request->message_type()) {
      case UiCallbackType::PASSKEY:
@@ -89,6 +89,10 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
        security_module_->GetSecurityManager()->OnConfirmYesNo(hci::AddressWithType(peer, remote_type),
                                                               request->boolean());
        break;
      case UiCallbackType::PAIRING_PROMPT:
        security_module_->GetSecurityManager()->OnPairingPromptAccepted(
            hci::AddressWithType(peer, remote_type), request->boolean());
        break;
      default:
        LOG_ERROR("Unknown UiCallbackType %d", static_cast<int>(request->message_type()));
        return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Unknown UiCallbackType");
@@ -108,6 +112,15 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    return ::grpc::Status::OK;
  }

  ::grpc::Status SetLeIoCapability(
      ::grpc::ServerContext* context,
      const LeIoCapabilityMessage* request,
      ::google::protobuf::Empty* response) override {
    security_module_->GetFacadeConfigurationApi()->SetLeIoCapability(
        static_cast<security::IoCapability>(request->capabilities()));
    return ::grpc::Status::OK;
  }

  ::grpc::Status SetAuthenticationRequirements(::grpc::ServerContext* context,
                                               const AuthenticationRequirementsMessage* request,
                                               ::google::protobuf::Empty* response) override {
@@ -138,8 +151,8 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s", peer.ToString().c_str());
    UiMsg display_yes_no;
    display_yes_no.mutable_peer()->mutable_address()->set_address(peer.ToString());
    display_yes_no.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    display_yes_no.set_message_type(UiMsgType::DISPLAY_YES_NO);
    display_yes_no.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    display_yes_no.set_message_type(UiMsgType::DISPLAY_PAIRING_PROMPT);
    display_yes_no.set_unique_id(unique_id++);
    ui_events_.OnIncomingEvent(display_yes_no);
  }
@@ -149,7 +162,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s value = 0x%x", peer.ToString().c_str(), numeric_value);
    UiMsg display_with_value;
    display_with_value.mutable_peer()->mutable_address()->set_address(peer.ToString());
    display_with_value.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    display_with_value.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    display_with_value.set_message_type(UiMsgType::DISPLAY_YES_NO_WITH_VALUE);
    display_with_value.set_numeric_value(numeric_value);
    display_with_value.set_unique_id(unique_id++);
@@ -160,7 +173,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s", peer.ToString().c_str());
    UiMsg display_yes_no;
    display_yes_no.mutable_peer()->mutable_address()->set_address(peer.ToString());
    display_yes_no.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    display_yes_no.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    display_yes_no.set_message_type(UiMsgType::DISPLAY_YES_NO);
    display_yes_no.set_unique_id(unique_id++);
    ui_events_.OnIncomingEvent(display_yes_no);
@@ -170,7 +183,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s value = 0x%x", peer.ToString().c_str(), passkey);
    UiMsg display_passkey;
    display_passkey.mutable_peer()->mutable_address()->set_address(peer.ToString());
    display_passkey.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    display_passkey.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    display_passkey.set_message_type(UiMsgType::DISPLAY_PASSKEY);
    display_passkey.set_numeric_value(passkey);
    display_passkey.set_unique_id(unique_id++);
@@ -181,7 +194,8 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s", peer.ToString().c_str());
    UiMsg display_passkey_input;
    display_passkey_input.mutable_peer()->mutable_address()->set_address(peer.ToString());
    display_passkey_input.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    display_passkey_input.mutable_peer()->set_type(
        static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    display_passkey_input.set_message_type(UiMsgType::DISPLAY_PASSKEY_ENTRY);
    display_passkey_input.set_unique_id(unique_id++);
    ui_events_.OnIncomingEvent(display_passkey_input);
@@ -191,7 +205,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s", peer.ToString().c_str());
    UiMsg display_cancel;
    display_cancel.mutable_peer()->mutable_address()->set_address(peer.ToString());
    display_cancel.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    display_cancel.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    display_cancel.set_message_type(UiMsgType::DISPLAY_CANCEL);
    display_cancel.set_unique_id(unique_id++);
    ui_events_.OnIncomingEvent(display_cancel);
@@ -201,7 +215,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s", peer.ToString().c_str());
    BondMsg bonded;
    bonded.mutable_peer()->mutable_address()->set_address(peer.ToString());
    bonded.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    bonded.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    bonded.set_message_type(BondMsgType::DEVICE_BONDED);
    bond_events_.OnIncomingEvent(bonded);
  }
@@ -212,7 +226,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s", peer.ToString().c_str());
    BondMsg unbonded;
    unbonded.mutable_peer()->mutable_address()->set_address(peer.ToString());
    unbonded.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    unbonded.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    unbonded.set_message_type(BondMsgType::DEVICE_UNBONDED);
    bond_events_.OnIncomingEvent(unbonded);
  }
@@ -221,7 +235,7 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    LOG_INFO("%s", peer.ToString().c_str());
    BondMsg bond_failed;
    bond_failed.mutable_peer()->mutable_address()->set_address(peer.ToString());
    bond_failed.mutable_peer()->set_type(facade::BluetoothAddressTypeEnum::PUBLIC_DEVICE_ADDRESS);
    bond_failed.mutable_peer()->set_type(static_cast<facade::BluetoothAddressTypeEnum>(peer.GetAddressType()));
    bond_failed.set_message_type(BondMsgType::DEVICE_BOND_FAILED);
    bond_events_.OnIncomingEvent(bond_failed);
  }
+14 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ service SecurityModuleFacade {
  rpc CancelBond(facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {}
  rpc RemoveBond(facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {}
  rpc SetIoCapability(IoCapabilityMessage) returns (google.protobuf.Empty) {}
  rpc SetLeIoCapability(LeIoCapabilityMessage) returns (google.protobuf.Empty) {}
  rpc SetAuthenticationRequirements(AuthenticationRequirementsMessage) returns (google.protobuf.Empty) {}
  rpc SetOobDataPresent(OobDataMessage) returns (google.protobuf.Empty) {}
  rpc SetLeInitiatorAddress(facade.BluetoothAddressWithType) returns (google.protobuf.Empty) {}
@@ -25,6 +26,7 @@ enum UiMsgType {
  DISPLAY_PASSKEY = 2;
  DISPLAY_PASSKEY_ENTRY = 3;
  DISPLAY_CANCEL = 4;
  DISPLAY_PAIRING_PROMPT = 5;
}

message UiMsg {
@@ -37,6 +39,7 @@ message UiMsg {
enum UiCallbackType {
  YES_NO = 0;
  PASSKEY = 1;
  PAIRING_PROMPT = 2;
}

message UiCallbackMsg {
@@ -69,6 +72,17 @@ message IoCapabilityMessage {
  IoCapabilities capability = 1;
}

message LeIoCapabilityMessage {
  enum LeIoCapabilities {
    DISPLAY_ONLY = 0;
    DISPLAY_YES_NO_IO_CAP = 1;
    KEYBOARD_ONLY = 2;
    NO_INPUT_NO_OUTPUT = 3;
    KEYBOARD_DISPLAY = 4;
  }
  LeIoCapabilities capabilities = 1;
}

enum AuthenticationRequirements {
  NO_BONDING = 0;
  NO_BONDING_MITM_PROTECTION = 1;
Loading