2022-10-19 14:19:50

by Tom Unbehau

[permalink] [raw]
Subject: Forcing MITM protection

Hi everyone,

could anyone give me advice on how to disable SSP "Just Works" pairing
via userspace? Due to regulatory requirements I am not allowed to
support BT pairing without MITM protection.
However when I pair (outgoing -- i am the initiator) with a device
which has IOCaps set to NoKeyboardNoDisplay and mitm to 0,
the "automatic" pairing is triggered in the kernel, without me
having the chance to cancel this.

The automatic accepting happens in event.c:

-------------------
static void hci_user_confirm_request_evt(struct hci_dev *hdev, void *data,
struct sk_buff *skb)

[...]

/* If we require MITM but the remote device can't provide that
* (it has NoInputNoOutput) then reject the confirmation
* request. We check the security level here since it doesn't
* necessarily match conn->auth_type.
*/
if (conn->pending_sec_level > BT_SECURITY_MEDIUM &&
conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
bt_dev_dbg(hdev, "Rejecting request: remote device can't provide MITM");
hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
sizeof(ev->bdaddr), &ev->bdaddr);
goto unlock;
}

/* If no side requires MITM protection; auto-accept */
if ((!loc_mitm || conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) &&
(!rem_mitm || conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)) {
-------------------

In my scenario the following happens:

-------------------
if ((!loc_mitm || conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) &&
-------------------

conn->remote_cap is HCI_IO_NO_INPUT_OUTPUT, loc_mitm is 1,
the check passes (right side of the logical OR).

-------------------
(!rem_mitm || conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)) {
-------------------

rem_mitm is not on,
the check passes as well (left side of the logical OR).

However, in the example here even the check before on conn could prevent
this, however conn seems to be the ACL connection,
which is set hard to BT_SECURITY_MEDIUM when doing outgoing pairing:

mgmt.c:

------------------
static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)

[...]
sec_level = BT_SECURITY_MEDIUM;
auth_type = HCI_AT_DEDICATED_BONDING;

if (cp->addr.type == BDADDR_BREDR) {
conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
auth_type, CONN_REASON_PAIR_DEVICE);
------------------

After some modifications to the kernel source I can get it to cancel,
but I really do not want to modify the kernel in order to do disable
"Just Works" handling.
Is there a way to force MITM protection in all cases (via IOCTL, or HCI
user socket or whatever). I would be very appreciative of anyone
who could point me in the right direction.

Thank you for your time.

Best regards,
Tom Unbehau


2022-10-19 19:24:22

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: Forcing MITM protection

Hi Tom,

On Wed, Oct 19, 2022 at 7:19 AM Tom Unbehau <[email protected]> wrote:
>
> Hi everyone,
>
> could anyone give me advice on how to disable SSP "Just Works" pairing
> via userspace? Due to regulatory requirements I am not allowed to
> support BT pairing without MITM protection.
> However when I pair (outgoing -- i am the initiator) with a device
> which has IOCaps set to NoKeyboardNoDisplay and mitm to 0,
> the "automatic" pairing is triggered in the kernel, without me
> having the chance to cancel this.
>
> The automatic accepting happens in event.c:
>
> -------------------
> static void hci_user_confirm_request_evt(struct hci_dev *hdev, void *data,
> struct sk_buff *skb)
>
> [...]
>
> /* If we require MITM but the remote device can't provide that
> * (it has NoInputNoOutput) then reject the confirmation
> * request. We check the security level here since it doesn't
> * necessarily match conn->auth_type.
> */
> if (conn->pending_sec_level > BT_SECURITY_MEDIUM &&
> conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) {
> bt_dev_dbg(hdev, "Rejecting request: remote device can't provide MITM");
> hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY,
> sizeof(ev->bdaddr), &ev->bdaddr);
> goto unlock;
> }

I guess you actually want to force BT_SECURITY_HIGH then, which is
something we currently don't support when doing MGMT Pair command,

> /* If no side requires MITM protection; auto-accept */
> if ((!loc_mitm || conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) &&
> (!rem_mitm || conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)) {
> -------------------
>
> In my scenario the following happens:
>
> -------------------
> if ((!loc_mitm || conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) &&
> -------------------
>
> conn->remote_cap is HCI_IO_NO_INPUT_OUTPUT, loc_mitm is 1,
> the check passes (right side of the logical OR).
>
> -------------------
> (!rem_mitm || conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)) {
> -------------------
>
> rem_mitm is not on,
> the check passes as well (left side of the logical OR).
>
> However, in the example here even the check before on conn could prevent
> this, however conn seems to be the ACL connection,
> which is set hard to BT_SECURITY_MEDIUM when doing outgoing pairing:
>
> mgmt.c:
>
> ------------------
> static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
> u16 len)
>
> [...]
> sec_level = BT_SECURITY_MEDIUM;
> auth_type = HCI_AT_DEDICATED_BONDING;
>
> if (cp->addr.type == BDADDR_BREDR) {
> conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
> auth_type, CONN_REASON_PAIR_DEVICE);
> ------------------
>
> After some modifications to the kernel source I can get it to cancel,
> but I really do not want to modify the kernel in order to do disable
> "Just Works" handling.
> Is there a way to force MITM protection in all cases (via IOCTL, or HCI
> user socket or whatever). I would be very appreciative of anyone
> who could point me in the right direction.

It might be possible to force via socket connect using setsockopt to
set the sec_level to BT_SECURITY_HIGH, that said I think we would need
some entry on main.conf like MinSecurityLevel=high and then use it in
the line bellow:

https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/src/device.c#n5436

We also need to change btd_le_connect_before_pairing to make it return
true whenever MinSecurityLevel is higher than medium so we use the
socket to connect instead Pair.

> Thank you for your time.
>
> Best regards,
> Tom Unbehau



--
Luiz Augusto von Dentz