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