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

Commit 69fd15b9 authored by Andre Eisenbach's avatar Andre Eisenbach
Browse files

Fix LE pairing LTK storage issue

Two separate issues prevented the correct LTK from being storred in
non-volatile storage and thus prevented an LE device from working after
Bluetooth was restarted:

1. tBTM_SEC_BLE_KEYS contained a field "pltk" which stored the LTK, but
   downstream the field "ltk" in the same structure was used to access
   the key.

2. The structure element p_key_value was not deep-copied for
   BTA_DM_BLE_KEY_EVT events, causing data corruption and instabilities.

This patch addresses both issues.

Bug: 20091926
Change-Id: I9f9481a44bfe83cacd351f9e578451e77b573564
parent 1d5499c2
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#define LOG_TAG "bt_btif_dm"

#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -53,6 +54,7 @@
#include "include/stack_config.h"

#include "osi/include/log.h"
#include "osi/include/allocator.h"

/******************************************************************************
**  Device specific workarounds
@@ -255,6 +257,32 @@ extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UIN
**  Functions
******************************************************************************/

static void btif_dm_data_copy(uint16_t event, char *dst, char *src)
{
    tBTA_DM_SEC *dst_dm_sec = (tBTA_DM_SEC*)dst;
    tBTA_DM_SEC *src_dm_sec = (tBTA_DM_SEC*)src;

    if (!src_dm_sec)
        return;

    assert(dst_dm_sec);
    memcpy(dst_dm_sec, src_dm_sec, sizeof(tBTA_DM_SEC));

    if (event == BTA_DM_BLE_KEY_EVT)
    {
        dst_dm_sec->ble_key.p_key_value = osi_malloc(sizeof(tBTM_LE_KEY_VALUE));
        assert(src_dm_sec->ble_key.p_key_value);
        assert(dst_dm_sec->ble_key.p_key_value);
        memcpy(dst_dm_sec->ble_key.p_key_value, src_dm_sec->ble_key.p_key_value, sizeof(tBTM_LE_KEY_VALUE));
    }
}

static void btif_dm_data_free(uint16_t event, tBTA_DM_SEC *dm_sec)
{
    if (event == BTA_DM_BLE_KEY_EVT)
        osi_free(dm_sec->ble_key.p_key_value);
}

bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
                                                BOOLEAN b_enable)
{
@@ -2016,8 +2044,9 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
            BTIF_TRACE_WARNING( "btif_dm_cback : unhandled event (%d)", event );
            break;
    }
} /* btui_security_cback() */

    btif_dm_data_free(event, p_data);
}

/*******************************************************************************
**
@@ -2104,10 +2133,9 @@ static void btif_dm_generic_evt(UINT16 event, char* p_param)

void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data)
{
    bt_status_t status;

    /* switch context to btif task context (copy full union size for convenience) */
    status = btif_transfer_context(btif_dm_upstreams_evt, (uint16_t)event, (void*)p_data, sizeof(tBTA_DM_SEC), NULL);
    bt_status_t status = btif_transfer_context(btif_dm_upstreams_evt, (uint16_t)event,
                                (void*)p_data, sizeof(tBTA_DM_SEC), btif_dm_data_copy);

    /* catch any failed context transfers */
    ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+4 −4
Original line number Diff line number Diff line
@@ -967,7 +967,7 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY
        switch (key_type)
        {
            case BTM_LE_KEY_PENC:
                memcpy(p_rec->ble.keys.pltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
                memcpy(p_rec->ble.keys.ltk, p_keys->penc_key.ltk, BT_OCTET16_LEN);
                memcpy(p_rec->ble.keys.rand, p_keys->penc_key.rand, BT_OCTET8_LEN);
                p_rec->ble.keys.sec_level = p_keys->penc_key.sec_level;
                p_rec->ble.keys.ediv = p_keys->penc_key.ediv;
@@ -998,7 +998,7 @@ void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY
                break;

            case BTM_LE_KEY_PCSRK:
                memcpy(p_rec->ble.keys.pcsrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
                memcpy(p_rec->ble.keys.csrk, p_keys->pcsrk_key.csrk, BT_OCTET16_LEN);
                p_rec->ble.keys.srk_sec_level = p_keys->pcsrk_key.sec_level;
                p_rec->ble.keys.counter  = p_keys->pcsrk_key.counter;
                p_rec->ble.key_type |= BTM_LE_KEY_PCSRK;
@@ -1337,7 +1337,7 @@ tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk)
    else if (p_rec->ble.key_type & BTM_LE_KEY_PENC)
    {
        if (btsnd_hcic_ble_start_enc(p_rec->ble_hci_handle, p_rec->ble.keys.rand,
                                     p_rec->ble.keys.ediv, p_rec->ble.keys.pltk))
                                     p_rec->ble.keys.ediv, p_rec->ble.keys.ltk))
            rt = BTM_CMD_STARTED;
    }
    else
@@ -2058,7 +2058,7 @@ BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, UINT16 len, UINT
        BTM_TRACE_DEBUG ("%s rcv_cnt=%d >= expected_cnt=%d", __func__, counter,
                          p_rec->ble.keys.counter);

        if (aes_cipher_msg_auth_code(p_rec->ble.keys.pcsrk, p_orig, len, BTM_CMAC_TLEN_SIZE, p_mac))
        if (aes_cipher_msg_auth_code(p_rec->ble.keys.csrk, p_orig, len, BTM_CMAC_TLEN_SIZE, p_mac))
        {
            if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0)
            {
+0 −2
Original line number Diff line number Diff line
@@ -445,8 +445,6 @@ typedef struct
typedef struct
{
    BT_OCTET16          irk;            /* peer diverified identity root */
    BT_OCTET16          pltk;           /* peer long term key */
    BT_OCTET16          pcsrk;          /* peer SRK peer device used to secured sign local data  */

    BT_OCTET16          lltk;           /* local long term key */
    BT_OCTET16          lcsrk;          /* local SRK peer device used to secured sign local data  */