1 /******************************************************************************
2 *
3 * Copyright 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include <base/strings/string_number_conversions.h>
20 #include <list>
21
22 #include "gatt_int.h"
23 #include "stack/crypto_toolbox/crypto_toolbox.h"
24
25 using bluetooth::Uuid;
26
calculate_database_info_size(std::list<tGATT_SRV_LIST_ELEM> * lst_ptr)27 static size_t calculate_database_info_size(std::list<tGATT_SRV_LIST_ELEM>* lst_ptr) {
28 size_t len = 0;
29 auto srv_it = lst_ptr->begin();
30 for (; srv_it != lst_ptr->end(); srv_it++) {
31 auto attr_list = &srv_it->p_db->attr_list;
32 auto attr_it = attr_list->begin();
33 for (; attr_it != attr_list->end(); attr_it++) {
34 if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_PRI_SERVICE) ||
35 attr_it->uuid == Uuid::From16Bit(GATT_UUID_SEC_SERVICE)) {
36 // Service declaration (Handle + Type + Value)
37 len += 4 + gatt_build_uuid_to_stream_len(attr_it->p_value->uuid);
38 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE)){
39 // Included service declaration (Handle + Type + Value)
40 len += 8 + gatt_build_uuid_to_stream_len(attr_it->p_value->incl_handle.service_type);
41 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DECLARE)) {
42 // Characteristic declaration (Handle + Type + Value)
43 len += 7 + gatt_build_uuid_to_stream_len((++attr_it)->uuid);
44 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DESCRIPTION) ||
45 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG) ||
46 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_SRVR_CONFIG) ||
47 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_PRESENT_FORMAT) ||
48 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_AGG_FORMAT)) {
49 // Descriptor (Handle + Type)
50 len += 4;
51 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
52 // Descriptor for ext property (Handle + Type + Value)
53 len += 6;
54 }
55 }
56 }
57 return len;
58 }
59
fill_database_info(std::list<tGATT_SRV_LIST_ELEM> * lst_ptr,uint8_t * p_data)60 static void fill_database_info(std::list<tGATT_SRV_LIST_ELEM>* lst_ptr, uint8_t* p_data) {
61 auto srv_it = lst_ptr->begin();
62 for (; srv_it != lst_ptr->end(); srv_it++) {
63 auto attr_list = &srv_it->p_db->attr_list;
64 auto attr_it = attr_list->begin();
65 for (; attr_it != attr_list->end(); attr_it++) {
66 if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_PRI_SERVICE) ||
67 attr_it->uuid == Uuid::From16Bit(GATT_UUID_SEC_SERVICE)) {
68 // Service declaration
69 UINT16_TO_STREAM(p_data, attr_it->handle);
70
71 if (srv_it->is_primary) {
72 UINT16_TO_STREAM(p_data, GATT_UUID_PRI_SERVICE);
73 } else {
74 UINT16_TO_STREAM(p_data, GATT_UUID_SEC_SERVICE);
75 }
76
77 gatt_build_uuid_to_stream(&p_data, attr_it->p_value->uuid);
78 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE)){
79 // Included service declaration
80 UINT16_TO_STREAM(p_data, attr_it->handle);
81 UINT16_TO_STREAM(p_data, GATT_UUID_INCLUDE_SERVICE);
82 UINT16_TO_STREAM(p_data, attr_it->p_value->incl_handle.s_handle);
83 UINT16_TO_STREAM(p_data, attr_it->p_value->incl_handle.e_handle);
84
85 gatt_build_uuid_to_stream(&p_data, attr_it->p_value->incl_handle.service_type);
86 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DECLARE)) {
87 // Characteristic declaration
88 UINT16_TO_STREAM(p_data, attr_it->handle);
89 UINT16_TO_STREAM(p_data, GATT_UUID_CHAR_DECLARE);
90 UINT8_TO_STREAM(p_data, attr_it->p_value->char_decl.property);
91 UINT16_TO_STREAM(p_data, attr_it->p_value->char_decl.char_val_handle);
92
93 // Increment 1 to fetch characteristic uuid from value declaration attribute
94 gatt_build_uuid_to_stream(&p_data, (++attr_it)->uuid);
95 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_DESCRIPTION) ||
96 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG) ||
97 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_SRVR_CONFIG) ||
98 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_PRESENT_FORMAT) ||
99 attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_AGG_FORMAT)) {
100 // Descriptor
101 UINT16_TO_STREAM(p_data, attr_it->handle);
102 UINT16_TO_STREAM(p_data, attr_it->uuid.As16Bit());
103 } else if (attr_it->uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
104 // Descriptor
105 UINT16_TO_STREAM(p_data, attr_it->handle);
106 UINT16_TO_STREAM(p_data, attr_it->uuid.As16Bit());
107 UINT16_TO_STREAM(p_data, attr_it->p_value
108 ? attr_it->p_value->char_ext_prop
109 : 0x0000);
110 }
111 }
112 }
113 }
114
gatts_calculate_database_hash(std::list<tGATT_SRV_LIST_ELEM> * lst_ptr)115 Octet16 gatts_calculate_database_hash(std::list<tGATT_SRV_LIST_ELEM>* lst_ptr) {
116 int len = calculate_database_info_size(lst_ptr);
117
118 std::vector<uint8_t> serialized(len);
119 fill_database_info(lst_ptr, serialized.data());
120
121 std::reverse(serialized.begin(), serialized.end());
122 Octet16 db_hash = crypto_toolbox::aes_cmac(Octet16{0}, serialized.data(),
123 serialized.size());
124 LOG(INFO) << __func__ << ": hash="
125 << base::HexEncode(db_hash.data(), db_hash.size());
126
127 return db_hash;
128 }
129