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 <string.h>
21 #include <errno.h>
22 #include "nimble/ble.h"
23 #include "nimble/nimble_opt.h"
24 #include "host/ble_sm.h"
25 #include "ble_hs_priv.h"
26
27 #if MYNEWT_VAL(BLE_SM_LEGACY)
28
29 /**
30 * Create some shortened names for the passkey actions so that the table is
31 * easier to read.
32 */
33 #define IOACT_NONE BLE_SM_IOACT_NONE
34 #define IOACT_OOB BLE_SM_IOACT_OOB
35 #define IOACT_INPUT BLE_SM_IOACT_INPUT
36 #define IOACT_DISP BLE_SM_IOACT_DISP
37
38 /* This is the initiator passkey action action dpeneding on the io
39 * capabilties of both parties
40 */
41 static const uint8_t ble_sm_lgcy_init_ioa[5 /*resp*/ ][5 /*init*/ ] =
42 {
43 {IOACT_NONE, IOACT_NONE, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
44 {IOACT_NONE, IOACT_NONE, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
45 {IOACT_DISP, IOACT_DISP, IOACT_INPUT, IOACT_NONE, IOACT_DISP},
46 {IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE},
47 {IOACT_DISP, IOACT_DISP, IOACT_INPUT, IOACT_NONE, IOACT_DISP},
48 };
49
50 /* This is the responder passkey action action depending on the io
51 * capabilities of both parties
52 */
53 static const uint8_t ble_sm_lgcy_resp_ioa[5 /*resp*/ ][5 /*init*/ ] =
54 {
55 {IOACT_NONE, IOACT_NONE, IOACT_DISP, IOACT_NONE, IOACT_DISP},
56 {IOACT_NONE, IOACT_NONE, IOACT_DISP, IOACT_NONE, IOACT_DISP},
57 {IOACT_INPUT, IOACT_INPUT, IOACT_INPUT, IOACT_NONE, IOACT_INPUT},
58 {IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE, IOACT_NONE},
59 {IOACT_INPUT, IOACT_INPUT, IOACT_DISP, IOACT_NONE, IOACT_INPUT},
60 };
61
62 int
ble_sm_lgcy_io_action(struct ble_sm_proc * proc,uint8_t * action)63 ble_sm_lgcy_io_action(struct ble_sm_proc *proc, uint8_t *action)
64 {
65 struct ble_sm_pair_cmd *pair_req, *pair_rsp;
66
67 pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1];
68 pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
69
70 if (pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES &&
71 pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES) {
72 *action = BLE_SM_IOACT_OOB;
73 } else if (!(pair_req->authreq & BLE_SM_PAIR_AUTHREQ_MITM) &&
74 !(pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_MITM)) {
75
76 *action = BLE_SM_IOACT_NONE;
77 } else if (pair_req->io_cap >= BLE_SM_IO_CAP_RESERVED ||
78 pair_rsp->io_cap >= BLE_SM_IO_CAP_RESERVED) {
79 *action = BLE_SM_IOACT_NONE;
80 } else if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
81 *action = ble_sm_lgcy_init_ioa[pair_rsp->io_cap][pair_req->io_cap];
82 } else {
83 *action = ble_sm_lgcy_resp_ioa[pair_rsp->io_cap][pair_req->io_cap];
84 }
85
86 switch (*action) {
87 case BLE_SM_IOACT_NONE:
88 proc->pair_alg = BLE_SM_PAIR_ALG_JW;
89 break;
90
91 case BLE_SM_IOACT_OOB:
92 proc->pair_alg = BLE_SM_PAIR_ALG_OOB;
93 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
94 break;
95
96 case BLE_SM_IOACT_INPUT:
97 case BLE_SM_IOACT_DISP:
98 proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY;
99 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
100 break;
101
102 default:
103 BLE_HS_DBG_ASSERT(0);
104 return BLE_HS_EINVAL;
105 }
106
107 return 0;
108 }
109
110 void
ble_sm_lgcy_confirm_exec(struct ble_sm_proc * proc,struct ble_sm_result * res)111 ble_sm_lgcy_confirm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res)
112 {
113 struct ble_sm_pair_confirm *cmd;
114 struct os_mbuf *txom;
115 uint8_t ia[6];
116 uint8_t ra[6];
117 uint8_t iat;
118 uint8_t rat;
119 int rc;
120
121 cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_CONFIRM, sizeof(*cmd), &txom);
122 if (cmd == NULL) {
123 rc = BLE_HS_ENOMEM;
124 goto err;
125 }
126
127 ble_sm_ia_ra(proc, &iat, ia, &rat, ra);
128
129 rc = ble_sm_alg_c1(proc->tk, ble_sm_our_pair_rand(proc), proc->pair_req,
130 proc->pair_rsp, iat, rat, ia, ra, cmd->value);
131 if (rc != 0) {
132 goto err;
133 }
134
135 rc = ble_sm_tx(proc->conn_handle, txom);
136 if (rc != 0) {
137 goto err;
138 }
139
140 if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
141 proc->state = BLE_SM_PROC_STATE_RANDOM;
142 }
143
144 return;
145
146 err:
147 if (txom) {
148 os_mbuf_free_chain(txom);
149 }
150
151 res->app_status = rc;
152 res->enc_cb = 1;
153 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
154 }
155
156 static int
ble_sm_gen_stk(struct ble_sm_proc * proc)157 ble_sm_gen_stk(struct ble_sm_proc *proc)
158 {
159 uint8_t key[16];
160 int rc;
161
162 rc = ble_sm_alg_s1(proc->tk, proc->rands, proc->randm, key);
163 if (rc != 0) {
164 return rc;
165 }
166
167 memcpy(proc->ltk, key, proc->key_size);
168
169 /* Ensure proper key size */
170 memset(proc->ltk + proc->key_size, 0, sizeof key - proc->key_size);
171
172 return 0;
173 }
174
175 void
ble_sm_lgcy_random_exec(struct ble_sm_proc * proc,struct ble_sm_result * res)176 ble_sm_lgcy_random_exec(struct ble_sm_proc *proc, struct ble_sm_result *res)
177 {
178 struct ble_sm_pair_random *cmd;
179 struct os_mbuf *txom;
180 int rc;
181
182 cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_RANDOM, sizeof(*cmd), &txom);
183 if (cmd == NULL) {
184 res->app_status = BLE_HS_ENOMEM;
185 res->enc_cb = 1;
186 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
187 return;
188 }
189
190 memcpy(cmd->value, ble_sm_our_pair_rand(proc), 16);
191
192 rc = ble_sm_tx(proc->conn_handle, txom);
193 if (rc != 0) {
194 res->app_status = rc;
195 res->enc_cb = 1;
196 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
197 return;
198 }
199
200 if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
201 proc->state = BLE_SM_PROC_STATE_LTK_START;
202 }
203 }
204
205 void
ble_sm_lgcy_random_rx(struct ble_sm_proc * proc,struct ble_sm_result * res)206 ble_sm_lgcy_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res)
207 {
208 uint8_t confirm_val[16];
209 uint8_t ia[6];
210 uint8_t ra[6];
211 uint8_t iat;
212 uint8_t rat;
213 int rc;
214
215 ble_sm_ia_ra(proc, &iat, ia, &rat, ra);
216
217 rc = ble_sm_alg_c1(proc->tk, ble_sm_peer_pair_rand(proc), proc->pair_req,
218 proc->pair_rsp, iat, rat, ia, ra, confirm_val);
219 if (rc != 0) {
220 res->app_status = rc;
221 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
222 res->enc_cb = 1;
223 return;
224 }
225
226 if (memcmp(proc->confirm_peer, confirm_val, 16) != 0) {
227 /* Random number mismatch. */
228 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH);
229 res->sm_err = BLE_SM_ERR_CONFIRM_MISMATCH;
230 res->enc_cb = 1;
231 return;
232 }
233
234 /* Generate the key. */
235 rc = ble_sm_gen_stk(proc);
236 if (rc != 0) {
237 res->app_status = rc;
238 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
239 res->enc_cb = 1;
240 return;
241 }
242
243 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
244 /* Send the start-encrypt HCI command to the controller. For
245 * short-term key generation, we always set ediv and rand to 0.
246 * (Vol. 3, part H, 2.4.4.1).
247 */
248 proc->state = BLE_SM_PROC_STATE_ENC_START;
249 }
250
251 res->execute = 1;
252 }
253
254 #endif
255