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

Commit c5c9ca3c authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I2a2a5217,If2357680

* changes:
  LE Security cert test SM/SLA/PROT/BV-02-C
  LE Security Cert Test: Set the initiator address correctly
parents 9e14e244 4f19d869
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)
+70 −3
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,13 +54,17 @@ 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'0D:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
            address=common.BluetoothAddress(address=bytes(b'DD:05:04:03:02:01')), type=common.RANDOM_DEVICE_ADDRESS)
        self.dut.security.SetLeInitiatorAddress(self.dut_address)
        self.cert_address = common.BluetoothAddressWithType(
            address=common.BluetoothAddress(address=bytes(b'55:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
            address=common.BluetoothAddress(address=bytes(b'C5:11:FF:AA:33:22')), type=common.RANDOM_DEVICE_ADDRESS)
        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()
@@ -80,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):
        """
@@ -89,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())
+36 −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 {
@@ -123,12 +136,23 @@ class SecurityModuleFacadeService : public SecurityModuleFacade::Service, public
    return ::grpc::Status::OK;
  }

  ::grpc::Status SetLeInitiatorAddress(
      ::grpc::ServerContext* context,
      const facade::BluetoothAddressWithType* request,
      ::google::protobuf::Empty* response) override {
    hci::Address peer;
    ASSERT(hci::Address::FromString(request->address().address(), peer));
    hci::AddressType peer_type = static_cast<hci::AddressType>(request->type());
    security_module_->GetSecurityManager()->SetLeInitiatorAddress(hci::AddressWithType(peer, peer_type));
    return ::grpc::Status::OK;
  }

  void DisplayPairingPrompt(const bluetooth::hci::AddressWithType& peer, std::string name) {
    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);
  }
@@ -138,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++);
@@ -149,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);
@@ -159,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++);
@@ -170,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);
@@ -180,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);
@@ -190,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);
  }
@@ -201,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);
  }
@@ -210,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);
  }
+15 −0
Original line number Diff line number Diff line
@@ -11,8 +11,10 @@ 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) {}
  rpc SendUiCallback(UiCallbackMsg) returns (google.protobuf.Empty) {}
  rpc FetchUiEvents(google.protobuf.Empty) returns (stream UiMsg) {}
  rpc FetchBondEvents(google.protobuf.Empty) returns (stream BondMsg) {}
@@ -24,6 +26,7 @@ enum UiMsgType {
  DISPLAY_PASSKEY = 2;
  DISPLAY_PASSKEY_ENTRY = 3;
  DISPLAY_CANCEL = 4;
  DISPLAY_PAIRING_PROMPT = 5;
}

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

message UiCallbackMsg {
@@ -68,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