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

Commit 2d3da485 authored by HsingYuan Lo's avatar HsingYuan Lo Committed by Jakub Pawlowski
Browse files

Robust Caching - client hash calculation

This code was extracted from a bigger patch in order to make review
easier.

Bug: 154056389
Test: atest net_test_stack_gatt_db_native
Tag: #feature
Change-Id: I7d1a90d656db3e58b9386c008c0aacdeae6c854a
parent 24be0a16
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ cc_test {
        "libprotobuf-cpp-lite",
    ],
    static_libs: [
        "crypto_toolbox_for_tests",
        "libbtcore",
        "libbt-bta",
        "libbt-audio-hal-interface",
+101 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include "database.h"
#include "bt_trace.h"
#include "stack/crypto_toolbox/crypto_toolbox.h"
#include "stack/include/gattdefs.h"

#include <base/logging.h>
@@ -40,6 +41,11 @@ bool HandleInRange(const Service& svc, uint16_t handle) {
}
}  // namespace

static size_t UuidSize(const Uuid& uuid) {
  size_t len = uuid.GetShortestRepresentationSize();
  return (len == Uuid::kNumBytes32) ? Uuid::kNumBytes128 : len;
}

Service* FindService(std::list<Service>& services, uint16_t handle) {
  for (Service& service : services) {
    if (handle >= service.handle && handle <= service.end_handle)
@@ -185,4 +191,99 @@ Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
  return result;
}

Octet16 Database::Hash() const {
  int len = 0;
  // Compute how much space we need to actually hold the data.
  for (const Service& service : services) {
    len += 4 + UuidSize(service.uuid);

    for (const auto& is : service.included_services) {
      len += 8 + UuidSize(is.uuid);
    }

    for (const Characteristic& c : service.characteristics) {
      len += 7 + UuidSize(c.uuid);

      for (const Descriptor& d : c.descriptors) {
        if (UuidSize(d.uuid) != Uuid::kNumBytes16) {
          continue;
        }
        uint16_t value = d.uuid.As16Bit();
        if (value == GATT_UUID_CHAR_DESCRIPTION ||
            value == GATT_UUID_CHAR_CLIENT_CONFIG ||
            value == GATT_UUID_CHAR_SRVR_CONFIG ||
            value == GATT_UUID_CHAR_PRESENT_FORMAT ||
            value == GATT_UUID_CHAR_AGG_FORMAT) {
          len += 2 + UuidSize(d.uuid);
        } else if (value == GATT_UUID_CHAR_EXT_PROP) {
          len += 4 + UuidSize(d.uuid);
        }
      }
    }
  }

  std::vector<uint8_t> serialized(len);
  uint8_t* p = serialized.data();
  for (const Service& service : services) {
    UINT16_TO_STREAM(p, service.handle);
    if (service.is_primary) {
      UINT16_TO_STREAM(p, GATT_UUID_PRI_SERVICE);
    } else {
      UINT16_TO_STREAM(p, GATT_UUID_SEC_SERVICE);
    }

    if (UuidSize(service.uuid) == Uuid::kNumBytes16) {
      UINT16_TO_STREAM(p, service.uuid.As16Bit());
    } else {
      ARRAY_TO_STREAM(p, service.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
    }

    for (const auto& is : service.included_services) {
      UINT16_TO_STREAM(p, is.handle);
      UINT16_TO_STREAM(p, GATT_UUID_INCLUDE_SERVICE);
      UINT16_TO_STREAM(p, is.start_handle);
      UINT16_TO_STREAM(p, is.end_handle);

      if (UuidSize(is.uuid) == Uuid::kNumBytes16) {
        UINT16_TO_STREAM(p, is.uuid.As16Bit());
      } else {
        ARRAY_TO_STREAM(p, is.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
      }
    }

    for (const Characteristic& c : service.characteristics) {
      UINT16_TO_STREAM(p, c.declaration_handle);
      UINT16_TO_STREAM(p, GATT_UUID_CHAR_DECLARE);
      UINT8_TO_STREAM(p, c.properties);
      UINT16_TO_STREAM(p, c.value_handle);

      if (UuidSize(c.uuid) == Uuid::kNumBytes16) {
        UINT16_TO_STREAM(p, c.uuid.As16Bit());
      } else {
        ARRAY_TO_STREAM(p, c.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
      }

      for (const Descriptor& d : c.descriptors) {
        if (UuidSize(d.uuid) != Uuid::kNumBytes16) continue;
        uint16_t value = d.uuid.As16Bit();
        if (value == GATT_UUID_CHAR_DESCRIPTION ||
            value == GATT_UUID_CHAR_CLIENT_CONFIG ||
            value == GATT_UUID_CHAR_SRVR_CONFIG ||
            value == GATT_UUID_CHAR_PRESENT_FORMAT ||
            value == GATT_UUID_CHAR_AGG_FORMAT) {
          UINT16_TO_STREAM(p, d.handle);
          UINT16_TO_STREAM(p, d.uuid.As16Bit());
        } else if (value == GATT_UUID_CHAR_EXT_PROP) {
          UINT16_TO_STREAM(p, d.handle);
          UINT16_TO_STREAM(p, d.uuid.As16Bit());
          UINT16_TO_STREAM(p, 0x0000);  // STORE!!!!! USE PROPER VALUE !!!
        }
      }
    }
  }

  std::reverse(serialized.begin(), serialized.end());
  return crypto_toolbox::aes_cmac(Octet16{0}, serialized.data(),
                                  serialized.size());
}
}  // namespace gatt
+4 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <utility>
#include <vector>

#include "stack/include/bt_types.h" /* for Octet16 */
#include "types/bluetooth/uuid.h"

namespace gatt {
@@ -114,6 +115,9 @@ class Database {
  static Database Deserialize(const std::vector<gatt::StoredAttribute>& nv_attr,
                              bool* success);

  /* Return 128 bit unique identifier of this GATT database */
  Octet16 Hash() const;

  friend class DatabaseBuilder;

 private:
+36 −0
Original line number Diff line number Diff line
@@ -204,4 +204,40 @@ TEST(GattCacheTest, stored_attribute_to_binary_descriptor_test) {
  // LOG(ERROR) << " " << base::HexEncode(&attr, len);
  EXPECT_EQ(memcmp(binary_form, &attr, len), 0);
}

// Example from Bluetooth SPEC V5.2, Vol 3, Part G, APPENDIX B
TEST(GattDatabaseTest, hash_test) {
  DatabaseBuilder builder;
  builder.AddService(0x0001, 0x0005, Uuid::From16Bit(0x1800), true);
  builder.AddService(0x0006, 0x000D, Uuid::From16Bit(0x1801), true);
  builder.AddService(0x000E, 0x0013, Uuid::From16Bit(0x1808), true);
  builder.AddService(0x0014, 0xFFFF, Uuid::From16Bit(0x180F), false);

  builder.AddCharacteristic(0x0002, 0x0003, Uuid::From16Bit(0x2A00), 0x0A);
  builder.AddCharacteristic(0x0004, 0x0005, Uuid::From16Bit(0x2A01), 0x02);

  builder.AddCharacteristic(0x0007, 0x0008, Uuid::From16Bit(0x2A05), 0x20);
  builder.AddDescriptor(0x0009, Uuid::From16Bit(0x2902));
  builder.AddCharacteristic(0x000A, 0x000B, Uuid::From16Bit(0x2B29), 0x0A);
  builder.AddCharacteristic(0x000C, 0x000D, Uuid::From16Bit(0x2B2A), 0x02);

  builder.AddIncludedService(0x000F, Uuid::From16Bit(0x180F), 0x0014, 0x0016);
  builder.AddCharacteristic(0x0010, 0x0011, Uuid::From16Bit(0x2A18), 0xA2);
  builder.AddDescriptor(0x0012, Uuid::From16Bit(0x2902));
  builder.AddDescriptor(0x0013, Uuid::From16Bit(0x2900));

  builder.AddCharacteristic(0x0015, 0x0016, Uuid::From16Bit(0x2A19), 0x02);

  Database db = builder.Build();

  // Big endian example from Bluetooth SPEC V5.2, Vol 3, Part G, APPENDIX B
  Octet16 expected_hash{0xF1, 0xCA, 0x2D, 0x48, 0xEC, 0xF5, 0x8B, 0xAC,
                        0x8A, 0x88, 0x30, 0xBB, 0xB9, 0xFB, 0xA9, 0x90};

  Octet16 hash = db.Hash();
  // Convert output hash from little endian to big endian
  std::reverse(hash.begin(), hash.end());

  EXPECT_EQ(hash, expected_hash);
}
}  // namespace gatt
 No newline at end of file
+9 −0
Original line number Diff line number Diff line
@@ -4,6 +4,15 @@ crypto_toolbox_srcs = [
    "crypto_toolbox/crypto_toolbox.cc",
]

cc_test_library {
    name: "crypto_toolbox_for_tests",
    defaults: ["fluoride_defaults"],
    include_dirs: [
        "packages/modules/Bluetooth/system",
    ],
    srcs: crypto_toolbox_srcs
}

// Bluetooth stack static library for target
// ========================================================
cc_library_static {
Loading