| /* |
| * 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 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 dpeneding 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 |