Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e12fd994 authored by Venkata Jagadeesh's avatar Venkata Jagadeesh Committed by Stanley Tng
Browse files

Add security handling for LE connection oriented channels

Use case:
Run PTS test cases TP/LE/CFC/BV-10-C to BV-16-C

Steps:
1. These test cases executed with two DUT as PTS support not available
2. Set desired security level on DUT and Remote with tool
3. Initiate LE COC connection request from DUT

Failure:
LE COC connection accepted though even remote security are not met.

Fix:
Added security handling for COC connection

Test: Ran sl4a test for BleCocTest
Change-Id: I5f6385d462698582e701b5a07953c0ccb932bbbf
parent cc5b28bf
Loading
Loading
Loading
Loading
+35 −10
Original line number Diff line number Diff line
@@ -1045,12 +1045,12 @@ tBTM_SEC_ACTION btm_ble_determine_security_act(bool is_originator,
 *                  p_callback : Pointer to the callback function.
 *                  p_ref_data : Pointer to be returned along with the callback.
 *
 * Returns          true if link already meets the required security; otherwise
 *                  false.
 * Returns          Returns  - L2CAP LE Connection Response Result Code.
 *
 ******************************************************************************/
bool btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm,
                             bool is_originator, tBTM_SEC_CALLBACK* p_callback,
tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check(const RawAddress& bd_addr,
                                              uint16_t psm, bool is_originator,
                                              tBTM_SEC_CALLBACK* p_callback,
                                              void* p_ref_data) {
  /* Find the service record for the PSM */
  tBTM_SEC_SERV_REC* p_serv_rec = btm_sec_find_first_serv(is_originator, psm);
@@ -1060,20 +1060,45 @@ bool btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm,
  if (!p_serv_rec) {
    BTM_TRACE_WARNING("%s PSM: %d no application registerd", __func__, psm);
    (*p_callback)(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED);
    return false;
    return L2CAP_LE_RESULT_NO_PSM;
  }
  uint8_t sec_flag = 0;
  BTM_GetSecurityFlagsByTransport(bd_addr, &sec_flag, BT_TRANSPORT_LE);

  if (!is_originator) {
    if ((p_serv_rec->security_flags & BTM_SEC_IN_ENCRYPT) &&
        !(sec_flag & BTM_SEC_ENCRYPTED)) {
      BTM_TRACE_ERROR(
          "%s: L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP. service "
          "security_flags=0x%x, "
          "sec_flag=0x%x",
          __func__, p_serv_rec->security_flags, sec_flag);
      return L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP;
    } else if ((p_serv_rec->security_flags & BTM_SEC_IN_AUTHENTICATE) &&
               !(sec_flag &
                 (BTM_SEC_LINK_KEY_AUTHED | BTM_SEC_AUTHENTICATED))) {
      BTM_TRACE_ERROR(
          "%s: L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION. service "
          "security_flags=0x%x, "
          "sec_flag=0x%x",
          __func__, p_serv_rec->security_flags, sec_flag);
      return L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION;
    }
    /* TODO: When security is required, then must check that the key size of our
       service is equal or smaller than the incoming connection key size. */
  }

  tBTM_SEC_ACTION sec_act = btm_ble_determine_security_act(
      is_originator, bd_addr, p_serv_rec->security_flags);

  tBTM_BLE_SEC_ACT ble_sec_act = BTM_BLE_SEC_NONE;
  bool status = false;
  tL2CAP_LE_RESULT_CODE result = L2CAP_LE_RESULT_CONN_OK;

  switch (sec_act) {
    case BTM_SEC_OK:
      BTM_TRACE_DEBUG("%s Security met", __func__);
      p_callback(&bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_SUCCESS);
      status = true;
      result = L2CAP_LE_RESULT_CONN_OK;
      break;

    case BTM_SEC_ENCRYPT:
@@ -1096,14 +1121,14 @@ bool btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm,
      break;
  }

  if (ble_sec_act == BTM_BLE_SEC_NONE) return status;
  if (ble_sec_act == BTM_BLE_SEC_NONE) return result;

  tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
  p_lcb->sec_act = sec_act;
  BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, p_callback, p_ref_data,
                    ble_sec_act);

  return false;
  return L2CAP_LE_RESULT_CONN_OK;
}

/*******************************************************************************
+4 −4
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@

#include "btm_ble_int.h"
#include "btm_int_types.h"
#include "l2cdefs.h"
#include "smp_api.h"

extern tBTM_CB btm_cb;
@@ -274,10 +275,9 @@ extern bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec,
                                     const RawAddress& new_pseudo_addr);
extern tBTM_SEC_SERV_REC* btm_sec_find_first_serv(CONNECTION_TYPE conn_type,
                                                  uint16_t psm);
extern bool btm_ble_start_sec_check(const RawAddress& bd_addr, uint16_t psm,
                                    bool is_originator,
                                    tBTM_SEC_CALLBACK* p_callback,
                                    void* p_ref_data);
extern tL2CAP_LE_RESULT_CODE btm_ble_start_sec_check(
    const RawAddress& bd_addr, uint16_t psm, bool is_originator,
    tBTM_SEC_CALLBACK* p_callback, void* p_ref_data);

extern tINQ_DB_ENT* btm_inq_db_new(const RawAddress& p_bda);

+13 −11
Original line number Diff line number Diff line
@@ -125,18 +125,20 @@
#define L2CAP_CONN_NO_LINK 255
#define L2CAP_CONN_CANCEL 256 /* L2CAP connection cancelled */

/* Define the LE L2CAP connection result codes
/* Define the LE L2CAP Connection Response Result codes
 */
#define L2CAP_LE_CONN_OK 0
#define L2CAP_LE_NO_PSM 2
#define L2CAP_LE_NO_RESOURCES 4
#define L2CAP_LE_INSUFFICIENT_AUTHENTICATION 5
#define L2CAP_LE_INSUFFICIENT_AUTHORIZATION 6
#define L2CAP_LE_INSUFFICIENT_ENCRYP_KEY_SIZE 7
#define L2CAP_LE_INSUFFICIENT_ENCRYP 8
#define L2CAP_LE_RESULT_CONN_OK 0
#define L2CAP_LE_RESULT_NO_PSM 2
#define L2CAP_LE_RESULT_NO_RESOURCES 4
#define L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION 5
#define L2CAP_LE_RESULT_INSUFFICIENT_AUTHORIZATION 6
#define L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP_KEY_SIZE 7
#define L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP 8
/* We don't like peer device response */
#define L2CAP_LE_INVALID_SOURCE_CID 9
#define L2CAP_LE_SOURCE_CID_ALREADY_ALLOCATED 0x0A
#define L2CAP_LE_RESULT_INVALID_SOURCE_CID 9
#define L2CAP_LE_RESULT_SOURCE_CID_ALREADY_ALLOCATED 0x0A

typedef uint8_t tL2CAP_LE_RESULT_CODE;

/* Define L2CAP Move Channel Response result codes
*/
+17 −17
Original line number Diff line number Diff line
@@ -684,8 +684,8 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
      if (p_ccb) {
        L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for duplicated cid: 0x%04x",
                            rcid);
        l2cu_reject_ble_connection(p_lcb, id,
                                   L2CAP_LE_SOURCE_CID_ALREADY_ALLOCATED);
        l2cu_reject_ble_connection(
            p_lcb, id, L2CAP_LE_RESULT_SOURCE_CID_ALREADY_ALLOCATED);
        break;
      }

@@ -693,7 +693,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
      if (p_rcb == NULL) {
        L2CAP_TRACE_WARNING("L2CAP - rcvd conn req for unknown PSM: 0x%04x",
                            con_info.psm);
        l2cu_reject_ble_connection(p_lcb, id, L2CAP_LE_NO_PSM);
        l2cu_reject_ble_connection(p_lcb, id, L2CAP_LE_RESULT_NO_PSM);
        break;
      } else {
        if (!p_rcb->api.pL2CA_ConnectInd_Cb) {
@@ -772,7 +772,7 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
            p_ccb->peer_conn_cfg.mps < L2CAP_LE_MIN_MPS ||
            p_ccb->peer_conn_cfg.mps > L2CAP_LE_MAX_MPS) {
          L2CAP_TRACE_ERROR("L2CAP don't like the params");
          con_info.l2cap_result = L2CAP_LE_NO_RESOURCES;
          con_info.l2cap_result = L2CAP_LE_RESULT_NO_RESOURCES;
          l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
          break;
        }
@@ -783,13 +783,13 @@ void l2cble_process_sig_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
        p_ccb->is_first_seg = true;
        p_ccb->peer_cfg.fcr.mode = L2CAP_FCR_LE_COC_MODE;

        if (con_info.l2cap_result == L2CAP_LE_CONN_OK)
        if (con_info.l2cap_result == L2CAP_LE_RESULT_CONN_OK)
          l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP, &con_info);
        else
          l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
      } else {
        L2CAP_TRACE_DEBUG("I DO NOT remember the connection req");
        con_info.l2cap_result = L2CAP_LE_INVALID_SOURCE_CID;
        con_info.l2cap_result = L2CAP_LE_RESULT_INVALID_SOURCE_CID;
        l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
      }
      break;
@@ -1404,20 +1404,20 @@ void l2cble_sec_comp(const RawAddress* bda, tBT_TRANSPORT transport,
 * Description      This function is called by LE COC link to meet the
 *                  security requirement for the link
 *
 * Returns          true - security procedures are started
 *                  false - failure
 * Returns          Returns  - L2CAP LE Connection Response Result Code.
 *
 ******************************************************************************/
bool l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm,
                          bool is_originator, tL2CAP_SEC_CBACK* p_callback,
tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr,
                                           uint16_t psm, bool is_originator,
                                           tL2CAP_SEC_CBACK* p_callback,
                                           void* p_ref_data) {
  L2CAP_TRACE_DEBUG("%s", __func__);
  bool status;
  tL2CAP_LE_RESULT_CODE result;
  tL2C_LCB* p_lcb = NULL;

  if (!p_callback) {
    L2CAP_TRACE_ERROR("%s No callback function", __func__);
    return false;
    return L2CAP_LE_RESULT_NO_RESOURCES;
  }

  p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE);
@@ -1425,14 +1425,14 @@ bool l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm,
  if (!p_lcb) {
    L2CAP_TRACE_ERROR("%s Security check for unknown device", __func__);
    p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_UNKNOWN_ADDR);
    return false;
    return L2CAP_LE_RESULT_NO_RESOURCES;
  }

  tL2CAP_SEC_DATA* p_buf =
      (tL2CAP_SEC_DATA*)osi_malloc((uint16_t)sizeof(tL2CAP_SEC_DATA));
  if (!p_buf) {
    p_callback(bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_NO_RESOURCES);
    return false;
    return L2CAP_LE_RESULT_NO_RESOURCES;
  }

  p_buf->psm = psm;
@@ -1440,10 +1440,10 @@ bool l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t psm,
  p_buf->p_callback = p_callback;
  p_buf->p_ref_data = p_ref_data;
  fixed_queue_enqueue(p_lcb->le_sec_pending_q, p_buf);
  status = btm_ble_start_sec_check(bd_addr, psm, is_originator,
  result = btm_ble_start_sec_check(bd_addr, psm, is_originator,
                                   &l2cble_sec_comp, p_ref_data);

  return status;
  return result;
}

/* This function is called to adjust the connection intervals based on various
+16 −4
Original line number Diff line number Diff line
@@ -238,8 +238,19 @@ static void l2c_csm_closed(tL2C_CCB* p_ccb, uint16_t event, void* p_data) {

      if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE) {
        p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
        l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
                             false, &l2c_link_sec_comp2, p_ccb);
        tL2CAP_LE_RESULT_CODE result = l2ble_sec_access_req(
            p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, false,
            &l2c_link_sec_comp2, p_ccb);

        switch (result) {
          case L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION:
          case L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP_KEY_SIZE:
          case L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP:
            l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id, result);
            l2cu_release_ccb(p_ccb);
            break;
            // TODO: Handle the other return codes
        }
      } else {
        /* Cancel sniff mode if needed */
        {
@@ -442,8 +453,9 @@ static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
                           l2c_ccb_timer_timeout, p_ccb);
      } else {
        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
          l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id,
                                     L2CAP_LE_INSUFFICIENT_AUTHENTICATION);
          l2cu_reject_ble_connection(
              p_ccb->p_lcb, p_ccb->remote_id,
              L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION);
        else
          l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
        l2cu_release_ccb(p_ccb);
Loading