diff options
Diffstat (limited to 'net/bluetooth/smp.c')
| -rw-r--r-- | net/bluetooth/smp.c | 468 | 
1 files changed, 454 insertions, 14 deletions
| diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b67749bb55bf..c09a821f381d 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -20,6 +20,7 @@     SOFTWARE IS DISCLAIMED.  */ +#include <linux/debugfs.h>  #include <linux/crypto.h>  #include <linux/scatterlist.h>  #include <crypto/b128ops.h> @@ -223,8 +224,9 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],  	return err;  } -static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16], -		  u8 a1[7], u8 a2[7], u8 mackey[16], u8 ltk[16]) +static int smp_f5(struct crypto_hash *tfm_cmac, const u8 w[32], +		  const u8 n1[16], const u8 n2[16], const u8 a1[7], +		  const u8 a2[7], u8 mackey[16], u8 ltk[16])  {  	/* The btle, salt and length "magic" values are as defined in  	 * the SMP section of the Bluetooth core specification. In ASCII @@ -276,7 +278,7 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],  }  static int smp_f6(struct crypto_hash *tfm_cmac, const u8 w[16], -		  const u8 n1[16], u8 n2[16], const u8 r[16], +		  const u8 n1[16], const u8 n2[16], const u8 r[16],  		  const u8 io_cap[3], const u8 a1[7], const u8 a2[7],  		  u8 res[16])  { @@ -298,7 +300,7 @@ static int smp_f6(struct crypto_hash *tfm_cmac, const u8 w[16],  	if (err)  		return err; -	BT_DBG("res %16phN", res); +	SMP_DBG("res %16phN", res);  	return err;  } @@ -618,7 +620,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,  		oob_data = hci_find_remote_oob_data(hdev, &hcon->dst,  						    bdaddr_type); -		if (oob_data) { +		if (oob_data && oob_data->present) {  			set_bit(SMP_FLAG_OOB, &smp->flags);  			oob_flag = SMP_OOB_PRESENT;  			memcpy(smp->rr, oob_data->rand256, 16); @@ -1674,7 +1676,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)  	if (conn->hcon->type == ACL_LINK) {  		/* We must have a BR/EDR SC link */  		if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags) && -		    !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags)) +		    !test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags))  			return SMP_CROSS_TRANSP_NOT_ALLOWED;  		set_bit(SMP_FLAG_SC, &smp->flags); @@ -2303,8 +2305,12 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,  	 * implementations are not known of and in order to not over  	 * complicate our implementation, simply pretend that we never  	 * received an IRK for such a device. +	 * +	 * The Identity Address must also be a Static Random or Public +	 * Address, which hci_is_identity_address() checks for.  	 */ -	if (!bacmp(&info->bdaddr, BDADDR_ANY)) { +	if (!bacmp(&info->bdaddr, BDADDR_ANY) || +	    !hci_is_identity_address(&info->bdaddr, info->addr_type)) {  		BT_ERR("Ignoring IRK with no identity address");  		goto distribute;  	} @@ -2737,7 +2743,7 @@ static void bredr_pairing(struct l2cap_chan *chan)  	/* BR/EDR must use Secure Connections for SMP */  	if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) && -	    !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags)) +	    !test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags))  		return;  	/* If our LE support is not enabled don't do anything */ @@ -2944,11 +2950,30 @@ create_chan:  	l2cap_chan_set_defaults(chan); -	bacpy(&chan->src, &hdev->bdaddr); -	if (cid == L2CAP_CID_SMP) -		chan->src_type = BDADDR_LE_PUBLIC; -	else +	if (cid == L2CAP_CID_SMP) { +		/* If usage of static address is forced or if the devices +		 * does not have a public address, then listen on the static +		 * address. +		 * +		 * In case BR/EDR has been disabled on a dual-mode controller +		 * and a static address has been configued, then listen on +		 * the static address instead. +		 */ +		if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || +		    !bacmp(&hdev->bdaddr, BDADDR_ANY) || +		    (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) && +		     bacmp(&hdev->static_addr, BDADDR_ANY))) { +			bacpy(&chan->src, &hdev->static_addr); +			chan->src_type = BDADDR_LE_RANDOM; +		} else { +			bacpy(&chan->src, &hdev->bdaddr); +			chan->src_type = BDADDR_LE_PUBLIC; +		} +	} else { +		bacpy(&chan->src, &hdev->bdaddr);  		chan->src_type = BDADDR_BREDR; +	} +  	chan->state = BT_LISTEN;  	chan->mode = L2CAP_MODE_BASIC;  	chan->imtu = L2CAP_DEFAULT_MTU; @@ -2975,21 +3000,108 @@ static void smp_del_chan(struct l2cap_chan *chan)  	l2cap_chan_put(chan);  } +static ssize_t force_bredr_smp_read(struct file *file, +				    char __user *user_buf, +				    size_t count, loff_t *ppos) +{ +	struct hci_dev *hdev = file->private_data; +	char buf[3]; + +	buf[0] = test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags) ? 'Y': 'N'; +	buf[1] = '\n'; +	buf[2] = '\0'; +	return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t force_bredr_smp_write(struct file *file, +				     const char __user *user_buf, +				     size_t count, loff_t *ppos) +{ +	struct hci_dev *hdev = file->private_data; +	char buf[32]; +	size_t buf_size = min(count, (sizeof(buf)-1)); +	bool enable; + +	if (copy_from_user(buf, user_buf, buf_size)) +		return -EFAULT; + +	buf[buf_size] = '\0'; +	if (strtobool(buf, &enable)) +		return -EINVAL; + +	if (enable == test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags)) +		return -EALREADY; + +	if (enable) { +		struct l2cap_chan *chan; + +		chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR); +		if (IS_ERR(chan)) +			return PTR_ERR(chan); + +		hdev->smp_bredr_data = chan; +	} else { +		struct l2cap_chan *chan; + +		chan = hdev->smp_bredr_data; +		hdev->smp_bredr_data = NULL; +		smp_del_chan(chan); +	} + +	change_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags); + +	return count; +} + +static const struct file_operations force_bredr_smp_fops = { +	.open		= simple_open, +	.read		= force_bredr_smp_read, +	.write		= force_bredr_smp_write, +	.llseek		= default_llseek, +}; +  int smp_register(struct hci_dev *hdev)  {  	struct l2cap_chan *chan;  	BT_DBG("%s", hdev->name); +	/* If the controller does not support Low Energy operation, then +	 * there is also no need to register any SMP channel. +	 */ +	if (!lmp_le_capable(hdev)) +		return 0; + +	if (WARN_ON(hdev->smp_data)) { +		chan = hdev->smp_data; +		hdev->smp_data = NULL; +		smp_del_chan(chan); +	} +  	chan = smp_add_cid(hdev, L2CAP_CID_SMP);  	if (IS_ERR(chan))  		return PTR_ERR(chan);  	hdev->smp_data = chan; -	if (!lmp_sc_capable(hdev) && -	    !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags)) +	/* If the controller does not support BR/EDR Secure Connections +	 * feature, then the BR/EDR SMP channel shall not be present. +	 * +	 * To test this with Bluetooth 4.0 controllers, create a debugfs +	 * switch that allows forcing BR/EDR SMP support and accepting +	 * cross-transport pairing on non-AES encrypted connections. +	 */ +	if (!lmp_sc_capable(hdev)) { +		debugfs_create_file("force_bredr_smp", 0644, hdev->debugfs, +				    hdev, &force_bredr_smp_fops);  		return 0; +	} + +	if (WARN_ON(hdev->smp_bredr_data)) { +		chan = hdev->smp_bredr_data; +		hdev->smp_bredr_data = NULL; +		smp_del_chan(chan); +	}  	chan = smp_add_cid(hdev, L2CAP_CID_SMP_BREDR);  	if (IS_ERR(chan)) { @@ -3021,3 +3133,331 @@ void smp_unregister(struct hci_dev *hdev)  		smp_del_chan(chan);  	}  } + +#if IS_ENABLED(CONFIG_BT_SELFTEST_SMP) + +static int __init test_ah(struct crypto_blkcipher *tfm_aes) +{ +	const u8 irk[16] = { +			0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34, +			0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec }; +	const u8 r[3] = { 0x94, 0x81, 0x70 }; +	const u8 exp[3] = { 0xaa, 0xfb, 0x0d }; +	u8 res[3]; +	int err; + +	err = smp_ah(tfm_aes, irk, r, res); +	if (err) +		return err; + +	if (memcmp(res, exp, 3)) +		return -EINVAL; + +	return 0; +} + +static int __init test_c1(struct crypto_blkcipher *tfm_aes) +{ +	const u8 k[16] = { +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +	const u8 r[16] = { +			0xe0, 0x2e, 0x70, 0xc6, 0x4e, 0x27, 0x88, 0x63, +			0x0e, 0x6f, 0xad, 0x56, 0x21, 0xd5, 0x83, 0x57 }; +	const u8 preq[7] = { 0x01, 0x01, 0x00, 0x00, 0x10, 0x07, 0x07 }; +	const u8 pres[7] = { 0x02, 0x03, 0x00, 0x00, 0x08, 0x00, 0x05 }; +	const u8 _iat = 0x01; +	const u8 _rat = 0x00; +	const bdaddr_t ra = { { 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1 } }; +	const bdaddr_t ia = { { 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1 } }; +	const u8 exp[16] = { +			0x86, 0x3b, 0xf1, 0xbe, 0xc5, 0x4d, 0xa7, 0xd2, +			0xea, 0x88, 0x89, 0x87, 0xef, 0x3f, 0x1e, 0x1e }; +	u8 res[16]; +	int err; + +	err = smp_c1(tfm_aes, k, r, preq, pres, _iat, &ia, _rat, &ra, res); +	if (err) +		return err; + +	if (memcmp(res, exp, 16)) +		return -EINVAL; + +	return 0; +} + +static int __init test_s1(struct crypto_blkcipher *tfm_aes) +{ +	const u8 k[16] = { +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +	const u8 r1[16] = { +			0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }; +	const u8 r2[16] = { +			0x00, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99 }; +	const u8 exp[16] = { +			0x62, 0xa0, 0x6d, 0x79, 0xae, 0x16, 0x42, 0x5b, +			0x9b, 0xf4, 0xb0, 0xe8, 0xf0, 0xe1, 0x1f, 0x9a }; +	u8 res[16]; +	int err; + +	err = smp_s1(tfm_aes, k, r1, r2, res); +	if (err) +		return err; + +	if (memcmp(res, exp, 16)) +		return -EINVAL; + +	return 0; +} + +static int __init test_f4(struct crypto_hash *tfm_cmac) +{ +	const u8 u[32] = { +			0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, +			0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, +			0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, +			0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20 }; +	const u8 v[32] = { +			0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b, +			0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59, +			0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90, +			0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55 }; +	const u8 x[16] = { +			0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, +			0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; +	const u8 z = 0x00; +	const u8 exp[16] = { +			0x2d, 0x87, 0x74, 0xa9, 0xbe, 0xa1, 0xed, 0xf1, +			0x1c, 0xbd, 0xa9, 0x07, 0xf1, 0x16, 0xc9, 0xf2 }; +	u8 res[16]; +	int err; + +	err = smp_f4(tfm_cmac, u, v, x, z, res); +	if (err) +		return err; + +	if (memcmp(res, exp, 16)) +		return -EINVAL; + +	return 0; +} + +static int __init test_f5(struct crypto_hash *tfm_cmac) +{ +	const u8 w[32] = { +			0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86, +			0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99, +			0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34, +			0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec }; +	const u8 n1[16] = { +			0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, +			0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; +	const u8 n2[16] = { +			0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21, +			0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 }; +	const u8 a1[7] = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56, 0x00 }; +	const u8 a2[7] = { 0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7, 0x00 }; +	const u8 exp_ltk[16] = { +			0x38, 0x0a, 0x75, 0x94, 0xb5, 0x22, 0x05, 0x98, +			0x23, 0xcd, 0xd7, 0x69, 0x11, 0x79, 0x86, 0x69 }; +	const u8 exp_mackey[16] = { +			0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd, +			0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 }; +	u8 mackey[16], ltk[16]; +	int err; + +	err = smp_f5(tfm_cmac, w, n1, n2, a1, a2, mackey, ltk); +	if (err) +		return err; + +	if (memcmp(mackey, exp_mackey, 16)) +		return -EINVAL; + +	if (memcmp(ltk, exp_ltk, 16)) +		return -EINVAL; + +	return 0; +} + +static int __init test_f6(struct crypto_hash *tfm_cmac) +{ +	const u8 w[16] = { +			0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd, +			0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 }; +	const u8 n1[16] = { +			0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, +			0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; +	const u8 n2[16] = { +			0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21, +			0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 }; +	const u8 r[16] = { +			0xc8, 0x0f, 0x2d, 0x0c, 0xd2, 0x42, 0xda, 0x08, +			0x54, 0xbb, 0x53, 0xb4, 0x3b, 0x34, 0xa3, 0x12 }; +	const u8 io_cap[3] = { 0x02, 0x01, 0x01 }; +	const u8 a1[7] = { 0xce, 0xbf, 0x37, 0x37, 0x12, 0x56, 0x00 }; +	const u8 a2[7] = { 0xc1, 0xcf, 0x2d, 0x70, 0x13, 0xa7, 0x00 }; +	const u8 exp[16] = { +			0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2, +			0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3 }; +	u8 res[16]; +	int err; + +	err = smp_f6(tfm_cmac, w, n1, n2, r, io_cap, a1, a2, res); +	if (err) +		return err; + +	if (memcmp(res, exp, 16)) +		return -EINVAL; + +	return 0; +} + +static int __init test_g2(struct crypto_hash *tfm_cmac) +{ +	const u8 u[32] = { +			0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, +			0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef, +			0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e, +			0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20 }; +	const u8 v[32] = { +			0xfd, 0xc5, 0x7f, 0xf4, 0x49, 0xdd, 0x4f, 0x6b, +			0xfb, 0x7c, 0x9d, 0xf1, 0xc2, 0x9a, 0xcb, 0x59, +			0x2a, 0xe7, 0xd4, 0xee, 0xfb, 0xfc, 0x0a, 0x90, +			0x9a, 0xbb, 0xf6, 0x32, 0x3d, 0x8b, 0x18, 0x55 }; +	const u8 x[16] = { +			0xab, 0xae, 0x2b, 0x71, 0xec, 0xb2, 0xff, 0xff, +			0x3e, 0x73, 0x77, 0xd1, 0x54, 0x84, 0xcb, 0xd5 }; +	const u8 y[16] = { +			0xcf, 0xc4, 0x3d, 0xff, 0xf7, 0x83, 0x65, 0x21, +			0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 }; +	const u32 exp_val = 0x2f9ed5ba % 1000000; +	u32 val; +	int err; + +	err = smp_g2(tfm_cmac, u, v, x, y, &val); +	if (err) +		return err; + +	if (val != exp_val) +		return -EINVAL; + +	return 0; +} + +static int __init test_h6(struct crypto_hash *tfm_cmac) +{ +	const u8 w[16] = { +			0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34, +			0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec }; +	const u8 key_id[4] = { 0x72, 0x62, 0x65, 0x6c }; +	const u8 exp[16] = { +			0x99, 0x63, 0xb1, 0x80, 0xe2, 0xa9, 0xd3, 0xe8, +			0x1c, 0xc9, 0x6d, 0xe7, 0x02, 0xe1, 0x9a, 0x2d }; +	u8 res[16]; +	int err; + +	err = smp_h6(tfm_cmac, w, key_id, res); +	if (err) +		return err; + +	if (memcmp(res, exp, 16)) +		return -EINVAL; + +	return 0; +} + +static int __init run_selftests(struct crypto_blkcipher *tfm_aes, +				struct crypto_hash *tfm_cmac) +{ +	ktime_t calltime, delta, rettime; +	unsigned long long duration; +	int err; + +	calltime = ktime_get(); + +	err = test_ah(tfm_aes); +	if (err) { +		BT_ERR("smp_ah test failed"); +		return err; +	} + +	err = test_c1(tfm_aes); +	if (err) { +		BT_ERR("smp_c1 test failed"); +		return err; +	} + +	err = test_s1(tfm_aes); +	if (err) { +		BT_ERR("smp_s1 test failed"); +		return err; +	} + +	err = test_f4(tfm_cmac); +	if (err) { +		BT_ERR("smp_f4 test failed"); +		return err; +	} + +	err = test_f5(tfm_cmac); +	if (err) { +		BT_ERR("smp_f5 test failed"); +		return err; +	} + +	err = test_f6(tfm_cmac); +	if (err) { +		BT_ERR("smp_f6 test failed"); +		return err; +	} + +	err = test_g2(tfm_cmac); +	if (err) { +		BT_ERR("smp_g2 test failed"); +		return err; +	} + +	err = test_h6(tfm_cmac); +	if (err) { +		BT_ERR("smp_h6 test failed"); +		return err; +	} + +	rettime = ktime_get(); +	delta = ktime_sub(rettime, calltime); +	duration = (unsigned long long) ktime_to_ns(delta) >> 10; + +	BT_INFO("SMP test passed in %llu usecs", duration); + +	return 0; +} + +int __init bt_selftest_smp(void) +{ +	struct crypto_blkcipher *tfm_aes; +	struct crypto_hash *tfm_cmac; +	int err; + +	tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); +	if (IS_ERR(tfm_aes)) { +		BT_ERR("Unable to create ECB crypto context"); +		return PTR_ERR(tfm_aes); +	} + +	tfm_cmac = crypto_alloc_hash("cmac(aes)", 0, CRYPTO_ALG_ASYNC); +	if (IS_ERR(tfm_cmac)) { +		BT_ERR("Unable to create CMAC crypto context"); +		crypto_free_blkcipher(tfm_aes); +		return PTR_ERR(tfm_cmac); +	} + +	err = run_selftests(tfm_aes, tfm_cmac); + +	crypto_free_hash(tfm_cmac); +	crypto_free_blkcipher(tfm_aes); + +	return err; +} + +#endif |