Skip to content

Commit c1d153d

Browse files
author
Marceau Fillon
committed
nimble/host: Support database hash
Supports database hash characteristic. Computes database hash and stores it on first pairing with device. Computes current hash and compares it with stored hash on reconnection. See BLE Core spec 5.2 section 7.2
1 parent 390744d commit c1d153d

File tree

9 files changed

+311
-4
lines changed

9 files changed

+311
-4
lines changed

nimble/host/include/host/ble_att.h

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct os_mbuf;
3838
#define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801
3939
#define BLE_ATT_UUID_INCLUDE 0x2802
4040
#define BLE_ATT_UUID_CHARACTERISTIC 0x2803
41+
#define BLE_ATT_UUID_DESCRIPTOR 0x2902
4142

4243
#define BLE_ATT_ERR_INVALID_HANDLE 0x01
4344
#define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02

nimble/host/include/host/ble_gatt.h

+2
Original file line numberDiff line numberDiff line change
@@ -894,3 +894,5 @@ int ble_gatts_start(void);
894894
*/
895895

896896
#endif
897+
898+
int ble_compute_db_hash(uint8_t db_hash[16]);

nimble/host/include/host/ble_store.h

+35
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extern "C" {
3030
#define BLE_STORE_OBJ_TYPE_OUR_SEC 1
3131
#define BLE_STORE_OBJ_TYPE_PEER_SEC 2
3232
#define BLE_STORE_OBJ_TYPE_CCCD 3
33+
#define BLE_STORE_OBJ_TYPE_HASH 4
3334

3435
/** Failed to persist record; insufficient storage capacity. */
3536
#define BLE_STORE_EVENT_OVERFLOW 1
@@ -120,13 +121,38 @@ struct ble_store_value_cccd {
120121
unsigned value_changed:1;
121122
};
122123

124+
/**
125+
* Used as a key for lookups of stored database hashes.
126+
* This struct corresponds to the BLE_STORE_OBJ_TYPE_HASH store object type.
127+
*/
128+
struct ble_store_key_hash {
129+
/**
130+
* Key by peer identity address;
131+
* peer_addr=BLE_ADDR_NONE means don't key off peer.
132+
*/
133+
ble_addr_t peer_addr;
134+
135+
/** Number of results to skip; 0 means retrieve the first match. */
136+
uint8_t idx;
137+
};
138+
139+
/**
140+
* Represents the last stored server database hash for a paired client device.
141+
* This struct corresponds to the BLE_STORE_OBJ_TYPE_HASH store object type.
142+
*/
143+
struct ble_store_value_hash{
144+
ble_addr_t peer_addr;
145+
uint8_t db_hash[16];
146+
};
147+
123148
/**
124149
* Used as a key for store lookups. This union must be accompanied by an
125150
* object type code to indicate which field is valid.
126151
*/
127152
union ble_store_key {
128153
struct ble_store_key_sec sec;
129154
struct ble_store_key_cccd cccd;
155+
struct ble_store_key_hash hash;
130156
};
131157

132158
/**
@@ -136,6 +162,7 @@ union ble_store_key {
136162
union ble_store_value {
137163
struct ble_store_value_sec sec;
138164
struct ble_store_value_cccd cccd;
165+
struct ble_store_value_hash hash;
139166
};
140167

141168
struct ble_store_status_event {
@@ -266,10 +293,18 @@ int ble_store_read_cccd(const struct ble_store_key_cccd *key,
266293
int ble_store_write_cccd(const struct ble_store_value_cccd *value);
267294
int ble_store_delete_cccd(const struct ble_store_key_cccd *key);
268295

296+
int ble_store_read_hash(uint16_t conn_handle,
297+
const struct ble_store_key_hash *key,
298+
struct ble_store_value_hash *out_value);
299+
int ble_store_write_hash(const struct ble_store_value_hash *value);
300+
int ble_store_delete_hash(const struct ble_store_key_hash *key);
301+
269302
void ble_store_key_from_value_sec(struct ble_store_key_sec *out_key,
270303
const struct ble_store_value_sec *value);
271304
void ble_store_key_from_value_cccd(struct ble_store_key_cccd *out_key,
272305
const struct ble_store_value_cccd *value);
306+
void ble_store_key_from_value_hash(struct ble_store_key_hash *out_key,
307+
const struct ble_store_value_hash *value);
273308

274309
void ble_store_key_from_value(int obj_type,
275310
union ble_store_key *out_key,

nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h

+2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ extern "C" {
2929
struct ble_hs_cfg;
3030

3131
#define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05
32+
#define BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16 0x2B2A
3233

3334
void ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle);
35+
void ble_svc_conn_gatt_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle);
3436
void ble_svc_gatt_init(void);
3537

3638
#ifdef __cplusplus

nimble/host/services/gatt/src/ble_svc_gatt.c

+53-3
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,21 @@
2222
#include "sysinit/sysinit.h"
2323
#include "host/ble_hs.h"
2424
#include "services/gatt/ble_svc_gatt.h"
25+
#include "host/ble_gatt.h"
2526

2627
static uint16_t ble_svc_gatt_changed_val_handle;
28+
static uint16_t ble_svc_gatt_hash_val_handle;
2729
static uint16_t ble_svc_gatt_start_handle;
2830
static uint16_t ble_svc_gatt_end_handle;
2931

3032
static int
3133
ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
3234
struct ble_gatt_access_ctxt *ctxt, void *arg);
3335

36+
static int
37+
ble_svc_gatt_db_hash_access(uint16_t conn_handle, uint16_t attr_handle,
38+
struct ble_gatt_access_ctxt *ctxt, void *arg);
39+
3440
static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
3541
{
3642
/*** Service: GATT */
@@ -41,7 +47,14 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
4147
.access_cb = ble_svc_gatt_access,
4248
.val_handle = &ble_svc_gatt_changed_val_handle,
4349
.flags = BLE_GATT_CHR_F_INDICATE,
44-
}, {
50+
},
51+
{
52+
.uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16),
53+
.access_cb = ble_svc_gatt_db_hash_access,
54+
.val_handle = &ble_svc_gatt_hash_val_handle,
55+
.flags = BLE_GATT_CHR_F_READ,
56+
},
57+
{
4558
0, /* No more characteristics in this service. */
4659
} },
4760
},
@@ -51,6 +64,28 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
5164
},
5265
};
5366

67+
static int
68+
ble_svc_gatt_db_hash_access(uint16_t conn_handle, uint16_t attr_handle,
69+
struct ble_gatt_access_ctxt *ctxt, void *arg)
70+
{
71+
int rc;
72+
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
73+
assert(ctxt->chr == &ble_svc_gatt_defs[0].characteristics[1]);
74+
uint8_t db_hash[16];
75+
uint16_t len_data = sizeof(db_hash);
76+
int res = ble_compute_db_hash(db_hash);
77+
if(res != 0){
78+
return BLE_ATT_ERR_UNLIKELY;
79+
}
80+
81+
rc = os_mbuf_append(ctxt->om, db_hash, len_data);
82+
if(rc !=0){
83+
return BLE_ATT_ERR_UNLIKELY;
84+
}
85+
86+
return 0;
87+
}
88+
5489
static int
5590
ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
5691
struct ble_gatt_access_ctxt *ctxt, void *arg)
@@ -73,7 +108,7 @@ ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
73108

74109
put_le16(u8p + 0, ble_svc_gatt_start_handle);
75110
put_le16(u8p + 2, ble_svc_gatt_end_handle);
76-
111+
77112
return 0;
78113
}
79114

@@ -89,7 +124,22 @@ ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle)
89124
{
90125
ble_svc_gatt_start_handle = start_handle;
91126
ble_svc_gatt_end_handle = end_handle;
92-
ble_gatts_chr_updated(ble_svc_gatt_changed_val_handle);
127+
ble_gatts_chr_updated(ble_svc_gatt_changed_val_handle);
128+
}
129+
130+
/**
131+
* Indicates a change in attribute assignment to specified peer.
132+
*
133+
* @param conn_handle The connection to indicate.
134+
* @param start_handle The start of the affected handle range.
135+
* @param end_handle The end of the affected handle range.
136+
*/
137+
void
138+
ble_svc_conn_gatt_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)
139+
{
140+
ble_svc_gatt_start_handle = start_handle;
141+
ble_svc_gatt_end_handle = end_handle;
142+
ble_gattc_indicate(conn_handle, ble_svc_gatt_changed_val_handle);
93143
}
94144

95145
void

nimble/host/src/ble_gatts.c

+124
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@
2828
#define BLE_GATTS_INCLUDE_SZ 6
2929
#define BLE_GATTS_CHR_MAX_SZ 19
3030

31+
#if NIMBLE_BLE_SM
32+
#include "tinycrypt/aes.h"
33+
#include "tinycrypt/constants.h"
34+
#include "tinycrypt/utils.h"
35+
36+
#if MYNEWT_VAL(BLE_SM_SC)
37+
#include "tinycrypt/cmac_mode.h"
38+
#include "tinycrypt/ecc_dh.h"
39+
#endif
40+
#endif
41+
3142
static const ble_uuid_t *uuid_pri =
3243
BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE);
3344
static const ble_uuid_t *uuid_sec =
@@ -1719,6 +1730,8 @@ ble_gatts_bonding_restored(uint16_t conn_handle)
17191730
{
17201731
struct ble_store_value_cccd cccd_value;
17211732
struct ble_store_key_cccd cccd_key;
1733+
struct ble_store_value_hash hash_value;
1734+
struct ble_store_key_hash hash_key;
17221735
struct ble_gatts_clt_cfg *clt_cfg;
17231736
struct ble_hs_conn *conn;
17241737
uint8_t att_op;
@@ -1799,6 +1812,13 @@ ble_gatts_bonding_restored(uint16_t conn_handle)
17991812

18001813
cccd_key.idx++;
18011814
}
1815+
1816+
hash_key.peer_addr = conn->bhc_peer_addr;
1817+
hash_key.peer_addr.type =
1818+
ble_hs_misc_peer_addr_type_to_id(conn->bhc_peer_addr.type);
1819+
hash_key.idx = 0;
1820+
1821+
rc = ble_store_read_hash(conn_handle, &hash_key, &hash_value); // read peer hash, read the database hash characteristic and compare, if rc != 0 => ble_svc_conn_gatt_changed(0, 0xffff)
18021822
}
18031823

18041824
static struct ble_gatts_svc_entry *
@@ -2182,3 +2202,107 @@ ble_gatts_init(void)
21822202
return 0;
21832203

21842204
}
2205+
2206+
static void ble_db_hash_message_append_u16(uint16_t val, uint8_t *buf, uint8_t *len) {
2207+
val = htole16(val);
2208+
memcpy(buf + *len, &val, sizeof(uint16_t));
2209+
*len += sizeof(uint16_t);
2210+
}
2211+
2212+
static void ble_db_hash_message_append_u32(uint32_t val, uint8_t *buf, uint8_t *len) {
2213+
val = htole32(val);
2214+
memcpy(buf + *len, &val, sizeof(uint32_t));
2215+
*len += sizeof(uint32_t);
2216+
}
2217+
2218+
static void ble_db_hash_message_append_uuid(const ble_uuid_t *uuid, uint8_t *buf, uint8_t *len) {
2219+
switch (uuid->type) {
2220+
case BLE_UUID_TYPE_16: {
2221+
ble_db_hash_message_append_u16( BLE_UUID16(uuid)->value, buf, len);
2222+
break;
2223+
}
2224+
case BLE_UUID_TYPE_32: {
2225+
ble_db_hash_message_append_u32(BLE_UUID32(uuid)->value, buf, len);
2226+
break;
2227+
}
2228+
case BLE_UUID_TYPE_128: {
2229+
memcpy(buf + *len, BLE_UUID128(uuid)->value, 16);
2230+
*len += 16;
2231+
break;
2232+
}
2233+
default:
2234+
break;
2235+
}
2236+
}
2237+
2238+
/**
2239+
* Called when the database cmac hash needs to be computed using the information
2240+
* from registered services, characteristics and descriptors. This
2241+
* function:
2242+
* o Sets up the cmac generator with a key of 0s
2243+
* o Parse services, characteristics and descriptors and adds information
2244+
* to the message to code.
2245+
* o Computes the cmac coded message.
2246+
*/
2247+
int ble_compute_db_hash(uint8_t db_hash[16])
2248+
{
2249+
uint8_t buf[24];
2250+
uint8_t buf_len;
2251+
2252+
struct tc_aes_key_sched_struct sched;
2253+
struct tc_cmac_struct state;
2254+
const uint8_t key[16] = {0};
2255+
2256+
if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) {
2257+
return BLE_HS_EUNKNOWN;
2258+
}
2259+
2260+
for (int i = 0; i < ble_gatts_num_svc_entries; i++) {
2261+
struct ble_gatts_svc_entry *entry = &ble_gatts_svc_entries[i];
2262+
buf_len = 0;
2263+
ble_db_hash_message_append_u16(entry->handle, buf, &buf_len);
2264+
ble_db_hash_message_append_u16(BLE_ATT_UUID_PRIMARY_SERVICE, buf, &buf_len);
2265+
ble_db_hash_message_append_uuid(entry->svc->uuid, buf, &buf_len);
2266+
2267+
if (tc_cmac_update(&state, buf, buf_len) == TC_CRYPTO_FAIL) {
2268+
return BLE_HS_EUNKNOWN;
2269+
}
2270+
buf_len = 0;
2271+
2272+
if (entry->svc->characteristics != NULL) {
2273+
for (const struct ble_gatt_chr_def *chr = entry->svc->characteristics; chr && chr->uuid; chr++) {
2274+
if (chr->val_handle == NULL) {
2275+
continue;
2276+
}
2277+
ble_db_hash_message_append_u16(*chr->val_handle - 1, buf, &buf_len);
2278+
ble_db_hash_message_append_u16(BLE_ATT_UUID_CHARACTERISTIC, buf, &buf_len);
2279+
ble_db_hash_message_append_u16(chr->flags, buf, &buf_len);
2280+
ble_db_hash_message_append_u16(*chr->val_handle, buf, &buf_len);
2281+
ble_db_hash_message_append_uuid(chr->uuid, buf, &buf_len);
2282+
2283+
if (tc_cmac_update(&state, buf, buf_len) == TC_CRYPTO_FAIL) {
2284+
return BLE_HS_EUNKNOWN;
2285+
}
2286+
buf_len = 0;
2287+
2288+
if (chr->descriptors != NULL) {
2289+
for (struct ble_gatt_dsc_def *dsc = chr->descriptors; dsc && dsc->uuid; dsc++) {
2290+
ble_db_hash_message_append_u16(*chr->val_handle + 1, buf, &buf_len);
2291+
ble_db_hash_message_append_u16(BLE_ATT_UUID_DESCRIPTOR, buf, &buf_len);
2292+
2293+
if (tc_cmac_update(&state, buf, buf_len) == TC_CRYPTO_FAIL) {
2294+
return BLE_HS_EUNKNOWN;
2295+
}
2296+
buf_len = 0;
2297+
}
2298+
}
2299+
}
2300+
}
2301+
}
2302+
2303+
if (tc_cmac_final(db_hash, &state) == TC_CRYPTO_FAIL) {
2304+
return BLE_HS_EUNKNOWN;
2305+
}
2306+
2307+
return 0;
2308+
}

nimble/host/src/ble_sm.c

+10
Original file line numberDiff line numberDiff line change
@@ -516,11 +516,13 @@ static void
516516
ble_sm_persist_keys(struct ble_sm_proc *proc)
517517
{
518518
struct ble_store_value_sec value_sec;
519+
struct ble_store_value_hash value_hash;
519520
struct ble_hs_conn *conn;
520521
ble_addr_t peer_addr;
521522
int authenticated;
522523
int identity_ev = 0;
523524
int sc;
525+
int rc;
524526

525527
ble_hs_lock();
526528

@@ -577,6 +579,14 @@ ble_sm_persist_keys(struct ble_sm_proc *proc)
577579
ble_sm_fill_store_value(&peer_addr, authenticated, sc, &proc->peer_keys,
578580
&value_sec);
579581
ble_store_write_peer_sec(&value_sec);
582+
583+
584+
// Compute current database hash and store it
585+
value_hash.peer_addr = peer_addr;
586+
rc = ble_compute_db_hash(value_hash.db_hash);
587+
if (rc == 0) {
588+
rc = ble_store_write_hash(&value_hash);
589+
}
580590
}
581591

582592
static int

0 commit comments

Comments
 (0)