You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/05/18 03:26:32 UTC
[2/2] incubator-mynewt-core git commit: bleprph - Add characteristics
which require enc.
bleprph - Add characteristics which require enc.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/05401e1e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/05401e1e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/05401e1e
Branch: refs/heads/090_dev
Commit: 05401e1ebad4bbcf3b0bb9a5575ce5a15d8f567d
Parents: c408561
Author: Christopher Collins <cc...@apache.org>
Authored: Tue May 17 20:25:10 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Tue May 17 20:25:10 2016 -0700
----------------------------------------------------------------------
apps/bleprph/src/bleprph.h | 5 ++
apps/bleprph/src/gatt_svr.c | 150 +++++++++++++++++++++++++++++++++++----
apps/bleprph/src/keystore.c | 100 ++++++++++++++++++++++++++
apps/bleprph/src/main.c | 126 ++++++++++++++++++++++++++------
4 files changed, 345 insertions(+), 36 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/05401e1e/apps/bleprph/src/bleprph.h
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/bleprph.h b/apps/bleprph/src/bleprph.h
index e903fe0..94024d7 100644
--- a/apps/bleprph/src/bleprph.h
+++ b/apps/bleprph/src/bleprph.h
@@ -24,6 +24,11 @@
void gatt_svr_init(void);
+int keystore_lookup(uint16_t ediv, uint64_t rand_num,
+ void *out_ltk, int *out_authenticated);
+int keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *key,
+ int authenticated);
+
extern struct log bleprph_log;
extern const char *bleprph_device_name;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/05401e1e/apps/bleprph/src/gatt_svr.c
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/gatt_svr.c b/apps/bleprph/src/gatt_svr.c
index 27a1433..aacc650 100644
--- a/apps/bleprph/src/gatt_svr.c
+++ b/apps/bleprph/src/gatt_svr.c
@@ -6,7 +6,7 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
@@ -18,6 +18,7 @@
*/
#include <assert.h>
+#include <stdio.h>
#include <string.h>
#include "bsp/bsp.h"
#include "console/console.h"
@@ -31,6 +32,35 @@
#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID 0x2A45
#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT 0x2A44
+/**
+ * The vendor specific "bleprph" service consists of two characteristics:
+ * o "read": a single-byte characteristic that can only be read of an
+ * encryptted connection.
+ * o "write": a single-byte characteristic that can always be read, but
+ * can only be written over an encrypted connection.
+ */
+
+/* 59462f12-9543-9999-12c8-58b459a2712d */
+static const uint8_t gatt_svr_svc_bleprph[16] = {
+ 0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
+ 0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59
+};
+
+/* 5c3a659e-897e-45e1-b016-007107c96df6 */
+static const uint8_t gatt_svr_chr_bleprph_read[16] = {
+ 0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
+ 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c
+};
+
+/* 5c3a659e-897e-45e1-b016-007107c96df7 */
+static const uint8_t gatt_svr_chr_bleprph_write[16] = {
+ 0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
+ 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c
+};
+
+static uint8_t gatt_svr_nimble_test_read_val;
+static uint8_t gatt_svr_nimble_test_write_val;
+
static int
gatt_svr_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op,
union ble_gatt_access_ctxt *ctxt, void *arg);
@@ -42,6 +72,11 @@ gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
uint8_t op, union ble_gatt_access_ctxt *ctxt,
void *arg);
+static int
+gatt_svr_chr_access_bleprph(uint16_t conn_handle, uint16_t attr_handle,
+ uint8_t op, union ble_gatt_access_ctxt *ctxt,
+ void *arg);
+
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
/*** Service: GAP. */
@@ -120,6 +155,26 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
},
{
+ /*** Service: bleprph. */
+ .type = BLE_GATT_SVC_TYPE_PRIMARY,
+ .uuid128 = (void *)gatt_svr_svc_bleprph,
+ .characteristics = (struct ble_gatt_chr_def[]) { {
+ /*** Characteristic: Read. */
+ .uuid128 = (void *)gatt_svr_chr_bleprph_read,
+ .access_cb = gatt_svr_chr_access_bleprph,
+ .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
+ }, {
+ /*** Characteristic: Write. */
+ .uuid128 = (void *)gatt_svr_chr_bleprph_write,
+ .access_cb = gatt_svr_chr_access_bleprph,
+ .flags = BLE_GATT_CHR_F_READ |
+ BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
+ }, {
+ 0, /* No more characteristics in this service. */
+ } },
+ },
+
+ {
0, /* No more services. */
},
};
@@ -295,34 +350,101 @@ gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle,
}
}
+static int
+gatt_svr_chr_access_bleprph(uint16_t conn_handle, uint16_t attr_handle,
+ uint8_t op, union ble_gatt_access_ctxt *ctxt,
+ void *arg)
+{
+ void *uuid128;
+ int rc;
+
+ uuid128 = ctxt->chr_access.chr->uuid128;
+
+ /* Determine which characteristic is being accessed by examining its
+ * 128-bit UUID.
+ */
+
+ if (memcmp(uuid128, gatt_svr_chr_bleprph_read, 16) == 0) {
+ assert(op == BLE_GATT_ACCESS_OP_READ_CHR);
+ ctxt->chr_access.data = &gatt_svr_nimble_test_read_val;
+ ctxt->chr_access.len = sizeof gatt_svr_nimble_test_read_val;
+ return 0;
+ }
+
+ if (memcmp(uuid128, gatt_svr_chr_bleprph_write, 16) == 0) {
+ switch (op) {
+ case BLE_GATT_ACCESS_OP_READ_CHR:
+ ctxt->chr_access.data = &gatt_svr_nimble_test_write_val;
+ ctxt->chr_access.len = sizeof gatt_svr_nimble_test_write_val;
+ return 0;
+
+ case BLE_GATT_ACCESS_OP_WRITE_CHR:
+ rc = gatt_svr_chr_write(op, ctxt,
+ sizeof gatt_svr_nimble_test_write_val,
+ sizeof gatt_svr_nimble_test_write_val,
+ &gatt_svr_nimble_test_write_val, NULL);
+ return rc;
+
+ default:
+ assert(0);
+ return BLE_ATT_ERR_UNLIKELY;
+ }
+ }
+
+ /* Unknown characteristic; the nimble stack should not have called this
+ * function.
+ */
+ assert(0);
+ return BLE_ATT_ERR_UNLIKELY;
+}
+
+static char *
+gatt_svr_uuid128_to_s(void *uuid128, char *dst)
+{
+ uint16_t uuid16;
+ uint8_t *u8p;
+
+ uuid16 = ble_uuid_128_to_16(uuid128);
+ if (uuid16 != 0) {
+ sprintf(dst, "0x%04x", uuid16);
+ return dst;
+ }
+
+ u8p = uuid128;
+
+ sprintf(dst, "%02x%02x%02x%02x-", u8p[15], u8p[14], u8p[13], u8p[12]);
+ sprintf(dst + 9, "%02x%02x-%02x%02x-", u8p[11], u8p[10], u8p[9], u8p[8]);
+ sprintf(dst + 19, "%02x%02x%02x%02x%02x%02x%02x%02x",
+ u8p[7], u8p[6], u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
+
+ return dst;
+}
+
static void
gatt_svr_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, void *arg)
{
- uint16_t uuid16;
+ char buf[40];
switch (op) {
case BLE_GATT_REGISTER_OP_SVC:
- uuid16 = ble_uuid_128_to_16(ctxt->svc_reg.svc->uuid128);
- assert(uuid16 != 0);
- BLEPRPH_LOG(DEBUG, "registered service 0x%04x with handle=%d\n",
- uuid16, ctxt->svc_reg.handle);
+ BLEPRPH_LOG(DEBUG, "registered service %s with handle=%d\n",
+ gatt_svr_uuid128_to_s(ctxt->svc_reg.svc->uuid128, buf),
+ ctxt->svc_reg.handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
- uuid16 = ble_uuid_128_to_16(ctxt->chr_reg.chr->uuid128);
- assert(uuid16 != 0);
- BLEPRPH_LOG(DEBUG, "registering characteristic 0x%04x with "
+ BLEPRPH_LOG(DEBUG, "registering characteristic %s with "
"def_handle=%d val_handle=%d\n",
- uuid16, ctxt->chr_reg.def_handle,
+ gatt_svr_uuid128_to_s(ctxt->chr_reg.chr->uuid128, buf),
+ ctxt->chr_reg.def_handle,
ctxt->chr_reg.val_handle);
break;
case BLE_GATT_REGISTER_OP_DSC:
- uuid16 = ble_uuid_128_to_16(ctxt->dsc_reg.dsc->uuid128);
- assert(uuid16 != 0);
- BLEPRPH_LOG(DEBUG, "registering descriptor 0x%04x with handle=%d "
+ BLEPRPH_LOG(DEBUG, "registering descriptor %s with handle=%d "
"chr_handle=%d\n",
- uuid16, ctxt->dsc_reg.dsc_handle,
+ gatt_svr_uuid128_to_s(ctxt->dsc_reg.dsc->uuid128, buf),
+ ctxt->dsc_reg.dsc_handle,
ctxt->dsc_reg.chr_def_handle);
break;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/05401e1e/apps/bleprph/src/keystore.c
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/keystore.c b/apps/bleprph/src/keystore.c
new file mode 100644
index 0000000..5f3ff55
--- /dev/null
+++ b/apps/bleprph/src/keystore.c
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * This file implements a simple in-RAM key database for long-term keys. A key
+ * is inserted into the database immediately after a successful pairing
+ * procedure. A key is retrieved from the database when the central performs
+ * the encryption procedure (bonding).
+ *
+ * As this database is only stored in RAM, its contents are lost if bleprph is
+ * restarted.
+ */
+
+#include <inttypes.h>
+#include <string.h>
+
+#include "host/ble_hs.h"
+
+#define KEYSTORE_MAX_ENTRIES 4
+
+struct keystore_entry {
+ uint64_t rand_num;
+ uint16_t ediv;
+ uint8_t ltk[16];
+
+ unsigned authenticated:1;
+
+ /* XXX: authreq. */
+};
+
+static struct keystore_entry keystore_entries[KEYSTORE_MAX_ENTRIES];
+static int keystore_num_entries;
+
+/**
+ * Searches the database for a long-term key matching the specified criteria.
+ *
+ * @return 0 if a key was found; else BLE_HS_ENOENT.
+ */
+int
+keystore_lookup(uint16_t ediv, uint64_t rand_num,
+ void *out_ltk, int *out_authenticated)
+{
+ struct keystore_entry *entry;
+ int i;
+
+ for (i = 0; i < keystore_num_entries; i++) {
+ entry = keystore_entries + i;
+
+ if (entry->ediv == ediv && entry->rand_num == rand_num) {
+ memcpy(out_ltk, entry->ltk, sizeof entry->ltk);
+ *out_authenticated = entry->authenticated;
+
+ return 0;
+ }
+ }
+
+ return BLE_HS_ENOENT;
+}
+
+/**
+ * Adds the specified key to the database.
+ *
+ * @return 0 on success; BLE_HS_ENOMEM if the database is
+ * full.
+ */
+int
+keystore_add(uint16_t ediv, uint64_t rand_num, uint8_t *ltk, int authenticated)
+{
+ struct keystore_entry *entry;
+
+ if (keystore_num_entries >= KEYSTORE_MAX_ENTRIES) {
+ return BLE_HS_ENOMEM;
+ }
+
+ entry = keystore_entries + keystore_num_entries;
+ keystore_num_entries++;
+
+ entry->ediv = ediv;
+ entry->rand_num = rand_num;
+ memcpy(entry->ltk, ltk, sizeof entry->ltk);
+ entry->authenticated = authenticated;
+
+ return 0;
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/05401e1e/apps/bleprph/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/main.c b/apps/bleprph/src/main.c
index 97a9367..8731c06 100755
--- a/apps/bleprph/src/main.c
+++ b/apps/bleprph/src/main.c
@@ -6,7 +6,7 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
@@ -36,6 +36,7 @@
#include "host/ble_att.h"
#include "host/ble_gap.h"
#include "host/ble_gatt.h"
+#include "host/ble_l2cap.h"
#include "controller/ble_ll.h"
#include "bleprph.h"
@@ -58,11 +59,10 @@ struct log bleprph_log;
/** Priority of the nimble host and controller tasks. */
#define BLE_LL_TASK_PRI (OS_TASK_PRI_HIGHEST)
-#define BLEPRPH_BLE_HS_PRIO (1)
/** bleprph task settings. */
+#define BLEPRPH_TASK_PRIO 1
#define BLEPRPH_STACK_SIZE (OS_STACK_ALIGN(336))
-#define BLEPRPH_TASK_PRIO (BLEPRPH_BLE_HS_PRIO + 1)
struct os_eventq bleprph_evq;
struct os_task bleprph_task;
@@ -84,7 +84,7 @@ uint8_t bleprph_reconnect_addr[6];
uint8_t bleprph_pref_conn_params[8];
uint8_t bleprph_gatt_service_changed[4];
-static int bleprph_on_connect(int event, int status,
+static int bleprph_gap_event(int event, int status,
struct ble_gap_conn_ctxt *ctxt, void *arg);
/**
@@ -107,11 +107,16 @@ static void
bleprph_print_conn_desc(struct ble_gap_conn_desc *desc)
{
BLEPRPH_LOG(INFO, "handle=%d peer_addr_type=%d peer_addr=",
- desc->conn_handle, desc->peer_addr_type);
+ desc->conn_handle,
+ desc->peer_addr_type);
bleprph_print_bytes(desc->peer_addr, 6);
- BLEPRPH_LOG(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d",
- desc->conn_itvl, desc->conn_latency,
- desc->supervision_timeout);
+ BLEPRPH_LOG(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
+ "encrypted=%d authenticated=%d",
+ desc->conn_itvl,
+ desc->conn_latency,
+ desc->supervision_timeout,
+ desc->sec_state.enc_enabled,
+ desc->sec_state.authenticated);
}
/**
@@ -138,19 +143,42 @@ bleprph_advertise(void)
/* Begin advertising. */
rc = ble_gap_adv_start(BLE_GAP_DISC_MODE_GEN, BLE_GAP_CONN_MODE_UND,
- NULL, 0, NULL, bleprph_on_connect, NULL);
+ NULL, 0, NULL, bleprph_gap_event, NULL);
if (rc != 0) {
BLEPRPH_LOG(ERROR, "error enabling advertisement; rc=%d\n", rc);
return;
}
}
+/**
+ * The nimble host executes this callback when a GAP event occurs. The
+ * application associates a GAP event callback with each connection that forms.
+ * bleprph uses the same callback for all connections.
+ *
+ * @param event The type of event being signalled.
+ * @param status The error code associated with the event
+ * (0 = success).
+ * @param ctxt Various information pertaining to the event.
+ * @param arg Application-specified argument; unuesd by
+ * bleprph.
+ *
+ * @return 0 if the application successfully handled the
+ * event; nonzero on failure. The semantics
+ * of the return code is specific to the
+ * particular GAP event being signalled.
+ */
static int
-bleprph_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
- void *arg)
+bleprph_gap_event(int event, int status, struct ble_gap_conn_ctxt *ctxt,
+ void *arg)
{
+ int authenticated;
+ int rc;
+
switch (event) {
case BLE_GAP_EVENT_CONN:
+ /* A new connection has been established or an existing one has been
+ * terminated.
+ */
BLEPRPH_LOG(INFO, "connection %s; status=%d ",
status == 0 ? "up" : "down", status);
bleprph_print_conn_desc(ctxt->desc);
@@ -160,18 +188,69 @@ bleprph_on_connect(int event, int status, struct ble_gap_conn_ctxt *ctxt,
/* Connection terminated; resume advertising. */
bleprph_advertise();
}
- break;
+ return 0;
case BLE_GAP_EVENT_CONN_UPDATED:
+ /* The central has updated the connection parameters. */
BLEPRPH_LOG(INFO, "connection updated; status=%d ", status);
bleprph_print_conn_desc(ctxt->desc);
BLEPRPH_LOG(INFO, "\n");
- break;
+ return 0;
+
+ case BLE_GAP_EVENT_LTK_REQUEST:
+ /* An encryption procedure (bonding) is being attempted. The nimble
+ * stack is asking us to look in our key database for a long-term key
+ * corresponding to the specified ediv and random number.
+ */
+ BLEPRPH_LOG(INFO, "looking up ltk with ediv=0x%02x rand=0x%llx\n",
+ ctxt->ltk_params->ediv, ctxt->ltk_params->rand_num);
+
+ /* Perform a key lookup and populate the context object with the
+ * result. The nimble stack will use this key if this function returns
+ * success.
+ */
+ rc = keystore_lookup(ctxt->ltk_params->ediv,
+ ctxt->ltk_params->rand_num, ctxt->ltk_params->ltk,
+ &authenticated);
+ if (rc == 0) {
+ ctxt->ltk_params->authenticated = authenticated;
+ BLEPRPH_LOG(INFO, "ltk=");
+ bleprph_print_bytes(ctxt->ltk_params->ltk,
+ sizeof ctxt->ltk_params->ltk);
+ BLEPRPH_LOG(INFO, " authenticated=%d\n", authenticated);
+ } else {
+ BLEPRPH_LOG(INFO, "no matching ltk\n");
+ }
+
+ /* Indicate whether we were able to find an appropriate key. */
+ return rc;
+
+ case BLE_GAP_EVENT_KEY_EXCHANGE:
+ /* The central is sending us key information or vice-versa. If the
+ * central is doing the sending, save the long-term key in the in-RAM
+ * database. This permits bonding to occur on subsequent connections
+ * with this peer (as long as bleprph isn't restarted!).
+ */
+ if (ctxt->key_params->is_ours &&
+ ctxt->key_params->ltk_valid &&
+ ctxt->key_params->ediv_rand_valid) {
+
+ rc = keystore_add(ctxt->key_params->ediv,
+ ctxt->key_params->rand_val,
+ ctxt->key_params->ltk,
+ ctxt->desc->sec_state.authenticated);
+ if (rc != 0) {
+ BLEPRPH_LOG(INFO, "error persisting LTK; status=%d\n", rc);
+ }
+ }
+ return 0;
- case BLE_GAP_EVENT_CONN_UPDATE_REQ:
- BLEPRPH_LOG(INFO, "connection update request; status=%d ", status);
- *ctxt->update.self_params = *ctxt->update.peer_params;
- break;
+ case BLE_GAP_EVENT_SECURITY:
+ /* Encryption has been enabled or disabled for this connection. */
+ BLEPRPH_LOG(INFO, "security event; status=%d ", status);
+ bleprph_print_conn_desc(ctxt->desc);
+ BLEPRPH_LOG(INFO, "\n");
+ return 0;
}
return 0;
@@ -243,8 +322,8 @@ main(void)
srand(seed);
/* Initialize msys mbufs. */
- rc = os_mempool_init(&bleprph_mbuf_mpool, MBUF_NUM_MBUFS,
- MBUF_MEMBLOCK_SIZE, bleprph_mbuf_mpool_data,
+ rc = os_mempool_init(&bleprph_mbuf_mpool, MBUF_NUM_MBUFS,
+ MBUF_MEMBLOCK_SIZE, bleprph_mbuf_mpool_data,
"bleprph_mbuf_data");
assert(rc == 0);
@@ -272,12 +351,15 @@ main(void)
cfg = ble_hs_cfg_dflt;
cfg.max_hci_bufs = 3;
cfg.max_connections = 1;
- cfg.max_attrs = 32;
- cfg.max_services = 4;
+ cfg.max_attrs = 42;
+ cfg.max_services = 5;
cfg.max_client_configs = 6;
cfg.max_gattc_procs = 2;
cfg.max_l2cap_chans = 3;
- cfg.max_l2cap_sig_procs = 2;
+ cfg.max_l2cap_sig_procs = 1;
+ cfg.sm_bonding = 1;
+ cfg.sm_our_key_dist = BLE_L2CAP_SM_PAIR_KEY_DIST_ENC;
+ cfg.sm_their_key_dist = BLE_L2CAP_SM_PAIR_KEY_DIST_ENC;
/* Initialize eventq */
os_eventq_init(&bleprph_evq);