Module Name: src Committed By: martin Date: Sat Sep 28 07:47:07 UTC 2019
Modified Files: src/sys/netbt [netbsd-8]: hci.h hci_event.c Log Message: Pull up following revision(s) (requested by plunky in ticket #1395): sys/netbt/hci_event.c: revision 1.26 sys/netbt/hci.h: revision 1.46 When encrypted connections are configured, verify that the encryption key length has a minimum size when the adaptor supports that. This addresses the 'Key Negotiation of Bluetooth' attack, CVE-2019-9506 https://www.bluetooth.com/security/statement-key-negotiation-of-bluetooth/ To generate a diff of this commit: cvs rdiff -u -r1.43 -r1.43.6.1 src/sys/netbt/hci.h cvs rdiff -u -r1.24 -r1.24.10.1 src/sys/netbt/hci_event.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netbt/hci.h diff -u src/sys/netbt/hci.h:1.43 src/sys/netbt/hci.h:1.43.6.1 --- src/sys/netbt/hci.h:1.43 Sat Jan 28 19:19:41 2017 +++ src/sys/netbt/hci.h Sat Sep 28 07:47:07 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: hci.h,v 1.43 2017/01/28 19:19:41 jakllsch Exp $ */ +/* $NetBSD: hci.h,v 1.43.6.1 2019/09/28 07:47:07 martin Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -54,7 +54,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: hci.h,v 1.43 2017/01/28 19:19:41 jakllsch Exp $ + * $Id: hci.h,v 1.43.6.1 2019/09/28 07:47:07 martin Exp $ * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.6 2005/01/07 01:45:43 imp Exp $ */ @@ -1811,6 +1811,17 @@ typedef struct { uint16_t accuracy; /* clock accuracy */ } __packed hci_read_clock_rp; +#define HCI_OCF_READ_ENCRYPTION_KEY_SIZE 0x0008 +#define HCI_CMD_READ_ENCRYPTION_KEY_SIZE 0x1408 +typedef struct { + uint16_t con_handle; /* connection handle */ +} __packed hci_read_encryption_key_size_cp; + +typedef struct { + uint8_t status; /* 0x00 - success */ + uint16_t con_handle; /* connection handle */ + uint8_t size; /* key size */ +} __packed hci_read_encryption_key_size_rp; /************************************************************************** ************************************************************************** Index: src/sys/netbt/hci_event.c diff -u src/sys/netbt/hci_event.c:1.24 src/sys/netbt/hci_event.c:1.24.10.1 --- src/sys/netbt/hci_event.c:1.24 Sat Nov 28 09:04:34 2015 +++ src/sys/netbt/hci_event.c Sat Sep 28 07:47:07 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: hci_event.c,v 1.24 2015/11/28 09:04:34 plunky Exp $ */ +/* $NetBSD: hci_event.c,v 1.24.10.1 2019/09/28 07:47:07 martin Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.24 2015/11/28 09:04:34 plunky Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.24.10.1 2019/09/28 07:47:07 martin Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -63,6 +63,7 @@ static void hci_cmd_read_local_features( static void hci_cmd_read_local_extended_features(struct hci_unit *, struct mbuf *); static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *); static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *); +static void hci_cmd_read_encryption_key_size(struct hci_unit *, struct mbuf *); static void hci_cmd_reset(struct hci_unit *, struct mbuf *); static void hci_cmd_create_con(struct hci_unit *unit, uint8_t status); @@ -351,6 +352,10 @@ hci_event_command_compl(struct hci_unit hci_cmd_read_local_commands(unit, m); break; + case HCI_CMD_READ_ENCRYPTION_KEY_SIZE: + hci_cmd_read_encryption_key_size(unit, m); + break; + case HCI_CMD_RESET: hci_cmd_reset(unit, m); break; @@ -618,10 +623,11 @@ hci_event_con_compl(struct hci_unit *uni return; } - /* XXX could check auth_enable here */ - - if (ep.encryption_mode) - link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); + /* + * We purposefully ignore ep.encryption_mode here - if that is set then + * the link will be authenticated and encrypted, but we still want to + * verify the key size and setmode sets the right flags + */ link->hl_state = HCI_LINK_OPEN; link->hl_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); @@ -772,17 +778,16 @@ hci_event_auth_compl(struct hci_unit *un /* * Encryption Change * - * The encryption status has changed. Basically, we note the change - * then notify the upper layer protocol unless further mode changes - * are pending. - * Note that if encryption gets disabled when it has been requested, - * we will attempt to enable it again.. (its a feature not a bug :) + * The encryption status has changed. Make a note if disabled, or + * check the key size if possible before allowing it is enabled. + * (checking of key size was enabled in 3.0 spec) */ static void hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m) { hci_encryption_change_ep ep; struct hci_link *link; + uint16_t con_handle; int err; if (m->m_pkthdr.len < sizeof(ep)) @@ -791,27 +796,34 @@ hci_event_encryption_change(struct hci_u m_copydata(m, 0, sizeof(ep), &ep); m_adj(m, sizeof(ep)); - ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); + con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n", - ep.con_handle, ep.status, ep.encryption_enable); + con_handle, ep.status, ep.encryption_enable); - link = hci_link_lookup_handle(unit, ep.con_handle); + link = hci_link_lookup_handle(unit, con_handle); if (link == NULL || link->hl_type != HCI_LINK_ACL) return; if (ep.status == 0) { - if (ep.encryption_enable == 0) + if (ep.encryption_enable == 0) { link->hl_flags &= ~HCI_LINK_ENCRYPT; - else + } else if (unit->hci_cmds[20] & (1<<4)) { + err = hci_send_cmd(unit, HCI_CMD_READ_ENCRYPTION_KEY_SIZE, + &ep.con_handle, sizeof(ep.con_handle)); + + if (err == 0) + return; + } else { link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); - if (link->hl_state == HCI_LINK_WAIT_ENCRYPT) - link->hl_state = HCI_LINK_OPEN; + if (link->hl_state == HCI_LINK_WAIT_ENCRYPT) + link->hl_state = HCI_LINK_OPEN; - err = hci_acl_setmode(link); - if (err == EINPROGRESS) - return; + err = hci_acl_setmode(link); + if (err == EINPROGRESS) + return; + } } hci_acl_linkmode(link); @@ -1170,6 +1182,57 @@ hci_cmd_read_local_commands(struct hci_u } /* + * process results of read_encryption_key_size command_complete event + */ +static void +hci_cmd_read_encryption_key_size(struct hci_unit *unit, struct mbuf *m) +{ + hci_read_encryption_key_size_rp rp; + struct hci_link *link; + int err; + + if (m->m_pkthdr.len < sizeof(rp)) + return; + + m_copydata(m, 0, sizeof(rp), &rp); + m_adj(m, sizeof(rp)); + + if (rp.status != 0) + return; + + rp.con_handle = HCI_CON_HANDLE(le16toh(rp.con_handle)); + + DPRINTFN(1, "handle #%d, status=0x%x, key_size=0x%x\n", + rp.con_handle, rp.status, rp.size); + + link = hci_link_lookup_handle(unit, rp.con_handle); + if (link == NULL || link->hl_type != HCI_LINK_ACL) + return; + + /* + * if the key size is less than minimum standard, go straight to + * linkmode as this is non-recoverable. Otherwise, we are encrypted + * so can proceed with setmode. + */ + if (rp.status == 0) { + if (rp.size < 7) { + link->hl_flags &= ~HCI_LINK_ENCRYPT; + } else { + link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); + + if (link->hl_state == HCI_LINK_WAIT_ENCRYPT) + link->hl_state = HCI_LINK_OPEN; + + err = hci_acl_setmode(link); + if (err == EINPROGRESS) + return; + } + } + + hci_acl_linkmode(link); +} + +/* * process results of reset command_complete event * * This has killed all the connections, so close down anything we have left,