From nobody Wed Aug 04 12:33:48 2021 X-Original-To: freebsd-hackers@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 10D6815EBBDA for ; Wed, 4 Aug 2021 12:33:54 +0000 (UTC) (envelope-from SRS0+Fut7=M3=moira.hest-guild.se=andkem@lysator.liu.se) Received: from mail.lysator.liu.se (mail.lysator.liu.se [IPv6:2001:6b0:17:f0a0::3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4Gfrl55JT2z3pqs for ; Wed, 4 Aug 2021 12:33:53 +0000 (UTC) (envelope-from SRS0+Fut7=M3=moira.hest-guild.se=andkem@lysator.liu.se) Received: from mail.lysator.liu.se (localhost [127.0.0.1]) by mail.lysator.liu.se (Postfix) with ESMTP id A2AE14000B for ; Wed, 4 Aug 2021 14:33:52 +0200 (CEST) Received: by mail.lysator.liu.se (Postfix, from userid 1004) id 8AD624000F; Wed, 4 Aug 2021 14:33:52 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on bernadotte.lysator.liu.se X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=AWL,UNPARSEABLE_RELAY autolearn=disabled version=3.4.2 X-Spam-Score: 0.0 Received: from moira.hest-guild.se (unknown [IPv6:2001:9b1:28ff:5100::1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.lysator.liu.se (Postfix) with ESMTPSA id 31FF04000B for ; Wed, 4 Aug 2021 14:33:49 +0200 (CEST) Received: from andkem (uid 1000) (envelope-from andkem@moira.hest-guild.se) id 1817869a by moira.hest-guild.se (DragonFly Mail Agent v0.13); Wed, 04 Aug 2021 14:33:48 +0200 Date: Wed, 4 Aug 2021 14:33:48 +0200 From: Andreas Kempe To: freebsd-bluetooth@freebsd.org Cc: freebsd-hackers@freebsd.org Subject: RFC: PoC: Bluetooth secure simple pairing support Message-ID: List-Id: Technical discussions relating to FreeBSD List-Archive: https://lists.freebsd.org/archives/freebsd-hackers List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-freebsd-hackers@freebsd.org MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="+pkO+WIezJok9CBI" Content-Disposition: inline X-Virus-Scanned: ClamAV using ClamSMTP X-Rspamd-Queue-Id: 4Gfrl55JT2z3pqs X-Spamd-Bar: ----- Authentication-Results: mx1.freebsd.org; dkim=none; dmarc=pass (policy=none) header.from=liu.se; spf=pass (mx1.freebsd.org: domain of SRS0@lysator.liu.se designates 2001:6b0:17:f0a0::3 as permitted sender) smtp.mailfrom=SRS0@lysator.liu.se X-Spamd-Result: default: False [-5.60 / 15.00]; ARC_NA(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; RCVD_COUNT_FIVE(0.00)[5]; NEURAL_HAM_MEDIUM(-1.00)[-1.000]; FROM_HAS_DN(0.00)[]; R_SPF_ALLOW(-0.20)[+a:mail.lysator.liu.se:c]; NEURAL_HAM_LONG(-1.00)[-1.000]; MIME_GOOD(-0.20)[multipart/signed,multipart/mixed,text/plain,text/x-diff]; PREVIOUSLY_DELIVERED(0.00)[freebsd-hackers@freebsd.org]; TO_DN_NONE(0.00)[]; HAS_ATTACHMENT(0.00)[]; TO_MATCH_ENVRCPT_SOME(0.00)[]; NEURAL_HAM_SHORT(-1.00)[-1.000]; RCPT_COUNT_TWO(0.00)[2]; DMARC_POLICY_ALLOW(-0.50)[liu.se,none]; RCVD_TLS_LAST(0.00)[]; FORGED_SENDER(0.30)[kempe@lysator.liu.se,SRS0@lysator.liu.se]; SIGNED_PGP(-2.00)[]; R_DKIM_NA(0.00)[]; MIME_TRACE(0.00)[0:+,1:+,2:+,3:+,4:~]; ASN(0.00)[asn:1653, ipnet:2001:6b0::/32, country:EU]; TAGGED_FROM(0.00)[Fut7=M3=moira.hest-guild.se=andkem]; FROM_NEQ_ENVFROM(0.00)[kempe@lysator.liu.se,SRS0@lysator.liu.se] X-ThisMailContainsUnwantedMimeParts: N --+pkO+WIezJok9CBI Content-Type: multipart/mixed; boundary="m88YXiM89buYlW4g" Content-Disposition: inline --m88YXiM89buYlW4g Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello everyone, A few months back I sent a mail titled "Wireless Logitecgh M557 mouse issues" to the bluetooth list and since then I finally found some time to do more digging into the issue. Comparing the FreeBSD behaviour to that of Linux via packet dumps, I found that the reason my buetooth mouse is not able to reconnect to my FreeBSD machine is that no pairing is performed. Currently, the initial connection to the mouse is made and the mouse is used in an unpaired state. When the mouse tries to reconnect, the computer has no authentication key and the connection fails. Attached to this mail, you can find a proof of concept patch for allowing pairing between my mouse and the FreeBSD host. Using the attached patch, I'm able to connect my mouse and it reconnects when switched off and on again. The patch applies on top of Git revision 142f0d36d90979a983e1bb0b69d1d859338b4d90. Using the PoC ------------- In its current form, hcsecd has a very rudimentary implementation of pairing support. No real state machine is used and error handling is pretty much non-existent. The implementation assumes all operations went well (which they have always done with my mouse so far). Using the patch and performing the pairing: 1. Ensure that /var/db/{hcsecd.keys,bthidd.hids} do not contain entries fro the mouse. 2. Prep the hcsecd configuration file with the mouse. device { bdaddr 00:1f:20:f5:cd:5f; name "Bluetooth Mouse M557"; key nokey; pin nopin; } 3. Prep the bthidd configuration file. device { bdaddr 00:1f:20:f5:cd:5f; name "Bluetooth Mouse M557"; vendor_id 0x046d; product_id 0xb010; version 0x1001; control_psm 0x11; interrupt_psm 0x13; reconnect_initiate true; battery_power true; normally_connectable false; hid_descriptor { [...] }; } 4. Start hcsecd. service hcsecd start 5. Create a connection to the mouse. hccontrol Create_connection 00:1f:20:f5:cd:5f Creating the connection causes the pairing to happen. 6. Start bthidd. service bthidd start The mouse should now connect and work as intended. After the initial pairing, the mouse can be turned off and on again and as long as hcsecd and bthidd are running the mouse should reconnect. During the initial pairing, bthidd can't be left running since it will try to connect to the mouse and send HID-related things disturbing the pairing process. Questions --------- Is implementing the pairing in hcsecd the correct approach? Is a more complex state machine needed or can the expected pairing flow be hard coded like the PoC albeit with proper error handling? static int pairing used in the PoC is the only "state machine" state currently present and should be done in a nicer way, but I deemed it sufficent for the PoC. How should one handle the interaction between bthidd and hcsecd? If one wants the initial to pairing to work, bthidd can't send its messages until the pairing is completed. Is my approach to this sane or am I going in the wrong direction? Looking forward to your feedback! Cordially, Andreas Kempe --m88YXiM89buYlW4g Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="secure_simple_pairing_v0.patch" Content-Transfer-Encoding: quoted-printable diff --git a/sys/netgraph/bluetooth/hci/ng_hci_cmds.c b/sys/netgraph/blueto= oth/hci/ng_hci_cmds.c index 9bef544cc98..2934206e634 100644 --- a/sys/netgraph/bluetooth/hci/ng_hci_cmds.c +++ b/sys/netgraph/bluetooth/hci/ng_hci_cmds.c @@ -615,8 +615,10 @@ process_hc_baseband_params(ng_hci_unit_p unit, u_int16= _t ocf, case NG_HCI_OCF_READ_LOCAL_NAME: case NG_HCI_OCF_READ_UNIT_CLASS: case NG_HCI_OCF_WRITE_UNIT_CLASS: + case NG_HCI_OCF_WRITE_SIMPLE_PAIRING: case NG_HCI_OCF_READ_LE_HOST_SUPPORTED: case NG_HCI_OCF_WRITE_LE_HOST_SUPPORTED: + case NG_HCI_OCF_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT: /* These do not need post processing */ break; =20 diff --git a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c b/sys/netgraph/blueto= oth/hci/ng_hci_evnt.c index b0dae0e18ec..6bd8f3b7e8c 100644 --- a/sys/netgraph/bluetooth/hci/ng_hci_evnt.c +++ b/sys/netgraph/bluetooth/hci/ng_hci_evnt.c @@ -121,6 +121,7 @@ ng_hci_process_event(ng_hci_unit_p unit, struct mbuf *e= vent) case NG_HCI_EVENT_VENDOR: case NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL: case NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL: + case NG_HCI_EVENT_IO_CAPABILITY_REQUEST: /* These do not need post processing */ NG_FREE_M(event); break; diff --git a/sys/netgraph/bluetooth/include/ng_hci.h b/sys/netgraph/bluetoo= th/include/ng_hci.h index ba23ba0563c..3effff8071b 100644 --- a/sys/netgraph/bluetooth/include/ng_hci.h +++ b/sys/netgraph/bluetooth/include/ng_hci.h @@ -115,6 +115,8 @@ #define NG_HCI_LMP_FLOW_CONTROL_LAG0 0x10 #define NG_HCI_LMP_FLOW_CONTROL_LAG1 0x20 #define NG_HCI_LMP_FLOW_CONTROL_LAG2 0x40 +/* ------------------- byte 6 --------------------*/ +#define NG_HCI_LMP_SIMPLE_SECURE_CONNECT 0x08 =20 /* Link types */ #define NG_HCI_LINK_SCO 0x00 /* Voice */ @@ -797,6 +799,30 @@ typedef struct { } __attribute__ ((packed)) ng_hci_read_clock_offset_cp; /* No return parameter(s) */ =20 +#define NG_HCI_IO_CAPABILITY_REQUEST_REPLY 0x002b +typedef struct { + bdaddr_t bdaddr; + u_int8_t io_capability; + u_int8_t oob_data_present; + u_int8_t authentication_requirements; +} __attribute__ ((packed)) ng_hci_io_capability_request_reply_cp; + +typedef struct { + u_int8_t status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) ng_hci_io_capability_request_reply_rp; + +#define NG_HCI_USER_CONFIRMATION_REQUEST_REPLY 0x002c +typedef struct { + bdaddr_t bdaddr; +} __attribute__ ((packed)) ng_hci_user_confirmation_request_reply_cp; + +typedef struct { + u_int8_t status; + bdaddr_t bdaddr; +} __attribute__ ((packed)) ng_hci_user_confirmation_request_reply_rp; + + /************************************************************************** ************************************************************************** ** Link policy commands and return parameters @@ -1311,6 +1337,13 @@ typedef struct { =20 typedef ng_hci_status_rp ng_hci_write_page_scan_rp; =20 +#define NG_HCI_OCF_WRITE_SIMPLE_PAIRING 0x0056 +typedef struct { + u_int8_t simple_pairing; /* 1 -> enabled, 0 -> disabled */ +} __attribute__ ((packed)) ng_hci_write_simple_pairing_cp; + +typedef ng_hci_status_rp ng_hcy_write_simple_pairing_rp; + #define NG_HCI_OCF_READ_LE_HOST_SUPPORTED 0x6c typedef struct { u_int8_t status; /* 0x00 - success */ @@ -1326,6 +1359,13 @@ typedef struct { =20 typedef ng_hci_status_rp ng_hci_write_le_host_supported_rp; =20 +#define NG_HCI_OCF_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT 0x7a +typedef struct { + u_int8_t support; /* 0 - disabled, 1 - enabled */ +} __attribute__ ((packed)) ng_hci_write_secure_connections_host_support_cp; + +typedef ng_hci_status_rp ng_hci_write_secure_connections_host_support_rp; + /************************************************************************** ************************************************************************** ** Informational commands and return parameters=20 @@ -1800,6 +1840,7 @@ typedef struct { u_int8_t features[NG_HCI_FEATURES_SIZE]; /* LMP features bitmsk*/ } __attribute__ ((packed)) ng_hci_read_remote_features_compl_ep; =20 + #define NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL 0x0c typedef struct { u_int8_t status; /* 0x00 - success */ @@ -1939,6 +1980,18 @@ typedef struct { bdaddr_t bdaddr; /* destination address */ u_int8_t page_scan_rep_mode; /* page scan repetition mode */ } __attribute__ ((packed)) ng_hci_page_scan_rep_mode_change_ep; + +#define NG_HCI_EVENT_IO_CAPABILITY_REQUEST 0x31 +typedef struct { + bdaddr_t bdaddr; +} __attribute__ ((packed)) ng_hci_io_capability_request_ep; + +#define NG_HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33 +typedef struct { + bdaddr_t bdaddr; + u_int32_t numeric_value; +} __attribute__ ((packed)) ng_hci_user_confirmation_request_ep; + #define NG_HCI_EVENT_LE 0x3e typedef struct { u_int8_t subevent_code;=09 diff --git a/usr.sbin/bluetooth/hcsecd/hcsecd.c b/usr.sbin/bluetooth/hcsecd= /hcsecd.c index 160b77e1b04..8a22a162f09 100644 --- a/usr.sbin/bluetooth/hcsecd/hcsecd.c +++ b/usr.sbin/bluetooth/hcsecd/hcsecd.c @@ -46,7 +46,10 @@ #include "hcsecd.h" =20 static int done =3D 0; +static int pairing =3D 0; =20 +static int enable_simple_pairing(int sock); +static int unmask_events(int sock); static int process_pin_code_request_event (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr); static int process_link_key_request_event @@ -57,6 +60,17 @@ static int send_link_key_reply (int sock, struct sockaddr_hci *addr, bdaddr_p bdaddr, uint8_t *key); static int process_link_key_notification_event (int sock, struct sockaddr_hci *addr, ng_hci_link_key_notification_ep *ep= ); +static int process_read_remote_features_compl_event + (int sock, struct sockaddr_hci *addr, + ng_hci_read_remote_features_compl_ep *ep); +static int process_con_compl_event + (int sock, struct sockaddr_hci *addr, ng_hci_con_compl_ep *ep); +static int process_io_capabilities_request_event + (int sock, struct sockaddr_hci *addr, ng_hci_io_capability_request_ep *ep= ); +static int process_user_confirmation_request_event + (int sock, struct sockaddr_hci *addr, ng_hci_user_confirmation_request_ep= *ep); +static int process_auth_compl_event + (int sock, struct sockaddr_hci *addr, ng_hci_auth_compl_ep *ep); static void sighup (int s); static void sigint @@ -126,6 +140,11 @@ main(int argc, char *argv[]) bit_set(filter.event_mask, NG_HCI_EVENT_PIN_CODE_REQ - 1); bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_REQ - 1); bit_set(filter.event_mask, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1); + bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1); + bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1); + bit_set(filter.event_mask, NG_HCI_EVENT_IO_CAPABILITY_REQUEST - 1); + bit_set(filter.event_mask, NG_HCI_EVENT_USER_CONFIRMATION_REQUEST - 1); + bit_set(filter.event_mask, NG_HCI_EVENT_AUTH_COMPL - 1); =20 if (setsockopt(sock, SOL_HCI_RAW, SO_HCI_RAW_FILTER, (void * const) &filter, sizeof(filter)) < 0) @@ -139,6 +158,9 @@ main(int argc, char *argv[]) read_config_file(); read_keys_file(); =20 + enable_simple_pairing(sock); + unmask_events(sock); + if (detach) { FILE *pid =3D NULL; =20 @@ -188,6 +210,31 @@ main(int argc, char *argv[]) (ng_hci_link_key_notification_ep *)(event + 1)); break; =20 + case NG_HCI_EVENT_CON_COMPL: + process_con_compl_event(sock, &addr, + (ng_hci_con_compl_ep *)(event + 1)); + break; + + case NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL: + process_read_remote_features_compl_event(sock, &addr, + (ng_hci_read_remote_features_compl_ep *)(event + 1)); + break; + + case NG_HCI_EVENT_IO_CAPABILITY_REQUEST: + process_io_capabilities_request_event(sock, + &addr, (ng_hci_io_capability_request_ep *)(event + 1)); + break; + + case NG_HCI_EVENT_USER_CONFIRMATION_REQUEST: + process_user_confirmation_request_event(sock, &addr, + (ng_hci_user_confirmation_request_ep *)(event + 1)); + break; + + case NG_HCI_EVENT_AUTH_COMPL: + process_auth_compl_event(sock, &addr, + (ng_hci_auth_compl_ep *)(event + 1)); + break; + default: syslog(LOG_ERR, "Received unexpected HCI event, " \ "event=3D%#x", event->event); @@ -208,6 +255,148 @@ main(int argc, char *argv[]) return (0); } =20 +static int +find_hci_nodes(struct nodeinfo** nodes) +{ + struct ng_btsocket_hci_raw_node_list_names r; + struct sockaddr_hci addr; + int s; + const char * node =3D "ubt0hci"; + + r.num_names =3D 16; + r.names =3D (struct nodeinfo*)calloc(16, sizeof(struct nodeinfo)); + if (r.names =3D=3D NULL) + err(8, "Could not allocate memory"); + + s =3D socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); + if (s < 0) + err(9, "Could not create socket"); + + memset(&addr, 0, sizeof(addr)); + addr.hci_len =3D sizeof(addr); + addr.hci_family =3D AF_BLUETOOTH; + strncpy(addr.hci_node, node, sizeof(addr.hci_node)); + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) + err(10, "Could not bind socket"); + + if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) + err(11, "Could not get list of HCI nodes"); + + close(s); + + *nodes =3D r.names; + + return (r.num_names); +} /* find_hci_nodes */ + +static int enable_simple_pairing(int sock) +{ + uint8_t buffer[HCSECD_BUFFER_SIZE]; + ng_hci_cmd_pkt_t *cmd =3D NULL; + struct nodeinfo *nodes; + struct sockaddr_hci addr; + int num; + char *node; + + num =3D find_hci_nodes(&nodes); + if (num =3D=3D 0) { + syslog(LOG_ERR, "Could not find HCI nodes"); + free(nodes); + return (-1); + } + + node =3D strdup(nodes[0].name); + + free(nodes); + + memset(&addr, 0, sizeof(addr)); + addr.hci_len =3D sizeof(addr); + addr.hci_family =3D AF_BLUETOOTH; + strncpy(addr.hci_node, node, sizeof(addr.hci_node)); + free(node); + + memset(buffer, 0, sizeof(buffer)); + + cmd =3D (ng_hci_cmd_pkt_t *) buffer; + cmd->type =3D NG_HCI_CMD_PKT; + + ng_hci_write_simple_pairing_cp *cp =3D NULL; + + cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, + NG_HCI_OCF_WRITE_SIMPLE_PAIRING)); + cmd->length =3D sizeof(*cp); + + cp =3D (ng_hci_write_simple_pairing_cp *)(cmd + 1); + cp->simple_pairing =3D 1; + +again: + if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, + (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (errno =3D=3D EINTR) + goto again; + + syslog(LOG_ERR, "Could not send write simple pairing. " \ + "%s (%d)", strerror(errno), errno); + return (-1); + } + + return (0); +} + +static int unmask_events(int sock) +{ + uint8_t buffer[HCSECD_BUFFER_SIZE]; + ng_hci_cmd_pkt_t *cmd =3D NULL; + struct nodeinfo *nodes; + struct sockaddr_hci addr; + int num; + char *node; + + num =3D find_hci_nodes(&nodes); + if (num =3D=3D 0) { + syslog(LOG_ERR, "Could not find HCI nodes"); + free(nodes); + return (-1); + } + + node =3D strdup(nodes[0].name); + + free(nodes); + + memset(&addr, 0, sizeof(addr)); + addr.hci_len =3D sizeof(addr); + addr.hci_family =3D AF_BLUETOOTH; + strncpy(addr.hci_node, node, sizeof(addr.hci_node)); + free(node); + + memset(buffer, 0, sizeof(buffer)); + + cmd =3D (ng_hci_cmd_pkt_t *) buffer; + cmd->type =3D NG_HCI_CMD_PKT; + + ng_hci_set_event_mask_cp *cp =3D NULL; + + cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_HC_BASEBAND, + NG_HCI_OCF_SET_EVENT_MASK)); + cmd->length =3D sizeof(*cp); + + cp =3D (ng_hci_set_event_mask_cp *)(cmd + 1); + memset(cp->event_mask, 0xff, NG_HCI_EVENT_MASK_SIZE); + +again: + if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, + (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (errno =3D=3D EINTR) + goto again; + + syslog(LOG_ERR, "Could not send set event mask. " \ + "%s (%d)", strerror(errno), errno); + return (-1); + } + + return (0); +} + /* Process PIN_Code_Request event */ static int process_pin_code_request_event(int sock, struct sockaddr_hci *addr, @@ -415,6 +604,225 @@ process_link_key_notification_event(int sock, struct = sockaddr_hci *addr, return (0); } =20 +static int send_auth_req(int sock, struct sockaddr_hci *addr, + u_int16_t con_handle) +{ + uint8_t buffer[HCSECD_BUFFER_SIZE]; + ng_hci_cmd_pkt_t *cmd =3D NULL; + + memset(buffer, 0, sizeof(buffer)); + + cmd =3D (ng_hci_cmd_pkt_t *) buffer; + cmd->type =3D NG_HCI_CMD_PKT; + + ng_hci_auth_req_cp *cp =3D NULL; + + cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, + NG_HCI_OCF_AUTH_REQ)); + cmd->length =3D sizeof(*cp); + + cp =3D (ng_hci_auth_req_cp *)(cmd + 1); + cp->con_handle =3D htole16(con_handle); + +again: + if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, + (struct sockaddr *) addr, sizeof(*addr)) < 0) { + if (errno =3D=3D EINTR) + goto again; + + syslog(LOG_ERR, "Could not send auth req to for con_handle =3D %d. " \ + "%s (%d)", con_handle, strerror(errno), errno); + return (-1); + } + + return (0); +} + +static int process_read_remote_features_compl_event(int sock, + struct sockaddr_hci *addr, ng_hci_read_remote_features_compl_ep *ep) +{ + if (ep->features[6] & NG_HCI_LMP_SIMPLE_SECURE_CONNECT) { + return (send_auth_req(sock, addr, ep->con_handle)); + } else + return (0); +} + +static int send_read_remote_features(int sock, struct sockaddr_hci *addr, + u_int16_t con_handle) +{ + uint8_t buffer[HCSECD_BUFFER_SIZE]; + ng_hci_cmd_pkt_t *cmd =3D NULL; + + memset(buffer, 0, sizeof(buffer)); + + cmd =3D (ng_hci_cmd_pkt_t *) buffer; + cmd->type =3D NG_HCI_CMD_PKT; + + ng_hci_read_remote_features_cp *cp =3D NULL; + + cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, + NG_HCI_OCF_READ_REMOTE_FEATURES)); + cmd->length =3D sizeof(*cp); + + cp =3D (ng_hci_read_remote_features_cp *)(cmd + 1); + cp->con_handle =3D htole16(con_handle); + +again: + if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, + (struct sockaddr *) addr, sizeof(*addr)) < 0) { + if (errno =3D=3D EINTR) + goto again; + + syslog(LOG_ERR, "Could not send read remote features for " \ + "con_handle =3D %d. %s (%d)", con_handle, strerror(errno), + errno); + return (-1); + } + + return (0); +} + +static int process_con_compl_event(int sock, struct sockaddr_hci *addr, + ng_hci_con_compl_ep *ep) +{ + return (send_read_remote_features(sock, addr, ep->con_handle)); +} + +static int send_io_capability_request_reply(int sock, struct sockaddr_hci = *addr, + bdaddr_p bdaddr) +{ + uint8_t buffer[HCSECD_BUFFER_SIZE]; + ng_hci_cmd_pkt_t *cmd =3D NULL; + + memset(buffer, 0, sizeof(buffer)); + + cmd =3D (ng_hci_cmd_pkt_t *) buffer; + cmd->type =3D NG_HCI_CMD_PKT; + + ng_hci_io_capability_request_reply_cp *cp =3D NULL; + + cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, + NG_HCI_IO_CAPABILITY_REQUEST_REPLY)); + cmd->length =3D sizeof(*cp); + + cp =3D (ng_hci_io_capability_request_reply_cp *)(cmd + 1); + memcpy(&cp->bdaddr, bdaddr, sizeof(bdaddr_t)); + cp->io_capability =3D 0x03; /* 0x03 - NoInputNoOutput */ + cp->oob_data_present =3D 0x00; /* 0x00 - OOB authentication data not pres= ent */ + /* 0x03 - MITM protection required - Dedicated Bonding. Use IO + * Capabilities to determine authentication procedure. */ + cp->authentication_requirements =3D 0x03; + + +again: + if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, + (struct sockaddr *) addr, sizeof(*addr)) < 0) { + if (errno =3D=3D EINTR) + goto again; + + syslog(LOG_ERR, "Could not send IO capability request reply to " \ + "remote bdaddr '%s'. %s (%d)", bt_ntoa(bdaddr, NULL), + strerror(errno), errno); + return (-1); + } + + return (0); +} + +static int process_io_capabilities_request_event(int sock, + struct sockaddr_hci *addr, ng_hci_io_capability_request_ep *ep) +{ + /* Requesting IO capabilities is the start of simple pairing. */ + pairing =3D 1; + return (send_io_capability_request_reply(sock, addr, &ep->bdaddr)); +} + +static int send_user_confirmation_request_reply(int sock, + struct sockaddr_hci *addr, bdaddr_p bdaddr) +{ + uint8_t buffer[HCSECD_BUFFER_SIZE]; + ng_hci_cmd_pkt_t *cmd =3D NULL; + + memset(buffer, 0, sizeof(buffer)); + + cmd =3D (ng_hci_cmd_pkt_t *) buffer; + cmd->type =3D NG_HCI_CMD_PKT; + + ng_hci_user_confirmation_request_reply_cp *cp =3D NULL; + + cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, + NG_HCI_USER_CONFIRMATION_REQUEST_REPLY)); + cmd->length =3D sizeof(*cp); + + cp =3D (ng_hci_user_confirmation_request_reply_cp *)(cmd + 1); + memcpy(&cp->bdaddr, bdaddr, sizeof(bdaddr_t)); + +again: + if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, + (struct sockaddr *) addr, sizeof(*addr)) < 0) { + if (errno =3D=3D EINTR) + goto again; + + syslog(LOG_ERR, "Could not user confirmation request reply to remote " \ + " bdaddr '%s'. %s (%d)", bt_ntoa(bdaddr, NULL), + strerror(errno), errno); + return (-1); + } + + return (0); +} + +static int process_user_confirmation_request_event(int sock, + struct sockaddr_hci *addr, ng_hci_user_confirmation_request_ep *ep) +{ + return (send_user_confirmation_request_reply(sock, addr, &ep->bdaddr)); +} + +static int send_set_con_encryption_enabled(int sock, struct sockaddr_hci *= addr, + u_int16_t con_handle) +{ + uint8_t buffer[HCSECD_BUFFER_SIZE]; + ng_hci_cmd_pkt_t *cmd =3D NULL; + + memset(buffer, 0, sizeof(buffer)); + + cmd =3D (ng_hci_cmd_pkt_t *) buffer; + cmd->type =3D NG_HCI_CMD_PKT; + + ng_hci_set_con_encryption_cp *cp =3D NULL; + + cmd->opcode =3D htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, + NG_HCI_OCF_SET_CON_ENCRYPTION)); + cmd->length =3D sizeof(*cp); + + cp =3D (ng_hci_set_con_encryption_cp *)(cmd + 1); + cp->con_handle =3D htole16(con_handle); + cp->encryption_enable =3D 0x01; /* 0x01 - encryption enabled */ + +again: + if (sendto(sock, buffer, sizeof(*cmd) + cmd->length, 0, + (struct sockaddr *) addr, sizeof(*addr)) < 0) { + if (errno =3D=3D EINTR) + goto again; + + syslog(LOG_ERR, "Could not set encryption enabled for con_handle =3D %d.= " \ + " %s (%d)", con_handle, strerror(errno), errno); + return (-1); + } + + return (0); +} + +static int process_auth_compl_event(int sock, struct sockaddr_hci *addr, + ng_hci_auth_compl_ep *ep) +{ + if (pairing =3D=3D 1) { + pairing =3D 0; + return (send_set_con_encryption_enabled(sock, addr, ep->con_handle)); + } else + return (0); +} + /* Signal handlers */ static void sighup(int s) --m88YXiM89buYlW4g-- --+pkO+WIezJok9CBI Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEETci4cPcl+ZcyiACiCkqKrhcKSD0FAmEKiSYACgkQCkqKrhcK SD1cQQ/+OHgphpdczZsG6lKjf4g+t+MsQiYmFJCRB49UyOSarn1VO6QbuOTioTp/ wqREt2c50PY5E2fYra4qo5AME8BalVJXMfcOqYfkp0b2BcgyxpW+SGzqn816QEAo I3Zc35ynhP39hwboU2Z3Omuh3WabksfJrVakKbnWd4wghMY6KRa66re91sKdxB17 uOW42HQpP4QLvOL0DkFlHcwL32kMHqbUoTFHv6S0LhAtEYa5NVpOyDJpWieadTUN 6BI6BSIvaCtUgH+rhQNC6XUpoCi7X3Sk3H3Kpx6Yiusj58CRwS1cnDamaiKKifRi 6T5FJBvQ10AtqZSrSn1xpKQoCjreSRz+1jd8FUybtAw4HFNk9iwePqLuM4OKHs4e FP2zAePZsllCCb31wMEvVyPOrKPexD9YICJ3828DYWIZ3TfJVX+Jk9kK0XCwLvyA jGJXfGpD0OAb/EKKi/8Kp9hxIoJIqeoBuMcrQ8QymRw2qz+86NuPOGRsjidr1Ge9 PnsIyzeJha1Ui1VJHzep8iji7lrT5li/K7JRvETFS5rkeFo0iXyqTNhgnrrBc9y+ Biqj041I+d73NrP9nreAwRXW0avqbXv+HK5TDudhiFLJ/GI0Kdlp7SxVBjl3fH4i PVracfCnG0GzZgf69wymCHrSVoSRmJsUo8pGeNoK/pWoq1f1y90= =Nnl2 -----END PGP SIGNATURE----- --+pkO+WIezJok9CBI--