From: Brian Gix <brian.gix@intel.com>
To: linux-bluetooth@vger.kernel.org
Cc: inga.stotland@intel.com, michal.lowas-rzechonek@silvair.com,
brian.gix@intel.com
Subject: [PATCH BlueZ 6/8] mesh: Fix implementation of Provisioner Initiator
Date: Wed, 10 Jul 2019 16:07:55 -0700 [thread overview]
Message-ID: <20190710230757.8425-7-brian.gix@intel.com> (raw)
In-Reply-To: <20190710230757.8425-1-brian.gix@intel.com>
This has had testing of baseline functionality that includes
OOB authentication type "3c" from BT Mesh v1.0 specification
---
mesh/prov-acceptor.c | 2 +-
mesh/prov-initiator.c | 253 ++++++++++++++++++++++++++++++++++++++------------
mesh/provision.h | 10 +-
3 files changed, 205 insertions(+), 60 deletions(-)
diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c
index 7b79fa916..111340db3 100644
--- a/mesh/prov-acceptor.c
+++ b/mesh/prov-acceptor.c
@@ -651,7 +651,7 @@ bool acceptor_start(uint8_t num_ele, uint8_t uuid[16],
goto error_fail;
/* Always register for PB-ADV */
- result = pb_adv_reg(acp_prov_open, acp_prov_close, acp_prov_rx,
+ result = pb_adv_reg(false, acp_prov_open, acp_prov_close, acp_prov_rx,
acp_prov_ack, uuid, prov);
if (result)
diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
index f147c7ad8..13fd6d086 100644
--- a/mesh/prov-initiator.c
+++ b/mesh/prov-initiator.c
@@ -29,6 +29,8 @@
#include "mesh/util.h"
#include "mesh/crypto.h"
#include "mesh/net.h"
+#include "mesh/node.h"
+#include "mesh/keyring.h"
#include "mesh/prov.h"
#include "mesh/provision.h"
#include "mesh/pb-adv.h"
@@ -76,14 +78,18 @@ enum int_state {
struct mesh_prov_initiator {
mesh_prov_initiator_complete_func_t cmplt;
+ mesh_prov_initiator_data_req_func_t get_prov_data;
prov_trans_tx_t trans_tx;
void *agent;
void *caller_data;
void *trans_data;
+ struct mesh_node *node;
struct l_timeout *timeout;
uint32_t to_secs;
enum int_state state;
enum trans_type transport;
+ uint16_t net_idx;
+ uint16_t unicast;
uint8_t material;
uint8_t expected;
int8_t previous;
@@ -102,7 +108,6 @@ static struct mesh_prov_initiator *prov = NULL;
static void initiator_free(void)
{
-
if (prov)
l_timeout_remove(prov->timeout);
@@ -116,7 +121,34 @@ static void initiator_free(void)
static void int_prov_close(void *user_data, uint8_t reason)
{
- /* TODO: Handle Close */
+ struct mesh_prov_initiator *prov = user_data;
+ struct mesh_prov_node_info info;
+
+ if (reason != PROV_ERR_SUCCESS) {
+ prov->cmplt(prov->caller_data, reason, NULL);
+ initiator_free();
+ return;
+ }
+
+ memcpy(info.device_key, prov->calc_key, 16);
+ info.net_index = prov->net_idx;
+ info.unicast = prov->unicast;
+ info.cnt = prov->conf_inputs.caps.num_ele;
+
+ prov->cmplt(prov->caller_data, PROV_ERR_SUCCESS, &info);
+ initiator_free();
+}
+
+static void swap_u256_bytes(uint8_t *u256)
+{
+ int i;
+
+ /* End-to-End byte reflection of 32 octet buffer */
+ for (i = 0; i < 16; i++) {
+ u256[i] ^= u256[31 - i];
+ u256[31 - i] ^= u256[i];
+ u256[i] ^= u256[31 - i];
+ }
}
static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
@@ -140,6 +172,8 @@ static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
/* Always use an ephemeral key when Initiator */
ecc_make_key(prov->conf_inputs.prv_pub_key, prov->private_key);
+ swap_u256_bytes(prov->conf_inputs.prv_pub_key);
+ swap_u256_bytes(prov->conf_inputs.prv_pub_key + 32);
prov->material |= MAT_LOCAL_PRIVATE;
prov->trans_tx = trans_tx;
@@ -152,18 +186,6 @@ static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
return;
}
-static void swap_u256_bytes(uint8_t *u256)
-{
- int i;
-
- /* End-to-End byte reflection of 32 octet buffer */
- for (i = 0; i < 16; i++) {
- u256[i] ^= u256[31 - i];
- u256[31 - i] ^= u256[i];
- u256[i] ^= u256[31 - i];
- }
-}
-
static void prov_calc_secret(const uint8_t *pub, const uint8_t *priv,
uint8_t *secret)
{
@@ -241,7 +263,6 @@ static void calc_local_material(const uint8_t *random)
print_packet("SessionKey", prov->s_key, sizeof(prov->s_key));
print_packet("Nonce", prov->s_nonce, sizeof(prov->s_nonce));
- print_packet("RandomDevice", prov->rand_auth_workspace, 16);
}
static void number_cb(void *user_data, int err, uint32_t number)
@@ -307,6 +328,108 @@ static void pub_key_cb(void *user_data, int err, uint8_t *key, uint32_t len)
int_credentials(prov);
}
+static void send_pub_key(struct mesh_prov_initiator *prov)
+{
+ uint8_t out[65];
+
+ out[0] = PROV_PUB_KEY;
+ memcpy(out + 1, prov->conf_inputs.prv_pub_key, 64);
+ prov->trans_tx(prov->trans_data, out, 65);
+ prov->state = INT_PROV_KEY_SENT;
+}
+
+static void send_confirm(struct mesh_prov_initiator *prov)
+{
+ uint8_t out[17];
+
+ out[0] = PROV_CONFIRM;
+ mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
+ 32, out + 1);
+ prov->trans_tx(prov->trans_data, out, 17);
+ prov->state = INT_PROV_CONF_SENT;
+ prov->expected = PROV_CONFIRM;
+}
+
+static void send_random(struct mesh_prov_initiator *prov)
+{
+ uint8_t out[17];
+
+ out[0] = PROV_RANDOM;
+ memcpy(out + 1, prov->rand_auth_workspace, 16);
+ prov->trans_tx(prov->trans_data, out, 17);
+ prov->state = INT_PROV_RAND_SENT;
+ prov->expected = PROV_RANDOM;
+}
+
+void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data)
+{
+ struct keyring_net_key key;
+ struct mesh_net *net;
+ uint64_t mic;
+ uint32_t iv_index;
+ uint8_t snb_flags;
+ uint8_t out[34];
+
+ if (!prov || caller_data != prov->caller_data)
+ return;
+
+ if (prov->state != INT_PROV_RAND_ACKED)
+ return;
+
+ net = node_get_net(prov->node);
+ prov->expected = PROV_COMPLETE;
+
+ /* Calculate remote device key */
+ mesh_crypto_device_key(prov->secret,
+ prov->salt,
+ prov->calc_key);
+
+ print_packet("DevKey", prov->calc_key, 16);
+
+ /* Fill Prov Data Structure */
+ if (!keyring_get_net_key(prov->node, net_idx, &key)) {
+ out[1] = PROV_ERR_UNEXPECTED_ERR;
+ goto failure;
+ }
+
+ prov->unicast = primary;
+ prov->net_idx = net_idx;
+ mesh_net_get_snb_state(net, &snb_flags, &iv_index);
+
+ out[0] = PROV_DATA;
+
+ if (key.phase == KEY_REFRESH_PHASE_TWO) {
+ memcpy(out + 1, key.new_key, 16);
+ snb_flags |= PROV_FLAG_KR;
+ } else
+ memcpy(out + 1, key.old_key, 16);
+
+ l_put_be16(net_idx, out + 1 + 16);
+ l_put_u8(snb_flags, out + 1 + 16 + 2);
+ l_put_be32(iv_index, out + 1 + 16 + 2 + 1);
+ l_put_be16(primary, out + 1 + 16 + 2 + 1 + 4);
+
+ print_packet("ProvData", out + 1, 25);
+ /* Encrypt Prov Data */
+ mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
+ NULL, 0,
+ out + 1,
+ 25,
+ out + 1,
+ &mic, sizeof(mic));
+ print_packet("EncData", out + 1, 25 + 8);
+ prov->trans_tx(prov->trans_data, out, 34);
+ prov->state = INT_PROV_DATA_SENT;
+ return;
+
+failure:
+ l_debug("Failing... %d", out[1]);
+ out[0] = PROV_FAILED;
+ prov->trans_tx(prov->trans_data, out, 2);
+ /* TODO: Call Complete Callback (Fail)*/
+}
+
+
static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
{
struct mesh_prov_initiator *rx_prov = user_data;
@@ -314,7 +437,6 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
uint8_t type = *data++;
uint8_t fail_code[2];
uint32_t oob_key;
- uint64_t mic;
if (rx_prov != prov || !prov->trans_tx)
return;
@@ -425,8 +547,7 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
int_credentials(prov);
prov->state = INT_PROV_KEY_ACKED;
- prov->expected = PROV_CONFIRM;
-
+ l_debug("auth_method: %d", prov->conf_inputs.start.auth_method);
memset(prov->rand_auth_workspace + 16, 0, 32);
switch (prov->conf_inputs.start.auth_method) {
default:
@@ -464,7 +585,6 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
break;
-
case 3:
/* Auth Type 3b - input OOB */
l_getrandom(&oob_key, sizeof(oob_key));
@@ -492,19 +612,16 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
break;
-
}
+
+ if (prov->material & MAT_RAND_AUTH)
+ send_confirm(prov);
+
break;
case PROV_INP_CMPLT: /* Provisioning Input Complete */
/* TODO: Cancel Agent prompt */
- prov->expected = PROV_CONFIRM;
- out = l_malloc(17);
- out[0] = PROV_CONFIRM;
- mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
- 32, out + 1);
- prov->trans_tx(prov->trans_data, out, 17);
- l_free(out);
+ send_confirm(prov);
break;
case PROV_CONFIRM: /* Confirmation */
@@ -512,58 +629,46 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
/* RXed Device Confirmation */
memcpy(prov->confirm, data, 16);
print_packet("ConfirmationDevice", prov->confirm, 16);
- prov->expected = PROV_RANDOM;
- out = l_malloc(17);
- out[0] = PROV_RANDOM;
- memcpy(out + 1, prov->rand_auth_workspace, 16);
- prov->trans_tx(prov->trans_data, out, 17);
- l_free(out);
+ send_random(prov);
break;
case PROV_RANDOM: /* Random */
prov->state = INT_PROV_RAND_ACKED;
/* RXed Device Confirmation */
+ calc_local_material(data);
memcpy(prov->rand_auth_workspace + 16, data, 16);
print_packet("RandomDevice", data, 16);
- calc_local_material(data);
mesh_crypto_aes_cmac(prov->calc_key,
prov->rand_auth_workspace + 16,
32, prov->rand_auth_workspace);
+ print_packet("Dev-Conf", prov->rand_auth_workspace, 16);
if (memcmp(prov->rand_auth_workspace, prov->confirm, 16)) {
- l_error("Provisioning Failed-Confirm compare)");
+ l_error("Provisioning Failed-Confirm compare");
fail_code[1] = PROV_ERR_CONFIRM_FAILED;
goto failure;
}
- if (prov->state == INT_PROV_RAND_ACKED) {
- prov->expected = PROV_COMPLETE;
- out = l_malloc(34);
- out[0] = PROV_DATA;
- /* TODO: Fill Prov Data Structure */
- /* Encrypt Prov Data */
- mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
- NULL, 0,
- out + 1,
- 25,
- out + 1,
- &mic, sizeof(mic));
- prov->trans_tx(prov->trans_data, out, 34);
- l_free(out);
+ if (!prov->get_prov_data(prov->caller_data,
+ prov->conf_inputs.caps.num_ele)) {
+ l_error("Provisioning Failed-Data Get");
+ fail_code[1] = PROV_ERR_CANT_ASSIGN_ADDR;
+ goto failure;
}
break;
case PROV_COMPLETE: /* Complete */
l_info("Provisioning Complete");
prov->state = INT_PROV_IDLE;
- //mesh_prov_close(prov, 0);
+ int_prov_close(prov, PROV_ERR_SUCCESS);
break;
case PROV_FAILED: /* Failed */
l_error("Provisioning Failed (reason: %d)", data[0]);
- //mesh_prov_close(prov, data[0]);
+ prov->state = INT_PROV_IDLE;
+ int_prov_close(prov, data[0]);
break;
default:
@@ -572,20 +677,51 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
goto failure;
}
- prov->previous = type;
+ if (prov)
+ prov->previous = type;
+
return;
failure:
+ l_debug("Failing... %d", fail_code[1]);
fail_code[0] = PROV_FAILED;
prov->trans_tx(prov->trans_data, fail_code, 2);
- /* TODO: Call Complete Callback (Fail)*/
+ int_prov_close(prov, fail_code[1]);
}
static void int_prov_ack(void *user_data, uint8_t msg_num)
{
- /* TODO: Handle PB-ADV Ack */
-}
+ struct mesh_prov_initiator *rx_prov = user_data;
+ if (rx_prov != prov || !prov->trans_tx)
+ return;
+
+ switch(prov->state) {
+ case INT_PROV_START_SENT:
+ prov->state = INT_PROV_START_ACKED;
+ if (prov->conf_inputs.caps.pub_type == 0)
+ send_pub_key(prov);
+ break;
+
+ case INT_PROV_DATA_SENT:
+ prov->state = INT_PROV_DATA_ACKED;
+ break;
+
+ case INT_PROV_IDLE:
+ case INT_PROV_INVITE_SENT:
+ case INT_PROV_INVITE_ACKED:
+ case INT_PROV_START_ACKED:
+ case INT_PROV_KEY_SENT:
+ case INT_PROV_KEY_ACKED:
+ case INT_PROV_CONF_SENT:
+ case INT_PROV_CONF_ACKED:
+ case INT_PROV_RAND_SENT:
+ case INT_PROV_RAND_ACKED:
+ case INT_PROV_DATA_ACKED:
+ default:
+ break;
+ }
+}
bool initiator_start(enum trans_type transport,
uint8_t uuid[16],
@@ -593,8 +729,9 @@ bool initiator_start(enum trans_type transport,
uint16_t server, /* Only valid for PB-Remote */
uint32_t timeout, /* in seconds from mesh.conf */
struct mesh_agent *agent,
+ mesh_prov_initiator_data_req_func_t get_prov_data,
mesh_prov_initiator_complete_func_t complete_cb,
- void *caller_data)
+ void *node, void *caller_data)
{
bool result;
@@ -607,13 +744,15 @@ bool initiator_start(enum trans_type transport,
prov = l_new(struct mesh_prov_initiator, 1);
prov->to_secs = timeout;
+ prov->node = node;
prov->agent = agent;
prov->cmplt = complete_cb;
+ prov->get_prov_data = get_prov_data;
prov->caller_data = caller_data;
prov->previous = -1;
/* Always register for PB-ADV */
- result = pb_adv_reg(int_prov_open, int_prov_close, int_prov_rx,
+ result = pb_adv_reg(true, int_prov_open, int_prov_close, int_prov_rx,
int_prov_ack, uuid, prov);
if (result)
diff --git a/mesh/provision.h b/mesh/provision.h
index 6b61a45be..6670de20c 100644
--- a/mesh/provision.h
+++ b/mesh/provision.h
@@ -90,6 +90,7 @@ struct mesh_prov_node_info {
uint32_t iv_index;
uint16_t unicast;
uint16_t net_index;
+ uint8_t cnt;
uint8_t net_key[16];
uint8_t device_key[16];
uint8_t flags; /* IVU and KR bits */
@@ -99,6 +100,9 @@ typedef bool (*mesh_prov_acceptor_complete_func_t)(void *user_data,
uint8_t status,
struct mesh_prov_node_info *info);
+typedef bool (*mesh_prov_initiator_data_req_func_t)(void *user_data,
+ uint8_t num_elem);
+
typedef bool (*mesh_prov_initiator_complete_func_t)(void *user_data,
uint8_t status,
struct mesh_prov_node_info *info);
@@ -117,6 +121,8 @@ bool initiator_start(enum trans_type transport,
uint16_t server, /* Only valid for PB-Remote */
uint32_t timeout, /* in seconds from mesh.conf */
struct mesh_agent *agent,
+ mesh_prov_initiator_data_req_func_t get_prov_data,
mesh_prov_initiator_complete_func_t complete_cb,
- void *caller_data);
-void initiator_cancel(void *user_data);
+ void *node, void *caller_data);
+void initiator_prov_data(uint16_t net_idx, uint16_t primary, void *caller_data);
+void initiator_cancel(void *caller_data);
--
2.14.5
next prev parent reply other threads:[~2019-07-10 23:08 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-07-10 23:07 [PATCH BlueZ 0/8] mesh: Provisioner Initiator added Brian Gix
2019-07-10 23:07 ` [PATCH BlueZ 1/8] doc: Cleanup API Provisioner1 interface Brian Gix
2019-07-10 23:07 ` [PATCH BlueZ 2/8] mesh: Fix support for Provisioner Initiator Brian Gix
2019-07-11 7:10 ` Michał Lowas-Rzechonek
2019-07-10 23:07 ` [PATCH BlueZ 3/8] mesh: Add special Beacon handler for Provisioning Brian Gix
2019-07-10 23:07 ` [PATCH BlueZ 4/8] mesh: Expose mapping function for D-Bus errors Brian Gix
2019-07-10 23:07 ` [PATCH BlueZ 5/8] mesh: Expose resources needed by Management1 interface Brian Gix
2019-07-10 23:07 ` Brian Gix [this message]
2019-07-11 7:33 ` [PATCH BlueZ 6/8] mesh: Fix implementation of Provisioner Initiator Michał Lowas-Rzechonek
2019-07-11 15:48 ` Gix, Brian
2019-07-10 23:07 ` [PATCH BlueZ 7/8] mesh: Implement DBus Provisioning methods Brian Gix
2019-07-10 23:07 ` [PATCH BlueZ 8/8] test: This extends the mesh tool to exercise " Brian Gix
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190710230757.8425-7-brian.gix@intel.com \
--to=brian.gix@intel.com \
--cc=inga.stotland@intel.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=michal.lowas-rzechonek@silvair.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).