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

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

Merge "Robust Caching - server hash calculation"

parents 109315f9 c58f4e48
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ cc_library_static {
        "gatt/gatt_db.cc",
        "gatt/gatt_main.cc",
        "gatt/gatt_sr.cc",
        "gatt/gatt_sr_hash.cc",
        "gatt/gatt_utils.cc",
        "hcic/hciblecmds.cc",
        "hcic/hcicmds.cc",
@@ -472,3 +473,29 @@ cc_test {
        misc_undefined: ["bounds"],
    },
}

// gatt sr hash test
cc_test {
    name: "net_test_stack_gatt_sr_hash_native",
    defaults: ["fluoride_defaults"],
    test_suites: ["device-tests"],
    host_supported: true,
    include_dirs: [
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/stack/include",
    ],
    srcs: crypto_toolbox_srcs + [
        "test/stack_gatt_sr_hash_test.cc",
        "gatt/gatt_sr_hash.cc",
    ],
    shared_libs: [
        "libcutils",
        "libcrypto",
    ],
    static_libs: [
        "liblog",
        "libosi",
        "libbt-common",
    ],
}
+4 −0
Original line number Diff line number Diff line
@@ -589,4 +589,8 @@ extern tGATT_STATUS gatts_read_attr_perm_check(tGATT_SVC_DB* p_db, bool is_long,
                                               uint8_t key_size);
extern bluetooth::Uuid* gatts_get_service_uuid(tGATT_SVC_DB* p_db);

/* gatt_sr_hash.cc */
extern Octet16 gatts_calculate_database_hash(
    std::list<tGATT_SRV_LIST_ELEM>* lst_ptr);

#endif
+127 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2020 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

#include <base/strings/string_number_conversions.h>
#include <list>

#include "crypto_toolbox/crypto_toolbox.h"
#include "gatt_int.h"

using bluetooth::Uuid;

static size_t calculate_database_info_size(std::list<tGATT_SRV_LIST_ELEM>* lst_ptr) {
  size_t len = 0;
  auto srv_it = lst_ptr->begin();
  for (; srv_it != lst_ptr->end(); srv_it++) {
    auto attr_list = &srv_it->p_db->attr_list;
    auto attr_it = attr_list->begin();
    for (; attr_it != attr_list->end(); attr_it++) {
      if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_PRI_SERVICE) ||
          attr_it->uuid == Uuid::From16Bit(GATT_UUID_SEC_SERVICE)) {
        // Service declaration (Handle + Type + Value)
        len += 4 + gatt_build_uuid_to_stream_len(attr_it->p_value->uuid);
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE)){
        // Included service declaration (Handle + Type + Value)
        len += 8 + gatt_build_uuid_to_stream_len(attr_it->p_value->incl_handle.service_type);
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DECLARE)) {
        // Characteristic declaration (Handle + Type + Value)
        len += 7 + gatt_build_uuid_to_stream_len((++attr_it)->uuid);
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DESCRIPTION) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_SRVR_CONFIG) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_PRESENT_FORMAT) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_AGG_FORMAT)) {
        // Descriptor (Handle + Type)
        len += 4;
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
        // Descriptor for ext property (Handle + Type + Value)
        len += 6;
      }
    }
  }
  return len;
}

static void fill_database_info(std::list<tGATT_SRV_LIST_ELEM>* lst_ptr, uint8_t* p_data) {
  auto srv_it = lst_ptr->begin();
  for (; srv_it != lst_ptr->end(); srv_it++) {
    auto attr_list = &srv_it->p_db->attr_list;
    auto attr_it = attr_list->begin();
    for (; attr_it != attr_list->end(); attr_it++) {
      if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_PRI_SERVICE) ||
          attr_it->uuid == Uuid::From16Bit(GATT_UUID_SEC_SERVICE)) {
        // Service declaration
        UINT16_TO_STREAM(p_data, attr_it->handle);

        if (srv_it->is_primary) {
          UINT16_TO_STREAM(p_data, GATT_UUID_PRI_SERVICE);
        } else {
          UINT16_TO_STREAM(p_data, GATT_UUID_SEC_SERVICE);
        }

        gatt_build_uuid_to_stream(&p_data, attr_it->p_value->uuid);
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE)){
        // Included service declaration
        UINT16_TO_STREAM(p_data, attr_it->handle);
        UINT16_TO_STREAM(p_data, GATT_UUID_INCLUDE_SERVICE);
        UINT16_TO_STREAM(p_data, attr_it->p_value->incl_handle.s_handle);
        UINT16_TO_STREAM(p_data, attr_it->p_value->incl_handle.e_handle);

        gatt_build_uuid_to_stream(&p_data, attr_it->p_value->incl_handle.service_type);
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DECLARE)) {
        // Characteristic declaration
        UINT16_TO_STREAM(p_data, attr_it->handle);
        UINT16_TO_STREAM(p_data, GATT_UUID_CHAR_DECLARE);
        UINT8_TO_STREAM(p_data, attr_it->p_value->char_decl.property);
        UINT16_TO_STREAM(p_data, attr_it->p_value->char_decl.char_val_handle);

        // Increment 1 to fetch characteristic uuid from value declaration attribute
        gatt_build_uuid_to_stream(&p_data, (++attr_it)->uuid);
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DESCRIPTION) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_SRVR_CONFIG) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_PRESENT_FORMAT) ||
                 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_AGG_FORMAT)) {
        // Descriptor
        UINT16_TO_STREAM(p_data, attr_it->handle);
        UINT16_TO_STREAM(p_data, attr_it->uuid.As16Bit());
      } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
        // Descriptor
        UINT16_TO_STREAM(p_data, attr_it->handle);
        UINT16_TO_STREAM(p_data, attr_it->uuid.As16Bit());
        // TODO: Store correct data for extended properties
        UINT16_TO_STREAM(p_data, 0x0000);
      }
    }
  }
}

Octet16 gatts_calculate_database_hash(std::list<tGATT_SRV_LIST_ELEM>* lst_ptr) {
  int len = calculate_database_info_size(lst_ptr);

  std::vector<uint8_t> serialized(len);
  fill_database_info(lst_ptr, serialized.data());

  std::reverse(serialized.begin(), serialized.end());
  Octet16 db_hash = crypto_toolbox::aes_cmac(Octet16{0}, serialized.data(),
                                  serialized.size());
  LOG(INFO) << __func__ << ": hash="
           << base::HexEncode(db_hash.data(), db_hash.size());

  return db_hash;
}
+184 −0
Original line number Diff line number Diff line
/******************************************************************************
 *
 *  Copyright 2020 The Android Open Source Project
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

#include <gtest/gtest.h>

#include "crypto_toolbox/crypto_toolbox.h"
#include "stack/gatt/gatt_int.h"

using bluetooth::Uuid;

namespace {
  std::list<tGATT_SRV_LIST_ELEM> srv_elem_list;
}

/** copy from gatt_db.cc, remove unnecessary log */
tGATT_ATTR& allocate_attr_in_db(tGATT_SVC_DB& db, const Uuid& uuid,
                                       tGATT_PERM perm) {
  db.attr_list.emplace_back();
  tGATT_ATTR& attr = db.attr_list.back();
  attr.handle = db.next_handle++;
  attr.uuid = uuid;
  attr.permission = perm;
  return attr;
}

/** copy from gatt_db.cc, remove unnecessary log */
void gatts_init_service_db(tGATT_SVC_DB& db, const Uuid& service_uuid,
                           bool is_pri, uint16_t s_hdl, uint16_t num_handle) {
  db.attr_list.reserve(num_handle);

  /* update service database information */
  db.next_handle = s_hdl;
  db.end_handle = s_hdl + num_handle;

  /* add service declration record */
  Uuid uuid =
      Uuid::From16Bit(is_pri ? GATT_UUID_PRI_SERVICE : GATT_UUID_SEC_SERVICE);
  tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
  attr.p_value.reset((tGATT_ATTR_VALUE*)(new Uuid));
  attr.p_value->uuid = service_uuid;
}

/** copy from gatt_db.cc, remove unnecessary log */
uint16_t gatts_add_included_service(tGATT_SVC_DB& db, uint16_t s_handle,
                                    uint16_t e_handle, const Uuid& service) {
  Uuid uuid = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);

  tGATT_ATTR& attr = allocate_attr_in_db(db, uuid, GATT_PERM_READ);

  attr.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_INCL_SRVC));
  attr.p_value->incl_handle.s_handle = s_handle;
  attr.p_value->incl_handle.e_handle = e_handle;
  attr.p_value->incl_handle.service_type = service;

  return attr.handle;
}

/** copy from gatt_db.cc, remove unnecessary log */
uint16_t gatts_add_characteristic(tGATT_SVC_DB& db, tGATT_PERM perm,
                                  tGATT_CHAR_PROP property,
                                  const Uuid& char_uuid) {
  Uuid uuid = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);

  tGATT_ATTR& char_decl = allocate_attr_in_db(db, uuid, GATT_PERM_READ);
  tGATT_ATTR& char_val = allocate_attr_in_db(db, char_uuid, perm);

  char_decl.p_value.reset((tGATT_ATTR_VALUE*)(new tGATT_CHAR_DECL));
  char_decl.p_value->char_decl.property = property;
  char_decl.p_value->char_decl.char_val_handle = char_val.handle;
  char_val.gatt_type = BTGATT_DB_CHARACTERISTIC;
  return char_val.handle;
}

/** copy from gatt_db.cc, remove unnecessary log */
uint16_t gatts_add_char_descr(tGATT_SVC_DB& db, tGATT_PERM perm,
                              const Uuid& descr_uuid) {
  /* Add characteristic descriptors */
  tGATT_ATTR& char_dscptr = allocate_attr_in_db(db, descr_uuid, perm);
  char_dscptr.gatt_type = BTGATT_DB_DESCRIPTOR;
  return char_dscptr.handle;
}

/** copy from gatt_utils.cc, used in gatt_sr_hash.cc */
uint8_t gatt_build_uuid_to_stream_len(const Uuid& uuid) {
  size_t len = uuid.GetShortestRepresentationSize();
  return len == Uuid::kNumBytes32 ? Uuid::kNumBytes128 : len;
}

/** copy from gatt_utils.cc, used in gatt_sr_hash.cc */
uint8_t gatt_build_uuid_to_stream(uint8_t** p_dst, const Uuid& uuid) {
  uint8_t* p = *p_dst;
  size_t len = uuid.GetShortestRepresentationSize();

  if (uuid.IsEmpty()) {
    return 0;
  }

  if (len == Uuid::kNumBytes16) {
    UINT16_TO_STREAM(p, uuid.As16Bit());
  } else if (len == Uuid::kNumBytes32) {
    /* always convert 32 bits into 128 bits */
    ARRAY_TO_STREAM(p, uuid.To128BitLE(), (int)Uuid::kNumBytes128);
    len = Uuid::kNumBytes128;
  } else if (len == Uuid::kNumBytes128) {
    ARRAY_TO_STREAM(p, uuid.To128BitLE(), (int)Uuid::kNumBytes128);
  }

  *p_dst = p;
  return len;
}

static void add_item_to_list(std::list<tGATT_SRV_LIST_ELEM>& srv_list_info,
                      tGATT_SVC_DB* db, bool is_primary) {
  srv_list_info.emplace_back();
  tGATT_SRV_LIST_ELEM& elem = srv_list_info.back();
  elem.p_db = db;
  elem.is_primary = is_primary;
}

// BT Spec 5.2, Vol 3, Part G, Appendix B
TEST(GattDatabaseTest, matchExampleInBtSpecV52) {
  tGATT_SVC_DB local_db[4];
  for (int i=0; i<4; i++) local_db[i] = tGATT_SVC_DB();
  std::list<tGATT_SRV_LIST_ELEM> srv_list_info;

  // 0x1800
  add_item_to_list(srv_list_info, &local_db[0], true);
  gatts_init_service_db(local_db[0], Uuid::From16Bit(0x1800), true, 0x0001, 5);
  gatts_add_characteristic(local_db[0],
    GATT_PERM_READ | GATT_PERM_WRITE,
    GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE,
    Uuid::From16Bit(0x2A00));
  gatts_add_characteristic(local_db[0], GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
    Uuid::From16Bit(0x2A01));
  // 0x1801
  add_item_to_list(srv_list_info, &local_db[1], true);
  gatts_init_service_db(local_db[1], Uuid::From16Bit(0x1801), true, 0x0006, 8);
  gatts_add_characteristic(local_db[1], 0, GATT_CHAR_PROP_BIT_INDICATE,
    Uuid::From16Bit(0x2A05));
  gatts_add_char_descr(local_db[1], GATT_CHAR_PROP_BIT_READ, Uuid::From16Bit(0x2902));
  gatts_add_characteristic(local_db[1],
    GATT_PERM_READ | GATT_PERM_WRITE,
    GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE,
    Uuid::From16Bit(0x2B29));
  gatts_add_characteristic(local_db[1], GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ,
    Uuid::From16Bit(0x2B2A));
  // 0x1808
  add_item_to_list(srv_list_info, &local_db[2], true);
  gatts_init_service_db(local_db[2], Uuid::From16Bit(0x1808), true, 0x000E, 6);
  gatts_add_included_service(local_db[2], 0x0014, 0x0016, Uuid::From16Bit(0x180F));
  gatts_add_characteristic(local_db[2], GATT_PERM_READ,
    GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_INDICATE | GATT_CHAR_PROP_BIT_EXT_PROP,
    Uuid::From16Bit(0x2A18));
  gatts_add_char_descr(local_db[2], 0x0000, Uuid::From16Bit(0x2902));
  gatts_add_char_descr(local_db[2], 0x0000, Uuid::From16Bit(0x2900));
  // 0x180F
  add_item_to_list(srv_list_info, &local_db[3], false);
  gatts_init_service_db(local_db[3], Uuid::From16Bit(0x180F), false, 0x0014, 3);
  gatts_add_characteristic(local_db[3], GATT_PERM_READ,  GATT_CHAR_PROP_BIT_READ,
    Uuid::From16Bit(0x2A19));

  Octet16 expected_hash{0xF1, 0xCA, 0x2D, 0x48, 0xEC, 0xF5, 0x8B, 0xAC,
                        0x8A, 0x88, 0x30, 0xBB, 0xB9, 0xFB, 0xA9, 0x90};
  std::reverse(expected_hash.begin(), expected_hash.end());

  Octet16 result_hash = gatts_calculate_database_hash(&srv_list_info);

  ASSERT_EQ(result_hash, expected_hash);
}