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

Commit 102b7e22 authored by Grzegorz Kołodziejczyk's avatar Grzegorz Kołodziejczyk
Browse files

csip: Don't keep bond with invalid CSIS devices

This extends CSIP part with verification of SIRK of connecting member
and general member verification. Verification is done by registered in
SMP callback that validates SIRK with group known value.

Tag: #fetature
Bug: 278514112
Test: atest bluetooth_csis_test
Change-Id: Ibffbfeb81884a955f1a9111dd6646955c3bedd07
parent 8c491c77
Loading
Loading
Loading
Loading
+142 −5
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include "stack/btm/btm_dev.h"
#include "stack/btm/btm_sec.h"
#include "stack/crypto_toolbox/crypto_toolbox.h"
#include "stack/gatt/gatt_int.h"

using base::Closure;
using bluetooth::Uuid;
@@ -131,6 +132,16 @@ class CsisClientImpl : public CsisClient {
            initCb),
        true);

    BTA_DmSirkSecCbRegister([](tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data) {
      if (event != BTA_DM_SIRK_VERIFICATION_REQ_EVT) {
        LOG_ERROR("Invalid event received by CSIP: %d",
                  static_cast<int>(event));
        return;
      }

      instance->VerifySetMember(p_data->ble_req.bd_addr);
    });

    DLOG(INFO) << __func__ << " Background scan enabled";
    CsisObserverSetBackground(true);
  }
@@ -706,7 +717,13 @@ class CsisClientImpl : public CsisClient {
             << static_cast<int>(g->GetTargetLockState()) << "\n"
             << "    devices: \n";
      for (auto& device : devices_) {
        if (!g->IsDeviceInTheGroup(device)) continue;
        if (!g->IsDeviceInTheGroup(device)) {
          if (device->GetExpectedGroupIdMember() == g->GetGroupId()) {
            stream << "        == candidate addr: "
                   << ADDRESS_TO_LOGGABLE_STR(device->addr) << "\n";
          }
          continue;
        }

        stream << "        == addr: "
               << ADDRESS_TO_LOGGABLE_STR(device->addr) << " ==\n"
@@ -1224,6 +1241,25 @@ class CsisClientImpl : public CsisClient {
    return std::move(devices);
  }

  void CacheAndAdvertiseExpectedMember(const RawAddress& address,
                                       int group_id) {
    auto device = FindDeviceByAddress(address);
    if (device == nullptr) {
      device = std::make_shared<CsisDevice>(address, false);
      devices_.push_back(device);
    }

    /*
     * Expected group ID will be checked while reading SIRK if this device
     * truly is member of group.
     */
    device.get()->SetExpectedGroupIdMember(group_id);
    devices_.push_back(device);

    callbacks_->OnSetMemberAvailable(address,
                                     device.get()->GetExpectedGroupIdMember());
  }

  void OnActiveScanResult(const tBTA_DM_INQ_RES* result) {
    auto csis_device = FindDeviceByAddress(result->bd_addr);
    if (csis_device) {
@@ -1256,7 +1292,8 @@ class CsisClientImpl : public CsisClient {
    if (discovered_group_rsi != all_rsi.cend()) {
      DLOG(INFO) << "Found set member "
                 << ADDRESS_TO_LOGGABLE_STR(result->bd_addr);
      callbacks_->OnSetMemberAvailable(result->bd_addr,

      CacheAndAdvertiseExpectedMember(result->bd_addr,
                                      csis_group->GetGroupId());

      /* Switch back to the opportunistic observer mode.
@@ -1376,8 +1413,8 @@ class CsisClientImpl : public CsisClient {
            break;
          }

          callbacks_->OnSetMemberAvailable(result->bd_addr,
                                           group->GetGroupId());
          CacheAndAdvertiseExpectedMember(result->bd_addr, group->GetGroupId());

          break;
        }
      }
@@ -1524,6 +1561,24 @@ class CsisClientImpl : public CsisClient {
               << loghex(csis_group->GetDesiredSize())
               << ", actual group Size: "
               << loghex(csis_group->GetCurrentSize());
    if (csis_group->GetDesiredSize() == csis_group->GetCurrentSize()) {
      auto iter = devices_.cbegin();

      /*
       * Remove devices which are expected members but are not connected and
       * group is already completed. Those devices are cached ivalid devices
       * kept on list to not trigger "new device" found every time advertising
       * event is received.
       */
      while (iter != devices_.cend()) {
        if (((*iter)->GetExpectedGroupIdMember() == csis_group->GetGroupId()) &&
            !(*iter)->IsConnected()) {
          iter = devices_.erase(iter);
        } else {
          ++iter;
        }
      }
    }
  }

  void DeregisterNotifications(std::shared_ptr<CsisDevice> device) {
@@ -2049,6 +2104,87 @@ class CsisClientImpl : public CsisClient {
    }
  }

  void ReadSirkValue(tGATT_STATUS status, const RawAddress& address,
                     uint8_t sirk_type, Octet16& received_sirk) {
    if (status != GATT_SUCCESS) {
      LOG_INFO("Invalid member, can't read SIRK (status: %02x)", status);
      BTA_DmSirkConfirmDeviceReply(address, false);
      return;
    }

    auto device = FindDeviceByAddress(address);
    if (device == nullptr) {
      LOG_ERROR("Invalid SIRK value read for unknown device");
      BTA_DmSirkConfirmDeviceReply(address, false);
      return;
    }

    LOG_DEBUG("%s, status: 0x%02x", ADDRESS_TO_LOGGABLE_CSTR(address), status);

    /* Verify if sirk is not all zeros */
    Octet16 zero{};
    if (memcmp(zero.data(), received_sirk.data(), 16) == 0) {
      LOG_ERROR("Received invalid zero SIRK address: %s ",
                ADDRESS_TO_LOGGABLE_CSTR(address));
      BTA_DmSirkConfirmDeviceReply(address, false);
      return;
    }

    if (sirk_type == bluetooth::csis::kCsisSirkTypeEncrypted) {
      /* Decrypt encrypted SIRK */
      Octet16 sirk;
      sdf(device->addr, received_sirk, sirk);
      received_sirk = sirk;
    }

    /* SIRK is ready. Add device to the group */

    /* Now having SIRK we can decide if the device belongs to some group we
     * know or this is a new group
     */
    auto csis_group = FindCsisGroup(device->GetExpectedGroupIdMember());
    if (!csis_group) {
      LOG_ERROR("Expected group with ID: %d, isn't cached",
                device->GetExpectedGroupIdMember());
      return;
    }

    /* Device will be added to group when upper layer decides */
    RemoveDevice(device->addr);

    if (csis_group->IsSirkBelongsToGroup(received_sirk)) {
      LOG_INFO("Device %s, verified successfully by SIRK",
               ADDRESS_TO_LOGGABLE_CSTR(address));
      BTA_DmSirkConfirmDeviceReply(address, true);
    } else {
      /*
       * Joining member must join already existing group otherwise it means
       * that its SIRK is different. Device connection was triggered by RSI
       * match for group.
       */
      LOG_ERROR("Joining device %s, does not match any existig group",
                ADDRESS_TO_LOGGABLE_CSTR(address));
      BTA_DmSirkConfirmDeviceReply(address, false);
    }
  }

  void VerifySetMember(const RawAddress& address) {
    auto device = FindDeviceByAddress(address);

    LOG_INFO("Device: %s", ADDRESS_TO_LOGGABLE_CSTR(address));

    /* It's ok for device to not be a CSIS device at all */
    if (!device) {
      LOG_INFO("Valid - new member");
      BTA_DmSirkConfirmDeviceReply(address, true);
      return;
    }

    gatt_cl_read_sirk_req(address,
                          base::BindOnce(&CsisClientImpl::ReadSirkValue,
                                         base::Unretained(instance)));
  }

  uint8_t gatt_if_;
  bluetooth::csis::CsisClientCallbacks* callbacks_;
  std::list<std::shared_ptr<CsisDevice>> devices_;
@@ -2130,6 +2266,7 @@ bool CsisClient::GetForStorage(const RawAddress& addr,

void CsisClient::CleanUp() {
  std::scoped_lock<std::mutex> lock(instance_mutex);
  BTA_DmSirkSecCbRegister(nullptr);
  CsisClientImpl* ptr = instance;
  instance = nullptr;

+8 −0
Original line number Diff line number Diff line
@@ -31,6 +31,14 @@
#include "hardware/bt_gatt_types.h"
#include "test/common/mock_functions.h"

bool gatt_cl_read_sirk_req(
    const RawAddress& peer_bda,
    base::OnceCallback<void(tGATT_STATUS status, const RawAddress&,
                            uint8_t sirk_type, Octet16& sirk)>
        cb) {
  return true;
}

namespace bluetooth {
namespace csis {
namespace internal {
+9 −0
Original line number Diff line number Diff line
@@ -271,9 +271,18 @@ class CsisDevice : public GattServiceDevice {
    }
  }

  void SetExpectedGroupIdMember(int group_id) {
    LOG_DEBUG("Expected Group ID: %d, for member: %s is set", group_id,
              ADDRESS_TO_LOGGABLE_CSTR(addr));
    expected_group_id_member = group_id;
  }

  inline int GetExpectedGroupIdMember() { return expected_group_id_member; }

 private:
  /* Instances per start handle  */
  std::map<uint16_t, std::shared_ptr<CsisInstance>> csis_instances_;
  int expected_group_id_member = bluetooth::groups::kGroupUnknown;
};

/*