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