/*
|
* 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 <string.h>
|
#include <errno.h>
|
#include "nimble/ble.h"
|
#include "nimble/nimble_opt.h"
|
#include "host/ble_sm.h"
|
#include "ble_hs_priv.h"
|
|
#if NIMBLE_BLE_CONNECT
|
#if MYNEWT_VAL(BLE_SM_LEGACY)
|
|
/**
|
* Create some shortened names for the passkey actions so that the table is
|
* easier to read.
|
*/
|
#define IOACT_NONE BLE_SM_IOACT_NONE
|
#define IOACT_OOB BLE_SM_IOACT_OOB
|
#define IOACT_INPUT BLE_SM_IOACT_INPUT
|
#define IOACT_DISP BLE_SM_IOACT_DISP
|
|
/* This is the initiator passkey action action depending on the io
|
* capabilties of both parties
|
*/
|
static const uint8_t ble_sm_lgcy_init_ioa[5 /*resp*/ ][5 /*init*/ ] =
|
{
|
{IOACT_NONE, IOACT_NONE, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
|
{IOACT_NONE, IOACT_NONE, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
|
{IOACT_DISP, IOACT_DISP, IOACT_INPUT, IOACT_NONE, IOACT_DISP},
|
{IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE},
|
{IOACT_DISP, IOACT_DISP, IOACT_INPUT, IOACT_NONE, IOACT_DISP},
|
};
|
|
/* This is the responder passkey action action depending on the io
|
* capabilities of both parties
|
*/
|
static const uint8_t ble_sm_lgcy_resp_ioa[5 /*resp*/ ][5 /*init*/ ] =
|
{
|
{IOACT_NONE, IOACT_NONE, IOACT_DISP, IOACT_NONE, IOACT_DISP},
|
{IOACT_NONE, IOACT_NONE, IOACT_DISP, IOACT_NONE, IOACT_DISP},
|
{IOACT_INPUT, IOACT_INPUT, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
|
{IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE},
|
{IOACT_INPUT, IOACT_INPUT, IOACT_DISP, IOACT_NONE, IOACT_INPUT},
|
};
|
|
int
|
ble_sm_lgcy_io_action(struct ble_sm_proc *proc, uint8_t *action)
|
{
|
struct ble_sm_pair_cmd *pair_req, *pair_rsp;
|
|
pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1];
|
pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
|
|
if (pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES &&
|
pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES) {
|
*action = BLE_SM_IOACT_OOB;
|
} else if (!(pair_req->authreq & BLE_SM_PAIR_AUTHREQ_MITM) &&
|
!(pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_MITM)) {
|
|
*action = BLE_SM_IOACT_NONE;
|
} else if (pair_req->io_cap >= BLE_SM_IO_CAP_RESERVED ||
|
pair_rsp->io_cap >= BLE_SM_IO_CAP_RESERVED) {
|
*action = BLE_SM_IOACT_NONE;
|
} else if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
|
*action = ble_sm_lgcy_init_ioa[pair_rsp->io_cap][pair_req->io_cap];
|
} else {
|
*action = ble_sm_lgcy_resp_ioa[pair_rsp->io_cap][pair_req->io_cap];
|
}
|
|
switch (*action) {
|
case BLE_SM_IOACT_NONE:
|
proc->pair_alg = BLE_SM_PAIR_ALG_JW;
|
break;
|
|
case BLE_SM_IOACT_OOB:
|
proc->pair_alg = BLE_SM_PAIR_ALG_OOB;
|
proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
|
break;
|
|
case BLE_SM_IOACT_INPUT:
|
case BLE_SM_IOACT_DISP:
|
proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY;
|
proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
|
break;
|
|
default:
|
BLE_HS_DBG_ASSERT(0);
|
return BLE_HS_EINVAL;
|
}
|
|
return 0;
|
}
|
|
void
|
ble_sm_lgcy_confirm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res)
|
{
|
struct ble_sm_pair_confirm *cmd;
|
struct os_mbuf *txom;
|
uint8_t ia[6];
|
uint8_t ra[6];
|
uint8_t iat;
|
uint8_t rat;
|
int rc;
|
|
cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_CONFIRM, sizeof(*cmd), &txom);
|
if (cmd == NULL) {
|
rc = BLE_HS_ENOMEM;
|
goto err;
|
}
|
|
ble_sm_ia_ra(proc, &iat, ia, &rat, ra);
|
|
rc = ble_sm_alg_c1(proc->tk, ble_sm_our_pair_rand(proc), proc->pair_req,
|
proc->pair_rsp, iat, rat, ia, ra, cmd->value);
|
if (rc != 0) {
|
goto err;
|
}
|
|
rc = ble_sm_tx(proc->conn_handle, txom);
|
if (rc != 0) {
|
goto err;
|
}
|
|
if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
|
proc->state = BLE_SM_PROC_STATE_RANDOM;
|
}
|
|
return;
|
|
err:
|
if (txom) {
|
os_mbuf_free_chain(txom);
|
}
|
|
res->app_status = rc;
|
res->enc_cb = 1;
|
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
|
}
|
|
static int
|
ble_sm_gen_stk(struct ble_sm_proc *proc)
|
{
|
uint8_t key[16];
|
int rc;
|
|
rc = ble_sm_alg_s1(proc->tk, proc->rands, proc->randm, key);
|
if (rc != 0) {
|
return rc;
|
}
|
|
memcpy(proc->ltk, key, proc->key_size);
|
|
/* Ensure proper key size */
|
memset(proc->ltk + proc->key_size, 0, sizeof key - proc->key_size);
|
|
return 0;
|
}
|
|
void
|
ble_sm_lgcy_random_exec(struct ble_sm_proc *proc, struct ble_sm_result *res)
|
{
|
struct ble_sm_pair_random *cmd;
|
struct os_mbuf *txom;
|
int rc;
|
|
cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_RANDOM, sizeof(*cmd), &txom);
|
if (cmd == NULL) {
|
res->app_status = BLE_HS_ENOMEM;
|
res->enc_cb = 1;
|
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
|
return;
|
}
|
|
memcpy(cmd->value, ble_sm_our_pair_rand(proc), 16);
|
|
rc = ble_sm_tx(proc->conn_handle, txom);
|
if (rc != 0) {
|
res->app_status = rc;
|
res->enc_cb = 1;
|
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
|
return;
|
}
|
|
if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
|
proc->state = BLE_SM_PROC_STATE_LTK_START;
|
}
|
}
|
|
void
|
ble_sm_lgcy_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res)
|
{
|
uint8_t confirm_val[16];
|
uint8_t ia[6];
|
uint8_t ra[6];
|
uint8_t iat;
|
uint8_t rat;
|
int rc;
|
|
ble_sm_ia_ra(proc, &iat, ia, &rat, ra);
|
|
rc = ble_sm_alg_c1(proc->tk, ble_sm_peer_pair_rand(proc), proc->pair_req,
|
proc->pair_rsp, iat, rat, ia, ra, confirm_val);
|
if (rc != 0) {
|
res->app_status = rc;
|
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
|
res->enc_cb = 1;
|
return;
|
}
|
|
if (memcmp(proc->confirm_peer, confirm_val, 16) != 0) {
|
/* Random number mismatch. */
|
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH);
|
res->sm_err = BLE_SM_ERR_CONFIRM_MISMATCH;
|
res->enc_cb = 1;
|
return;
|
}
|
|
/* Generate the key. */
|
rc = ble_sm_gen_stk(proc);
|
if (rc != 0) {
|
res->app_status = rc;
|
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
|
res->enc_cb = 1;
|
return;
|
}
|
|
if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
|
/* Send the start-encrypt HCI command to the controller. For
|
* short-term key generation, we always set ediv and rand to 0.
|
* (Vol. 3, part H, 2.4.4.1).
|
*/
|
proc->state = BLE_SM_PROC_STATE_ENC_START;
|
}
|
|
res->execute = 1;
|
}
|
|
#endif
|
#endif
|