/* * 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 #include "nimble/nimble_opt.h" #include "host/ble_sm.h" #include "ble_hs_priv.h" #include "ble_sm_priv.h" #if MYNEWT_VAL(BLE_SM_SC) #define BLE_SM_SC_PASSKEY_BYTES 4 #define BLE_SM_SC_PASSKEY_BITS 20 static uint8_t ble_sm_sc_pub_key[64]; static uint8_t ble_sm_sc_priv_key[32]; /** * Whether our public-private key pair has been generated. We generate it on * startup for now until we have a non-volatile storage mechanism. */ static uint8_t ble_sm_sc_keys_generated; /** * 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 #define IOACT_NUMCMP BLE_SM_IOACT_NUMCMP /** * This table expresses the required initiator IO action. Inputs are: * o Responder IO capabilities (from pair response). * o Initiator IO capabilities (from pair request). */ static const uint8_t ble_sm_sc_init_ioa[5 /*resp*/ ][5 /*init*/ ] = { /* init */ /*r*/ {IOACT_NONE, IOACT_NONE, IOACT_INPUT, IOACT_NONE, IOACT_INPUT}, /*e*/ {IOACT_NONE, IOACT_NUMCMP, IOACT_INPUT, IOACT_NONE, IOACT_NUMCMP}, /*s*/ {IOACT_DISP, IOACT_DISP, IOACT_INPUT, IOACT_NONE, IOACT_DISP}, /*p*/ {IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE}, {IOACT_DISP, IOACT_NUMCMP, IOACT_INPUT, IOACT_NONE, IOACT_NUMCMP}, }; /** * This table expresses the required responder IO action. Inputs are: * o Responder IO capabilities (from pair response). * o Initiator IO capabilities (from pair request). */ static const uint8_t ble_sm_sc_resp_ioa[5 /*resp*/ ][5 /*init*/ ] = { /* init */ /*r*/ {IOACT_NONE, IOACT_NONE, IOACT_DISP, IOACT_NONE, IOACT_DISP}, /*e*/ {IOACT_NONE, IOACT_NUMCMP, IOACT_DISP, IOACT_NONE, IOACT_NUMCMP}, /*s*/ {IOACT_INPUT, IOACT_INPUT, IOACT_INPUT, IOACT_NONE, IOACT_INPUT}, /*p*/ {IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE}, {IOACT_INPUT, IOACT_NUMCMP, IOACT_DISP, IOACT_NONE, IOACT_NUMCMP}, }; #if MYNEWT_VAL(BLE_HS_DEBUG) static uint8_t ble_sm_dbg_sc_pub_key[64]; static uint8_t ble_sm_dbg_sc_priv_key[32]; static uint8_t ble_sm_dbg_sc_keys_set; void ble_sm_dbg_set_sc_keys(uint8_t *pubkey, uint8_t *privkey) { memcpy(ble_sm_dbg_sc_pub_key, pubkey, sizeof ble_sm_dbg_sc_pub_key); memcpy(ble_sm_dbg_sc_priv_key, privkey, sizeof ble_sm_dbg_sc_priv_key); ble_sm_dbg_sc_keys_set = 1; } #endif int ble_sm_sc_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_SC; } 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_sc_init_ioa[pair_rsp->io_cap][pair_req->io_cap]; } else { *action = ble_sm_sc_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_SC: 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; case BLE_SM_IOACT_NUMCMP: proc->pair_alg = BLE_SM_PAIR_ALG_NUMCMP; proc->flags |= BLE_SM_PROC_F_AUTHENTICATED; break; default: BLE_HS_DBG_ASSERT(0); return BLE_HS_EINVAL; } return 0; } static int ble_sm_gen_pub_priv(uint8_t *pub, uint8_t *priv) { int rc; #if MYNEWT_VAL(BLE_HS_DEBUG) if (ble_sm_dbg_sc_keys_set) { ble_sm_dbg_sc_keys_set = 0; memcpy(pub, ble_sm_dbg_sc_pub_key, sizeof ble_sm_dbg_sc_pub_key); memcpy(priv, ble_sm_dbg_sc_priv_key, sizeof ble_sm_dbg_sc_priv_key); return 0; } #endif rc = ble_sm_alg_gen_key_pair(pub, priv); if (rc != 0) { return rc; } return 0; } static int ble_sm_sc_ensure_keys_generated(void) { int rc; if (!ble_sm_sc_keys_generated) { rc = ble_sm_gen_pub_priv(ble_sm_sc_pub_key, ble_sm_sc_priv_key); if (rc != 0) { return rc; } ble_sm_sc_keys_generated = 1; } BLE_HS_LOG(DEBUG, "our pubkey="); ble_hs_log_flat_buf(&ble_sm_sc_pub_key, 64); BLE_HS_LOG(DEBUG, "\n"); BLE_HS_LOG(DEBUG, "our privkey="); ble_hs_log_flat_buf(&ble_sm_sc_priv_key, 32); BLE_HS_LOG(DEBUG, "\n"); return 0; } /* Initiator does not send a confirm when pairing algorithm is any of: * o just works * o numeric comparison * (vol. 3, part H, 2.3.5.6.2) */ static int ble_sm_sc_initiator_txes_confirm(struct ble_sm_proc *proc) { BLE_HS_DBG_ASSERT(proc->flags & BLE_SM_PROC_F_SC); return proc->pair_alg != BLE_SM_PAIR_ALG_JW && proc->pair_alg != BLE_SM_PAIR_ALG_NUMCMP; } /* Responder does not verify the initiator's random number when pairing * algorithm is any of: * o just works * o numeric comparison * (vol. 3, part H, 2.3.5.6.2) */ static int ble_sm_sc_responder_verifies_random(struct ble_sm_proc *proc) { BLE_HS_DBG_ASSERT(proc->flags & BLE_SM_PROC_F_SC); return proc->pair_alg != BLE_SM_PAIR_ALG_JW && proc->pair_alg != BLE_SM_PAIR_ALG_NUMCMP; } /** * Generates the Ri byte used in the confirm message. On success, the byte is * written to the supplied procedure object. */ static int ble_sm_sc_gen_ri(struct ble_sm_proc *proc) { int byte; int bit; switch (proc->pair_alg) { case BLE_SM_PAIR_ALG_JW: case BLE_SM_PAIR_ALG_NUMCMP: case BLE_SM_PAIR_ALG_OOB: proc->ri = 0; return 0; case BLE_SM_PAIR_ALG_PASSKEY: BLE_HS_DBG_ASSERT(proc->passkey_bits_exchanged < BLE_SM_SC_PASSKEY_BITS); byte = proc->passkey_bits_exchanged / 8; bit = proc->passkey_bits_exchanged % 8; proc->ri = 0x80 | !!(proc->tk[byte] & (1 << bit)); proc->passkey_bits_exchanged++; return 0; default: BLE_HS_DBG_ASSERT(0); return BLE_HS_EUNKNOWN; } } void ble_sm_sc_oob_confirm(struct ble_sm_proc *proc, struct ble_sm_result *res) { int err; bool match; uint8_t c[16]; /* Authentication stage 1: Step 5 */ if (proc->oob_data_remote) { err = ble_sm_alg_f4(proc->pub_key_peer.x, proc->pub_key_peer.x, proc->oob_data_remote->r, 0, c); if (err) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED); res->enc_cb = 1; return; } match = (memcmp(c, proc->oob_data_remote->c, sizeof(c)) == 0); if (!match) { /* Random number mismatch. */ res->sm_err = BLE_SM_ERR_CONFIRM_MISMATCH; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH); res->enc_cb = 1; return; } } if ((proc->flags & BLE_SM_PROC_F_INITIATOR) || (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) { /* If is initiator or was waiting on * IO then execute step 6: send Random */ res->execute = 1; } } void ble_sm_sc_confirm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res) { struct ble_sm_pair_confirm *cmd; struct os_mbuf *txom; int rc; rc = ble_sm_sc_gen_ri(proc); if (rc != 0) { res->app_status = rc; res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_CONFIRM, sizeof(*cmd), &txom); if (cmd == NULL) { rc = BLE_HS_ENOMEM; res->app_status = rc; res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } rc = ble_sm_alg_f4(ble_sm_sc_pub_key, proc->pub_key_peer.x, ble_sm_our_pair_rand(proc), proc->ri, cmd->value); if (rc != 0) { os_mbuf_free_chain(txom); res->app_status = rc; res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } 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_RANDOM; } } static void ble_sm_sc_gen_numcmp(struct ble_sm_proc *proc, struct ble_sm_result *res) { uint8_t *pka; uint8_t *pkb; if (proc->flags & BLE_SM_PROC_F_INITIATOR) { pka = ble_sm_sc_pub_key; pkb = proc->pub_key_peer.x; } else { pka = proc->pub_key_peer.x; pkb = ble_sm_sc_pub_key; } res->app_status = ble_sm_alg_g2(pka, pkb, proc->randm, proc->rands, &res->passkey_params.numcmp); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; } } /** * Advances the supplied procedure object to the next state after it has * completed the random state. */ static int ble_sm_sc_random_advance(struct ble_sm_proc *proc) { int rc; if (proc->pair_alg != BLE_SM_PAIR_ALG_PASSKEY || proc->passkey_bits_exchanged >= BLE_SM_SC_PASSKEY_BITS) { proc->state = BLE_SM_PROC_STATE_DHKEY_CHECK; } else { proc->state = BLE_SM_PROC_STATE_CONFIRM; rc = ble_sm_gen_pair_rand(ble_sm_our_pair_rand(proc)); if (rc != 0) { return rc; } } return 0; } void ble_sm_sc_random_exec(struct ble_sm_proc *proc, struct ble_sm_result *res) { struct ble_sm_pair_random *cmd; struct os_mbuf *txom; uint8_t ioact; int rc; cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_RANDOM, sizeof(*cmd), &txom); if (cmd == NULL) { rc = 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)) { rc = ble_sm_sc_random_advance(proc); if (rc != 0) { res->app_status = rc; res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } rc = ble_sm_sc_io_action(proc, &ioact); BLE_HS_DBG_ASSERT(rc == 0); if (ble_sm_ioact_state(ioact) == proc->state && !(proc->flags & BLE_SM_PROC_F_IO_INJECTED)) { res->passkey_params.action = ioact; BLE_HS_DBG_ASSERT(ioact == BLE_SM_IOACT_NUMCMP); ble_sm_sc_gen_numcmp(proc, res); } } } void ble_sm_sc_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 ioact; uint8_t iat; uint8_t rat; int rc; if (proc->pair_alg != BLE_SM_PAIR_ALG_OOB && ( proc->flags & BLE_SM_PROC_F_INITIATOR || ble_sm_sc_responder_verifies_random(proc))) { BLE_HS_LOG(DEBUG, "tk="); ble_hs_log_flat_buf(proc->tk, 16); BLE_HS_LOG(DEBUG, "\n"); rc = ble_sm_alg_f4(proc->pub_key_peer.x, ble_sm_sc_pub_key, ble_sm_peer_pair_rand(proc), proc->ri, 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; } } /* Calculate the mac key and ltk. */ ble_sm_ia_ra(proc, &iat, ia, &rat, ra); rc = ble_sm_alg_f5(proc->dhkey, proc->randm, proc->rands, iat, ia, rat, ra, proc->mackey, proc->ltk); if (rc != 0) { res->app_status = rc; res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; return; } /* Ensure proper key size */ memset(proc->ltk + proc->key_size, 0, sizeof proc->ltk - proc->key_size); /* Ensure the ltk gets persisted when the pairing procedure succeeds. */ memcpy(proc->our_keys.ltk, proc->ltk, sizeof proc->our_keys.ltk); proc->our_keys.ltk_valid = 1; proc->our_keys.ediv = 0; proc->our_keys.rand_val = 0; proc->our_keys.ediv_rand_valid = 1; proc->our_keys.key_size = proc->key_size; memcpy(proc->peer_keys.ltk, proc->ltk, sizeof proc->peer_keys.ltk); proc->peer_keys.ltk_valid = 1; proc->peer_keys.ediv = 0; proc->peer_keys.rand_val = 0; proc->peer_keys.ediv_rand_valid = 1; proc->peer_keys.key_size = proc->key_size; if (proc->flags & BLE_SM_PROC_F_INITIATOR) { ble_sm_sc_random_advance(proc); rc = ble_sm_sc_io_action(proc, &ioact); if (rc != 0) { BLE_HS_DBG_ASSERT(0); } if (ble_sm_ioact_state(ioact) == proc->state && !(proc->flags & BLE_SM_PROC_F_IO_INJECTED)) { res->passkey_params.action = ioact; BLE_HS_DBG_ASSERT(ioact == BLE_SM_IOACT_NUMCMP); ble_sm_sc_gen_numcmp(proc, res); } else { res->execute = 1; } } else { if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB && !(proc->flags & BLE_SM_PROC_F_IO_INJECTED)) { proc->flags |= BLE_SM_PROC_F_ADVANCE_ON_IO; } else { res->execute = 1; } } } void ble_sm_sc_public_key_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg) { struct ble_sm_public_key *cmd; struct os_mbuf *txom; uint8_t ioact; int rc; res->app_status = ble_sm_sc_ensure_keys_generated(); if (res->app_status != 0) { res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_PUBLIC_KEY, sizeof(*cmd), &txom); if (!cmd) { res->app_status = BLE_HS_ENOMEM; res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } memcpy(cmd->x, ble_sm_sc_pub_key + 0, 32); memcpy(cmd->y, ble_sm_sc_pub_key + 32, 32); res->app_status = ble_sm_tx(proc->conn_handle, txom); if (res->app_status != 0) { res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) { if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) { proc->state = BLE_SM_PROC_STATE_RANDOM; } else { proc->state = BLE_SM_PROC_STATE_CONFIRM; } rc = ble_sm_sc_io_action(proc, &ioact); if (rc != 0) { BLE_HS_DBG_ASSERT(0); } if (ble_sm_ioact_state(ioact) == proc->state) { res->passkey_params.action = ioact; } if (ble_sm_proc_can_advance(proc) && !ble_sm_sc_initiator_txes_confirm(proc)) { res->execute = 1; } } } void ble_sm_sc_public_key_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res) { struct ble_sm_public_key *cmd; struct ble_sm_proc *proc; uint8_t ioact; int rc; res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd)); if (res->app_status != 0) { res->enc_cb = 1; return; } res->app_status = ble_sm_sc_ensure_keys_generated(); if (res->app_status != 0) { res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } cmd = (struct ble_sm_public_key *)(*om)->om_data; ble_hs_lock(); proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PUBLIC_KEY, -1, NULL); if (proc == NULL) { res->app_status = BLE_HS_ENOENT; res->sm_err = BLE_SM_ERR_UNSPECIFIED; } else { memcpy(&proc->pub_key_peer, cmd, sizeof(*cmd)); rc = ble_sm_alg_gen_dhkey(proc->pub_key_peer.x, proc->pub_key_peer.y, ble_sm_sc_priv_key, proc->dhkey); if (rc != 0) { res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_DHKEY); res->sm_err = BLE_SM_ERR_DHKEY; res->enc_cb = 1; } else { if (proc->flags & BLE_SM_PROC_F_INITIATOR) { if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) { proc->state = BLE_SM_PROC_STATE_RANDOM; } else { proc->state = BLE_SM_PROC_STATE_CONFIRM; } rc = ble_sm_sc_io_action(proc, &ioact); if (rc != 0) { BLE_HS_DBG_ASSERT(0); } if (ble_sm_ioact_state(ioact) == proc->state) { res->passkey_params.action = ioact; } if (ble_sm_proc_can_advance(proc) && ble_sm_sc_initiator_txes_confirm(proc)) { res->execute = 1; } } else { res->execute = 1; } } } ble_hs_unlock(); } static void ble_sm_sc_dhkey_addrs(struct ble_sm_proc *proc, ble_addr_t *our_addr, ble_addr_t *peer_addr) { struct ble_hs_conn_addrs addrs; struct ble_hs_conn *conn; conn = ble_hs_conn_find_assert(proc->conn_handle); ble_hs_conn_addrs(conn, &addrs); *our_addr = addrs.our_ota_addr; *peer_addr = addrs.peer_ota_addr; } void ble_sm_sc_dhkey_check_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg) { struct ble_sm_dhkey_check *cmd; ble_addr_t our_addr; ble_addr_t peer_addr; struct os_mbuf *txom; uint8_t *iocap; int rc; if (proc->flags & BLE_SM_PROC_F_INITIATOR) { struct ble_sm_pair_cmd *pair_req; pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1]; iocap = &pair_req->io_cap; } else { struct ble_sm_pair_cmd *pair_rsp; pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1]; iocap = &pair_rsp->io_cap; } if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) { if (proc->oob_data_remote) { memcpy(proc->tk, proc->oob_data_remote->r, 16); } else { memset(proc->tk, 0, 16); } } ble_sm_sc_dhkey_addrs(proc, &our_addr, &peer_addr); cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_DHKEY_CHECK, sizeof(*cmd), &txom); if (!cmd) { rc = BLE_HS_ENOMEM; goto err; } rc = ble_sm_alg_f6(proc->mackey, ble_sm_our_pair_rand(proc), ble_sm_peer_pair_rand(proc), proc->tk, iocap, our_addr.type, our_addr.val, peer_addr.type, peer_addr.val, cmd->value); if (rc != 0) { os_mbuf_free_chain(txom); 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_LTK_START; } return; err: res->app_status = rc; res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; } static void ble_sm_dhkey_check_process(struct ble_sm_proc *proc, struct ble_sm_dhkey_check *cmd, struct ble_sm_result *res) { uint8_t exp_value[16]; ble_addr_t our_addr; ble_addr_t peer_addr; uint8_t *iocap; uint8_t ioact; int rc; if (proc->flags & BLE_SM_PROC_F_INITIATOR) { struct ble_sm_pair_cmd *pair_rsp; pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1]; iocap = &pair_rsp->io_cap; if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) { if (pair_rsp->oob_data_flag) { memcpy(proc->tk, proc->oob_data_local->r, 16); } else { memset(proc->tk, 0, 16); } } } else { struct ble_sm_pair_cmd *pair_req; pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1]; iocap = &pair_req->io_cap; if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) { if (pair_req->oob_data_flag) { memcpy(proc->tk, proc->oob_data_local->r, 16); } else { memset(proc->tk, 0, 16); } } } ble_sm_sc_dhkey_addrs(proc, &our_addr, &peer_addr); BLE_HS_LOG(DEBUG, "tk="); ble_hs_log_flat_buf(proc->tk, 16); BLE_HS_LOG(DEBUG, "\n"); res->app_status = ble_sm_alg_f6(proc->mackey, ble_sm_peer_pair_rand(proc), ble_sm_our_pair_rand(proc), proc->tk, iocap, peer_addr.type, peer_addr.val, our_addr.type, our_addr.val, exp_value); if (res->app_status != 0) { res->sm_err = BLE_SM_ERR_UNSPECIFIED; res->enc_cb = 1; return; } if (memcmp(cmd->value, exp_value, 16) != 0) { /* Random number mismatch. */ res->sm_err = BLE_SM_ERR_DHKEY; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_DHKEY); res->enc_cb = 1; return; } rc = ble_sm_sc_io_action(proc, &ioact); if (rc != 0) { BLE_HS_DBG_ASSERT(0); } if (ble_sm_ioact_state(ioact) == proc->state) { proc->flags |= BLE_SM_PROC_F_ADVANCE_ON_IO; } if (ble_sm_proc_can_advance(proc)) { if (proc->flags & BLE_SM_PROC_F_INITIATOR) { proc->state = BLE_SM_PROC_STATE_ENC_START; } res->execute = 1; } } void ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res) { struct ble_sm_dhkey_check *cmd; struct ble_sm_proc *proc; res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd)); if (res->app_status != 0) { res->enc_cb = 1; res->sm_err = BLE_SM_ERR_UNSPECIFIED; return; } cmd = (struct ble_sm_dhkey_check *)(*om)->om_data; ble_hs_lock(); proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_DHKEY_CHECK, -1, NULL); if (proc == NULL) { res->app_status = BLE_HS_ENOENT; } else { ble_sm_dhkey_check_process(proc, cmd, res); } ble_hs_unlock(); } bool ble_sm_sc_oob_data_check(struct ble_sm_proc *proc, bool oob_data_local_present, bool oob_data_remote_present) { struct ble_sm_pair_cmd *pair_req; struct ble_sm_pair_cmd *pair_rsp; bool req_oob_present; bool rsp_oob_present; pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1]; pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1]; req_oob_present = pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES; rsp_oob_present = pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES; if (proc->flags & BLE_SM_PROC_F_INITIATOR) { return req_oob_present == oob_data_remote_present; } else { return rsp_oob_present == oob_data_remote_present; } } int ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data) { int rc; #if !MYNEWT_VAL(BLE_SM_SC) return BLE_HS_ENOTSUP; #endif rc = ble_sm_sc_ensure_keys_generated(); if (rc) { return rc; } rc = ble_hs_hci_util_rand(oob_data->r, 16); if (rc) { return rc; } rc = ble_sm_alg_f4(ble_sm_sc_pub_key, ble_sm_sc_pub_key, oob_data->r, 0, oob_data->c); if (rc) { return rc; } return 0; } void ble_sm_sc_init(void) { ble_sm_alg_ecc_init(); ble_sm_sc_keys_generated = 0; } #endif /* MYNEWT_VAL(BLE_SM_SC) */