Home | History | Annotate | Download | only in gatt
      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 
     26 #if BLE_INCLUDED == TRUE
     27 #include <string.h>
     28 #include "gki.h"
     29 
     30 #include "gatt_int.h"
     31 #include "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 static BOOLEAN gatt_sign_data (tGATT_CLCB *p_clcb)
     44 {
     45     tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
     46     UINT8               *p_data = NULL, *p;
     47     UINT16              payload_size = p_clcb->p_tcb->payload_size;
     48     BOOLEAN             status = FALSE;
     49     UINT8                *p_signature;
     50 
     51     p_data = (UINT8 *)GKI_getbuf((UINT16)(p_attr->len + 3)); /* 3 = 2 byte handle + opcode */
     52 
     53     if (p_data != NULL)
     54     {
     55         p = p_data;
     56         UINT8_TO_STREAM(p, GATT_SIGN_CMD_WRITE);
     57         UINT16_TO_STREAM(p, p_attr->handle);
     58         ARRAY_TO_STREAM(p, p_attr->value, p_attr->len);
     59 
     60         /* sign data length should be attribulte value length plus 2B handle + 1B op code */
     61         if ((payload_size - GATT_AUTH_SIGN_LEN - 3) < p_attr->len)
     62             p_attr->len = payload_size - GATT_AUTH_SIGN_LEN - 3;
     63 
     64         p_signature = p_attr->value + p_attr->len;
     65         if (BTM_BleDataSignature(p_clcb->p_tcb->peer_bda,
     66                                 p_data,
     67                                 (UINT16)(p_attr->len + 3), /* 3 = 2 byte handle + opcode */
     68                                 p_signature))
     69         {
     70             p_attr->len += BTM_BLE_AUTH_SIGN_LEN;
     71             gatt_set_ch_state(p_clcb->p_tcb, GATT_CH_OPEN);
     72             gatt_act_write(p_clcb);
     73         }
     74         else
     75         {
     76             gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, NULL);
     77         }
     78 
     79         GKI_freebuf(p_data);
     80     }
     81 
     82     return status;
     83 }
     84 
     85 /*******************************************************************************
     86 **
     87 ** Function         gatt_verify_signature
     88 **
     89 ** Description      This function start to verify the sign data when receiving
     90 **                  the data from peer device.
     91 **
     92 ** Returns
     93 **
     94 *******************************************************************************/
     95 void gatt_verify_signature(tGATT_TCB *p_tcb, BT_HDR *p_buf)
     96 {
     97     UINT16  cmd_len;
     98     UINT8   op_code;
     99     UINT8   *p, *p_orig = (UINT8 *)(p_buf + 1) + p_buf->offset;
    100     UINT32  counter;
    101 
    102     cmd_len = p_buf->len - GATT_AUTH_SIGN_LEN + 4;
    103     p =  p_orig + cmd_len - 4;
    104     STREAM_TO_UINT32(counter, p);
    105 
    106     if (BTM_BleVerifySignature(p_tcb->peer_bda, p_orig, cmd_len, counter, p))
    107     {
    108         STREAM_TO_UINT8(op_code, p_orig);
    109         gatt_server_handle_client_req (p_tcb, op_code, (UINT16)(p_buf->len - 1), p_orig);
    110     }
    111     else
    112     {
    113         /* if this is a bad signature, assume from attacker, ignore it */
    114         GATT_TRACE_ERROR0("Signature Verification Failed");
    115         gatt_disconnect(p_tcb->peer_bda);
    116     }
    117 
    118     return;
    119 }
    120 /*******************************************************************************
    121 **
    122 ** Function         gatt_sec_check_complete
    123 **
    124 ** Description      security check complete and proceed to data sending action.
    125 **
    126 ** Returns          void.
    127 **
    128 *******************************************************************************/
    129 void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB   *p_clcb)
    130 {
    131     p_clcb->p_tcb->p_clcb = NULL;
    132     gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
    133 
    134     if (!sec_check_ok)
    135     {
    136         gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
    137     }
    138     else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
    139     {
    140         gatt_act_write(p_clcb);
    141     }
    142     else if (p_clcb->operation == GATTC_OPTYPE_READ)
    143     {
    144         gatt_act_read(p_clcb, p_clcb->counter);
    145     }
    146 }
    147 /*******************************************************************************
    148 **
    149 ** Function         gatt_enc_cmpl_cback
    150 **
    151 ** Description      link encryption complete callback.
    152 **
    153 ** Returns
    154 **
    155 *******************************************************************************/
    156 void gatt_enc_cmpl_cback(BD_ADDR bd_addr, void *p_ref_data, tBTM_STATUS result)
    157 {
    158     tGATT_TCB   *p_tcb;
    159     UINT8       sec_flag;
    160     BOOLEAN     status = FALSE;
    161 
    162     GATT_TRACE_DEBUG0("gatt_enc_cmpl_cback");
    163     if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL)
    164     {
    165         gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    166 
    167         if (result == BTM_SUCCESS)
    168         {
    169             if (gatt_get_sec_act(p_tcb) == GATT_SEC_ENCRYPT_MITM )
    170             {
    171                 BTM_GetSecurityFlags(bd_addr, &sec_flag);
    172                 if (sec_flag & sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
    173                 {
    174                     status = TRUE;
    175                 }
    176             }
    177             else
    178             {
    179                 status = TRUE;
    180             }
    181         }
    182         gatt_sec_check_complete(status , (tGATT_CLCB   *)p_tcb->p_clcb);
    183     }
    184     else
    185     {
    186         GATT_TRACE_ERROR0("enc callback for unknown bd_addr");
    187     }
    188 }
    189 
    190 /*******************************************************************************
    191 **
    192 ** Function         gatt_set_sec_act
    193 **
    194 ** Description      This function set the sec_act in clcb
    195 **
    196 ** Returns          none
    197 **
    198 *******************************************************************************/
    199 void gatt_set_sec_act(tGATT_TCB *p_tcb, tGATT_SEC_ACTION sec_act)
    200 {
    201     if (p_tcb)
    202     {
    203         p_tcb->sec_act = sec_act;
    204     }
    205 }
    206 /*******************************************************************************
    207 **
    208 ** Function         gatt_get_sec_act
    209 **
    210 ** Description      This function get the sec_act in clcb
    211 **
    212 ** Returns          none
    213 **
    214 *******************************************************************************/
    215 tGATT_SEC_ACTION gatt_get_sec_act(tGATT_TCB *p_tcb)
    216 {
    217     tGATT_SEC_ACTION sec_act = GATT_SEC_NONE;
    218     if (p_tcb)
    219     {
    220         sec_act = p_tcb->sec_act;
    221     }
    222     return sec_act;
    223 }
    224 /*******************************************************************************
    225 **
    226 ** Function         gatt_determine_sec_act
    227 **
    228 ** Description      This routine determine the security action based on auth_request and
    229 **                  current link status
    230 **
    231 ** Returns          tGATT_SEC_ACTION security action
    232 **
    233 *******************************************************************************/
    234 tGATT_SEC_ACTION gatt_determine_sec_act(tGATT_CLCB *p_clcb )
    235 {
    236     tGATT_SEC_ACTION    act = GATT_SEC_OK;
    237     UINT8               sec_flag;
    238     tGATT_TCB           *p_tcb = p_clcb->p_tcb;
    239     tGATT_AUTH_REQ      auth_req = p_clcb->auth_req;
    240 
    241     BOOLEAN             is_link_encrypted= FALSE;
    242     BOOLEAN             is_le_link=FALSE;
    243     BOOLEAN             is_link_key_known=FALSE;
    244     BOOLEAN             is_key_mitm=FALSE;
    245     UINT8               key_type;
    246 
    247     if (auth_req == GATT_AUTH_REQ_NONE )
    248         return act;
    249 
    250     is_le_link = btm_ble_check_link_type(p_tcb->peer_bda);
    251     BTM_GetSecurityFlags(p_tcb->peer_bda, &sec_flag);
    252 
    253     if (sec_flag & BTM_SEC_FLAG_ENCRYPTED)
    254     {
    255         is_link_encrypted = TRUE;
    256     }
    257     if (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN)
    258     {
    259         is_link_key_known = TRUE;
    260         if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
    261         {
    262             is_key_mitm = TRUE;
    263         }
    264     }
    265 
    266     /* first check link key upgrade required or not */
    267     switch (auth_req)
    268     {
    269         case GATT_AUTH_REQ_MITM:
    270         case GATT_AUTH_REQ_SIGNED_MITM:
    271             if (!is_key_mitm)
    272                 act = GATT_SEC_ENCRYPT_MITM;
    273             break;
    274 
    275         case GATT_AUTH_REQ_NO_MITM:
    276         case GATT_AUTH_REQ_SIGNED_NO_MITM:
    277             if (!is_link_key_known)
    278                 act = GATT_SEC_ENCRYPT_NO_MITM;
    279             break;
    280         default:
    281             break;
    282     }
    283 
    284     /* now check link needs to be encrypted or not if the link key upgrade is not required */
    285     if (act == GATT_SEC_OK)
    286     {
    287         if (is_le_link &&
    288             (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
    289             (p_clcb->op_subtype == GATT_WRITE_NO_RSP))
    290         {
    291             /* this is a write command request
    292                check data signing required or not */
    293             if (!is_link_encrypted)
    294             {
    295                 btm_ble_get_enc_key_type(p_tcb->peer_bda, &key_type);
    296 
    297                 if ( (key_type & BTM_LE_KEY_LCSRK) &&
    298                      ((auth_req == GATT_AUTH_REQ_SIGNED_NO_MITM) ||
    299                       (auth_req == GATT_AUTH_REQ_SIGNED_MITM)))
    300                 {
    301                     act = GATT_SEC_SIGN_DATA;
    302                 }
    303                 else
    304                 {
    305                     act = GATT_SEC_ENCRYPT;
    306                 }
    307             }
    308         }
    309         else
    310         {
    311             if (!is_link_encrypted)
    312             {
    313                 act = GATT_SEC_ENCRYPT;
    314             }
    315         }
    316 
    317     }
    318 
    319     return  act ;
    320 
    321 }
    322 
    323 
    324 
    325 /*******************************************************************************
    326 **
    327 ** Function         gatt_get_link_encrypt_status
    328 **
    329 ** Description      This routine get the encryption status of the specified link
    330 **
    331 **
    332 ** Returns          tGATT_STATUS link encryption status
    333 **
    334 *******************************************************************************/
    335 tGATT_STATUS gatt_get_link_encrypt_status(tGATT_TCB *p_tcb)
    336 {
    337     tGATT_STATUS    encrypt_status = GATT_NOT_ENCRYPTED;
    338     UINT8           sec_flag=0;
    339 
    340     BTM_GetSecurityFlags(p_tcb->peer_bda, &sec_flag);
    341 
    342     if ((sec_flag & BTM_SEC_FLAG_ENCRYPTED) && (sec_flag & BTM_SEC_FLAG_LKEY_KNOWN))
    343     {
    344         encrypt_status = GATT_ENCRYPED_NO_MITM;
    345         if (sec_flag & BTM_SEC_FLAG_LKEY_AUTHED)
    346             encrypt_status = GATT_ENCRYPED_MITM;
    347     }
    348 
    349     GATT_TRACE_DEBUG1("gatt_get_link_encrypt_status status=0x%x",encrypt_status);
    350     return  encrypt_status ;
    351 }
    352 
    353 
    354 /*******************************************************************************
    355 **
    356 ** Function          gatt_convert_sec_action
    357 **
    358 ** Description      Convert GATT security action enum into equivalent BTM BLE security action enum
    359 **
    360 ** Returns          BOOLEAN TRUE - conversation is successful
    361 **
    362 *******************************************************************************/
    363 static BOOLEAN gatt_convert_sec_action(tGATT_SEC_ACTION gatt_sec_act, tBTM_BLE_SEC_ACT *p_btm_sec_act )
    364 {
    365     BOOLEAN status = TRUE;
    366     switch (gatt_sec_act)
    367     {
    368         case GATT_SEC_ENCRYPT:
    369             *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT;
    370             break;
    371         case GATT_SEC_ENCRYPT_NO_MITM:
    372             *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_NO_MITM;
    373             break;
    374         case GATT_SEC_ENCRYPT_MITM:
    375             *p_btm_sec_act = BTM_BLE_SEC_ENCRYPT_MITM;
    376             break;
    377         default:
    378             status = FALSE;
    379             break;
    380     }
    381 
    382     return status;
    383 }
    384 /*******************************************************************************
    385 **
    386 ** Function         gatt_check_enc_req
    387 **
    388 ** Description      check link security.
    389 **
    390 ** Returns          TRUE if encrypted, otherwise FALSE.
    391 **
    392 *******************************************************************************/
    393 BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
    394 {
    395     tGATT_TCB           *p_tcb = p_clcb->p_tcb;
    396     tGATT_SEC_ACTION    gatt_sec_act;
    397     tBTM_BLE_SEC_ACT    btm_ble_sec_act;
    398     BOOLEAN             status = TRUE;
    399     tBTM_STATUS         btm_status;
    400 
    401     if ( gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)
    402     {
    403         gatt_sec_act = gatt_determine_sec_act(p_clcb);
    404         gatt_set_sec_act(p_tcb, gatt_sec_act);
    405         switch (gatt_sec_act )
    406         {
    407             case GATT_SEC_SIGN_DATA:
    408                 GATT_TRACE_DEBUG0("gatt_security_check_start: Do data signing");
    409                 gatt_set_ch_state(p_tcb, GATT_CH_W4_DATA_SIGN_COMP);
    410                 gatt_sign_data(p_clcb);
    411                 break;
    412             case GATT_SEC_ENCRYPT:
    413             case GATT_SEC_ENCRYPT_NO_MITM:
    414             case GATT_SEC_ENCRYPT_MITM:
    415                 GATT_TRACE_DEBUG0("gatt_security_check_start: Encrypt now or key upgreade first");
    416                 gatt_convert_sec_action(p_tcb->sec_act, &btm_ble_sec_act);
    417                 gatt_set_ch_state(p_tcb, GATT_CH_W4_SEC_COMP);
    418                 p_tcb->p_clcb = p_clcb;           /* keep the clcb pointer in CCB */
    419                 btm_status = BTM_SetEncryption(p_tcb->peer_bda, gatt_enc_cmpl_cback, &btm_ble_sec_act);
    420                 if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED))
    421                 {
    422                     GATT_TRACE_ERROR1("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
    423                     p_tcb->p_clcb  = NULL;
    424                     status = FALSE;
    425                 }
    426                 break;
    427             default:
    428                 gatt_sec_check_complete(TRUE, p_clcb);
    429                 break;
    430         }
    431 
    432         if (status == FALSE)
    433         {
    434             gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
    435             gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
    436         }
    437     }
    438     else
    439     {
    440         GATT_TRACE_ERROR0("gatt_security_check_start channel not open");
    441         status = FALSE;
    442     }
    443 
    444     return status;
    445 }
    446 
    447 
    448 #endif  /* BLE_INCLUDED */
    449