diff options
author | Anderson Briglia <anderson.briglia@openbossa.org> | 2011-06-09 17:50:46 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-13 14:48:25 -0400 |
commit | 7d24ddcc1140d2f796436e476c8d69469610588b (patch) | |
tree | c2bb98242fb3e8e9b441ce92fccfabea3a7bf492 | |
parent | f01ead315785768cdb6e928646f90a47640bcdd9 (diff) |
Bluetooth: Add SMP confirmation checks methods
This patch includes support for generating and sending the random value
used to produce the confirmation value.
Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r-- | include/net/bluetooth/l2cap.h | 1 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 97 |
2 files changed, 84 insertions, 14 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index b03d9c4dfc78..01c993b6b263 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -399,6 +399,7 @@ struct l2cap_conn { | |||
399 | __u8 prsp[7]; /* SMP Pairing Response */ | 399 | __u8 prsp[7]; /* SMP Pairing Response */ |
400 | __u8 prnd[16]; /* SMP Pairing Random */ | 400 | __u8 prnd[16]; /* SMP Pairing Random */ |
401 | __u8 pcnf[16]; /* SMP Pairing Confirm */ | 401 | __u8 pcnf[16]; /* SMP Pairing Confirm */ |
402 | __u8 tk[16]; /* SMP Temporary Key */ | ||
402 | 403 | ||
403 | struct list_head chan_l; | 404 | struct list_head chan_l; |
404 | rwlock_t chan_lock; | 405 | rwlock_t chan_lock; |
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index fa22f4aa3b04..7a9a195c27d3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
@@ -198,6 +198,9 @@ static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
198 | rp->resp_key_dist = 0x00; | 198 | rp->resp_key_dist = 0x00; |
199 | rp->auth_req &= (SMP_AUTH_BONDING | SMP_AUTH_MITM); | 199 | rp->auth_req &= (SMP_AUTH_BONDING | SMP_AUTH_MITM); |
200 | 200 | ||
201 | /* Just works */ | ||
202 | memset(conn->tk, 0, sizeof(conn->tk)); | ||
203 | |||
201 | conn->prsp[0] = SMP_CMD_PAIRING_RSP; | 204 | conn->prsp[0] = SMP_CMD_PAIRING_RSP; |
202 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); | 205 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); |
203 | 206 | ||
@@ -208,54 +211,120 @@ static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | |||
208 | { | 211 | { |
209 | struct smp_cmd_pairing *rp = (void *) skb->data; | 212 | struct smp_cmd_pairing *rp = (void *) skb->data; |
210 | struct smp_cmd_pairing_confirm cp; | 213 | struct smp_cmd_pairing_confirm cp; |
214 | struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; | ||
215 | int ret; | ||
216 | u8 res[16]; | ||
211 | 217 | ||
212 | BT_DBG("conn %p", conn); | 218 | BT_DBG("conn %p", conn); |
213 | 219 | ||
214 | memset(&cp, 0, sizeof(cp)); | 220 | /* Just works */ |
221 | memset(conn->tk, 0, sizeof(conn->tk)); | ||
215 | 222 | ||
216 | conn->prsp[0] = SMP_CMD_PAIRING_RSP; | 223 | conn->prsp[0] = SMP_CMD_PAIRING_RSP; |
217 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); | 224 | memcpy(&conn->prsp[1], rp, sizeof(*rp)); |
218 | skb_pull(skb, sizeof(*rp)); | 225 | skb_pull(skb, sizeof(*rp)); |
219 | 226 | ||
227 | ret = smp_rand(conn->prnd); | ||
228 | if (ret) | ||
229 | return; | ||
230 | |||
231 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0, | ||
232 | conn->src, conn->hcon->dst_type, conn->dst, res); | ||
233 | if (ret) | ||
234 | return; | ||
235 | |||
236 | swap128(res, cp.confirm_val); | ||
237 | |||
220 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); | 238 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); |
221 | } | 239 | } |
222 | 240 | ||
223 | static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, | 241 | static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, |
224 | struct sk_buff *skb) | 242 | struct sk_buff *skb) |
225 | { | 243 | { |
244 | struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; | ||
245 | |||
226 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); | 246 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); |
227 | 247 | ||
228 | if (conn->hcon->out) { | 248 | memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf)); |
229 | struct smp_cmd_pairing_random random; | 249 | skb_pull(skb, sizeof(conn->pcnf)); |
230 | 250 | ||
231 | memset(&random, 0, sizeof(random)); | 251 | if (conn->hcon->out) { |
252 | u8 random[16]; | ||
232 | 253 | ||
254 | swap128(conn->prnd, random); | ||
233 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), | 255 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random), |
234 | &random); | 256 | random); |
235 | } else { | 257 | } else { |
236 | struct smp_cmd_pairing_confirm confirm; | 258 | struct smp_cmd_pairing_confirm cp; |
259 | int ret; | ||
260 | u8 res[16]; | ||
237 | 261 | ||
238 | memset(&confirm, 0, sizeof(confirm)); | 262 | ret = smp_rand(conn->prnd); |
263 | if (ret) | ||
264 | return; | ||
239 | 265 | ||
240 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(confirm), | 266 | ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, |
241 | &confirm); | 267 | conn->hcon->dst_type, conn->dst, |
268 | 0, conn->src, res); | ||
269 | if (ret) | ||
270 | return; | ||
271 | |||
272 | swap128(res, cp.confirm_val); | ||
273 | |||
274 | smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp); | ||
242 | } | 275 | } |
243 | } | 276 | } |
244 | 277 | ||
245 | static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) | 278 | static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) |
246 | { | 279 | { |
247 | struct smp_cmd_pairing_random cp; | 280 | struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm; |
281 | int ret; | ||
282 | u8 key[16], res[16], random[16], confirm[16], buf[128]; | ||
283 | |||
284 | swap128(skb->data, random); | ||
285 | skb_pull(skb, sizeof(random)); | ||
286 | |||
287 | if (conn->hcon->out) | ||
288 | ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0, | ||
289 | conn->src, conn->hcon->dst_type, conn->dst, | ||
290 | res); | ||
291 | else | ||
292 | ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, | ||
293 | conn->hcon->dst_type, conn->dst, 0, conn->src, | ||
294 | res); | ||
295 | if (ret) | ||
296 | return; | ||
248 | 297 | ||
249 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); | 298 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); |
250 | 299 | ||
251 | skb_pull(skb, sizeof(cp)); | 300 | swap128(res, confirm); |
301 | |||
302 | if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) { | ||
303 | struct smp_cmd_pairing_fail cp; | ||
304 | |||
305 | BT_ERR("Pairing failed (confirmation values mismatch)"); | ||
306 | cp.reason = SMP_CONFIRM_FAILED; | ||
307 | smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(cp), &cp); | ||
308 | return; | ||
309 | } | ||
252 | 310 | ||
253 | if (conn->hcon->out) { | 311 | if (conn->hcon->out) { |
254 | /* FIXME: start encryption */ | 312 | smp_s1(tfm, conn->tk, random, conn->prnd, key); |
313 | |||
314 | hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, | ||
315 | sizeof(buf), 0); | ||
316 | BT_DBG("key %s", buf); | ||
255 | } else { | 317 | } else { |
256 | memset(&cp, 0, sizeof(cp)); | 318 | u8 r[16]; |
319 | |||
320 | swap128(conn->prnd, r); | ||
321 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r); | ||
322 | |||
323 | smp_s1(tfm, conn->tk, conn->prnd, random, key); | ||
257 | 324 | ||
258 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(cp), &cp); | 325 | hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, |
326 | sizeof(buf), 0); | ||
327 | BT_DBG("key %s", buf); | ||
259 | } | 328 | } |
260 | } | 329 | } |
261 | 330 | ||