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 #include <com_android_bluetooth_flags.h>
24
25 #include <cstdint>
26
27 #include "internal_include/bt_trace.h"
28 #include "internal_include/stack_config.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() ? BTM_SEC_MODE_SC
85 : BTM_SEC_MODE_SP);
86 }
87
BTM_Sec_Free()88 void BTM_Sec_Free() { btm_sec_cb.Free(); }
89
90 /*******************************************************************************
91 *
92 * Function find_first_serv_rec
93 *
94 * Description Look for the first record in the service database
95 * with specified PSM
96 *
97 * Returns Pointer to the record or NULL
98 *
99 ******************************************************************************/
find_first_serv_rec(bool is_originator,uint16_t psm)100 tBTM_SEC_SERV_REC* tBTM_SEC_CB::find_first_serv_rec(bool is_originator, uint16_t psm) {
101 tBTM_SEC_SERV_REC* p_serv_rec = &sec_serv_rec[0];
102 int i;
103
104 if (is_originator && p_out_serv && p_out_serv->psm == psm) {
105 /* If this is outgoing connection and the PSM matches p_out_serv,
106 * use it as the current service */
107 return p_out_serv;
108 }
109
110 /* otherwise, just find the first record with the specified PSM */
111 for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_serv_rec++) {
112 if ((p_serv_rec->security_flags & BTM_SEC_IN_USE) && (p_serv_rec->psm == psm)) {
113 return p_serv_rec;
114 }
115 }
116 return NULL;
117 }
118
getSecRec(const RawAddress bd_addr)119 tBTM_SEC_REC* tBTM_SEC_CB::getSecRec(const RawAddress bd_addr) {
120 tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
121 if (p_dev_rec != nullptr) {
122 return &p_dev_rec->sec_rec;
123 }
124 return nullptr;
125 }
126
IsDeviceEncrypted(const RawAddress bd_addr,tBT_TRANSPORT transport)127 bool tBTM_SEC_CB::IsDeviceEncrypted(const RawAddress bd_addr, tBT_TRANSPORT transport) {
128 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
129 if (sec_rec) {
130 if (transport == BT_TRANSPORT_BR_EDR) {
131 return sec_rec->is_device_encrypted();
132 } else if (transport == BT_TRANSPORT_LE) {
133 return sec_rec->is_le_device_encrypted();
134 }
135 log::error("unknown transport:{}", bt_transport_text(transport));
136 return false;
137 }
138
139 log::error("unknown device:{}", bd_addr);
140 return false;
141 }
142
IsLinkKeyAuthenticated(const RawAddress bd_addr,tBT_TRANSPORT transport)143 bool tBTM_SEC_CB::IsLinkKeyAuthenticated(const RawAddress bd_addr, tBT_TRANSPORT transport) {
144 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
145 if (sec_rec) {
146 if (transport == BT_TRANSPORT_BR_EDR) {
147 return sec_rec->is_link_key_authenticated();
148 } else if (transport == BT_TRANSPORT_LE) {
149 return sec_rec->is_le_link_key_authenticated();
150 }
151 log::error("unknown transport:{}", bt_transport_text(transport));
152 return false;
153 }
154
155 log::error("unknown device:{}", bd_addr);
156 return false;
157 }
158
IsDeviceAuthenticated(const RawAddress bd_addr,tBT_TRANSPORT transport)159 bool tBTM_SEC_CB::IsDeviceAuthenticated(const RawAddress bd_addr, tBT_TRANSPORT transport) {
160 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
161 if (sec_rec) {
162 if (transport == BT_TRANSPORT_BR_EDR) {
163 return sec_rec->is_device_authenticated();
164 } else if (transport == BT_TRANSPORT_LE) {
165 return sec_rec->is_le_device_authenticated();
166 }
167 log::error("unknown transport:{}", bt_transport_text(transport));
168 return false;
169 }
170
171 log::error("unknown device:{}", bd_addr);
172 return false;
173 }
174
IsDeviceBonded(const RawAddress bd_addr,tBT_TRANSPORT transport)175 bool tBTM_SEC_CB::IsDeviceBonded(const RawAddress bd_addr, tBT_TRANSPORT transport) {
176 tBTM_SEC_REC* sec_rec = getSecRec(bd_addr);
177 if (sec_rec == nullptr) {
178 return false;
179 }
180
181 bool bonded = false;
182
183 // Check BR/EDR bond status if requested transport is BT_TRANSPORT_BR_EDR or BT_TRANSPORT_AUTO
184 if (transport != BT_TRANSPORT_LE) {
185 if (com::android::bluetooth::flags::temporary_pairing_tracking()) {
186 bonded = sec_rec->is_bond_type_persistent() && sec_rec->is_link_key_known();
187 } else {
188 bonded = sec_rec->is_link_key_known();
189 }
190 }
191
192 // Check LE bond status if requested transport is BT_TRANSPORT_LE or BT_TRANSPORT_AUTO
193 if (transport != BT_TRANSPORT_BR_EDR) {
194 bonded |= (sec_rec->ble_keys.key_type != BTM_LE_KEY_NONE && sec_rec->is_le_link_key_known());
195 }
196
197 return bonded;
198 }
199
200 #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)201 bool tBTM_SEC_CB::AddService(bool is_originator, const char* p_name, uint8_t service_id,
202 uint16_t sec_level, uint16_t psm, uint32_t mx_proto_id,
203 uint32_t mx_chan_id) {
204 tBTM_SEC_SERV_REC* p_srec;
205 uint16_t index;
206 uint16_t first_unused_record = BTM_NO_AVAIL_SEC_SERVICES;
207 bool record_allocated = false;
208
209 log::verbose("sec_level:0x{:x}", sec_level);
210
211 /* See if the record can be reused (same service name, psm, mx_proto_id,
212 service_id, and mx_chan_id), or obtain the next unused record */
213
214 p_srec = &sec_serv_rec[0];
215
216 for (index = 0; index < BTM_SEC_MAX_SERVICE_RECORDS; index++, p_srec++) {
217 /* Check if there is already a record for this service */
218 if (p_srec->security_flags & BTM_SEC_IN_USE) {
219 if (p_srec->psm == psm && p_srec->mx_proto_id == mx_proto_id &&
220 service_id == p_srec->service_id && p_name &&
221 (!strncmp(p_name, (char*)p_srec->orig_service_name,
222 /* strlcpy replaces end char with termination char*/
223 BT_MAX_SERVICE_NAME_LEN - 1) ||
224 !strncmp(p_name, (char*)p_srec->term_service_name,
225 /* strlcpy replaces end char with termination char*/
226 BT_MAX_SERVICE_NAME_LEN - 1))) {
227 record_allocated = true;
228 break;
229 }
230 } else if (!record_allocated) {
231 /* Mark the first available service record */
232 *p_srec = {};
233 record_allocated = true;
234 first_unused_record = index;
235 }
236 }
237
238 if (!record_allocated) {
239 log::warn("Out of Service Records ({})", BTM_SEC_MAX_SERVICE_RECORDS);
240 return record_allocated;
241 }
242
243 /* Process the request if service record is valid */
244 /* If a duplicate service wasn't found, use the first available */
245 if (index >= BTM_SEC_MAX_SERVICE_RECORDS) {
246 index = first_unused_record;
247 p_srec = &sec_serv_rec[index];
248 }
249
250 p_srec->psm = psm;
251 p_srec->service_id = service_id;
252 p_srec->mx_proto_id = mx_proto_id;
253
254 if (is_originator) {
255 p_srec->orig_mx_chan_id = mx_chan_id;
256 osi_strlcpy((char*)p_srec->orig_service_name, p_name, BT_MAX_SERVICE_NAME_LEN + 1);
257 /* clear out the old setting, just in case it exists */
258 {
259 p_srec->security_flags &=
260 ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
261 }
262
263 /* Parameter validation. Originator should not set requirements for
264 * incoming connections */
265 sec_level &= ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
266 BTM_SEC_IN_MIN_16_DIGIT_PIN);
267
268 if (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) {
269 if (sec_level & BTM_SEC_OUT_AUTHENTICATE) {
270 sec_level |= BTM_SEC_OUT_MITM;
271 }
272 }
273
274 /* Make sure the authenticate bit is set, when encrypt bit is set */
275 if (sec_level & BTM_SEC_OUT_ENCRYPT) {
276 sec_level |= BTM_SEC_OUT_AUTHENTICATE;
277 }
278
279 /* outgoing connections usually set the security level right before
280 * the connection is initiated.
281 * set it to be the outgoing service */
282 p_out_serv = p_srec;
283 } else {
284 p_srec->term_mx_chan_id = mx_chan_id;
285 osi_strlcpy((char*)p_srec->term_service_name, p_name, BT_MAX_SERVICE_NAME_LEN + 1);
286 /* clear out the old setting, just in case it exists */
287 {
288 p_srec->security_flags &= ~(BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_MITM |
289 BTM_SEC_IN_MIN_16_DIGIT_PIN);
290 }
291
292 /* Parameter validation. Acceptor should not set requirements for outgoing
293 * connections */
294 sec_level &= ~(BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_MITM);
295
296 if (security_mode == BTM_SEC_MODE_SP || security_mode == BTM_SEC_MODE_SC) {
297 if (sec_level & BTM_SEC_IN_AUTHENTICATE) {
298 sec_level |= BTM_SEC_IN_MITM;
299 }
300 }
301
302 /* Make sure the authenticate bit is set, when encrypt bit is set */
303 if (sec_level & BTM_SEC_IN_ENCRYPT) {
304 sec_level |= BTM_SEC_IN_AUTHENTICATE;
305 }
306 }
307
308 p_srec->security_flags |= (uint16_t)(sec_level | BTM_SEC_IN_USE);
309
310 log::debug(
311 "[{}]: id:{}, is_orig:{} psm:0x{:04x} proto_id:{} chan_id:{} : "
312 "sec:0x{:x} service_name:[{}] (up to {} chars saved)",
313 index, service_id, is_originator, psm, mx_proto_id, mx_chan_id, p_srec->security_flags,
314 p_name, BT_MAX_SERVICE_NAME_LEN);
315
316 return record_allocated;
317 }
318
RemoveServiceById(uint8_t service_id)319 uint8_t tBTM_SEC_CB::RemoveServiceById(uint8_t service_id) {
320 tBTM_SEC_SERV_REC* p_srec = &sec_serv_rec[0];
321 uint8_t num_freed = 0;
322 int i;
323
324 for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
325 /* Delete services with specified name (if in use and not SDP) */
326 if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm != BT_PSM_SDP) &&
327 (!service_id || (service_id == p_srec->service_id))) {
328 log::verbose("BTM_SEC_CLR[{}]: id:{}", i, service_id);
329 p_srec->security_flags = 0;
330 num_freed++;
331 }
332 }
333 return num_freed;
334 }
335
RemoveServiceByPsm(uint16_t psm)336 uint8_t tBTM_SEC_CB::RemoveServiceByPsm(uint16_t psm) {
337 tBTM_SEC_SERV_REC* p_srec = &sec_serv_rec[0];
338 uint8_t num_freed = 0;
339 int i;
340
341 for (i = 0; i < BTM_SEC_MAX_SERVICE_RECORDS; i++, p_srec++) {
342 /* Delete services with specified name (if in use and not SDP) */
343 if ((p_srec->security_flags & BTM_SEC_IN_USE) && (p_srec->psm == psm)) {
344 log::verbose("BTM_SEC_CLR[{}]: id {}", i, p_srec->service_id);
345 p_srec->security_flags = 0;
346 num_freed++;
347 }
348 }
349 log::verbose("psm:0x{:x} num_freed:{}", psm, num_freed);
350
351 return num_freed;
352 }
353