1 /******************************************************************************
2  *
3  *  Copyright (C) 1999-2012 Broadcom Corporation
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 /******************************************************************************
20  *
21  *  this file contains GATT authentication handling functions
22  *
23  ******************************************************************************/
24 #include "common/bt_target.h"
25 #include "osi/allocator.h"
26 
27 #if BLE_INCLUDED == TRUE
28 #include <string.h>
29 
30 #include "gatt_int.h"
31 #include "stack/gatt_api.h"
32 #include "btm_int.h"
33 
34 /*******************************************************************************
35 **
36 ** Function         gatt_sign_data
37 **
38 ** Description      This function sign the data for write command.
39 **
40 ** Returns          TRUE if encrypted, otherwise FALSE.
41 **
42 *******************************************************************************/
43 #if (SMP_INCLUDED == TRUE)
gatt_sign_data(tGATT_CLCB * p_clcb)44 static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb)
45 {
46     tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
47     UINT8               *p_data = NULL, *p;
48     UINT16              payload_size = p_clcb->p_tcb->payload_size;
49     BOOLEAN             status = FALSE;
50     UINT8                *p_signature;
51 
52     /* do not need to mark channel securoty activity for data signing */
53     gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_OK);
54 
55     p_data = (UINT8 *)osi_malloc((UINT16)(p_attr->len + 3)); /* 3 = 2 byte handle + opcode */
56 
57     if (p_data != NULL) {
58         p = p_data;
59         UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE);
60         UINT16_TO_STREAM(p, p_attr->handle);
61         ARRAY_TO_STREAM(p, p_attr->value, p_attr->len);
62 
63         /* sign data length should be attribulte value length plus 2B handle + 1B op code */
64         if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len) {
65             p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3;
66         }
67 
68         p_signature = p_attr->value + p_attr->len;
69         if (BTM_BleDataSignature(p_clcb->p_tcb->peer_bda,
70                                  p_data,
71                                  (UINT16)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */
72                                  p_signature)) {
73             p_attr->len += BTM_BLE_AUTH_SIGN_LEN;
74             gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN);
75 #if (GATTC_INCLUDED == TRUE)
76             gatt_act_write(p_clcb, GATT_SEC_SIGN_DATA);
77 #endif  ///GATTC_INCLUDED == TRUE
78         } else {
79             gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL);
80         }
81 
82         osi_free(p_data);
83     }
84 
85     return status;
86 }
87 #endif  ///SMP_INCLUDED == TRUE
88 
89 /*******************************************************************************
90 **
91 ** Function         gatt_verify_signature
92 **
93 ** Description      This function start to verify the sign data when receiving
94 **                  the data from peer device.
95 **
96 ** Returns
97 **
98 *******************************************************************************/
99 #if (SMP_INCLUDED == TRUE)
gatt_verify_signature(tGATT_TCB * p_tcb,BT_HDR * p_buf)100 void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf)
101 {
102     UINT16  cmd_len;
103 #if (GATTS_INCLUDED == TRUE)
104     UINT8   op_code;
105 #endif  ///GATTS_INCLUDED == TRUE
106     UINT8   *p, *p_orig = (UINT8 *)(p_buf + 1) + p_buf->offset;
107     UINT32  counter;
108 
109     if (p_buf->len < GATT_AUTH_SIGN_LEN + 4) {
110         GATT_TRACE_ERROR("%s: Data length %u less than expected %u",
111                          __func__, p_buf->len, GATT_AUTH_SIGN_LEN + 4);
112         return;
113     }
114     cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
115     p =  p_orig + cmd_len - 4;
116     STREAM_TO_UINT32(counter, p);
117 
118     if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p)) {
119 #if (GATTS_INCLUDED == TRUE)
120         STREAM_TO_UINT8(op_code, p_orig);
121         gatt_server_handle_client_req (p_tcb, op_code, (UINT16)(p_buf->len - 1), p_orig);
122 #endif  ///GATTS_INCLUDED == TRUE
123     } else {
124         /* if this is a bad signature, assume from attacker, ignore it  */
125         GATT_TRACE_ERROR("Signature Verification Failed, data ignored");
126     }
127 
128     return;
129 }
130 #endif  ///SMP_INCLUDED == TRUE
131 
132 /*******************************************************************************
133 **
134 ** Function         gatt_sec_check_complete
135 **
136 ** Description      security check complete and proceed to data sending action.
137 **
138 ** Returns          void.
139 **
140 *******************************************************************************/
gatt_sec_check_complete(BOOLEAN sec_check_ok,tGATT_CLCB * p_clcb,UINT8 sec_act)141 void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB   *p_clcb, UINT8 sec_act)
142 {
143     if (p_clcb && p_clcb->p_tcb) {
144         if (fixed_queue_is_empty(p_clcb->p_tcb->pending_enc_clcb)) {
145             gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
146         }
147 #if (GATTC_INCLUDED == TRUE)
148         if (!sec_check_ok) {
149             gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
150         } else if (p_clcb->operation == GATTC_OPTYPE_WRITE) {
151             gatt_act_write(p_clcb, sec_act);
152         } else if (p_clcb->operation == GATTC_OPTYPE_READ) {
153             gatt_act_read(p_clcb, p_clcb->counter);
154         }
155 #endif  ///GATTC_INCLUDED == TRUE
156     }
157 }
158 /*******************************************************************************
159 **
160 ** Function         gatt_enc_cmpl_cback
161 **
162 ** Description      link encryption complete callback.
163 **
164 ** Returns
165 **
166 *******************************************************************************/
gatt_enc_cmpl_cback(BD_ADDR bd_addr,tBT_TRANSPORT transport,void * p_ref_data,tBTM_STATUS result)167 void gatt_enc_cmpl_cback(BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, tBTM_STATUS result)
168 {
169     tGATT_TCB   *p_tcb;
170     UINT8       sec_flag;
171     BOOLEAN     status = FALSE;
172     UNUSED(p_ref_data);
173 
174     GATT_TRACE_DEBUG("gatt_enc_cmpl_cback");
175     if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, transport)) != NULL) {
176         if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
177             return;
178         }
179         tGATT_PENDING_ENC_CLCB *p_buf =
180             (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
181         if (p_buf != NULL) {
182             if (result == BTM_SUCCESS) {
183                 if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM ) {
184                     BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, transport);
185 
186                     if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
187                         status = TRUE;
188                     }
189                 } else {
190                     status = TRUE;
191                 }
192             }
193             gatt_sec_check_complete(status , p_buf->p_clcb, p_tcb->sec_act);
194             osi_free(p_buf);
195             /* start all other pending operation in queue */
196             for (size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
197                  count > 0; count--) {
198                 p_buf = (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
199                 if (p_buf != NULL) {
200                     gatt_security_check_start(p_buf->p_clcb);
201                     osi_free(p_buf);
202                 } else {
203                     break;
204                 }
205             }
206         } else {
207             GATT_TRACE_ERROR("Unknown operation encryption completed");
208         }
209     } else {
210         GATT_TRACE_ERROR("enc callback for unknown bd_addr");
211     }
212 }
213 
214 /*******************************************************************************
215 **
216 ** Function         gatt_notify_enc_cmpl
217 **
218 ** Description      link encryption complete notification for all encryption process
219 **                  initiated outside GATT.
220 **
221 ** Returns
222 **
223 *******************************************************************************/
gatt_notify_enc_cmpl(BD_ADDR bd_addr)224 void gatt_notify_enc_cmpl(BD_ADDR bd_addr)
225 {
226     tGATT_TCB   *p_tcb;
227     UINT8        i = 0;
228 
229     if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) {
230         for (i = 0; i < GATT_MAX_APPS; i++) {
231             if (gatt_cb.cl_rcb[i].in_use && gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb) {
232                 (*gatt_cb.cl_rcb[i].app_cb.p_enc_cmpl_cb)(gatt_cb.cl_rcb[i].gatt_if, bd_addr);
233             }
234         }
235 
236         if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENC_PENDING) {
237             gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
238 
239             size_t count = fixed_queue_length(p_tcb->pending_enc_clcb);
240             for (; count > 0; count--) {
241                 tGATT_PENDING_ENC_CLCB *p_buf =
242                     (tGATT_PENDING_ENC_CLCB *)fixed_queue_dequeue(p_tcb->pending_enc_clcb, 0);
243                 if (p_buf != NULL) {
244                     gatt_security_check_start(p_buf->p_clcb);
245                     osi_free(p_buf);
246                 } else {
247                     break;
248                 }
249             }
250         }
251     } else {
252         GATT_TRACE_DEBUG("notify GATT for encryption completion of unknown device");
253     }
254     return;
255 }
256 /*******************************************************************************
257 **
258 ** Function         gatt_set_sec_act
259 **
260 ** Description      This function set the sec_act in clcb
261 **
262 ** Returns          none
263 **
264 *******************************************************************************/
gatt_set_sec_act(tGATT_TCB * p_tcb,tGATT_SEC_ACTION sec_act)265 void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act)
266 {
267     if (p_tcb) {
268         p_tcb->sec_act = sec_act;
269     }
270 }
271 /*******************************************************************************
272 **
273 ** Function         gatt_get_sec_act
274 **
275 ** Description      This function get the sec_act in clcb
276 **
277 ** Returns          none
278 **
279 *******************************************************************************/
gatt_get_sec_act(tGATT_TCB * p_tcb)280 tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb)
281 {
282     tGATT_SEC_ACTION sec_act = GATT_SEC_NONE;
283     if (p_tcb) {
284         sec_act = p_tcb->sec_act;
285     }
286     return sec_act;
287 }
288 /*******************************************************************************
289 **
290 ** Function         gatt_determine_sec_act
291 **
292 ** Description      This routine determine the security action based on auth_request and
293 **                  current link status
294 **
295 ** Returns          tGATT_SEC_ACTION security action
296 **
297 *******************************************************************************/
gatt_determine_sec_act(tGATT_CLCB * p_clcb)298 tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb )
299 {
300     tGATT_SEC_ACTION    act = GATT_SEC_OK;
301     UINT8               sec_flag;
302     tGATT_TCB           *p_tcb = p_clcb->p_tcb;
303     tGATT_AUTH_REQ      auth_req = p_clcb->auth_req;
304     BOOLEAN             is_link_encrypted = FALSE;
305     BOOLEAN             is_link_key_known = FALSE;
306     BOOLEAN             is_key_mitm = FALSE;
307 #if (SMP_INCLUDED == TRUE)
308     UINT8               key_type;
309     tBTM_BLE_SEC_REQ_ACT    sec_act = BTM_LE_SEC_NONE;
310 #endif  ///SMP_INCLUDED == TRUE
311     if (auth_req == GATT_AUTH_REQ_NONE ) {
312         return act;
313     }
314 
315     BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_clcb->p_tcb->transport);
316 #if (SMP_INCLUDED == TRUE)
317     btm_ble_link_sec_check(p_tcb->peer_bda, auth_req, &sec_act);
318 #endif  ///SMP_INCLUDED == TRUE
319     /* if a encryption is pending, need to wait */
320     if (
321 #if (SMP_INCLUDED == TRUE)
322     sec_act == BTM_BLE_SEC_REQ_ACT_DISCARD &&
323 #endif  ///SMP_INCLUDED == TRUE
324             auth_req != GATT_AUTH_REQ_NONE) {
325         return GATT_SEC_ENC_PENDING;
326     }
327 
328     if (sec_flag & (BTM_SEC_FLAG_ENCRYPTED | BTM_SEC_FLAG_LKEY_KNOWN)) {
329         if (sec_flag & BTM_SEC_FLAG_ENCRYPTED) {
330             is_link_encrypted = TRUE;
331         }
332 
333         is_link_key_known = TRUE;
334 
335         if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
336             is_key_mitm = TRUE;
337         }
338     }
339 
340     /* first check link key upgrade required or not */
341     switch (auth_req) {
342     case GATT_AUTH_REQ_MITM:
343     case GATT_AUTH_REQ_SIGNED_MITM:
344         if (!is_key_mitm) {
345             act = GATT_SEC_ENCRYPT_MITM;
346         }
347         break;
348 
349     case GATT_AUTH_REQ_NO_MITM:
350     case GATT_AUTH_REQ_SIGNED_NO_MITM:
351         if (!is_link_key_known) {
352             act = GATT_SEC_ENCRYPT_NO_MITM;
353         }
354         break;
355     default:
356         break;
357     }
358 
359     /* now check link needs to be encrypted or not if the link key upgrade is not required */
360     if (act == GATT_SEC_OK) {
361         if (p_tcb->transport == BT_TRANSPORT_LE &&
362                 (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
363                 (p_clcb->op_subtype == GATT_WRITE_NO_RSP)) {
364             /* this is a write command request
365                check data signing required or not */
366             if (!is_link_encrypted) {
367 #if (SMP_INCLUDED == TRUE)
368                 btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type);
369 #endif  ///SMP_INCLUDED == TRUE
370                 if (
371 #if (SMP_INCLUDED == TRUE)
372                     (key_type & BTM_LE_KEY_LCSRK) &&
373 #endif  ///SMP_INCLUDED == TRUE
374                         ((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) ||
375                          (auth_req == GATT_AUTH_REQ_SIGNED_MITM))) {
376                     act = GATT_SEC_SIGN_DATA;
377                 } else {
378                     act = GATT_SEC_ENCRYPT;
379                 }
380             }
381         } else {
382             if (!is_link_encrypted) {
383                 act = GATT_SEC_ENCRYPT;
384             }
385         }
386 
387     }
388 
389     return  act ;
390 
391 }
392 
393 
394 
395 /*******************************************************************************
396 **
397 ** Function         gatt_get_link_encrypt_status
398 **
399 ** Description      This routine get the encryption status of the specified link
400 **
401 **
402 ** Returns          tGATT_STATUS link encryption status
403 **
404 *******************************************************************************/
gatt_get_link_encrypt_status(tGATT_TCB * p_tcb)405 tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb)
406 {
407     tGATT_STATUS    encrypt_status = GATT_NOT_ENCRYPTED;
408     UINT8           sec_flag = 0;
409 
410     BTM_GetSecurityFlagsByTransport(p_tcb->peer_bda, &sec_flag, p_tcb->transport);
411 
412     if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) && (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)) {
413         encrypt_status = GATT_ENCRYPED_NO_MITM;
414         if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED) {
415             encrypt_status = GATT_ENCRYPED_MITM;
416         }
417     }
418 
419     GATT_TRACE_DEBUG("gatt_get_link_encrypt_status status=0x%x", encrypt_status);
420     return  encrypt_status ;
421 }
422 
423 
424 /*******************************************************************************
425 **
426 ** Function          gatt_convert_sec_action
427 **
428 ** Description      Convert GATT security action enum into equivalent BTM BLE security action enum
429 **
430 ** Returns          BOOLEAN TRUE - conversation is successful
431 **
432 *******************************************************************************/
gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act,tBTM_BLE_SEC_ACT * p_btm_sec_act)433 static BOOLEAN gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act, tBTM_BLE_SEC_ACT *p_btm_sec_act )
434 {
435     BOOLEAN status = TRUE;
436     switch (gatt_sec_act) {
437     case GATT_SEC_ENCRYPT:
438         *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT;
439         break;
440     case GATT_SEC_ENCRYPT_NO_MITM:
441         *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
442         break;
443     case GATT_SEC_ENCRYPT_MITM:
444         *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
445         break;
446     default:
447         status = FALSE;
448         break;
449     }
450 
451     return status;
452 }
453 /*******************************************************************************
454 **
455 ** Function         gatt_check_enc_req
456 **
457 ** Description      check link security.
458 **
459 ** Returns          TRUE if encrypted, otherwise FALSE.
460 **
461 *******************************************************************************/
gatt_security_check_start(tGATT_CLCB * p_clcb)462 BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
463 {
464     tGATT_TCB           *p_tcb = p_clcb->p_tcb;
465     tGATT_SEC_ACTION    gatt_sec_act;
466     tBTM_BLE_SEC_ACT    btm_ble_sec_act;
467     BOOLEAN             status = TRUE;
468 #if (SMP_INCLUDED == TRUE)
469     tBTM_STATUS         btm_status;
470 #endif  ///SMP_INCLUDED == TRUE
471     tGATT_SEC_ACTION    sec_act_old =  gatt_get_sec_act(p_tcb);
472 
473     gatt_sec_act = gatt_determine_sec_act(p_clcb);
474 
475     if (sec_act_old == GATT_SEC_NONE) {
476         gatt_set_sec_act(p_tcb, gatt_sec_act);
477     }
478 
479     switch (gatt_sec_act ) {
480     case GATT_SEC_SIGN_DATA:
481 #if (SMP_INCLUDED == TRUE)
482         GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
483         gatt_sign_data(p_clcb);
484 #endif  ///SMP_INCLUDED == TRUE
485         break;
486     case GATT_SEC_ENCRYPT:
487     case GATT_SEC_ENCRYPT_NO_MITM:
488     case GATT_SEC_ENCRYPT_MITM:
489         if (sec_act_old < GATT_SEC_ENCRYPT) {
490             GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
491             gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
492 #if (SMP_INCLUDED == TRUE)
493             btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act);
494             if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED)) {
495                 GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
496                 status = FALSE;
497             }
498 #endif  ///SMP_INCLUDED == TRUE
499         }
500         if (status) {
501             gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
502         }
503         break;
504     case GATT_SEC_ENC_PENDING:
505         gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
506         /* wait for link encrypotion to finish */
507         break;
508     default:
509         gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
510         break;
511     }
512 
513     if (status == FALSE) {
514         gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
515         gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
516     }
517 
518     return status;
519 }
520 
521 
522 #endif  /* BLE_INCLUDED */
523