1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 #define LOG_TAG "SEC_CB"
19
20 #include "stack/btm/btm_sec_cb.h"
21
22 #include <bluetooth/log.h>
23
24 #include <cstdint>
25
26 #include "internal_include/bt_trace.h"
27 #include "internal_include/stack_config.h"
28 #include "os/log.h"
29 #include "osi/include/allocator.h"
30 #include "osi/include/fixed_queue.h"
31 #include "osi/include/list.h"
32 #include "stack/btm/btm_dev.h"
33 #include "stack/btm/security_device_record.h"
34 #include "stack/include/bt_psm_types.h"
35 #include "types/raw_address.h"
36
37 using namespace bluetooth;
38
Init(uint8_t initial_security_mode)39 void tBTM_SEC_CB::Init(uint8_t initial_security_mode) {
40 memset(&cfg, 0, sizeof(cfg));
41 memset(&devcb, 0, sizeof(devcb));
42 memset(&enc_rand, 0, sizeof(enc_rand));
43 memset(&api, 0, sizeof(api));
44 memset(&pin_code, 0, sizeof(pin_code));
45 memset(sec_serv_rec, 0, sizeof(sec_serv_rec));
46 connecting_bda = RawAddress::kEmpty;
47 connecting_dc = kDevClassEmpty;
48
49 sec_pending_q = fixed_queue_new(SIZE_MAX);
50 sec_collision_timer = alarm_new("btm.sec_collision_timer");
51 pairing_timer = alarm_new("btm.pairing_timer");
52 execution_wait_timer = alarm_new("btm.execution_wait_timer");
53
54 security_mode = initial_security_mode;
55 pairing_bda = RawAddress::kAny;
56 sec_dev_rec = list_new([](void* ptr) {
57 // Invoke destructor for all record objects and reset to default
58 // initialized value so memory may be properly freed
59 *((tBTM_SEC_DEV_REC*)ptr) = {};
60 osi_free(ptr);
61 });
62 }
63
Free()64 void tBTM_SEC_CB::Free() {
65 fixed_queue_free(sec_pending_q, nullptr);
66 sec_pending_q = nullptr;
67
68 list_free(sec_dev_rec);
69 sec_dev_rec = nullptr;
70
71 alarm_free(sec_collision_timer);
72 sec_collision_timer = nullptr;
73
74 alarm_free(pairing_timer);
75 pairing_timer = nullptr;
76
77 alarm_free(execution_wait_timer);
78 execution_wait_timer = nullptr;
79 }
80
81 tBTM_SEC_CB btm_sec_cb;
82
BTM_Sec_Init()83 void BTM_Sec_Init() {
84 btm_sec_cb.Init(stack_config_get_interface()->get_pts_secure_only_mode()
85 ? BTM_SEC_MODE_SC
86 : BTM_SEC_MODE_SP);
87 }
88
BTM_Sec_Free()89 void BTM_Sec_Free() { btm_sec_cb.Free(); }
90
91 /*******************************************************************************
92 *
93 * Function find_first_serv_rec
94 *
95 * Description Look for the first record in the service database
96 * with specified PSM
97 *
98 * Returns Pointer to the record or NULL
99 *
100 ******************************************************************************/
find_first_serv_rec(bool is_originator,uint16_t psm)101 tBTM_SEC_SERV_REC* tBTM_SEC_CB::find_first_serv_rec(bool is_originator,
102 uint16_t psm) {
103 tBTM_SEC_SERV_REC* p_serv_rec = &sec_serv_rec[0];
104 int i;
105
106 if (is_originator && p_out_serv && p_out_serv->psm == psm) {
107 /* If this is outgoing connection and the PSM matches p_out_serv,
108 * use it as the current service */
109 return p_out_serv;
110 }
111
112 /* otherwise, just find the first record with the specified PSM */
113 for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
114 if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) &&
115 (p_serv_rec->psm == psm))
116 return (p_serv_rec);
117 }
118 return (NULL);
119 }
120
getSecRec(const RawAddress bd_addr)121 tBTM_SEC_REC* tBTM_SEC_CB::getSecRec(const RawAddress bd_addr) {
122 tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
123 if (p_dev_rec) {
124 return &p_dev_rec->sec_rec;
125 }
126 return nullptr;
127 }
128
IsDeviceEncrypted(const RawAddress bd_addr,tBT_TRANSPORT transport)129 bool tBTM_SEC_CB::IsDeviceEncrypted(const RawAddress bd_addr,
130 tBT_TRANSPORT transport) {
131 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
132 if (sec_rec) {
133 if (transport == BT_TRANSPORT_BR_EDR) {
134 return sec_rec->is_device_encrypted();
135 } else if (transport == BT_TRANSPORT_LE) {
136 return sec_rec->is_le_device_encrypted();
137 }
138 log::error("unknown transport:{}", bt_transport_text(transport));
139 return false;
140 }
141
142 log::error("unknown device:{}", bd_addr);
143 return false;
144 }
145
IsLinkKeyAuthenticated(const RawAddress bd_addr,tBT_TRANSPORT transport)146 bool tBTM_SEC_CB::IsLinkKeyAuthenticated(const RawAddress bd_addr,
147 tBT_TRANSPORT transport) {
148 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
149 if (sec_rec) {
150 if (transport == BT_TRANSPORT_BR_EDR) {
151 return sec_rec->is_link_key_authenticated();
152 } else if (transport == BT_TRANSPORT_LE) {
153 return sec_rec->is_le_link_key_authenticated();
154 }
155 log::error("unknown transport:{}", bt_transport_text(transport));
156 return false;
157 }
158
159 log::error("unknown device:{}", bd_addr);
160 return false;
161 }
162
IsDeviceAuthenticated(const RawAddress bd_addr,tBT_TRANSPORT transport)163 bool tBTM_SEC_CB::IsDeviceAuthenticated(const RawAddress bd_addr,
164 tBT_TRANSPORT transport) {
165 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
166 if (sec_rec) {
167 if (transport == BT_TRANSPORT_BR_EDR) {
168 return sec_rec->is_device_authenticated();
169 } else if (transport == BT_TRANSPORT_LE) {
170 return sec_rec->is_le_device_authenticated();
171 }
172 log::error("unknown transport:{}", bt_transport_text(transport));
173 return false;
174 }
175
176 log::error("unknown device:{}", bd_addr);
177 return false;
178 }
179
IsLinkKeyKnown(const RawAddress bd_addr,tBT_TRANSPORT transport)180 bool tBTM_SEC_CB::IsLinkKeyKnown(const RawAddress bd_addr,
181 tBT_TRANSPORT transport) {
182 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
183 if (sec_rec) {
184 if (transport == BT_TRANSPORT_BR_EDR) {
185 return sec_rec->is_link_key_known();
186 } else if (transport == BT_TRANSPORT_LE) {
187 return sec_rec->is_le_link_key_known();
188 }
189 log::error("unknown transport:{}", bt_transport_text(transport));
190 return false;
191 }
192
193 log::error("unknown device:{}", bd_addr);
194 return false;
195 }
196
IsDeviceBonded(const RawAddress bd_addr)197 bool tBTM_SEC_CB::IsDeviceBonded(const RawAddress bd_addr) {
198 tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
199 bool is_bonded = false;
200
201 if (p_dev_rec && ((p_dev_rec->sec_rec.ble_keys.key_type &&
202 p_dev_rec->sec_rec.is_le_link_key_known()) ||
203 p_dev_rec->sec_rec.is_link_key_known())) {
204 is_bonded = true;
205 }
206 log::debug("Device record bonded check peer:{} is_bonded:{}", bd_addr,
207 is_bonded);
208 return is_bonded;
209 }
210
211 #define BTM_NO_AVAIL_SEC_SERVICES ((uint16_t)0xffff)
AddService(bool is_originator,const char * p_name,uint8_t service_id,uint16_t sec_level,uint16_t psm,uint32_t mx_proto_id,uint32_t mx_chan_id)212 bool tBTM_SEC_CB::AddService(bool is_originator, const char* p_name,
213 uint8_t service_id, uint16_t sec_level,
214 uint16_t psm, uint32_t mx_proto_id,
215 uint32_t mx_chan_id) {
216 tBTM_SEC_SERV_REC* p_srec;
217 uint16_t index;
218 uint16_t first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;
219 bool record_allocated = false;
220
221 log::verbose("sec_level:0x{:x}", sec_level);
222
223 /* See if the record can be reused (same service name, psm, mx_proto_id,
224 service_id, and mx_chan_id), or obtain the next unused record */
225
226 p_srec = &sec_serv_rec[0];
227
228 for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) {
229 /* Check if there is already a record for this service */
230 if (p_srec->security_flags & BTM_SEC_IN_USE) {
231 if (p_srec->psm == psm && p_srec->mx_proto_id == mx_proto_id &&
232 service_id == p_srec->service_id && p_name &&
233 (!strncmp(p_name, (char*)p_srec->orig_service_name,
234 /* strlcpy replaces end char with termination char*/
235 BT_MAX_SERVICE_NAME_LEN - 1) ||
236 !strncmp(p_name, (char*)p_srec->term_service_name,
237 /* strlcpy replaces end char with termination char*/
238 BT_MAX_SERVICE_NAME_LEN - 1))) {
239 record_allocated = true;
240 break;
241 }
242 }
243 /* Mark the first available service record */
244 else if (!record_allocated) {
245 *p_srec = {};
246 record_allocated = true;
247 first_unused_record = index;
248 }
249 }
250
251 if (!record_allocated) {
252 log::warn("Out of Service Records ({})", BTM_SEC_MAX_SERVICE_RECORDS);
253 return (record_allocated);
254 }
255
256 /* Process the request if service record is valid */
257 /* If a duplicate service wasn't found, use the first available */
258 if (index >= BTM_SEC_MAX_SERVICE_RECORDS) {
259 index = first_unused_record;
260 p_srec = &sec_serv_rec[index];
261 }
262
263 p_srec->psm = psm;
264 p_srec->service_id = service_id;
265 p_srec->mx_proto_id = mx_proto_id;
266
267 if (is_originator) {
268 p_srec->orig_mx_chan_id = mx_chan_id;
269 strlcpy((char*)p_srec->orig_service_name, p_name,
270 BT_MAX_SERVICE_NAME_LEN + 1);
271 /* clear out the old setting, just in case it exists */
272 {
273 p_srec->security_flags &=
274 ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
275 }
276
277 /* Parameter validation. Originator should not set requirements for
278 * incoming connections */
279 sec_level &= ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE |
280 BTM_SEC_IN_MITM | BTM_SEC_IN_MIN_16_DIGIT_PIN);
281
282 if (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) {
283 if (sec_level & BTM_SEC_OUT_AUTHENTICATE) sec_level |= BTM_SEC_OUT_MITM;
284 }
285
286 /* Make sure the authenticate bit is set, when encrypt bit is set */
287 if (sec_level & BTM_SEC_OUT_ENCRYPT) sec_level |= BTM_SEC_OUT_AUTHENTICATE;
288
289 /* outgoing connections usually set the security level right before
290 * the connection is initiated.
291 * set it to be the outgoing service */
292 p_out_serv = p_srec;
293 } else {
294 p_srec->term_mx_chan_id = mx_chan_id;
295 strlcpy((char*)p_srec->term_service_name, p_name,
296 BT_MAX_SERVICE_NAME_LEN + 1);
297 /* clear out the old setting, just in case it exists */
298 {
299 p_srec->security_flags &=
300 ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
301 BTM_SEC_IN_MIN_16_DIGIT_PIN);
302 }
303
304 /* Parameter validation. Acceptor should not set requirements for outgoing
305 * connections */
306 sec_level &=
307 ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
308
309 if (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) {
310 if (sec_level & BTM_SEC_IN_AUTHENTICATE) sec_level |= BTM_SEC_IN_MITM;
311 }
312
313 /* Make sure the authenticate bit is set, when encrypt bit is set */
314 if (sec_level & BTM_SEC_IN_ENCRYPT) sec_level |= BTM_SEC_IN_AUTHENTICATE;
315 }
316
317 p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
318
319 log::debug(
320 "[{}]: id:{}, is_orig:{} psm:0x{:04x} proto_id:{} chan_id:{} : "
321 "sec:0x{:x} service_name:[{}] (up to {} chars saved)",
322 index, service_id, is_originator, psm, mx_proto_id, mx_chan_id,
323 p_srec->security_flags, p_name, BT_MAX_SERVICE_NAME_LEN);
324
325 return (record_allocated);
326 }
327
RemoveServiceById(uint8_t service_id)328 uint8_t tBTM_SEC_CB::RemoveServiceById(uint8_t service_id) {
329 tBTM_SEC_SERV_REC* p_srec = &sec_serv_rec[0];
330 uint8_t num_freed = 0;
331 int i;
332
333 for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
334 /* Delete services with specified name (if in use and not SDP) */
335 if ((p_srec->security_flags & BTM_SEC_IN_USE) &&
336 (p_srec->psm != BT_PSM_SDP) &&
337 (!service_id || (service_id == p_srec->service_id))) {
338 log::verbose("BTM_SEC_CLR[{}]: id:{}", i, service_id);
339 p_srec->security_flags = 0;
340 num_freed++;
341 }
342 }
343 return (num_freed);
344 }
345
RemoveServiceByPsm(uint16_t psm)346 uint8_t tBTM_SEC_CB::RemoveServiceByPsm(uint16_t psm) {
347 tBTM_SEC_SERV_REC* p_srec = &sec_serv_rec[0];
348 uint8_t num_freed = 0;
349 int i;
350
351 for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
352 /* Delete services with specified name (if in use and not SDP) */
353 if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm)) {
354 log::verbose("BTM_SEC_CLR[{}]: id {}", i, p_srec->service_id);
355 p_srec->security_flags = 0;
356 num_freed++;
357 }
358 }
359 log::verbose("psm:0x{:x} num_freed:{}", psm, num_freed);
360
361 return (num_freed);
362 }
363