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