/*
|
* 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.
|
*/
|
|
#include <stddef.h>
|
#include <string.h>
|
#include <errno.h>
|
#include "testutil/testutil.h"
|
#include "nimble/hci_common.h"
|
#include "nimble/nimble_opt.h"
|
#include "host/ble_sm.h"
|
#include "ble_hs_test.h"
|
#include "host/ble_hs_id.h"
|
#include "ble_hs_test_util.h"
|
#include "ble_sm_test_util.h"
|
|
#define BLE_HCI_LT_KEY_REQ_REPLY_LEN (18)
|
#define BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN (2)
|
#define BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN (2) /* No status byte. */
|
#define BLE_HCI_LT_KEY_REQ_NEG_REPLY_ACK_PARAM_LEN (2)
|
#define BLE_HCI_LE_START_ENCRYPT_LEN (28)
|
#define BLE_HCI_ADD_TO_RESOLV_LIST_LEN (39)
|
|
int ble_sm_test_gap_event_type;
|
int ble_sm_test_gap_status;
|
struct ble_gap_sec_state ble_sm_test_sec_state;
|
static struct ble_gap_passkey_params ble_sm_test_ioact;
|
|
static struct {
|
/** Handle reported in previous repeat pairing event. */
|
struct ble_gap_repeat_pairing rp;
|
|
struct ble_sm_test_params params;
|
|
/** What the callback should return this time. */
|
int rc;
|
|
/** What the callback should return next time. */
|
int next_rc;
|
|
/**
|
* Whether the callback should erase the conflicting entry before retrying.
|
*/
|
int erase_on_retry;
|
|
/** The number of times the event got reported. */
|
int num_calls;
|
} ble_sm_test_repeat_pairing;
|
|
struct ble_sm_test_util_entity {
|
uint8_t addr_type;
|
uint8_t id_addr_type;
|
uint8_t *id_addr;
|
uint8_t *rpa;
|
|
struct ble_sm_pair_cmd *pair_cmd;
|
struct ble_sm_pair_confirm *confirms;
|
struct ble_sm_pair_random *randoms;
|
struct ble_sm_id_info *id_info;
|
struct ble_sm_id_addr_info *id_addr_info;
|
struct ble_sm_sign_info *sign_info;
|
uint8_t *ltk;
|
|
uint8_t key_dist;
|
|
/*** Secure connections fields. */
|
struct ble_sm_public_key *public_key;
|
struct ble_sm_dhkey_check *dhkey_check;
|
|
/*** Legacy fields. */
|
struct ble_sm_enc_info *enc_info;
|
struct ble_sm_master_id *master_id;
|
uint64_t rand_num;
|
uint16_t ediv;
|
};
|
|
static void ble_sm_test_util_repeat_pairing(struct ble_sm_test_params *params,
|
int sc);
|
|
#define BLE_SM_TEST_UTIL_HCI_HDR(handle, pb, len) \
|
((struct hci_data_hdr) { \
|
.hdh_handle_pb_bc = ((handle) << 0) | \
|
((pb) << 12), \
|
.hdh_len = (len) \
|
})
|
|
static void
|
ble_sm_pair_cmd_parse(void *payload, int len, struct ble_sm_pair_cmd *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_cmd));
|
|
u8ptr = payload;
|
cmd->io_cap = u8ptr[0];
|
cmd->oob_data_flag = u8ptr[1];
|
cmd->authreq = u8ptr[2];
|
cmd->max_enc_key_size = u8ptr[3];
|
cmd->init_key_dist = u8ptr[4];
|
cmd->resp_key_dist = u8ptr[5];
|
}
|
|
static void
|
ble_sm_pair_cmd_write(void *payload, int len, int is_req,
|
struct ble_sm_pair_cmd *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_cmd));
|
|
u8ptr = payload;
|
u8ptr[0] = is_req ? BLE_SM_OP_PAIR_REQ : BLE_SM_OP_PAIR_RSP;
|
u8ptr[1] = cmd->io_cap;
|
u8ptr[2] = cmd->oob_data_flag;
|
u8ptr[3] = cmd->authreq;
|
u8ptr[4] = cmd->max_enc_key_size;
|
u8ptr[5] = cmd->init_key_dist;
|
u8ptr[6] = cmd->resp_key_dist;
|
}
|
|
static void
|
ble_sm_pair_confirm_parse(void *payload, int len,
|
struct ble_sm_pair_confirm *cmd)
|
{
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_confirm));
|
memcpy(cmd->value, payload, sizeof cmd->value);
|
}
|
|
static void
|
ble_sm_pair_confirm_write(void *payload, int len,
|
struct ble_sm_pair_confirm *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_confirm));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_PAIR_CONFIRM;
|
memcpy(u8ptr + sizeof(struct ble_sm_hdr), cmd->value, sizeof cmd->value);
|
}
|
|
static void
|
ble_sm_pair_random_parse(void *payload, int len,
|
struct ble_sm_pair_random *cmd)
|
{
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_random));
|
memcpy(cmd->value, payload, sizeof cmd->value);
|
}
|
|
static void
|
ble_sm_pair_random_write(void *payload, int len,
|
struct ble_sm_pair_random *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_random));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_PAIR_RANDOM;
|
memcpy(u8ptr + sizeof(struct ble_sm_hdr), cmd->value, sizeof cmd->value);
|
}
|
|
static void
|
ble_sm_pair_fail_parse(void *payload, int len, struct ble_sm_pair_fail *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_pair_fail));
|
|
u8ptr = payload;
|
cmd->reason = u8ptr[0];
|
}
|
|
static void
|
ble_sm_enc_info_parse(void *payload, int len, struct ble_sm_enc_info *cmd)
|
{
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_enc_info));
|
|
memcpy(cmd->ltk, payload, sizeof cmd->ltk);
|
}
|
|
static void
|
ble_sm_enc_info_write(void *payload, int len, struct ble_sm_enc_info *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_enc_info));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_ENC_INFO;
|
memcpy(u8ptr + 1, cmd->ltk, sizeof cmd->ltk);
|
}
|
|
static void
|
ble_sm_master_id_parse(void *payload, int len, struct ble_sm_master_id *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_master_id));
|
|
u8ptr = payload;
|
|
cmd->ediv = get_le16(u8ptr);
|
cmd->rand_val = get_le64(u8ptr + 2);
|
}
|
|
static void
|
ble_sm_master_id_write(void *payload, int len, struct ble_sm_master_id *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_master_id));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_MASTER_ID;
|
put_le16(u8ptr + 1, cmd->ediv);
|
put_le64(u8ptr + 3, cmd->rand_val);
|
}
|
|
static void
|
ble_sm_id_info_parse(void *payload, int len, struct ble_sm_id_info *cmd)
|
{
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_id_info));
|
|
memcpy(cmd->irk, payload, 16);
|
}
|
|
static void
|
ble_sm_id_info_write(void *payload, int len, struct ble_sm_id_info *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_info));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_IDENTITY_INFO;
|
memcpy(u8ptr + sizeof(struct ble_sm_hdr), cmd->irk, sizeof cmd->irk);
|
}
|
|
static void
|
ble_sm_id_addr_info_parse(void *payload, int len,
|
struct ble_sm_id_addr_info *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_id_addr_info));
|
|
u8ptr = payload;
|
|
cmd->addr_type = *u8ptr;
|
memcpy(cmd->bd_addr, u8ptr + 1, 6);
|
}
|
|
static void
|
ble_sm_id_addr_info_write(void *payload, int len,
|
struct ble_sm_id_addr_info *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_addr_info));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_IDENTITY_ADDR_INFO;
|
u8ptr[1] = cmd->addr_type;
|
memcpy(u8ptr + 2, cmd->bd_addr, sizeof cmd->bd_addr);
|
}
|
|
static void
|
ble_sm_sign_info_parse(void *payload, int len, struct ble_sm_sign_info *cmd)
|
{
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_sign_info));
|
|
memcpy(cmd->sig_key, payload, 16);
|
}
|
|
static void
|
ble_sm_sign_info_write(void *payload, int len, struct ble_sm_sign_info *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sign_info));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_SIGN_INFO;
|
memcpy(u8ptr + sizeof(struct ble_sm_hdr),
|
cmd->sig_key, sizeof cmd->sig_key);
|
}
|
|
static void
|
ble_sm_sec_req_parse(void *payload, int len, struct ble_sm_sec_req *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_sec_req));
|
|
u8ptr = payload;
|
cmd->authreq = *u8ptr;
|
}
|
|
static void
|
ble_sm_sec_req_write(void *payload, int len, struct ble_sm_sec_req *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sec_req));
|
|
u8ptr = payload;
|
|
u8ptr[0] = BLE_SM_OP_SEC_REQ;
|
u8ptr[1] = cmd->authreq;
|
}
|
|
static void
|
ble_sm_public_key_parse(void *payload, int len, struct ble_sm_public_key *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_public_key));
|
|
u8ptr = payload;
|
|
memcpy(cmd->x, u8ptr, sizeof cmd->x);
|
u8ptr += sizeof cmd->x;
|
|
memcpy(cmd->y, u8ptr, sizeof cmd->y);
|
u8ptr += sizeof cmd->y;
|
}
|
|
static void
|
ble_sm_public_key_write(void *payload, int len, struct ble_sm_public_key *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key));
|
|
u8ptr = payload;
|
|
*u8ptr = BLE_SM_OP_PAIR_PUBLIC_KEY;
|
u8ptr++;
|
|
memcpy(u8ptr, cmd->x, sizeof cmd->x);
|
memcpy(u8ptr + 32, cmd->y, sizeof cmd->y);
|
}
|
|
static void
|
ble_sm_dhkey_check_parse(void *payload, int len,
|
struct ble_sm_dhkey_check *cmd)
|
{
|
BLE_HS_DBG_ASSERT(len >= sizeof(struct ble_sm_dhkey_check));
|
|
memcpy(cmd->value, payload, sizeof cmd->value);
|
}
|
|
static void
|
ble_sm_dhkey_check_write(void *payload, int len,
|
struct ble_sm_dhkey_check *cmd)
|
{
|
uint8_t *u8ptr;
|
|
BLE_HS_DBG_ASSERT(
|
len >= sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_dhkey_check));
|
|
u8ptr = payload;
|
|
*u8ptr = BLE_SM_OP_PAIR_DHKEY_CHECK;
|
u8ptr++;
|
|
memcpy(u8ptr, cmd->value, sizeof cmd->value);
|
}
|
|
void
|
ble_sm_test_util_init(void)
|
{
|
ble_hs_test_util_init();
|
|
ble_sm_test_gap_event_type = -1;
|
ble_sm_test_gap_status = -1;
|
memset(&ble_sm_test_repeat_pairing, 0, sizeof ble_sm_test_repeat_pairing);
|
ble_sm_test_repeat_pairing.rp.conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
|
memset(&ble_sm_test_ioact, 0, sizeof ble_sm_test_ioact);
|
memset(&ble_sm_test_sec_state, 0xff, sizeof ble_sm_test_sec_state);
|
}
|
|
static void
|
ble_sm_test_util_params_to_entity(struct ble_sm_test_params *params,
|
int initiator,
|
struct ble_sm_test_util_entity *out_entity)
|
{
|
int sc;
|
|
memset(out_entity, 0, sizeof *out_entity);
|
|
sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC &&
|
params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC;
|
|
if (initiator) {
|
out_entity->key_dist = params->pair_rsp.init_key_dist;
|
|
out_entity->addr_type = params->init_addr_type;
|
out_entity->id_addr = params->init_id_addr;
|
out_entity->rpa = params->init_rpa;
|
|
out_entity->pair_cmd = ¶ms->pair_req;
|
out_entity->confirms = params->confirm_req;
|
out_entity->randoms = params->random_req;
|
out_entity->id_info = ¶ms->id_info_rsp;
|
out_entity->id_addr_info = ¶ms->id_addr_info_rsp;
|
out_entity->sign_info = ¶ms->sign_info_rsp;
|
|
if (sc) {
|
out_entity->ltk = params->ltk;
|
out_entity->public_key = ¶ms->public_key_req;
|
out_entity->dhkey_check = ¶ms->dhkey_check_req;
|
} else {
|
out_entity->enc_info = ¶ms->enc_info_rsp;
|
out_entity->master_id = ¶ms->master_id_rsp;
|
if (out_entity->key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
|
out_entity->rand_num = params->master_id_rsp.rand_val;
|
out_entity->ediv = params->master_id_rsp.ediv;
|
out_entity->ltk = params->enc_info_rsp.ltk;
|
}
|
}
|
} else {
|
out_entity->key_dist = params->pair_rsp.resp_key_dist;
|
|
out_entity->addr_type = params->resp_addr_type;
|
out_entity->id_addr = params->resp_id_addr;
|
out_entity->rpa = params->resp_rpa;
|
|
out_entity->pair_cmd = ¶ms->pair_rsp;
|
out_entity->confirms = params->confirm_rsp;
|
out_entity->randoms = params->random_rsp;
|
out_entity->id_info = ¶ms->id_info_req;
|
out_entity->id_addr_info = ¶ms->id_addr_info_req;
|
out_entity->sign_info = ¶ms->sign_info_req;
|
|
if (sc) {
|
out_entity->ltk = params->ltk;
|
out_entity->public_key = ¶ms->public_key_rsp;
|
out_entity->dhkey_check = ¶ms->dhkey_check_rsp;
|
} else {
|
out_entity->enc_info = ¶ms->enc_info_req;
|
out_entity->master_id = ¶ms->master_id_req;
|
if (out_entity->key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
|
out_entity->rand_num = params->master_id_req.rand_val;
|
out_entity->ediv = params->master_id_req.ediv;
|
out_entity->ltk = params->enc_info_req.ltk;
|
}
|
}
|
}
|
|
out_entity->id_addr_type =
|
ble_hs_misc_own_addr_type_to_id(out_entity->addr_type);
|
}
|
|
static void
|
ble_sm_test_util_params_to_entities(struct ble_sm_test_params *params,
|
int we_are_initiator,
|
struct ble_sm_test_util_entity *out_us,
|
struct ble_sm_test_util_entity *out_peer)
|
{
|
ble_sm_test_util_params_to_entity(params, we_are_initiator, out_us);
|
ble_sm_test_util_params_to_entity(params, !we_are_initiator, out_peer);
|
}
|
|
static void
|
ble_sm_test_util_init_good(struct ble_sm_test_params *params,
|
int we_are_initiator,
|
struct ble_hs_conn **out_conn,
|
struct ble_sm_test_util_entity *out_us,
|
struct ble_sm_test_util_entity *out_peer)
|
{
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init();
|
|
ble_sm_test_util_params_to_entities(params, we_are_initiator,
|
out_us, out_peer);
|
|
ble_hs_cfg.sm_io_cap = out_us->pair_cmd->io_cap;
|
ble_hs_cfg.sm_oob_data_flag = out_us->pair_cmd->oob_data_flag;
|
ble_hs_cfg.sm_bonding = !!(out_us->pair_cmd->authreq &
|
BLE_SM_PAIR_AUTHREQ_BOND);
|
ble_hs_cfg.sm_mitm = !!(out_us->pair_cmd->authreq &
|
BLE_SM_PAIR_AUTHREQ_MITM);
|
ble_hs_cfg.sm_sc = !!(out_us->pair_cmd->authreq &
|
BLE_SM_PAIR_AUTHREQ_SC);
|
ble_hs_cfg.sm_keypress = !!(out_us->pair_cmd->authreq &
|
BLE_SM_PAIR_AUTHREQ_KEYPRESS);
|
|
if (we_are_initiator) {
|
ble_hs_cfg.sm_our_key_dist = out_us->pair_cmd->init_key_dist;
|
ble_hs_cfg.sm_their_key_dist = out_us->pair_cmd->resp_key_dist;
|
} else {
|
ble_hs_cfg.sm_our_key_dist = out_us->pair_cmd->resp_key_dist;
|
ble_hs_cfg.sm_their_key_dist = out_us->pair_cmd->init_key_dist;
|
}
|
|
ble_hs_id_set_pub(out_us->id_addr);
|
ble_sm_dbg_set_next_pair_rand(out_us->randoms[0].value);
|
ble_sm_dbg_set_next_ediv(out_us->ediv);
|
ble_sm_dbg_set_next_master_id_rand(out_us->rand_num);
|
ble_sm_dbg_set_next_ltk(out_us->ltk);
|
ble_hs_test_util_set_our_irk(out_us->id_info->irk, 0, 0);
|
ble_sm_dbg_set_next_csrk(out_us->sign_info->sig_key);
|
|
if (out_us->public_key != NULL) {
|
ble_sm_dbg_set_sc_keys((uint8_t *)out_us->public_key,
|
params->our_priv_key);
|
}
|
|
ble_hs_test_util_create_rpa_conn(2, out_us->addr_type, out_us->rpa,
|
out_peer->addr_type,
|
out_peer->id_addr, out_peer->rpa,
|
BLE_HS_TEST_CONN_FEAT_ALL,
|
ble_sm_test_util_conn_cb,
|
NULL);
|
|
/* This test code and modifies the connection object after unlocking
|
* the host mutex. It is not OK for real code to do this, but this test
|
* can assume the connection list is unchanging.
|
*/
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
ble_hs_unlock();
|
|
if (!we_are_initiator) {
|
/* Peer is the initiator so we must be the slave. */
|
conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
|
}
|
|
if (out_conn != NULL) {
|
*out_conn = conn;
|
}
|
}
|
|
static int
|
ble_sm_test_util_repeat_pairing_cb(const struct ble_gap_repeat_pairing *rp)
|
{
|
struct ble_store_value_sec value_sec;
|
struct ble_store_key_sec key_sec;
|
struct ble_gap_conn_desc desc;
|
int rc;
|
|
TEST_ASSERT_FATAL(rp->conn_handle != BLE_HS_CONN_HANDLE_NONE);
|
|
ble_sm_test_repeat_pairing.num_calls++;
|
|
rc = ble_gap_conn_find(rp->conn_handle, &desc);
|
TEST_ASSERT_FATAL(rc == 0);
|
|
memset(&key_sec, 0, sizeof key_sec);
|
key_sec.peer_addr = desc.peer_id_addr;
|
rc = ble_store_read_peer_sec(&key_sec, &value_sec);
|
TEST_ASSERT_FATAL(rc == 0);
|
|
/* Verify current bond is reported correctly. */
|
TEST_ASSERT(rp->cur_key_size == value_sec.key_size);
|
TEST_ASSERT(rp->cur_authenticated == value_sec.authenticated);
|
TEST_ASSERT(rp->cur_sc == value_sec.sc);
|
|
/* Verify new pairing request is reported correctly. */
|
TEST_ASSERT(
|
rp->new_key_size ==
|
min(ble_sm_test_repeat_pairing.params.pair_req.max_enc_key_size,
|
ble_sm_test_repeat_pairing.params.pair_rsp.max_enc_key_size));
|
TEST_ASSERT(
|
rp->new_authenticated ==
|
!!(ble_sm_test_repeat_pairing.params.passkey_info.passkey.action));
|
TEST_ASSERT(
|
rp->new_sc ==
|
((ble_sm_test_repeat_pairing.params.pair_req.authreq &
|
BLE_SM_PAIR_AUTHREQ_SC)
|
&&
|
(ble_sm_test_repeat_pairing.params.pair_rsp.authreq &
|
BLE_SM_PAIR_AUTHREQ_SC)));
|
TEST_ASSERT(
|
rp->new_bonding ==
|
((ble_sm_test_repeat_pairing.params.pair_req.authreq &
|
BLE_SM_PAIR_AUTHREQ_BOND)
|
&&
|
(ble_sm_test_repeat_pairing.params.pair_rsp.authreq &
|
BLE_SM_PAIR_AUTHREQ_BOND)));
|
|
if (ble_sm_test_repeat_pairing.rp.conn_handle ==
|
BLE_HS_CONN_HANDLE_NONE) {
|
|
ble_sm_test_repeat_pairing.rp.conn_handle = rp->conn_handle;
|
} else {
|
/* Ensure the correct connection handle gets reported each time. */
|
TEST_ASSERT(rp->conn_handle ==
|
ble_sm_test_repeat_pairing.rp.conn_handle);
|
}
|
|
ble_sm_test_repeat_pairing.rp = *rp;
|
|
if (ble_sm_test_repeat_pairing.rc == BLE_GAP_REPEAT_PAIRING_RETRY &&
|
ble_sm_test_repeat_pairing.erase_on_retry) {
|
|
rc = ble_gap_conn_find(rp->conn_handle, &desc);
|
TEST_ASSERT_FATAL(rc == 0);
|
|
rc = ble_store_util_delete_peer(&desc.peer_id_addr);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
rc = ble_sm_test_repeat_pairing.rc;
|
ble_sm_test_repeat_pairing.rc = ble_sm_test_repeat_pairing.next_rc;
|
|
return rc;
|
}
|
|
int
|
ble_sm_test_util_conn_cb(struct ble_gap_event *event, void *arg)
|
{
|
struct ble_gap_conn_desc desc;
|
int rc;
|
|
switch (event->type) {
|
case BLE_GAP_EVENT_ENC_CHANGE:
|
ble_sm_test_gap_status = event->enc_change.status;
|
|
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
|
TEST_ASSERT_FATAL(rc == 0);
|
ble_sm_test_sec_state = desc.sec_state;
|
rc = 0;
|
break;
|
|
case BLE_GAP_EVENT_PASSKEY_ACTION:
|
ble_sm_test_ioact = event->passkey.params;
|
rc = 0;
|
break;
|
|
case BLE_GAP_EVENT_REPEAT_PAIRING:
|
rc = ble_sm_test_util_repeat_pairing_cb(&event->repeat_pairing);
|
break;
|
|
default:
|
return 0;
|
}
|
|
ble_sm_test_gap_event_type = event->type;
|
return rc;
|
}
|
|
static void
|
ble_sm_test_util_rx_pair_cmd(uint16_t conn_handle, uint8_t op,
|
struct ble_sm_pair_cmd *cmd,
|
int rx_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ +
|
sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_cmd));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_cmd);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_pair_cmd_write(v, payload_len, op == BLE_SM_OP_PAIR_REQ, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT(rc == rx_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_pair_req(uint16_t conn_handle,
|
struct ble_sm_pair_cmd *req,
|
int rx_status)
|
{
|
ble_sm_test_util_rx_pair_cmd(conn_handle, BLE_SM_OP_PAIR_REQ,
|
req, rx_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_pair_rsp(uint16_t conn_handle, struct ble_sm_pair_cmd *rsp,
|
int rx_status)
|
{
|
ble_sm_test_util_rx_pair_cmd(conn_handle, BLE_SM_OP_PAIR_RSP,
|
rsp, rx_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_confirm(uint16_t conn_handle,
|
struct ble_sm_pair_confirm *cmd)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ +
|
sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_confirm));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len =
|
sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_confirm);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_pair_confirm_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
static void
|
ble_sm_test_util_rx_random(uint16_t conn_handle,
|
struct ble_sm_pair_random *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_random));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_pair_random);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_pair_random_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
void
|
ble_sm_test_util_rx_sec_req(uint16_t conn_handle, struct ble_sm_sec_req *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sec_req));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sec_req);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_sec_req_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_public_key(uint16_t conn_handle,
|
struct ble_sm_public_key *cmd)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_public_key_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
static void
|
ble_sm_test_util_rx_public_key_bad(uint16_t conn_handle,
|
struct ble_sm_public_key *cmd)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_public_key);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_public_key_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc != 0);
|
}
|
|
static void
|
ble_sm_test_util_rx_dhkey_check(uint16_t conn_handle,
|
struct ble_sm_dhkey_check *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_dhkey_check));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_dhkey_check);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_dhkey_check_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_enc_info(uint16_t conn_handle,
|
struct ble_sm_enc_info *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_enc_info));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_enc_info);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_enc_info_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_master_id(uint16_t conn_handle,
|
struct ble_sm_master_id *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_master_id));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_master_id);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_master_id_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_id_info(uint16_t conn_handle,
|
struct ble_sm_id_info *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_info));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_info);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_id_info_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_id_addr_info(uint16_t conn_handle,
|
struct ble_sm_id_addr_info *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_addr_info));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_id_addr_info);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_id_addr_info_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
static void
|
ble_sm_test_util_rx_sign_info(uint16_t conn_handle,
|
struct ble_sm_sign_info *cmd,
|
int exp_status)
|
{
|
struct hci_data_hdr hci_hdr;
|
struct os_mbuf *om;
|
void *v;
|
int payload_len;
|
int rc;
|
|
hci_hdr = BLE_SM_TEST_UTIL_HCI_HDR(
|
2, BLE_HCI_PB_FIRST_FLUSH,
|
BLE_L2CAP_HDR_SZ + sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sign_info));
|
|
om = ble_hs_mbuf_l2cap_pkt();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
payload_len = sizeof(struct ble_sm_hdr) + sizeof(struct ble_sm_sign_info);
|
|
v = os_mbuf_extend(om, payload_len);
|
TEST_ASSERT_FATAL(v != NULL);
|
|
ble_sm_sign_info_write(v, payload_len, cmd);
|
|
rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
|
&hci_hdr, om);
|
TEST_ASSERT_FATAL(rc == exp_status);
|
}
|
|
static struct os_mbuf *
|
ble_sm_test_util_verify_tx_hdr(uint8_t sm_op, uint16_t payload_len)
|
{
|
struct os_mbuf *om;
|
|
om = ble_hs_test_util_prev_tx_dequeue_pullup();
|
TEST_ASSERT_FATAL(om != NULL);
|
|
TEST_ASSERT(OS_MBUF_PKTLEN(om) == sizeof(struct ble_sm_hdr) + payload_len);
|
TEST_ASSERT_FATAL(om->om_data[0] == sm_op);
|
|
om->om_data += sizeof(struct ble_sm_hdr);
|
om->om_len -= sizeof(struct ble_sm_hdr);
|
|
return om;
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_pair_cmd(
|
uint8_t op,
|
struct ble_sm_pair_cmd *exp_cmd)
|
{
|
struct ble_sm_pair_cmd cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(op, sizeof(struct ble_sm_pair_cmd));
|
ble_sm_pair_cmd_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(cmd.io_cap == exp_cmd->io_cap);
|
TEST_ASSERT(cmd.oob_data_flag == exp_cmd->oob_data_flag);
|
TEST_ASSERT(cmd.authreq == exp_cmd->authreq);
|
TEST_ASSERT(cmd.max_enc_key_size == exp_cmd->max_enc_key_size);
|
TEST_ASSERT(cmd.init_key_dist == exp_cmd->init_key_dist);
|
TEST_ASSERT(cmd.resp_key_dist == exp_cmd->resp_key_dist);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_pair_req(
|
struct ble_sm_pair_cmd *exp_req)
|
{
|
ble_sm_test_util_verify_tx_pair_cmd(BLE_SM_OP_PAIR_REQ,
|
exp_req);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_pair_rsp(
|
struct ble_sm_pair_cmd *exp_rsp)
|
{
|
ble_sm_test_util_verify_tx_pair_cmd(BLE_SM_OP_PAIR_RSP,
|
exp_rsp);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_pair_confirm(
|
struct ble_sm_pair_confirm *exp_cmd)
|
{
|
struct ble_sm_pair_confirm cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_CONFIRM, sizeof(cmd));
|
ble_sm_pair_confirm_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(memcmp(cmd.value, exp_cmd->value, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_pair_random(
|
struct ble_sm_pair_random *exp_cmd)
|
{
|
struct ble_sm_pair_random cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_RANDOM,
|
sizeof(struct ble_sm_pair_random));
|
ble_sm_pair_random_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(memcmp(cmd.value, exp_cmd->value, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_public_key(
|
struct ble_sm_public_key *exp_cmd)
|
{
|
struct ble_sm_public_key cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_PUBLIC_KEY,
|
sizeof(struct ble_sm_public_key));
|
ble_sm_public_key_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(memcmp(cmd.x, exp_cmd->x, sizeof cmd.x) == 0);
|
TEST_ASSERT(memcmp(cmd.y, exp_cmd->y, sizeof cmd.y) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_dhkey_check(
|
struct ble_sm_dhkey_check *exp_cmd)
|
{
|
struct ble_sm_dhkey_check cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_DHKEY_CHECK,
|
sizeof(struct ble_sm_dhkey_check));
|
ble_sm_dhkey_check_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(memcmp(cmd.value, exp_cmd->value, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_enc_info(struct ble_sm_enc_info *exp_cmd)
|
{
|
struct ble_sm_enc_info cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_ENC_INFO,
|
sizeof(struct ble_sm_enc_info));
|
ble_sm_enc_info_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(memcmp(cmd.ltk, exp_cmd->ltk, 16) == 0);
|
|
/* Ensure LTK is sent in little endian. */
|
TEST_ASSERT(memcmp(om->om_data, cmd.ltk, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_master_id(struct ble_sm_master_id *exp_cmd)
|
{
|
struct ble_sm_master_id cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_MASTER_ID,
|
sizeof(struct ble_sm_master_id));
|
ble_sm_master_id_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(cmd.ediv == exp_cmd->ediv);
|
TEST_ASSERT(cmd.rand_val == exp_cmd->rand_val);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_id_info(struct ble_sm_id_info *exp_cmd)
|
{
|
struct ble_sm_id_info cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_IDENTITY_INFO,
|
sizeof(struct ble_sm_id_info));
|
ble_sm_id_info_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(memcmp(cmd.irk, exp_cmd->irk, 16) == 0);
|
|
/* Ensure IRK is sent in little endian. */
|
TEST_ASSERT(memcmp(om->om_data, cmd.irk, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_id_addr_info(struct ble_sm_id_addr_info *exp_cmd)
|
{
|
struct ble_sm_id_addr_info cmd;
|
struct os_mbuf *om;
|
const uint8_t *our_id_addr;
|
int rc;
|
|
ble_hs_lock();
|
rc = ble_hs_id_addr(exp_cmd->addr_type, &our_id_addr, NULL);
|
ble_hs_unlock();
|
|
TEST_ASSERT_FATAL(rc == 0);
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_IDENTITY_ADDR_INFO,
|
sizeof(struct ble_sm_id_addr_info));
|
ble_sm_id_addr_info_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(cmd.addr_type == exp_cmd->addr_type);
|
TEST_ASSERT(memcmp(cmd.bd_addr, exp_cmd->bd_addr, 6) == 0);
|
TEST_ASSERT(memcmp(cmd.bd_addr, our_id_addr, 6) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_sign_info(struct ble_sm_sign_info *exp_cmd)
|
{
|
struct ble_sm_sign_info cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_SIGN_INFO,
|
sizeof(struct ble_sm_sign_info));
|
ble_sm_sign_info_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(memcmp(cmd.sig_key, exp_cmd->sig_key, 16) == 0);
|
|
/* Ensure CSRK is sent in little endian. */
|
TEST_ASSERT(memcmp(om->om_data, cmd.sig_key, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_sec_req(struct ble_sm_sec_req *exp_cmd)
|
{
|
struct ble_sm_sec_req cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_SEC_REQ, sizeof(struct ble_sm_sec_req));
|
ble_sm_sec_req_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(cmd.authreq == exp_cmd->authreq);
|
}
|
|
void
|
ble_sm_test_util_verify_tx_pair_fail(
|
struct ble_sm_pair_fail *exp_cmd)
|
{
|
struct ble_sm_pair_fail cmd;
|
struct os_mbuf *om;
|
|
om = ble_sm_test_util_verify_tx_hdr(BLE_SM_OP_PAIR_FAIL,
|
sizeof(struct ble_sm_pair_fail));
|
ble_sm_pair_fail_parse(om->om_data, om->om_len, &cmd);
|
|
TEST_ASSERT(cmd.reason == exp_cmd->reason);
|
}
|
|
static void
|
ble_sm_test_util_rx_lt_key_req(uint16_t conn_handle, uint64_t r, uint16_t ediv)
|
{
|
struct ble_hci_ev_le_subev_lt_key_req evt;
|
int rc;
|
|
evt.subev_code = BLE_HCI_LE_SUBEV_LT_KEY_REQ;
|
evt.conn_handle = htole16(conn_handle);
|
evt.rand = htole64(r);
|
evt.div = htole16(ediv);
|
|
rc = ble_sm_ltk_req_rx(&evt);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_lt_key_req_reply(uint16_t conn_handle, uint8_t *stk)
|
{
|
uint8_t param_len;
|
uint8_t *param;
|
|
param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY,
|
¶m_len);
|
TEST_ASSERT(param_len == BLE_HCI_LT_KEY_REQ_REPLY_LEN);
|
TEST_ASSERT(get_le16(param + 0) == conn_handle);
|
TEST_ASSERT(memcmp(param + 2, stk, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_lt_key_req_neg_reply(uint16_t conn_handle)
|
{
|
uint8_t param_len;
|
uint8_t *param;
|
|
param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY,
|
¶m_len);
|
TEST_ASSERT(param_len == BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN);
|
TEST_ASSERT(get_le16(param + 0) == conn_handle);
|
}
|
|
static void
|
ble_sm_test_util_set_lt_key_req_neg_reply_ack(uint8_t status,
|
uint16_t conn_handle)
|
{
|
static uint8_t params[BLE_HCI_LT_KEY_REQ_NEG_REPLY_ACK_PARAM_LEN];
|
|
put_le16(params, conn_handle);
|
ble_hs_test_util_hci_ack_set_params(
|
ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY),
|
status, params, sizeof params);
|
}
|
|
static void
|
ble_sm_test_util_set_lt_key_req_reply_ack(uint8_t status, uint16_t conn_handle)
|
{
|
static uint8_t params[BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN];
|
|
put_le16(params, conn_handle);
|
ble_hs_test_util_hci_ack_set_params(
|
ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY),
|
status, params, sizeof params);
|
}
|
|
static void
|
ble_sm_test_util_rx_enc_change(uint16_t conn_handle, uint8_t status,
|
uint8_t encryption_enabled)
|
{
|
struct ble_hci_ev_enrypt_chg evt;
|
|
evt.status = status;
|
evt.enabled = encryption_enabled;
|
evt.connection_handle = htole16(conn_handle);
|
|
ble_sm_enc_change_rx(&evt);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_start_enc(uint16_t conn_handle,
|
uint64_t random_number,
|
uint16_t ediv,
|
uint8_t *ltk)
|
{
|
uint8_t param_len;
|
uint8_t *param;
|
|
param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_START_ENCRYPT,
|
¶m_len);
|
TEST_ASSERT(param_len == BLE_HCI_LE_START_ENCRYPT_LEN);
|
TEST_ASSERT(get_le16(param + 0) == conn_handle);
|
TEST_ASSERT(get_le64(param + 2) == random_number);
|
TEST_ASSERT(get_le16(param + 10) == ediv);
|
TEST_ASSERT(memcmp(param + 12, ltk, 16) == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_add_resolve_list(uint8_t peer_id_addr_type,
|
uint8_t *peer_id_addr,
|
uint8_t *peer_irk,
|
uint8_t *our_irk)
|
{
|
uint8_t param_len;
|
uint8_t *param;
|
|
ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_SET_ADV_ENABLE,
|
NULL);
|
|
param = ble_hs_test_util_hci_verify_tx(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_ADD_RESOLV_LIST,
|
¶m_len);
|
TEST_ASSERT(param_len == BLE_HCI_ADD_TO_RESOLV_LIST_LEN);
|
TEST_ASSERT(param[0] == peer_id_addr_type);
|
TEST_ASSERT(memcmp(param + 1, peer_id_addr, 6) == 0);
|
|
/* Ensure IRKs are sent in little endian. */
|
TEST_ASSERT(memcmp(param + 7, peer_irk, 16) == 0);
|
TEST_ASSERT(memcmp(param + 23, our_irk, 16) == 0);
|
}
|
|
void
|
ble_sm_test_util_io_inject(struct ble_sm_test_passkey_info *passkey_info,
|
uint8_t cur_sm_state)
|
{
|
uint8_t io_sm_state;
|
int rc;
|
|
io_sm_state = ble_sm_ioact_state(passkey_info->passkey.action);
|
if (io_sm_state != cur_sm_state) {
|
TEST_ASSERT(ble_sm_test_ioact.action == BLE_SM_IOACT_NONE);
|
return;
|
}
|
|
TEST_ASSERT(ble_sm_test_ioact.action == passkey_info->passkey.action);
|
|
if (passkey_info->passkey.action == BLE_SM_IOACT_NUMCMP) {
|
TEST_ASSERT(ble_sm_test_ioact.numcmp == passkey_info->exp_numcmp);
|
}
|
|
rc = ble_sm_inject_io(2, &passkey_info->passkey);
|
TEST_ASSERT(rc == 0);
|
|
ble_sm_test_ioact.action = BLE_SM_IOACT_NONE;
|
}
|
|
void
|
ble_sm_test_util_io_inject_bad(uint16_t conn_handle, uint8_t correct_io_act)
|
{
|
struct ble_sm_proc *proc;
|
struct ble_sm_io io;
|
uint8_t io_sm_state;
|
int already_injected;
|
int rc;
|
int i;
|
|
/* Lock mutex to prevent thread-safety assert from failing. */
|
ble_hs_lock();
|
proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
|
ble_hs_unlock();
|
|
TEST_ASSERT_FATAL(proc != NULL);
|
|
io_sm_state = ble_sm_ioact_state(correct_io_act);
|
|
for (i = 1; i < BLE_SM_IOACT_MAX_PLUS_ONE; i++) {
|
if (io_sm_state != proc->state ||
|
i != correct_io_act ||
|
proc->flags & BLE_SM_PROC_F_IO_INJECTED) {
|
|
already_injected = proc->flags & BLE_SM_PROC_F_IO_INJECTED;
|
|
io.action = i;
|
rc = ble_sm_inject_io(conn_handle, &io);
|
|
if (already_injected) {
|
TEST_ASSERT(rc == BLE_HS_EALREADY);
|
} else {
|
TEST_ASSERT(rc == BLE_HS_EINVAL);
|
}
|
}
|
}
|
}
|
|
void
|
ble_sm_test_util_io_check_pre(struct ble_sm_test_passkey_info *passkey_info,
|
uint8_t cur_sm_state)
|
{
|
uint8_t io_sm_state;
|
int rc;
|
|
io_sm_state = ble_sm_ioact_state(passkey_info->passkey.action);
|
if (io_sm_state != cur_sm_state) {
|
return;
|
}
|
|
if (!passkey_info->io_before_rx) {
|
return;
|
}
|
|
if (passkey_info->passkey.action == BLE_SM_IOACT_NUMCMP) {
|
TEST_ASSERT(ble_sm_test_ioact.numcmp == passkey_info->exp_numcmp);
|
}
|
|
rc = ble_sm_inject_io(2, &passkey_info->passkey);
|
TEST_ASSERT(rc == 0);
|
}
|
|
void
|
ble_sm_test_util_io_check_post(struct ble_sm_test_passkey_info *passkey_info,
|
uint8_t cur_sm_state)
|
{
|
uint8_t io_sm_state;
|
int rc;
|
|
io_sm_state = ble_sm_ioact_state(passkey_info->passkey.action);
|
if (io_sm_state != cur_sm_state) {
|
return;
|
}
|
|
if (passkey_info->io_before_rx) {
|
return;
|
}
|
|
if (passkey_info->passkey.action == BLE_SM_IOACT_NUMCMP) {
|
TEST_ASSERT(ble_sm_test_ioact.numcmp == passkey_info->exp_numcmp);
|
}
|
|
/* Ensure response not sent until user performs IO. */
|
TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0);
|
|
rc = ble_sm_inject_io(2, &passkey_info->passkey);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
static void
|
ble_sm_test_util_verify_persist(struct ble_sm_test_params *params,
|
int we_are_initiator)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
struct ble_store_value_sec value_sec;
|
struct ble_store_key_sec key_sec;
|
int csrk_expected;
|
int ltk_expected;
|
int peer_irk_expected;
|
int our_irk_expected;
|
int bonding;
|
int sc;
|
int rc;
|
|
ble_sm_test_util_params_to_entities(params, we_are_initiator,
|
&our_entity, &peer_entity);
|
|
sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC &&
|
params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC;
|
|
bonding = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_BOND &&
|
params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_BOND;
|
|
memset(&key_sec, 0, sizeof key_sec);
|
key_sec.peer_addr = *BLE_ADDR_ANY;
|
|
rc = ble_store_read_peer_sec(&key_sec, &value_sec);
|
if (!bonding) {
|
TEST_ASSERT(rc == BLE_HS_ENOENT);
|
peer_irk_expected = 0;
|
} else {
|
TEST_ASSERT_FATAL(rc == 0);
|
|
ltk_expected =
|
sc || !!(peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC);
|
peer_irk_expected =
|
!!(peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ID);
|
csrk_expected =
|
!!(peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_SIGN);
|
|
TEST_ASSERT(value_sec.peer_addr.type == peer_entity.id_addr_type);
|
TEST_ASSERT(
|
memcmp(value_sec.peer_addr.val, peer_entity.id_addr, 6) == 0);
|
TEST_ASSERT(value_sec.ediv == peer_entity.ediv);
|
TEST_ASSERT(value_sec.rand_num == peer_entity.rand_num);
|
TEST_ASSERT(value_sec.authenticated == params->authenticated);
|
|
TEST_ASSERT(value_sec.ltk_present == ltk_expected);
|
TEST_ASSERT(memcmp(value_sec.ltk, peer_entity.ltk, 16) == 0);
|
|
TEST_ASSERT(value_sec.irk_present == peer_irk_expected);
|
if (peer_irk_expected) {
|
TEST_ASSERT(memcmp(value_sec.irk,
|
peer_entity.id_info->irk, 16) == 0);
|
}
|
|
TEST_ASSERT(value_sec.csrk_present == csrk_expected);
|
if (csrk_expected) {
|
TEST_ASSERT(memcmp(value_sec.csrk,
|
peer_entity.sign_info->sig_key, 16) == 0);
|
}
|
}
|
|
rc = ble_store_read_our_sec(&key_sec, &value_sec);
|
if (!bonding) {
|
TEST_ASSERT(rc == BLE_HS_ENOENT);
|
} else {
|
TEST_ASSERT_FATAL(rc == 0);
|
|
ltk_expected =
|
sc || !!(our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC);
|
our_irk_expected =
|
!!(our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ID);
|
csrk_expected =
|
!!(our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_SIGN);
|
|
TEST_ASSERT(value_sec.peer_addr.type == peer_entity.id_addr_type);
|
TEST_ASSERT(memcmp(value_sec.peer_addr.val, peer_entity.id_addr, 6) == 0);
|
TEST_ASSERT(value_sec.ediv == our_entity.ediv);
|
TEST_ASSERT(value_sec.rand_num == our_entity.rand_num);
|
TEST_ASSERT(value_sec.authenticated == params->authenticated);
|
|
TEST_ASSERT(value_sec.ltk_present == ltk_expected);
|
TEST_ASSERT(memcmp(value_sec.ltk, our_entity.ltk, 16) == 0);
|
|
TEST_ASSERT(value_sec.irk_present == our_irk_expected);
|
if (our_irk_expected) {
|
TEST_ASSERT(memcmp(value_sec.irk,
|
our_entity.id_info->irk, 16) == 0);
|
}
|
|
TEST_ASSERT(value_sec.csrk_present == csrk_expected);
|
if (csrk_expected) {
|
TEST_ASSERT(memcmp(value_sec.csrk,
|
our_entity.sign_info->sig_key, 16) == 0);
|
}
|
}
|
|
/* Verify no other keys were persisted. */
|
key_sec.idx++;
|
rc = ble_store_read_our_sec(&key_sec, &value_sec);
|
TEST_ASSERT_FATAL(rc == BLE_HS_ENOENT);
|
rc = ble_store_read_peer_sec(&key_sec, &value_sec);
|
TEST_ASSERT_FATAL(rc == BLE_HS_ENOENT);
|
|
/* Verify we sent the peer's IRK to the controller. */
|
if (peer_irk_expected) {
|
ble_sm_test_util_verify_tx_add_resolve_list(peer_entity.id_addr_type,
|
peer_entity.id_addr,
|
peer_entity.id_info->irk,
|
our_entity.id_info->irk);
|
}
|
}
|
|
static void
|
ble_sm_test_util_peer_bonding_good(int send_enc_req,
|
uint8_t our_addr_type,
|
uint8_t *our_rpa,
|
uint8_t peer_addr_type,
|
uint8_t *peer_id_addr,
|
uint8_t *peer_rpa,
|
uint8_t *ltk, int authenticated,
|
uint16_t ediv, uint64_t rand_num)
|
{
|
struct ble_hs_conn *conn;
|
int rc;
|
|
ble_hs_test_util_create_rpa_conn(2, our_addr_type, our_rpa, peer_addr_type,
|
peer_id_addr, peer_rpa,
|
BLE_HS_TEST_CONN_FEAT_ALL,
|
ble_sm_test_util_conn_cb, NULL);
|
|
/* This test inspects and modifies the connection object after unlocking
|
* the host mutex. It is not OK for real code to do this, but this test
|
* can assume the connection list is unchanging.
|
*/
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
|
ble_hs_unlock();
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
if (send_enc_req) {
|
rc = ble_sm_slave_initiate(2);
|
TEST_ASSERT(rc == 0);
|
}
|
|
/* Receive a long term key request from the controller. */
|
ble_sm_test_util_set_lt_key_req_reply_ack(0, 2);
|
ble_sm_test_util_rx_lt_key_req(2, rand_num, ediv);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
|
/* Ensure the LTK request event got sent to the application. */
|
TEST_ASSERT(ble_sm_test_store_obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC);
|
TEST_ASSERT(ble_sm_test_store_key.sec.peer_addr.type ==
|
ble_hs_misc_peer_addr_type_to_id(peer_addr_type));
|
TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present);
|
TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv);
|
TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num);
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE);
|
|
/* Ensure we sent the expected long term key request reply command. */
|
ble_sm_test_util_verify_tx_lt_key_req_reply(2, ltk);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE);
|
|
/* Receive an encryption changed event. */
|
ble_sm_test_util_rx_enc_change(2, 0, 1);
|
|
/* Pairing should now be complete. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE);
|
TEST_ASSERT(ble_sm_test_gap_status == 0);
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
authenticated);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
authenticated);
|
|
ble_hs_test_util_conn_disconnect(2);
|
}
|
|
void
|
ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num)
|
{
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init();
|
|
ble_hs_test_util_create_conn(2, ((uint8_t[6]){1,2,3,4,5,6}),
|
ble_sm_test_util_conn_cb,
|
NULL);
|
|
/* This test inspects and modifies the connection object after unlocking
|
* the host mutex. It is not OK for real code to do this, but this test
|
* can assume the connection list is unchanging.
|
*/
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
|
ble_hs_unlock();
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Receive a long term key request from the controller. */
|
ble_sm_test_util_set_lt_key_req_neg_reply_ack(0, 2);
|
ble_sm_test_util_rx_lt_key_req(2, rand_num, ediv);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
|
/* Ensure the LTK request event got sent to the application. */
|
TEST_ASSERT(ble_sm_test_store_obj_type ==
|
BLE_STORE_OBJ_TYPE_OUR_SEC);
|
TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present);
|
TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv);
|
TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num);
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
|
/* Ensure we sent the expected long term key request neg reply command. */
|
ble_sm_test_util_verify_tx_lt_key_req_neg_reply(2);
|
|
/* Ensure the security procedure was aborted. */
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(!conn->bhc_sec_state.authenticated);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
}
|
|
/**
|
* @param send_enc_req Whether this procedure is initiated by a slave
|
* security request;
|
* 1: Peer sends a security request at start.
|
* 0: No security request; we initiate.
|
*/
|
static void
|
ble_sm_test_util_us_bonding_good(int send_enc_req, uint8_t our_addr_type,
|
uint8_t *our_rpa,
|
uint8_t peer_addr_type,
|
uint8_t *peer_id_addr, uint8_t *peer_rpa,
|
uint8_t *ltk, int authenticated,
|
uint16_t ediv, uint64_t rand_num)
|
{
|
struct ble_sm_sec_req sec_req;
|
struct ble_hs_conn *conn;
|
|
ble_hs_test_util_create_rpa_conn(2, our_addr_type, our_rpa,
|
peer_addr_type, peer_id_addr,
|
peer_rpa, BLE_HS_TEST_CONN_FEAT_ALL,
|
ble_sm_test_util_conn_cb, NULL);
|
|
/* This test inspects and modifies the connection object after unlocking
|
* the host mutex. It is not OK for real code to do this, but this test
|
* can assume the connection list is unchanging.
|
*/
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
ble_hs_unlock();
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
ble_hs_test_util_hci_ack_set(
|
ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_START_ENCRYPT),
|
0);
|
|
if (send_enc_req) {
|
sec_req.authreq = 0;
|
sec_req.authreq |= BLE_SM_PAIR_AUTHREQ_BOND;
|
if (authenticated) {
|
sec_req.authreq |= BLE_SM_PAIR_AUTHREQ_MITM;
|
}
|
ble_sm_test_util_rx_sec_req(2, &sec_req, 0);
|
} else {
|
ble_gap_security_initiate(2);
|
}
|
|
/* Ensure we sent the expected start encryption command. */
|
ble_sm_test_util_verify_tx_start_enc(2, rand_num, ediv, ltk);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE);
|
|
/* Receive an encryption changed event. */
|
ble_sm_test_util_rx_enc_change(2, 0, 1);
|
|
/* Pairing should now be complete. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE);
|
TEST_ASSERT(ble_sm_test_gap_status == 0);
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
authenticated);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
authenticated);
|
|
ble_hs_test_util_conn_disconnect(2);
|
}
|
|
void
|
ble_sm_test_util_peer_fail_inval(
|
int we_are_master,
|
uint8_t *init_id_addr,
|
uint8_t *resp_addr,
|
struct ble_sm_pair_cmd *pair_req,
|
struct ble_sm_pair_fail *pair_fail)
|
{
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init();
|
ble_hs_id_set_pub(resp_addr);
|
|
ble_hs_test_util_create_conn(2, init_id_addr, ble_sm_test_util_conn_cb,
|
NULL);
|
|
/* This test inspects and modifies the connection object after unlocking
|
* the host mutex. It is not OK for real code to do this, but this test
|
* can assume the connection list is unchanging.
|
*/
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
ble_hs_unlock();
|
|
if (!we_are_master) {
|
conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
|
}
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Receive a pair request from the peer. */
|
ble_sm_test_util_rx_pair_req(2, pair_req,
|
BLE_HS_SM_US_ERR(pair_fail->reason));
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Ensure we sent the expected pair fail. */
|
ble_sm_test_util_verify_tx_pair_fail(pair_fail);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was not executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == -1);
|
TEST_ASSERT(ble_sm_test_gap_status == -1);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(!conn->bhc_sec_state.authenticated);
|
}
|
|
void
|
ble_sm_test_util_peer_lgcy_fail_confirm(
|
uint8_t *init_id_addr,
|
uint8_t *resp_addr,
|
struct ble_sm_pair_cmd *pair_req,
|
struct ble_sm_pair_cmd *pair_rsp,
|
struct ble_sm_pair_confirm *confirm_req,
|
struct ble_sm_pair_confirm *confirm_rsp,
|
struct ble_sm_pair_random *random_req,
|
struct ble_sm_pair_random *random_rsp,
|
struct ble_sm_pair_fail *fail_rsp)
|
{
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init();
|
ble_hs_id_set_pub(resp_addr);
|
ble_sm_dbg_set_next_pair_rand(random_rsp->value);
|
|
if (pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_SC) {
|
ble_hs_cfg.sm_sc = 1;
|
} else {
|
ble_hs_cfg.sm_sc = 0;
|
}
|
|
ble_hs_test_util_create_conn(2, init_id_addr, ble_sm_test_util_conn_cb,
|
NULL);
|
|
/* This test inspects and modifies the connection object after unlocking
|
* the host mutex. It is not OK for real code to do this, but this test
|
* can assume the connection list is unchanging.
|
*/
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
ble_hs_unlock();
|
|
/* Peer is the initiator so we must be the slave. */
|
conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
|
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Receive a pair request from the peer. */
|
ble_sm_test_util_rx_pair_req(2, pair_req, 0);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE);
|
|
/* Ensure we sent the expected pair response. */
|
ble_sm_test_util_verify_tx_pair_rsp(pair_rsp);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE);
|
|
/* Receive a pair confirm from the peer. */
|
ble_sm_test_util_rx_confirm(2, confirm_req);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE);
|
|
/* Ensure we sent the expected pair confirm. */
|
ble_sm_test_util_verify_tx_pair_confirm(confirm_rsp);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, BLE_SM_IOACT_NONE);
|
|
/* Receive a pair random from the peer. */
|
ble_sm_test_util_rx_random(
|
2, random_req, BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH));
|
|
/* Ensure we sent the expected pair fail. */
|
ble_sm_test_util_verify_tx_pair_fail(fail_rsp);
|
|
/* The proc should now be freed. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE);
|
TEST_ASSERT(ble_sm_test_gap_status ==
|
BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH));
|
TEST_ASSERT(!ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(!ble_sm_test_sec_state.authenticated);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted ==
|
conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
conn->bhc_sec_state.authenticated);
|
}
|
|
static void
|
ble_sm_test_util_bonding_all(struct ble_sm_test_params *params,
|
int we_are_original_initiator)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
int sc;
|
|
if (!(params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_BOND) ||
|
!(params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_BOND)) {
|
|
/* Bonding not performed. */
|
return;
|
}
|
|
sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC &&
|
params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC;
|
|
ble_sm_test_util_params_to_entities(params, we_are_original_initiator,
|
&our_entity, &peer_entity);
|
|
if (sc || peer_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
|
/* We are master; we initiate procedure. */
|
ble_sm_test_util_us_bonding_good(0, our_entity.addr_type,
|
our_entity.rpa,
|
peer_entity.addr_type,
|
peer_entity.id_addr,
|
peer_entity.rpa,
|
peer_entity.ltk,
|
params->authenticated,
|
peer_entity.ediv,
|
peer_entity.rand_num);
|
|
/* We are master; peer initiates procedure via security request. */
|
ble_sm_test_util_us_bonding_good(1, our_entity.addr_type,
|
our_entity.rpa,
|
peer_entity.addr_type,
|
peer_entity.id_addr,
|
peer_entity.rpa,
|
peer_entity.ltk,
|
params->authenticated,
|
peer_entity.ediv,
|
peer_entity.rand_num);
|
}
|
|
if (sc || our_entity.key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
|
/* Peer is master; peer initiates procedure. */
|
ble_sm_test_util_peer_bonding_good(0, our_entity.addr_type,
|
our_entity.rpa,
|
peer_entity.addr_type,
|
peer_entity.id_addr,
|
peer_entity.rpa,
|
our_entity.ltk,
|
params->authenticated,
|
our_entity.ediv,
|
our_entity.rand_num);
|
|
/* Peer is master; we initiate procedure via security request. */
|
ble_sm_test_util_peer_bonding_good(1, our_entity.addr_type,
|
our_entity.rpa,
|
peer_entity.addr_type,
|
peer_entity.id_addr,
|
peer_entity.rpa,
|
our_entity.ltk,
|
params->authenticated,
|
our_entity.ediv,
|
our_entity.rand_num);
|
}
|
}
|
|
static void
|
ble_sm_test_util_rx_keys(struct ble_sm_test_params *params,
|
int we_are_initiator)
|
{
|
struct ble_sm_id_addr_info *peer_id_addr_info;
|
struct ble_sm_sign_info *peer_sign_info;
|
struct ble_sm_master_id *peer_master_id;
|
struct ble_sm_enc_info *peer_enc_info;
|
struct ble_sm_id_info *peer_id_info;
|
uint8_t peer_key_dist;
|
int sc;
|
|
if (we_are_initiator) {
|
peer_key_dist = params->pair_rsp.resp_key_dist;
|
peer_id_addr_info = ¶ms->id_addr_info_req;
|
peer_sign_info = ¶ms->sign_info_req;
|
peer_master_id = ¶ms->master_id_req;
|
peer_enc_info = ¶ms->enc_info_req;
|
peer_id_info = ¶ms->id_info_req;
|
} else {
|
peer_key_dist = params->pair_rsp.init_key_dist;
|
peer_id_addr_info = ¶ms->id_addr_info_rsp;
|
peer_sign_info = ¶ms->sign_info_rsp;
|
peer_master_id = ¶ms->master_id_rsp;
|
peer_enc_info = ¶ms->enc_info_rsp;
|
peer_id_info = ¶ms->id_info_rsp;
|
}
|
|
sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC &&
|
params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC;
|
|
/* Receive key material from peer. */
|
if (!sc && (peer_key_dist & BLE_SM_PAIR_KEY_DIST_ENC)) {
|
ble_sm_test_util_rx_enc_info(2, peer_enc_info, 0);
|
ble_sm_test_util_rx_master_id(2, peer_master_id, 0);
|
}
|
if (peer_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
|
|
ble_hs_test_util_hci_ack_set_seq(((struct ble_hs_test_util_hci_ack[]) {
|
{
|
.opcode = ble_hs_hci_util_opcode_join(
|
BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE),
|
},
|
{
|
.opcode = ble_hs_hci_util_opcode_join(
|
BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST),
|
},
|
{
|
.opcode = ble_hs_hci_util_opcode_join(
|
BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PRIVACY_MODE),
|
},
|
{ 0 }
|
}));
|
|
ble_sm_test_util_rx_id_info(2, peer_id_info, 0);
|
ble_sm_test_util_rx_id_addr_info(2, peer_id_addr_info, 0);
|
}
|
if (peer_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
|
ble_sm_test_util_rx_sign_info(2, peer_sign_info, 0);
|
}
|
}
|
|
static void
|
ble_sm_test_util_verify_tx_keys(struct ble_sm_test_params *params,
|
int we_are_initiator)
|
{
|
struct ble_sm_id_addr_info *our_id_addr_info;
|
struct ble_sm_sign_info *our_sign_info;
|
struct ble_sm_master_id *our_master_id;
|
struct ble_sm_enc_info *our_enc_info;
|
struct ble_sm_id_info *our_id_info;
|
uint8_t our_key_dist;
|
int sc;
|
|
if (we_are_initiator) {
|
our_key_dist = params->pair_rsp.init_key_dist;
|
our_id_addr_info = ¶ms->id_addr_info_rsp;
|
our_sign_info = ¶ms->sign_info_rsp;
|
our_master_id = ¶ms->master_id_rsp;
|
our_enc_info = ¶ms->enc_info_rsp;
|
our_id_info = ¶ms->id_info_rsp;
|
} else {
|
our_key_dist = params->pair_rsp.resp_key_dist;
|
our_id_addr_info = ¶ms->id_addr_info_req;
|
our_sign_info = ¶ms->sign_info_req;
|
our_master_id = ¶ms->master_id_req;
|
our_enc_info = ¶ms->enc_info_req;
|
our_id_info = ¶ms->id_info_req;
|
}
|
|
sc = params->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC &&
|
params->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC;
|
|
if (!sc && our_key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
|
ble_sm_test_util_verify_tx_enc_info(our_enc_info);
|
ble_sm_test_util_verify_tx_master_id(our_master_id);
|
}
|
if (our_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
|
ble_sm_test_util_verify_tx_id_info(our_id_info);
|
ble_sm_test_util_verify_tx_id_addr_info(our_id_addr_info);
|
}
|
if (our_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
|
ble_sm_test_util_verify_tx_sign_info(our_sign_info);
|
}
|
}
|
|
static void
|
ble_sm_test_util_us_lgcy_good_once_no_init(
|
struct ble_sm_test_params *params,
|
struct ble_hs_conn *conn,
|
struct ble_sm_test_util_entity *our_entity,
|
struct ble_sm_test_util_entity *peer_entity)
|
{
|
int rc;
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
ble_hs_test_util_hci_ack_set(
|
ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_START_ENCRYPT), 0);
|
if (params->sec_req.authreq != 0) {
|
ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0);
|
} else {
|
/* Initiate the pairing procedure. */
|
rc = ble_gap_security_initiate(2);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
/* Ensure we sent the expected pair request. */
|
ble_sm_test_util_verify_tx_pair_req(our_entity->pair_cmd);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair response from the peer. */
|
ble_sm_test_util_rx_pair_rsp(2, peer_entity->pair_cmd, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
ble_sm_test_util_io_inject(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_CONFIRM);
|
|
/* Ensure we sent the expected pair confirm. */
|
ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair confirm from the peer. */
|
ble_sm_test_util_rx_confirm(2, peer_entity->confirms);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected pair random. */
|
ble_sm_test_util_verify_tx_pair_random(our_entity->randoms);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair random from the peer. */
|
ble_sm_test_util_rx_random(2, peer_entity->randoms, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected start encryption command. */
|
ble_sm_test_util_verify_tx_start_enc(2, 0, 0, params->stk);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive an encryption changed event. */
|
ble_sm_test_util_rx_enc_change(2, 0, 1);
|
|
/* Receive key material from peer. */
|
ble_sm_test_util_rx_keys(params, 1);
|
|
/* Verify key material gets sent to peer. */
|
ble_sm_test_util_verify_tx_keys(params, 1);
|
|
/* Pairing should now be complete. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE);
|
TEST_ASSERT(ble_sm_test_gap_status == 0);
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated == params->authenticated);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted ==
|
conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
conn->bhc_sec_state.authenticated);
|
|
/* Verify the appropriate security material was persisted. */
|
ble_sm_test_util_verify_persist(params, 1);
|
|
ble_hs_test_util_conn_disconnect(2);
|
}
|
|
static void
|
ble_sm_test_util_us_lgcy_good_once(struct ble_sm_test_params *params)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init_good(params, 1, &conn, &our_entity, &peer_entity);
|
ble_sm_test_util_us_lgcy_good_once_no_init(
|
params, conn, &our_entity, &peer_entity);
|
}
|
|
void
|
ble_sm_test_util_us_lgcy_good(struct ble_sm_test_params *params)
|
{
|
ble_addr_t peer_addr;
|
int rc;
|
|
/*** We are master. */
|
|
/* We initiate pairing. */
|
params->sec_req.authreq = 0;
|
ble_sm_test_util_us_lgcy_good_once(params);
|
|
/* Peer initiates with security request. */
|
params->sec_req.authreq = params->pair_rsp.authreq;
|
ble_sm_test_util_us_lgcy_good_once(params);
|
|
/* Verify link can be restored via the encryption procedure. */
|
ble_sm_test_util_bonding_all(params, 1);
|
|
/* Verify programmatic unbonding. */
|
peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->resp_addr_type);
|
memcpy(peer_addr.val, params->resp_id_addr, sizeof peer_addr.val);
|
rc = ble_store_util_delete_peer(&peer_addr);
|
TEST_ASSERT(rc == 0);
|
|
TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0);
|
TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0);
|
}
|
|
void
|
ble_sm_test_util_peer_lgcy_good_once_no_init(
|
struct ble_sm_test_params *params,
|
struct ble_hs_conn *conn,
|
struct ble_sm_test_util_entity *our_entity,
|
struct ble_sm_test_util_entity *peer_entity)
|
{
|
int rc;
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
if (params->sec_req.authreq != 0) {
|
rc = ble_sm_slave_initiate(2);
|
TEST_ASSERT(rc == 0);
|
|
/* Ensure we sent the expected security request. */
|
ble_sm_test_util_verify_tx_sec_req(¶ms->sec_req);
|
}
|
|
/* Receive a pair request from the peer. */
|
ble_sm_test_util_rx_pair_req(2, peer_entity->pair_cmd, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected pair response. */
|
ble_sm_test_util_verify_tx_pair_rsp(our_entity->pair_cmd);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
ble_sm_test_util_io_check_pre(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_CONFIRM);
|
|
/* Receive a pair confirm from the peer. */
|
ble_sm_test_util_rx_confirm(2, peer_entity->confirms);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
ble_sm_test_util_io_check_post(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_CONFIRM);
|
|
/* Ensure we sent the expected pair confirm. */
|
ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair random from the peer. */
|
ble_sm_test_util_rx_random(2, peer_entity->randoms, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected pair random. */
|
ble_sm_test_util_verify_tx_pair_random(our_entity->randoms);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a long term key request from the controller. */
|
ble_sm_test_util_set_lt_key_req_reply_ack(0, 2);
|
ble_sm_test_util_rx_lt_key_req(2, 0, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected long term key request reply command. */
|
ble_sm_test_util_verify_tx_lt_key_req_reply(2, params->stk);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive an encryption changed event. */
|
ble_sm_test_util_rx_enc_change(2, 0, 1);
|
|
/* Verify key material gets sent to peer. */
|
ble_sm_test_util_verify_tx_keys(params, 0);
|
|
/* Receive key material from peer. */
|
ble_sm_test_util_rx_keys(params, 0);
|
|
/* Pairing should now be complete. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE);
|
TEST_ASSERT(ble_sm_test_gap_status == 0);
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
params->authenticated);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted ==
|
conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
conn->bhc_sec_state.authenticated);
|
|
/* Verify the appropriate security material was persisted. */
|
ble_sm_test_util_verify_persist(params, 0);
|
|
ble_hs_test_util_conn_disconnect(2);
|
}
|
|
void
|
ble_sm_test_util_peer_lgcy_good_once(struct ble_sm_test_params *params)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init_good(params, 0, &conn, &our_entity, &peer_entity);
|
ble_sm_test_util_peer_lgcy_good_once_no_init(
|
params, conn, &our_entity, &peer_entity);
|
}
|
|
void
|
ble_sm_test_util_peer_lgcy_good(struct ble_sm_test_params *params)
|
{
|
ble_addr_t peer_addr;
|
int rc;
|
|
/*** Peer is master. */
|
|
/* Peer performs IO first; peer initiates pairing. */
|
params->passkey_info.io_before_rx = 0;
|
params->sec_req.authreq = 0;
|
ble_sm_test_util_peer_lgcy_good_once(params);
|
|
/* Peer performs IO first; we initiate with security request. */
|
params->passkey_info.io_before_rx = 0;
|
params->sec_req.authreq = params->pair_rsp.authreq;
|
ble_sm_test_util_peer_lgcy_good_once(params);
|
|
/* We perform IO first; peer initiates pairing. */
|
params->passkey_info.io_before_rx = 1;
|
params->sec_req.authreq = 0;
|
ble_sm_test_util_peer_lgcy_good_once(params);
|
|
/* We perform IO first; we initiate with security request. */
|
params->passkey_info.io_before_rx = 1;
|
params->sec_req.authreq = params->pair_rsp.authreq;
|
ble_sm_test_util_peer_lgcy_good_once(params);
|
|
/* Verify link can be restored via the encryption procedure. */
|
ble_sm_test_util_bonding_all(params, 0);
|
|
/* Verify repeating pairing event generated when peer attempts to pair
|
* while bonded.
|
*/
|
ble_sm_test_util_repeat_pairing(params, 0);
|
|
/* Verify programmatic unbonding. */
|
peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->init_addr_type);
|
memcpy(peer_addr.val, params->init_id_addr, sizeof peer_addr.val);
|
rc = ble_store_util_delete_peer(&peer_addr);
|
TEST_ASSERT(rc == 0);
|
|
TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0);
|
TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0);
|
}
|
|
static void
|
ble_sm_test_util_us_sc_good_once_no_init(
|
struct ble_sm_test_params *params,
|
struct ble_hs_conn *conn,
|
struct ble_sm_test_util_entity *our_entity,
|
struct ble_sm_test_util_entity *peer_entity)
|
{
|
int num_iters;
|
int rc;
|
int i;
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
ble_hs_test_util_hci_ack_set(
|
ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_START_ENCRYPT), 0);
|
if (params->sec_req.authreq != 0) {
|
ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0);
|
} else {
|
/* Initiate the pairing procedure. */
|
rc = ble_gap_security_initiate(2);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
/* Ensure we sent the expected pair request. */
|
ble_sm_test_util_verify_tx_pair_req(our_entity->pair_cmd);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair response from the peer. */
|
ble_sm_test_util_rx_pair_rsp(2, peer_entity->pair_cmd, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected public key. */
|
ble_sm_test_util_verify_tx_public_key(our_entity->public_key);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a public key from the peer. */
|
ble_sm_test_util_rx_public_key(2, peer_entity->public_key);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
switch (params->pair_alg) {
|
case BLE_SM_PAIR_ALG_PASSKEY:
|
num_iters = 20;
|
break;
|
|
default:
|
num_iters = 1;
|
break;
|
}
|
|
ble_sm_test_util_io_inject(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_CONFIRM);
|
|
for (i = 0; i < num_iters; i++) {
|
if (params->pair_alg != BLE_SM_PAIR_ALG_JW &&
|
params->pair_alg != BLE_SM_PAIR_ALG_NUMCMP) {
|
|
if (i < num_iters - 1) {
|
ble_sm_dbg_set_next_pair_rand(
|
our_entity->randoms[i + 1].value);
|
}
|
|
/* Ensure we sent the expected pair confirm. */
|
ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms + i);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(
|
2, params->passkey_info.passkey.action);
|
}
|
|
/* Receive a pair confirm from the peer. */
|
ble_sm_test_util_rx_confirm(2, peer_entity->confirms + i);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected pair random. */
|
ble_sm_test_util_verify_tx_pair_random(our_entity->randoms + i);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair random from the peer. */
|
ble_sm_test_util_rx_random(2, peer_entity->randoms + i, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
}
|
|
ble_sm_test_util_io_inject(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_DHKEY_CHECK);
|
|
/* Ensure we sent the expected dhkey check. */
|
ble_sm_test_util_verify_tx_dhkey_check(our_entity->dhkey_check);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a dhkey check from the peer. */
|
ble_sm_test_util_rx_dhkey_check(2, peer_entity->dhkey_check, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected start encryption command. */
|
ble_sm_test_util_verify_tx_start_enc(2, 0, 0, params->ltk);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive an encryption changed event. */
|
ble_sm_test_util_rx_enc_change(2, 0, 1);
|
|
/* Receive key material from peer. */
|
ble_sm_test_util_rx_keys(params, 1);
|
|
/* Verify key material gets sent to peer. */
|
ble_sm_test_util_verify_tx_keys(params, 1);
|
|
/* Pairing should now be complete. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE);
|
TEST_ASSERT(ble_sm_test_gap_status == 0);
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
params->authenticated);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted ==
|
conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
conn->bhc_sec_state.authenticated);
|
|
/* Verify the appropriate security material was persisted. */
|
ble_sm_test_util_verify_persist(params, 1);
|
|
ble_hs_test_util_conn_disconnect(2);
|
}
|
|
static void
|
ble_sm_test_util_us_sc_bad_once_no_init(struct ble_sm_test_params *params,
|
struct ble_hs_conn *conn,
|
struct ble_sm_test_util_entity *our_entity,
|
struct ble_sm_test_util_entity *peer_entity)
|
{
|
int rc;
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
ble_hs_test_util_hci_ack_set(
|
ble_hs_hci_util_opcode_join(BLE_HCI_OGF_LE,
|
BLE_HCI_OCF_LE_START_ENCRYPT), 0);
|
if (params->sec_req.authreq != 0) {
|
ble_sm_test_util_rx_sec_req(2, ¶ms->sec_req, 0);
|
} else {
|
/* Initiate the pairing procedure. */
|
rc = ble_gap_security_initiate(2);
|
TEST_ASSERT_FATAL(rc == 0);
|
}
|
|
/* Ensure we sent the expected pair request. */
|
ble_sm_test_util_verify_tx_pair_req(our_entity->pair_cmd);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair response from the peer. */
|
ble_sm_test_util_rx_pair_rsp(2, peer_entity->pair_cmd, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected public key. */
|
ble_sm_test_util_verify_tx_public_key(our_entity->public_key);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a wrong public key from the peer. */
|
ble_sm_test_util_rx_public_key_bad(2, peer_entity->public_key);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
}
|
|
static void
|
ble_sm_test_util_us_sc_good_once(struct ble_sm_test_params *params)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init_good(params, 1, &conn, &our_entity, &peer_entity);
|
ble_sm_test_util_us_sc_good_once_no_init(
|
params, conn, &our_entity, &peer_entity);
|
}
|
|
static void
|
ble_sm_test_util_us_sc_bad_once(struct ble_sm_test_params *params)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init_good(params, 1, &conn, &our_entity, &peer_entity);
|
ble_sm_test_util_us_sc_bad_once_no_init(
|
params, conn, &our_entity, &peer_entity);
|
}
|
void
|
ble_sm_test_util_us_sc_good(struct ble_sm_test_params *params)
|
{
|
ble_addr_t peer_addr;
|
int rc;
|
|
/*** We are master. */
|
|
/* We initiate pairing. */
|
params->passkey_info.io_before_rx = 0;
|
params->sec_req.authreq = 0;
|
ble_sm_test_util_us_sc_good_once(params);
|
|
/* Peer initiates with security request. */
|
params->passkey_info.io_before_rx = 0;
|
params->sec_req.authreq = params->pair_rsp.authreq;
|
ble_sm_test_util_us_sc_good_once(params);
|
|
/* Verify link can be restored via the encryption procedure. */
|
ble_sm_test_util_bonding_all(params, 1);
|
|
/* Verify programmatic unbonding. */
|
peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->resp_addr_type);
|
memcpy(peer_addr.val, params->resp_id_addr, sizeof peer_addr.val);
|
rc = ble_store_util_delete_peer(&peer_addr);
|
TEST_ASSERT(rc == 0);
|
|
TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0);
|
TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0);
|
}
|
|
void
|
ble_sm_test_util_us_sc_bad(struct ble_sm_test_params *params)
|
{
|
/*** We are master. */
|
|
/* We initiate pairing. */
|
params->passkey_info.io_before_rx = 0;
|
params->sec_req.authreq = 0;
|
ble_sm_test_util_us_sc_bad_once(params);
|
}
|
|
static void
|
ble_sm_test_util_peer_sc_good_once_no_init(struct ble_sm_test_params *params,
|
struct ble_hs_conn *conn,
|
struct ble_sm_test_util_entity *our_entity,
|
struct ble_sm_test_util_entity *peer_entity)
|
{
|
int num_iters;
|
int rc;
|
int i;
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
if (params->sec_req.authreq != 0) {
|
rc = ble_sm_slave_initiate(2);
|
TEST_ASSERT(rc == 0);
|
|
/* Ensure we sent the expected security request. */
|
ble_sm_test_util_verify_tx_sec_req(¶ms->sec_req);
|
}
|
|
/* Receive a pair request from the peer. */
|
ble_sm_test_util_rx_pair_req(2, peer_entity->pair_cmd, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected pair response. */
|
ble_sm_test_util_verify_tx_pair_rsp(our_entity->pair_cmd);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a public key from the peer. */
|
ble_sm_test_util_rx_public_key(2, peer_entity->public_key);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected public key. */
|
ble_sm_test_util_verify_tx_public_key(our_entity->public_key);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
switch (params->pair_alg) {
|
case BLE_SM_PAIR_ALG_PASSKEY:
|
num_iters = 20;
|
break;
|
|
default:
|
num_iters = 1;
|
break;
|
}
|
|
ble_sm_test_util_io_check_pre(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_CONFIRM);
|
|
for (i = 0; i < num_iters; i++) {
|
if (params->pair_alg != BLE_SM_PAIR_ALG_JW &&
|
params->pair_alg != BLE_SM_PAIR_ALG_NUMCMP) {
|
|
/* Receive a pair confirm from the peer. */
|
ble_sm_test_util_rx_confirm(2, peer_entity->confirms + i);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(
|
2, params->passkey_info.passkey.action);
|
|
if (i < num_iters - 1) {
|
ble_sm_dbg_set_next_pair_rand(
|
our_entity->randoms[i + 1].value);
|
}
|
}
|
|
if (i == 0) {
|
ble_sm_test_util_io_check_post(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_CONFIRM);
|
}
|
|
/* Ensure we sent the expected pair confirm. */
|
ble_sm_test_util_verify_tx_pair_confirm(our_entity->confirms + i);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair random from the peer. */
|
ble_sm_test_util_rx_random(2, peer_entity->randoms + i, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected pair random. */
|
ble_sm_test_util_verify_tx_pair_random(our_entity->randoms + i);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
}
|
|
ble_sm_test_util_io_check_pre(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_DHKEY_CHECK);
|
|
/* Receive a dhkey check from the peer. */
|
ble_sm_test_util_rx_dhkey_check(2, peer_entity->dhkey_check, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
ble_sm_test_util_io_check_post(¶ms->passkey_info,
|
BLE_SM_PROC_STATE_DHKEY_CHECK);
|
|
/* Ensure we sent the expected dhkey check. */
|
ble_sm_test_util_verify_tx_dhkey_check(our_entity->dhkey_check);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a long term key request from the controller. */
|
ble_sm_test_util_set_lt_key_req_reply_ack(0, 2);
|
ble_sm_test_util_rx_lt_key_req(2, 0, 0);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Ensure we sent the expected long term key request reply command. */
|
ble_sm_test_util_verify_tx_lt_key_req_reply(2, params->ltk);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive an encryption changed event. */
|
ble_sm_test_util_rx_enc_change(2, 0, 1);
|
|
/* Verify key material gets sent to peer. */
|
ble_sm_test_util_verify_tx_keys(params, 0);
|
|
/* Receive key material from peer. */
|
ble_sm_test_util_rx_keys(params, 0);
|
|
/* Pairing should now be complete. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == BLE_GAP_EVENT_ENC_CHANGE);
|
TEST_ASSERT(ble_sm_test_gap_status == 0);
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
params->authenticated);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(ble_sm_test_sec_state.encrypted ==
|
conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_test_sec_state.authenticated ==
|
conn->bhc_sec_state.authenticated);
|
|
/* Verify the appropriate security material was persisted. */
|
ble_sm_test_util_verify_persist(params, 0);
|
|
ble_hs_test_util_conn_disconnect(2);
|
}
|
|
static void
|
ble_sm_test_util_peer_sc_good_once(struct ble_sm_test_params *params)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_init_good(params, 0, &conn, &our_entity, &peer_entity);
|
ble_sm_test_util_peer_sc_good_once_no_init(
|
params, conn, &our_entity, &peer_entity);
|
}
|
|
void
|
ble_sm_test_util_peer_sc_good(struct ble_sm_test_params *params)
|
{
|
ble_addr_t peer_addr;
|
int rc;
|
|
/*** Peer is master. */
|
|
/* Peer performs IO first; peer initiates pairing. */
|
params->passkey_info.io_before_rx = 0;
|
params->sec_req.authreq = 0;
|
ble_sm_test_util_peer_sc_good_once(params);
|
|
/* Peer performs IO first; we initiate with security request. */
|
params->passkey_info.io_before_rx = 0;
|
params->sec_req.authreq = params->pair_req.authreq;
|
ble_sm_test_util_peer_sc_good_once(params);
|
|
/* We perform IO first; peer initiates pairing. */
|
params->passkey_info.io_before_rx = 1;
|
params->sec_req.authreq = 0;
|
ble_sm_test_util_peer_sc_good_once(params);
|
|
/* We perform IO first; we initiate with security request. */
|
params->passkey_info.io_before_rx = 1;
|
params->sec_req.authreq = params->pair_req.authreq;
|
ble_sm_test_util_peer_sc_good_once(params);
|
|
/* Verify link can be restored via the encryption procedure. */
|
ble_sm_test_util_bonding_all(params, 0);
|
|
/* Verify repeating pairing event generated when peer attempts to pair
|
* while bonded.
|
*/
|
ble_sm_test_util_repeat_pairing(params, 1);
|
|
/* Verify programmatic unbonding. */
|
peer_addr.type = ble_hs_misc_peer_addr_type_to_id(params->init_addr_type);
|
memcpy(peer_addr.val, params->init_id_addr, sizeof peer_addr.val);
|
rc = ble_store_util_delete_peer(&peer_addr);
|
TEST_ASSERT(rc == 0);
|
|
TEST_ASSERT(ble_hs_test_util_num_our_secs() == 0);
|
TEST_ASSERT(ble_hs_test_util_num_peer_secs() == 0);
|
}
|
|
void
|
ble_sm_test_util_us_fail_inval(struct ble_sm_test_params *params)
|
{
|
struct ble_hs_conn *conn;
|
int rc;
|
|
ble_sm_test_util_init();
|
ble_hs_id_set_pub(params->resp_id_addr);
|
|
ble_sm_dbg_set_next_pair_rand(((uint8_t[16]){0}));
|
|
ble_hs_test_util_create_conn(2, params->init_id_addr,
|
ble_sm_test_util_conn_cb,
|
NULL);
|
|
/* This test inspects and modifies the connection object after unlocking
|
* the host mutex. It is not OK for real code to do this, but this test
|
* can assume the connection list is unchanging.
|
*/
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
ble_hs_unlock();
|
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Initiate the pairing procedure. */
|
rc = ble_hs_test_util_security_initiate(2, 0);
|
TEST_ASSERT_FATAL(rc == 0);
|
|
/* Ensure we sent the expected pair request. */
|
ble_sm_test_util_verify_tx_pair_req(¶ms->pair_req);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 1);
|
ble_sm_test_util_io_inject_bad(2, params->passkey_info.passkey.action);
|
|
/* Receive a pair response from the peer. */
|
ble_sm_test_util_rx_pair_rsp(
|
2, ¶ms->pair_rsp, BLE_HS_SM_US_ERR(params->pair_fail.reason));
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Ensure we sent the expected pair fail. */
|
ble_sm_test_util_verify_tx_pair_fail(¶ms->pair_fail);
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify that security callback was not executed. */
|
TEST_ASSERT(ble_sm_test_gap_event_type == -1);
|
TEST_ASSERT(ble_sm_test_gap_status == -1);
|
|
/* Verify that connection has correct security state. */
|
TEST_ASSERT(!conn->bhc_sec_state.encrypted);
|
TEST_ASSERT(!conn->bhc_sec_state.authenticated);
|
}
|
|
static void
|
ble_sm_test_util_repeat_pairing(struct ble_sm_test_params *params, int sc)
|
{
|
struct ble_sm_test_util_entity peer_entity;
|
struct ble_sm_test_util_entity our_entity;
|
struct ble_hs_conn *conn;
|
|
ble_sm_test_util_params_to_entities(params, 0, &our_entity, &peer_entity);
|
|
ble_sm_test_repeat_pairing.params = *params;
|
ble_hs_id_set_pub(our_entity.id_addr);
|
ble_sm_dbg_set_next_pair_rand(our_entity.randoms[0].value);
|
ble_sm_dbg_set_next_ediv(our_entity.ediv);
|
ble_sm_dbg_set_next_master_id_rand(our_entity.rand_num);
|
ble_sm_dbg_set_next_ltk(our_entity.ltk);
|
ble_hs_test_util_set_our_irk(our_entity.id_info->irk, 0, 0);
|
ble_sm_dbg_set_next_csrk(our_entity.sign_info->sig_key);
|
|
ble_hs_test_util_create_rpa_conn(2, our_entity.addr_type, our_entity.rpa,
|
peer_entity.addr_type,
|
peer_entity.id_addr, peer_entity.rpa,
|
BLE_HS_TEST_CONN_FEAT_ALL,
|
ble_sm_test_util_conn_cb,
|
NULL);
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
|
ble_hs_unlock();
|
|
ble_hs_test_util_prev_tx_queue_clear();
|
|
/* First repeat pairing event: retry;
|
* Second repeat pairing event: ignore.
|
*/
|
ble_sm_test_repeat_pairing.rc = BLE_GAP_REPEAT_PAIRING_RETRY;
|
ble_sm_test_repeat_pairing.next_rc = BLE_GAP_REPEAT_PAIRING_IGNORE;
|
|
/* Receive a pair request from the peer. */
|
ble_sm_test_util_rx_pair_req(2, peer_entity.pair_cmd, BLE_HS_EALREADY);
|
|
/* Verify repeat pairing event got reported twice. */
|
TEST_ASSERT(ble_sm_test_repeat_pairing.num_calls == 2);
|
|
/* Verify no pairing procedures in progress. */
|
TEST_ASSERT(ble_sm_num_procs() == 0);
|
|
/* Verify no SM messages were sent. */
|
TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() == NULL);
|
|
/*** Receive another pairing request. */
|
|
ble_sm_test_repeat_pairing.num_calls = 0;
|
|
/* First repeat pairing event: erase and retry. */
|
ble_sm_test_repeat_pairing.rc = BLE_GAP_REPEAT_PAIRING_RETRY;
|
ble_sm_test_repeat_pairing.erase_on_retry = 1;
|
|
ble_hs_lock();
|
conn = ble_hs_conn_find(2);
|
TEST_ASSERT_FATAL(conn != NULL);
|
ble_hs_unlock();
|
|
/* Receive a pair request from the peer; verify pairing procedure completes
|
* successfully.
|
*/
|
if (!sc) {
|
ble_sm_test_util_peer_lgcy_good_once_no_init(
|
params, conn, &our_entity, &peer_entity);
|
} else {
|
ble_sm_test_util_peer_sc_good_once_no_init(
|
params, conn, &our_entity, &peer_entity);
|
}
|
|
/* Verify repeat pairing event got reported once. */
|
TEST_ASSERT(ble_sm_test_repeat_pairing.num_calls == 1);
|
}
|