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