1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include "securec.h"
21 #include "nimble/ble.h"
22 #include "nimble/nimble_opt.h"
23 #include "host/ble_sm.h"
24 #include "ble_hs_priv.h"
25
26 #if MYNEWT_VAL(BLE_SM_LEGACY)
27
28 /**
29 * Create some shortened names for the passkey actions so that the table is
30 * easier to read.
31 */
32 #define IOACT_NONE BLE_SM_IOACT_NONE
33 #define IOACT_OOB BLE_SM_IOACT_OOB
34 #define IOACT_INPUT BLE_SM_IOACT_INPUT
35 #define IOACT_DISP BLE_SM_IOACT_DISP
36
37 /* This is the initiator passkey action action dpeneding on the io
38 * capabilties of both parties
39 */
40 static const uint8_t ble_sm_lgcy_init_ioa[5][5] = {
41 {IOACT_NONE, IOACT_NONE, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
42 {IOACT_NONE, IOACT_NONE, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
43 {IOACT_DISP, IOACT_DISP, IOACT_INPUT, IOACT_NONE, IOACT_DISP},
44 {IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE},
45 {IOACT_DISP, IOACT_DISP, IOACT_INPUT, IOACT_NONE, IOACT_DISP},
46 };
47
48 /* This is the responder passkey action action depending on the io
49 * capabilities of both parties
50 */
51 static const uint8_t ble_sm_lgcy_resp_ioa[5][5] = {
52 {IOACT_NONE, IOACT_NONE, IOACT_DISP, IOACT_NONE, IOACT_DISP},
53 {IOACT_NONE, IOACT_NONE, IOACT_DISP, IOACT_NONE, IOACT_DISP},
54 {IOACT_INPUT, IOACT_INPUT, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
55 {IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE},
56 {IOACT_INPUT, IOACT_INPUT, IOACT_DISP, IOACT_NONE, IOACT_INPUT},
57 };
58
ble_sm_lgcy_io_action(struct ble_sm_proc * proc,uint8_t * action)59 int ble_sm_lgcy_io_action(struct ble_sm_proc *proc, uint8_t *action)
60 {
61 struct ble_sm_pair_cmd *pair_req, *pair_rsp;
62 pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1];
63 pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
64
65 if (pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES &&
66 pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES) {
67 *action = BLE_SM_IOACT_OOB;
68 } else if (!(pair_req->authreq & BLE_SM_PAIR_AUTHREQ_MITM) &&
69 !(pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_MITM)) {
70 *action = BLE_SM_IOACT_NONE;
71 } else if (pair_req->io_cap >= BLE_SM_IO_CAP_RESERVED ||
72 pair_rsp->io_cap >= BLE_SM_IO_CAP_RESERVED) {
73 *action = BLE_SM_IOACT_NONE;
74 } else if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
75 *action = ble_sm_lgcy_init_ioa[pair_rsp->io_cap][pair_req->io_cap];
76 } else {
77 *action = ble_sm_lgcy_resp_ioa[pair_rsp->io_cap][pair_req->io_cap];
78 }
79
80 switch (*action) {
81 case BLE_SM_IOACT_NONE:
82 proc->pair_alg = BLE_SM_PAIR_ALG_JW;
83 break;
84
85 case BLE_SM_IOACT_OOB:
86 proc->pair_alg = BLE_SM_PAIR_ALG_OOB;
87 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
88 break;
89
90 case BLE_SM_IOACT_INPUT:
91 case BLE_SM_IOACT_DISP:
92 proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY;
93 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
94 break;
95
96 default:
97 BLE_HS_DBG_ASSERT(0);
98 return BLE_HS_EINVAL;
99 }
100
101 return 0;
102 }
103
ble_sm_lgcy_confirm_exec(struct ble_sm_proc * proc,struct ble_sm_result * res)104 void ble_sm_lgcy_confirm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res)
105 {
106 struct ble_sm_pair_confirm *cmd;
107 struct os_mbuf *txom;
108 uint8_t ia[6];
109 uint8_t ra[6];
110 uint8_t iat;
111 uint8_t rat;
112 int rc;
113 cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_CONFIRM, sizeof(*cmd), &txom);
114 if (cmd == NULL) {
115 rc = BLE_HS_ENOMEM;
116 goto err;
117 }
118
119 ble_sm_ia_ra(proc, &iat, ia, &rat, ra);
120 rc = ble_sm_alg_c1(proc->tk, ble_sm_our_pair_rand(proc), proc->pair_req,
121 proc->pair_rsp, iat, rat, ia, ra, cmd->value);
122 if (rc != 0) {
123 goto err;
124 }
125
126 rc = ble_sm_tx(proc->conn_handle, txom);
127 if (rc != 0) {
128 goto err;
129 }
130
131 if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
132 proc->state = BLE_SM_PROC_STATE_RANDOM;
133 }
134
135 return;
136 err:
137
138 if (txom) {
139 os_mbuf_free_chain(txom);
140 }
141
142 res->app_status = rc;
143 res->enc_cb = 1;
144 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
145 }
146
ble_sm_gen_stk(struct ble_sm_proc * proc)147 static int ble_sm_gen_stk(struct ble_sm_proc *proc)
148 {
149 uint8_t key[16];
150 int rc;
151 rc = ble_sm_alg_s1(proc->tk, proc->rands, proc->randm, key);
152 if (rc != 0) {
153 return rc;
154 }
155
156 memcpy_s(proc->ltk, sizeof(proc->ltk), key, proc->key_size);
157 /* Ensure proper key size */
158 memset_s(proc->ltk + proc->key_size, sizeof(proc->ltk + proc->key_size), 0, sizeof key - proc->key_size);
159 return 0;
160 }
161
ble_sm_lgcy_random_exec(struct ble_sm_proc * proc,struct ble_sm_result * res)162 void ble_sm_lgcy_random_exec(struct ble_sm_proc *proc, struct ble_sm_result *res)
163 {
164 struct ble_sm_pair_random *cmd;
165 struct os_mbuf *txom;
166 int rc;
167 cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_RANDOM, sizeof(*cmd), &txom);
168 if (cmd == NULL) {
169 res->app_status = BLE_HS_ENOMEM;
170 res->enc_cb = 1;
171 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
172 return;
173 }
174
175 memcpy_s(cmd->value, sizeof(cmd->value), ble_sm_our_pair_rand(proc), 16); // 16:size
176 rc = ble_sm_tx(proc->conn_handle, txom);
177 if (rc != 0) {
178 res->app_status = rc;
179 res->enc_cb = 1;
180 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
181 return;
182 }
183
184 if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
185 proc->state = BLE_SM_PROC_STATE_LTK_START;
186 }
187 }
188
ble_sm_lgcy_random_rx(struct ble_sm_proc * proc,struct ble_sm_result * res)189 void ble_sm_lgcy_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res)
190 {
191 uint8_t confirm_val[16];
192 uint8_t ia[6];
193 uint8_t ra[6];
194 uint8_t iat;
195 uint8_t rat;
196 int rc;
197 ble_sm_ia_ra(proc, &iat, ia, &rat, ra);
198 rc = ble_sm_alg_c1(proc->tk, ble_sm_peer_pair_rand(proc), proc->pair_req,
199 proc->pair_rsp, iat, rat, ia, ra, confirm_val);
200 if (rc != 0) {
201 res->app_status = rc;
202 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
203 res->enc_cb = 1;
204 return;
205 }
206
207 if (memcmp(proc->confirm_peer, confirm_val, 16) != 0) { // 16:size
208 /* Random number mismatch. */
209 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH);
210 res->sm_err = BLE_SM_ERR_CONFIRM_MISMATCH;
211 res->enc_cb = 1;
212 return;
213 }
214
215 /* Generate the key. */
216 rc = ble_sm_gen_stk(proc);
217 if (rc != 0) {
218 res->app_status = rc;
219 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
220 res->enc_cb = 1;
221 return;
222 }
223
224 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
225 /* Send the start-encrypt HCI command to the controller. For
226 * short-term key generation, we always set ediv and rand to 0.
227 * (Vol. 3, part H, 2.4.4.1).
228 */
229 proc->state = BLE_SM_PROC_STATE_ENC_START;
230 }
231
232 res->execute = 1;
233 }
234
235 #endif