| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2013-2014 Intel Corporation
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdio.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <endian.h>
- #include <stdbool.h>
- #include <sys/socket.h>
- #include "lib/bluetooth.h"
- #include "lib/hci.h"
- #include "src/shared/util.h"
- #include "src/shared/crypto.h"
- #include "src/shared/ecc.h"
- #include "monitor/bt.h"
- #include "bthost.h"
- #define SMP_CID 0x0006
- #define SMP_BREDR_CID 0x0007
- #define L2CAP_FC_SMP_BREDR 0x80
- #define SMP_PASSKEY_ENTRY_FAILED 0x01
- #define SMP_OOB_NOT_AVAIL 0x02
- #define SMP_AUTH_REQUIREMENTS 0x03
- #define SMP_CONFIRM_FAILED 0x04
- #define SMP_PAIRING_NOTSUPP 0x05
- #define SMP_ENC_KEY_SIZE 0x06
- #define SMP_CMD_NOTSUPP 0x07
- #define SMP_UNSPECIFIED 0x08
- #define SMP_REPEATED_ATTEMPTS 0x09
- #define SMP_INVALID_PARAMS 0x0a
- #define SMP_DHKEY_CHECK_FAILED 0x0b
- #define SMP_NUMERIC_COMP_FAILED 0x0c
- #define SMP_BREDR_PAIRING_IN_PROGRESS 0x0d
- #define DIST_ENC_KEY 0x01
- #define DIST_ID_KEY 0x02
- #define DIST_SIGN 0x04
- #define DIST_LINK_KEY 0x08
- #define SC_NO_DIST (DIST_ENC_KEY | DIST_LINK_KEY)
- #define MAX_IO_CAP 0x04
- #define SMP_AUTH_NONE 0x00
- #define SMP_AUTH_BONDING 0x01
- #define SMP_AUTH_MITM 0x04
- #define SMP_AUTH_SC 0x08
- #define SMP_AUTH_KEYPRESS 0x10
- struct smp {
- struct bthost *bthost;
- struct smp_conn *conn;
- struct bt_crypto *crypto;
- };
- struct smp_conn {
- struct smp *smp;
- uint16_t handle;
- uint8_t addr_type;
- bool out;
- bool sc;
- bool initiator;
- uint8_t method;
- uint8_t local_key_dist;
- uint8_t remote_key_dist;
- uint8_t ia[6];
- uint8_t ia_type;
- uint8_t ra[6];
- uint8_t ra_type;
- uint8_t tk[16];
- uint8_t prnd[16];
- uint8_t rrnd[16];
- uint8_t pcnf[16];
- uint8_t preq[7];
- uint8_t prsp[7];
- uint8_t ltk[16];
- uint8_t local_sk[32];
- uint8_t local_pk[64];
- uint8_t remote_pk[64];
- uint8_t dhkey[32];
- uint8_t mackey[16];
- uint8_t passkey_notify;
- uint8_t passkey_round;
- };
- enum {
- JUST_WORKS,
- JUST_CFM,
- REQ_PASSKEY,
- CFM_PASSKEY,
- REQ_OOB,
- DSP_PASSKEY,
- OVERLAP,
- };
- static const uint8_t gen_method[5][5] = {
- { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
- { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
- { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
- { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM },
- { CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP },
- };
- static const uint8_t sc_method[5][5] = {
- { JUST_WORKS, JUST_CFM, REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
- { JUST_WORKS, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
- { DSP_PASSKEY, DSP_PASSKEY, REQ_PASSKEY, JUST_WORKS, DSP_PASSKEY },
- { JUST_WORKS, JUST_CFM, JUST_WORKS, JUST_WORKS, JUST_CFM },
- { DSP_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
- };
- static uint8_t get_auth_method(struct smp_conn *conn, uint8_t local_io,
- uint8_t remote_io)
- {
- /* If either side has unknown io_caps, use JUST_CFM (which gets
- * converted later to JUST_WORKS if we're initiators.
- */
- if (local_io > MAX_IO_CAP || remote_io > MAX_IO_CAP)
- return JUST_CFM;
- if (conn->sc)
- return sc_method[remote_io][local_io];
- return gen_method[remote_io][local_io];
- }
- static uint8_t sc_select_method(struct smp_conn *conn)
- {
- struct bt_l2cap_smp_pairing_request *local, *remote;
- uint8_t local_mitm, remote_mitm, local_io, remote_io, method;
- if (conn->out) {
- local = (void *) &conn->preq[1];
- remote = (void *) &conn->prsp[1];
- } else {
- local = (void *) &conn->prsp[1];
- remote = (void *) &conn->preq[1];
- }
- local_io = local->io_capa;
- remote_io = remote->io_capa;
- local_mitm = (local->auth_req & SMP_AUTH_MITM);
- remote_mitm = (remote->auth_req & SMP_AUTH_MITM);
- /* If either side wants MITM, look up the method from the table,
- * otherwise use JUST WORKS.
- */
- if (local_mitm || remote_mitm)
- method = get_auth_method(conn, local_io, remote_io);
- else
- method = JUST_WORKS;
- /* Don't confirm locally initiated pairing attempts */
- if (method == JUST_CFM && conn->initiator)
- method = JUST_WORKS;
- return method;
- }
- static uint8_t key_dist(struct bthost *host)
- {
- if (!bthost_bredr_capable(host))
- return (DIST_ENC_KEY | DIST_ID_KEY | DIST_SIGN);
- return (DIST_ENC_KEY | DIST_ID_KEY | DIST_SIGN | DIST_LINK_KEY);
- }
- static void smp_send(struct smp_conn *conn, uint8_t smp_cmd, const void *data,
- uint8_t len)
- {
- struct iovec iov[2];
- uint16_t cid;
- iov[0].iov_base = &smp_cmd;
- iov[0].iov_len = 1;
- iov[1].iov_base = (void *) data;
- iov[1].iov_len = len;
- if (conn->addr_type == BDADDR_BREDR)
- cid = SMP_BREDR_CID;
- else
- cid = SMP_CID;
- bthost_send_cid_v(conn->smp->bthost, conn->handle, cid, iov, 2);
- }
- static bool send_public_key(struct smp_conn *conn)
- {
- if (!ecc_make_key(conn->local_pk, conn->local_sk))
- return false;
- smp_send(conn, BT_L2CAP_SMP_PUBLIC_KEY, conn->local_pk, 64);
- return true;
- }
- static void sc_dhkey_check(struct smp_conn *conn)
- {
- uint8_t io_cap[3], r[16], a[7], b[7], *local_addr, *remote_addr;
- struct bt_l2cap_smp_dhkey_check check;
- memcpy(a, conn->ia, 6);
- memcpy(b, conn->ra, 6);
- a[6] = conn->ia_type;
- b[6] = conn->ra_type;
- if (conn->out) {
- local_addr = a;
- remote_addr = b;
- memcpy(io_cap, &conn->preq[1], 3);
- } else {
- local_addr = b;
- remote_addr = a;
- memcpy(io_cap, &conn->prsp[1], 3);
- }
- memset(r, 0, sizeof(r));
- bt_crypto_f6(conn->smp->crypto, conn->mackey, conn->prnd, conn->rrnd,
- r, io_cap, local_addr, remote_addr, check.e);
- smp_send(conn, BT_L2CAP_SMP_DHKEY_CHECK, &check, sizeof(check));
- }
- static void sc_mackey_and_ltk(struct smp_conn *conn)
- {
- uint8_t *na, *nb, a[7], b[7];
- if (conn->out) {
- na = conn->prnd;
- nb = conn->rrnd;
- } else {
- na = conn->rrnd;
- nb = conn->prnd;
- }
- memcpy(a, conn->ia, 6);
- memcpy(b, conn->ra, 6);
- a[6] = conn->ia_type;
- b[6] = conn->ra_type;
- bt_crypto_f5(conn->smp->crypto, conn->dhkey, na, nb, a, b,
- conn->mackey, conn->ltk);
- }
- static uint8_t sc_passkey_send_confirm(struct smp_conn *conn)
- {
- struct bt_l2cap_smp_pairing_confirm cfm;
- uint8_t r;
- r = ((conn->passkey_notify >> conn->passkey_round) & 0x01);
- r |= 0x80;
- if (!bt_crypto_f4(conn->smp->crypto, conn->local_pk, conn->remote_pk,
- conn->prnd, r, cfm.value))
- return SMP_UNSPECIFIED;
- smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, &cfm, sizeof(cfm));
- return 0;
- }
- static uint8_t sc_passkey_round(struct smp_conn *conn, uint8_t smp_op)
- {
- uint8_t cfm[16], r;
- /* Ignore the PDU if we've already done 20 rounds (0 - 19) */
- if (conn->passkey_round >= 20)
- return 0;
- switch (smp_op) {
- case BT_L2CAP_SMP_PAIRING_RANDOM:
- r = ((conn->passkey_notify >> conn->passkey_round) & 0x01);
- r |= 0x80;
- if (!bt_crypto_f4(conn->smp->crypto, conn->remote_pk,
- conn->local_pk, conn->rrnd, r, cfm))
- return SMP_UNSPECIFIED;
- if (memcmp(conn->pcnf, cfm, 16))
- return SMP_CONFIRM_FAILED;
- conn->passkey_round++;
- if (conn->passkey_round == 20) {
- /* Generate MacKey and LTK */
- sc_mackey_and_ltk(conn);
- }
- /* The round is only complete when the initiator
- * receives pairing random.
- */
- if (!conn->out) {
- smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM,
- conn->prnd, sizeof(conn->prnd));
- return 0;
- }
- /* Start the next round */
- if (conn->passkey_round != 20)
- return sc_passkey_round(conn, 0);
- /* Passkey rounds are complete - start DHKey Check */
- sc_dhkey_check(conn);
- break;
- case BT_L2CAP_SMP_PAIRING_CONFIRM:
- if (conn->out) {
- smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM,
- conn->prnd, sizeof(conn->prnd));
- return 0;
- }
- return sc_passkey_send_confirm(conn);
- case BT_L2CAP_SMP_PUBLIC_KEY:
- default:
- /* Initiating device starts the round */
- if (!conn->out)
- return 0;
- return sc_passkey_send_confirm(conn);
- }
- return 0;
- }
- static bool verify_random(struct smp_conn *conn, const uint8_t rnd[16])
- {
- uint8_t confirm[16];
- if (!bt_crypto_c1(conn->smp->crypto, conn->tk, conn->rrnd, conn->prsp,
- conn->preq, conn->ia_type, conn->ia,
- conn->ra_type, conn->ra, confirm))
- return false;
- if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
- bthost_debug(conn->smp->bthost,
- "Confirmation values don't match");
- return false;
- }
- if (conn->out) {
- bt_crypto_s1(conn->smp->crypto, conn->tk, conn->rrnd,
- conn->prnd, conn->ltk);
- bthost_le_start_encrypt(conn->smp->bthost, conn->handle,
- conn->ltk);
- } else {
- bt_crypto_s1(conn->smp->crypto, conn->tk, conn->prnd,
- conn->rrnd, conn->ltk);
- }
- return true;
- }
- static void distribute_keys(struct smp_conn *conn)
- {
- uint8_t buf[16];
- if (conn->local_key_dist & DIST_ENC_KEY) {
- memset(buf, 0, sizeof(buf));
- smp_send(conn, BT_L2CAP_SMP_ENCRYPT_INFO, buf, sizeof(buf));
- smp_send(conn, BT_L2CAP_SMP_CENTRAL_IDENT, buf, 10);
- }
- if (conn->local_key_dist & DIST_ID_KEY) {
- memset(buf, 0, sizeof(buf));
- smp_send(conn, BT_L2CAP_SMP_IDENT_INFO, buf, sizeof(buf));
- memset(buf, 0, sizeof(buf));
- if (conn->out) {
- buf[0] = conn->ia_type;
- memcpy(&buf[1], conn->ia, 6);
- } else {
- buf[0] = conn->ra_type;
- memcpy(&buf[1], conn->ra, 6);
- }
- smp_send(conn, BT_L2CAP_SMP_IDENT_ADDR_INFO, buf, 7);
- }
- if (conn->local_key_dist & DIST_SIGN) {
- memset(buf, 0, sizeof(buf));
- smp_send(conn, BT_L2CAP_SMP_SIGNING_INFO, buf, sizeof(buf));
- }
- }
- static void pairing_req(struct smp_conn *conn, const void *data, uint16_t len)
- {
- struct bthost *bthost = conn->smp->bthost;
- struct bt_l2cap_smp_pairing_response rsp;
- memcpy(conn->preq, data, sizeof(conn->preq));
- if (conn->addr_type == BDADDR_BREDR) {
- rsp.io_capa = 0x00;
- rsp.oob_data = 0x00;
- rsp.auth_req = 0x00;
- } else {
- rsp.io_capa = bthost_get_io_capability(bthost);
- rsp.oob_data = 0x00;
- rsp.auth_req = bthost_get_auth_req(bthost);
- }
- rsp.max_key_size = 0x10;
- rsp.init_key_dist = conn->preq[5] & key_dist(bthost);
- rsp.resp_key_dist = conn->preq[6] & key_dist(bthost);
- conn->prsp[0] = BT_L2CAP_SMP_PAIRING_RESPONSE;
- memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
- conn->local_key_dist = rsp.resp_key_dist;
- conn->remote_key_dist = rsp.init_key_dist;
- if (((conn->prsp[3] & 0x08) && (conn->preq[3] & 0x08)) ||
- conn->addr_type == BDADDR_BREDR) {
- conn->sc = true;
- conn->local_key_dist &= ~SC_NO_DIST;
- conn->remote_key_dist &= ~SC_NO_DIST;
- }
- smp_send(conn, BT_L2CAP_SMP_PAIRING_RESPONSE, &rsp, sizeof(rsp));
- if (conn->addr_type == BDADDR_BREDR)
- distribute_keys(conn);
- }
- static void pairing_rsp(struct smp_conn *conn, const void *data, uint16_t len)
- {
- struct smp *smp = conn->smp;
- uint8_t cfm[16];
- memcpy(conn->prsp, data, sizeof(conn->prsp));
- conn->local_key_dist = conn->prsp[5];
- conn->remote_key_dist = conn->prsp[6];
- if (conn->addr_type == BDADDR_BREDR) {
- conn->local_key_dist &= ~SC_NO_DIST;
- conn->remote_key_dist &= ~SC_NO_DIST;
- distribute_keys(conn);
- return;
- }
- if (((conn->prsp[3] & 0x08) && (conn->preq[3] & 0x08)) ||
- conn->addr_type == BDADDR_BREDR) {
- conn->sc = true;
- conn->local_key_dist &= ~SC_NO_DIST;
- conn->remote_key_dist &= ~SC_NO_DIST;
- if (conn->addr_type == BDADDR_BREDR)
- distribute_keys(conn);
- else
- send_public_key(conn);
- return;
- }
- bt_crypto_c1(smp->crypto, conn->tk, conn->prnd, conn->prsp,
- conn->preq, conn->ia_type, conn->ia,
- conn->ra_type, conn->ra, cfm);
- smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, cfm, sizeof(cfm));
- }
- static void sc_check_confirm(struct smp_conn *conn)
- {
- if (conn->method == REQ_PASSKEY || conn->method == DSP_PASSKEY) {
- sc_passkey_round(conn, BT_L2CAP_SMP_PAIRING_CONFIRM);
- return;
- }
- if (conn->out)
- smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd,
- sizeof(conn->prnd));
- }
- static void pairing_cfm(struct smp_conn *conn, const void *data, uint16_t len)
- {
- uint8_t rsp[16];
- memcpy(conn->pcnf, data + 1, 16);
- if (conn->sc) {
- sc_check_confirm(conn);
- return;
- }
- if (conn->out) {
- memset(rsp, 0, sizeof(rsp));
- smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd,
- sizeof(conn->prnd));
- } else {
- bt_crypto_c1(conn->smp->crypto, conn->tk, conn->prnd,
- conn->prsp, conn->preq, conn->ia_type,
- conn->ia, conn->ra_type, conn->ra, rsp);
- smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, rsp, sizeof(rsp));
- }
- }
- static uint8_t sc_random(struct smp_conn *conn)
- {
- /* Passkey entry has special treatment */
- if (conn->method == REQ_PASSKEY || conn->method == DSP_PASSKEY)
- return sc_passkey_round(conn, BT_L2CAP_SMP_PAIRING_RANDOM);
- if (conn->out) {
- uint8_t cfm[16];
- bt_crypto_f4(conn->smp->crypto, conn->remote_pk,
- conn->local_pk, conn->rrnd, 0, cfm);
- if (memcmp(conn->pcnf, cfm, 16))
- return 0x04; /* Confirm Value Failed */
- } else {
- smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd, 16);
- }
- sc_mackey_and_ltk(conn);
- if (conn->out)
- sc_dhkey_check(conn);
- return 0;
- }
- static void pairing_rnd(struct smp_conn *conn, const void *data, uint16_t len)
- {
- memcpy(conn->rrnd, data + 1, 16);
- if (conn->sc) {
- uint8_t reason = sc_random(conn);
- if (reason)
- smp_send(conn, BT_L2CAP_SMP_PAIRING_FAILED, &reason,
- sizeof(reason));
- return;
- }
- if (!verify_random(conn, data + 1))
- return;
- if (conn->out)
- return;
- smp_send(conn, BT_L2CAP_SMP_PAIRING_RANDOM, conn->prnd,
- sizeof(conn->prnd));
- }
- static void encrypt_info(struct smp_conn *conn, const void *data, uint16_t len)
- {
- }
- static void central_ident(struct smp_conn *conn, const void *data, uint16_t len)
- {
- conn->remote_key_dist &= ~DIST_ENC_KEY;
- if (conn->out && !conn->remote_key_dist)
- distribute_keys(conn);
- }
- static void ident_addr_info(struct smp_conn *conn, const void *data,
- uint16_t len)
- {
- }
- static void ident_info(struct smp_conn *conn, const void *data, uint16_t len)
- {
- conn->remote_key_dist &= ~DIST_ID_KEY;
- if (conn->out && !conn->remote_key_dist)
- distribute_keys(conn);
- }
- static void signing_info(struct smp_conn *conn, const void *data, uint16_t len)
- {
- conn->remote_key_dist &= ~DIST_SIGN;
- if (conn->out && !conn->remote_key_dist)
- distribute_keys(conn);
- }
- static void public_key(struct smp_conn *conn, const void *data, uint16_t len)
- {
- struct smp *smp = conn->smp;
- uint8_t buf[16];
- memcpy(conn->remote_pk, data + 1, 64);
- if (!conn->out) {
- if (!send_public_key(conn))
- return;
- }
- if (!ecdh_shared_secret(conn->remote_pk, conn->local_sk, conn->dhkey))
- return;
- conn->method = sc_select_method(conn);
- if (conn->method == DSP_PASSKEY || conn->method == REQ_PASSKEY) {
- sc_passkey_round(conn, BT_L2CAP_SMP_PUBLIC_KEY);
- return;
- }
- if (conn->out)
- return;
- if (!bt_crypto_f4(smp->crypto, conn->local_pk, conn->remote_pk,
- conn->prnd, 0, buf))
- return;
- smp_send(conn, BT_L2CAP_SMP_PAIRING_CONFIRM, buf, sizeof(buf));
- }
- static void dhkey_check(struct smp_conn *conn, const void *data, uint16_t len)
- {
- const struct bt_l2cap_smp_dhkey_check *cmd = data + 1;
- uint8_t a[7], b[7], *local_addr, *remote_addr;
- uint8_t io_cap[3], r[16], e[16];
- memcpy(a, &conn->ia, 6);
- memcpy(b, &conn->ra, 6);
- a[6] = conn->ia_type;
- b[6] = conn->ra_type;
- if (conn->out) {
- local_addr = a;
- remote_addr = b;
- memcpy(io_cap, &conn->prsp[1], 3);
- } else {
- local_addr = b;
- remote_addr = a;
- memcpy(io_cap, &conn->preq[1], 3);
- }
- memset(r, 0, sizeof(r));
- if (conn->method == REQ_PASSKEY || conn->method == DSP_PASSKEY)
- put_le32(conn->passkey_notify, r);
- if (!bt_crypto_f6(conn->smp->crypto, conn->mackey, conn->rrnd,
- conn->prnd, r, io_cap, remote_addr, local_addr, e))
- return;
- if (memcmp(cmd->e, e, 16)) {
- uint8_t reason = 0x0b; /* DHKey Check Failed */
- smp_send(conn, BT_L2CAP_SMP_PAIRING_FAILED, &reason,
- sizeof(reason));
- }
- if (conn->out)
- bthost_le_start_encrypt(conn->smp->bthost, conn->handle,
- conn->ltk);
- else
- sc_dhkey_check(conn);
- }
- void smp_pair(void *conn_data, uint8_t io_cap, uint8_t auth_req)
- {
- struct smp_conn *conn = conn_data;
- struct bt_l2cap_smp_pairing_request req;
- req.io_capa = io_cap;
- req.oob_data = 0x00;
- req.auth_req = auth_req;
- req.max_key_size = 0x10;
- req.init_key_dist = key_dist(conn->smp->bthost);
- req.resp_key_dist = key_dist(conn->smp->bthost);
- conn->preq[0] = BT_L2CAP_SMP_PAIRING_REQUEST;
- memcpy(&conn->preq[1], &req, sizeof(req));
- smp_send(conn, BT_L2CAP_SMP_PAIRING_REQUEST, &req, sizeof(req));
- }
- void smp_data(void *conn_data, const void *data, uint16_t len)
- {
- struct smp_conn *conn = conn_data;
- uint8_t opcode;
- if (len < 1) {
- bthost_debug(conn->smp->bthost, "Received too small SMP PDU");
- return;
- }
- if (conn->addr_type == BDADDR_BREDR) {
- bthost_debug(conn->smp->bthost,
- "Received BR/EDR SMP data on LE link");
- return;
- }
- opcode = *((const uint8_t *) data);
- switch (opcode) {
- case BT_L2CAP_SMP_PAIRING_REQUEST:
- pairing_req(conn, data, len);
- break;
- case BT_L2CAP_SMP_PAIRING_RESPONSE:
- pairing_rsp(conn, data, len);
- break;
- case BT_L2CAP_SMP_PAIRING_CONFIRM:
- pairing_cfm(conn, data, len);
- break;
- case BT_L2CAP_SMP_PAIRING_RANDOM:
- pairing_rnd(conn, data, len);
- break;
- case BT_L2CAP_SMP_ENCRYPT_INFO:
- encrypt_info(conn, data, len);
- break;
- case BT_L2CAP_SMP_CENTRAL_IDENT:
- central_ident(conn, data, len);
- break;
- case BT_L2CAP_SMP_IDENT_ADDR_INFO:
- ident_addr_info(conn, data, len);
- break;
- case BT_L2CAP_SMP_IDENT_INFO:
- ident_info(conn, data, len);
- break;
- case BT_L2CAP_SMP_SIGNING_INFO:
- signing_info(conn, data, len);
- break;
- case BT_L2CAP_SMP_PUBLIC_KEY:
- public_key(conn, data, len);
- break;
- case BT_L2CAP_SMP_DHKEY_CHECK:
- dhkey_check(conn, data, len);
- break;
- default:
- break;
- }
- }
- void smp_bredr_data(void *conn_data, const void *data, uint16_t len)
- {
- struct smp_conn *conn = conn_data;
- uint8_t opcode;
- if (len < 1) {
- bthost_debug(conn->smp->bthost, "Received too small SMP PDU");
- return;
- }
- if (conn->addr_type != BDADDR_BREDR) {
- bthost_debug(conn->smp->bthost,
- "Received LE SMP data on BR/EDR link");
- return;
- }
- opcode = *((const uint8_t *) data);
- switch (opcode) {
- case BT_L2CAP_SMP_PAIRING_REQUEST:
- pairing_req(conn, data, len);
- break;
- case BT_L2CAP_SMP_PAIRING_RESPONSE:
- pairing_rsp(conn, data, len);
- break;
- default:
- break;
- }
- }
- int smp_get_ltk(void *smp_data, uint64_t rand, uint16_t ediv, uint8_t *ltk)
- {
- struct smp_conn *conn = smp_data;
- static const uint8_t no_ltk[16] = { 0 };
- if (!memcmp(conn->ltk, no_ltk, 16))
- return -ENOENT;
- memcpy(ltk, conn->ltk, 16);
- return 0;
- }
- static void smp_conn_bredr(struct smp_conn *conn, uint8_t encrypt)
- {
- struct smp *smp = conn->smp;
- struct bt_l2cap_smp_pairing_request req;
- uint64_t fixed_chan;
- if (encrypt != 0x02)
- return;
- conn->sc = true;
- if (!conn->out)
- return;
- fixed_chan = bthost_conn_get_fixed_chan(smp->bthost, conn->handle);
- if (!(fixed_chan & L2CAP_FC_SMP_BREDR))
- return;
- memset(&req, 0, sizeof(req));
- req.max_key_size = 0x10;
- req.init_key_dist = key_dist(smp->bthost);
- req.resp_key_dist = key_dist(smp->bthost);
- smp_send(conn, BT_L2CAP_SMP_PAIRING_REQUEST, &req, sizeof(req));
- }
- void smp_conn_encrypted(void *conn_data, uint8_t encrypt)
- {
- struct smp_conn *conn = conn_data;
- if (!encrypt)
- return;
- if (conn->addr_type == BDADDR_BREDR) {
- smp_conn_bredr(conn, encrypt);
- return;
- }
- if (conn->out && conn->remote_key_dist)
- return;
- distribute_keys(conn);
- }
- static uint8_t type2hci(uint8_t addr_type)
- {
- switch (addr_type) {
- case BDADDR_BREDR:
- case BDADDR_LE_PUBLIC:
- return LE_PUBLIC_ADDRESS;
- case BDADDR_LE_RANDOM:
- return LE_RANDOM_ADDRESS;
- }
- return 0x00;
- }
- void *smp_conn_add(void *smp_data, uint16_t handle,
- const uint8_t *ia, uint8_t ia_type,
- const uint8_t *ra, uint8_t ra_type, bool conn_init)
- {
- struct smp *smp = smp_data;
- struct smp_conn *conn;
- char ia_str[18], ra_str[18];
- conn = malloc(sizeof(struct smp_conn));
- if (!conn)
- return NULL;
- memset(conn, 0, sizeof(*conn));
- conn->smp = smp;
- conn->handle = handle;
- conn->out = conn_init;
- conn->addr_type = conn_init ? ia_type : ra_type;
- conn->ia_type = type2hci(ia_type);
- conn->ra_type = type2hci(ra_type);
- memcpy(conn->ia, ia, 6);
- memcpy(conn->ra, ra, 6);
- ba2str((bdaddr_t *) ia, ia_str);
- ba2str((bdaddr_t *) ra, ra_str);
- bthost_debug(smp->bthost, "ia %s type 0x%02x ra %s type 0x%02x",
- ia_str, ia_type, ra_str, ra_type);
- bt_crypto_random_bytes(smp->crypto, conn->prnd, sizeof(conn->prnd));
- return conn;
- }
- void smp_conn_del(void *conn_data)
- {
- struct smp_conn *conn = conn_data;
- free(conn);
- }
- void *smp_start(struct bthost *bthost)
- {
- struct smp *smp;
- smp = malloc(sizeof(struct smp));
- if (!smp)
- return NULL;
- memset(smp, 0, sizeof(*smp));
- smp->crypto = bt_crypto_new();
- if (!smp->crypto) {
- free(smp);
- return NULL;
- }
- smp->bthost = bthost;
- return smp;
- }
- void smp_stop(void *smp_data)
- {
- struct smp *smp = smp_data;
- bt_crypto_unref(smp->crypto);
- free(smp);
- }
|