xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_sm_lgcy.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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