Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da85e5e5 authored by Vinicius Costa Gomes's avatar Vinicius Costa Gomes Committed by Gustavo Padovan
Browse files

Bluetooth: Add support for Pairing features exchange



This patch implements a simple version of the SMP Pairing Features
exchange procedure (Vol. 3 Part H, Section 2.3.5.1).

For now, everything that would cause a Pairing Method different of
Just Works to be chosen is rejected.

Signed-off-by: default avatarVinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: default avatarGustavo F. Padovan <padovan@profusion.mobi>
parent b8e66eac
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1622,6 +1622,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
				/* Encryption implies authentication */
				conn->link_mode |= HCI_LM_AUTH;
				conn->link_mode |= HCI_LM_ENCRYPT;
				conn->sec_level = conn->pending_sec_level;
			} else
				conn->link_mode &= ~HCI_LM_ENCRYPT;
		}
+53 −53
Original line number Diff line number Diff line
@@ -181,6 +181,18 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
	hci_send_acl(conn->hcon, skb, 0);
}

static __u8 seclevel_to_authreq(__u8 level)
{
	switch (level) {
	case BT_SECURITY_HIGH:
		/* Right now we don't support bonding */
		return SMP_AUTH_MITM;

	default:
		return SMP_AUTH_NONE;
	}
}

static void build_pairing_cmd(struct l2cap_conn *conn,
				struct smp_cmd_pairing *cmd, __u8 authreq)
{
@@ -192,7 +204,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
	cmd->auth_req = authreq;
}

static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
	struct smp_cmd_pairing *rp = (void *) skb->data;

@@ -202,12 +214,11 @@ static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
	memcpy(&conn->preq[1], rp, sizeof(*rp));
	skb_pull(skb, sizeof(*rp));

	rp->io_capability = 0x00;
	rp->oob_flag = 0x00;
	rp->max_key_size = 16;
	rp->init_key_dist = 0x00;
	rp->resp_key_dist = 0x00;
	rp->auth_req &= (SMP_AUTH_BONDING | SMP_AUTH_MITM);
	if (rp->oob_flag)
		return SMP_OOB_NOT_AVAIL;

	/* We didn't start the pairing, so no requirements */
	build_pairing_cmd(conn, rp, SMP_AUTH_NONE);

	/* Just works */
	memset(conn->tk, 0, sizeof(conn->tk));
@@ -216,9 +227,11 @@ static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
	memcpy(&conn->prsp[1], rp, sizeof(*rp));

	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(*rp), rp);

	return 0;
}

static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
{
	struct smp_cmd_pairing *rp = (void *) skb->data;
	struct smp_cmd_pairing_confirm cp;
@@ -228,29 +241,34 @@ static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)

	BT_DBG("conn %p", conn);

	skb_pull(skb, sizeof(*rp));

	if (rp->oob_flag)
		return SMP_OOB_NOT_AVAIL;

	/* Just works */
	memset(conn->tk, 0, sizeof(conn->tk));

	conn->prsp[0] = SMP_CMD_PAIRING_RSP;
	memcpy(&conn->prsp[1], rp, sizeof(*rp));
	skb_pull(skb, sizeof(*rp));

	ret = smp_rand(conn->prnd);
	if (ret)
		return;
		return SMP_UNSPECIFIED;

	ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
			conn->src, conn->hcon->dst_type, conn->dst, res);
	if (ret)
		return;
		return SMP_UNSPECIFIED;

	swap128(res, cp.confirm_val);

	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);

	return 0;
}

static void smp_cmd_pairing_confirm(struct l2cap_conn *conn,
							struct sk_buff *skb)
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
{
	struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;

@@ -272,21 +290,23 @@ static void smp_cmd_pairing_confirm(struct l2cap_conn *conn,

		ret = smp_rand(conn->prnd);
		if (ret)
			return;
			return SMP_UNSPECIFIED;

		ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
						conn->hcon->dst_type, conn->dst,
						0, conn->src, res);
		if (ret)
			return;
			return SMP_CONFIRM_FAILED;

		swap128(res, cp.confirm_val);

		smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
	}

	return 0;
}

static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
{
	struct hci_conn *hcon = conn->hcon;
	struct crypto_blkcipher *tfm = hcon->hdev->tfm;
@@ -307,19 +327,15 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
				conn->hcon->dst_type, conn->dst, 0, conn->src,
				res);
	if (ret)
		return;
		return SMP_UNSPECIFIED;

	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");

	swap128(res, confirm);

	if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
		struct smp_cmd_pairing_fail cp;

		BT_ERR("Pairing failed (confirmation values mismatch)");
		cp.reason = SMP_CONFIRM_FAILED;
		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(cp), &cp);
		return;
		return SMP_CONFIRM_FAILED;
	}

	if (conn->hcon->out) {
@@ -341,9 +357,11 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
		smp_s1(tfm, conn->tk, conn->prnd, random, key);
		swap128(key, hcon->ltk);
	}

	return 0;
}

static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
	struct smp_cmd_security_req *rp = (void *) skb->data;
	struct smp_cmd_pairing cp;
@@ -352,17 +370,12 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
	BT_DBG("conn %p", conn);

	if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
		return;
		return 0;

	skb_pull(skb, sizeof(*rp));
	memset(&cp, 0, sizeof(cp));

	cp.io_capability = 0x00;
	cp.oob_flag = 0x00;
	cp.max_key_size = 16;
	cp.init_key_dist = 0x00;
	cp.resp_key_dist = 0x00;
	cp.auth_req = rp->auth_req & (SMP_AUTH_BONDING | SMP_AUTH_MITM);
	memset(&cp, 0, sizeof(cp));
	build_pairing_cmd(conn, &cp, rp->auth_req);

	conn->preq[0] = SMP_CMD_PAIRING_REQ;
	memcpy(&conn->preq[1], &cp, sizeof(cp));
@@ -370,18 +383,8 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);

	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
}

static __u8 seclevel_to_authreq(__u8 level)
{
	switch (level) {
	case BT_SECURITY_HIGH:
		/* For now we don't support bonding */
		return SMP_AUTH_MITM;

	default:
		return SMP_AUTH_NONE;
	}
	return 0;
}

int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
@@ -407,13 +410,8 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)

	if (hcon->link_mode & HCI_LM_MASTER) {
		struct smp_cmd_pairing cp;
		cp.io_capability = 0x00;
		cp.oob_flag = 0x00;
		cp.max_key_size = 16;
		cp.init_key_dist = 0x00;
		cp.resp_key_dist = 0x00;
		cp.auth_req = authreq;

		build_pairing_cmd(conn, &cp, authreq);
		conn->preq[0] = SMP_CMD_PAIRING_REQ;
		memcpy(&conn->preq[1], &cp, sizeof(cp));

@@ -446,26 +444,28 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)

	switch (code) {
	case SMP_CMD_PAIRING_REQ:
		smp_cmd_pairing_req(conn, skb);
		reason = smp_cmd_pairing_req(conn, skb);
		break;

	case SMP_CMD_PAIRING_FAIL:
		reason = 0;
		err = -EPERM;
		break;

	case SMP_CMD_PAIRING_RSP:
		smp_cmd_pairing_rsp(conn, skb);
		reason = smp_cmd_pairing_rsp(conn, skb);
		break;

	case SMP_CMD_SECURITY_REQ:
		smp_cmd_security_req(conn, skb);
		reason = smp_cmd_security_req(conn, skb);
		break;

	case SMP_CMD_PAIRING_CONFIRM:
		smp_cmd_pairing_confirm(conn, skb);
		reason = smp_cmd_pairing_confirm(conn, skb);
		break;

	case SMP_CMD_PAIRING_RANDOM:
		smp_cmd_pairing_random(conn, skb);
		reason = smp_cmd_pairing_random(conn, skb);
		break;

	case SMP_CMD_ENCRYPT_INFO: