linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/18] usbip: Crypto and ACLs
@ 2014-09-16 23:38 Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 01/18] usbip: sysfs_utils: add read_sysfs_attribute Maximilian Eschenbacher
                   ` (18 more replies)
  0 siblings, 19 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel; +Cc: valentina.manea.m, shuah.kh, gregkh, Maximilian Eschenbacher

Hi,

As follow-up to Dominik Paulus' and Tobias Polzers series of patches from 19
Oct 2013 (which hasn't been accepted) and due to the fact that usb/ip has
recently been moved out of staging we rebased the patches on top of v3.17-rc5
and would like to resubmit.

This patch series includes:

 - The client/server authentication support using GnuTLS

 - Support for restricting the access to devices to specific IP address ranges

 - Improved error reporting and new error codes to be passed over the TCP
   protocol.

 - Minor changes to fit to the current state of usb/ip source.

As Dominik and Tobias suggested the added features justify a version bump to
1.2.0. The corresponding patch is also included. All protocol changes are
backwards-compatible, thus, we don't increment the protocol version.

Regards,

Maximilian Eschenbacher, Fjodor Schelichow and Johannes Stadlinger

---

 drivers/usb/usbip/Kconfig                  |   2 +-
 drivers/usb/usbip/stub.h                   |   8 +
 drivers/usb/usbip/stub_dev.c               | 104 +++++++-
 drivers/usb/usbip/stub_rx.c                |   2 +-
 drivers/usb/usbip/stub_tx.c                |   6 +-
 drivers/usb/usbip/usbip_common.c           | 411 ++++++++++++++++++++++++++---
 drivers/usb/usbip/usbip_common.h           |  41 ++-
 drivers/usb/usbip/vhci_hcd.c               |   4 +-
 drivers/usb/usbip/vhci_rx.c                |   2 +-
 drivers/usb/usbip/vhci_sysfs.c             |  47 +++-
 drivers/usb/usbip/vhci_tx.c                |   4 +-
 tools/usb/usbip/README                     |  72 ++---
 tools/usb/usbip/configure.ac               |  15 +-
 tools/usb/usbip/doc/usbip.8                |  14 +-
 tools/usb/usbip/doc/usbipd.8               |   7 +
 tools/usb/usbip/libsrc/list.h              |   3 +-
 tools/usb/usbip/libsrc/sysfs_utils.c       |  23 ++
 tools/usb/usbip/libsrc/sysfs_utils.h       |   1 +
 tools/usb/usbip/libsrc/usbip_common.c      |  15 ++
 tools/usb/usbip/libsrc/usbip_common.h      |  24 ++
 tools/usb/usbip/libsrc/usbip_host_driver.c |  17 +-
 tools/usb/usbip/libsrc/usbip_host_driver.h |   3 +-
 tools/usb/usbip/libsrc/vhci_driver.c       |  25 +-
 tools/usb/usbip/libsrc/vhci_driver.h       |   9 +-
 tools/usb/usbip/src/Makefile.am            |   2 +-
 tools/usb/usbip/src/usbip.c                |  30 ++-
 tools/usb/usbip/src/usbip_attach.c         |  75 +++++-
 tools/usb/usbip/src/usbip_bind.c           |  71 +++--
 tools/usb/usbip/src/usbip_list.c           |  29 +-
 tools/usb/usbip/src/usbip_network.c        | 360 ++++++++++++++++++++++---
 tools/usb/usbip/src/usbip_network.h        |  81 +++++-
 tools/usb/usbip/src/usbipd.c               | 323 ++++++++++++++++-------
 tools/usb/usbip/src/utils.c                |  88 ++++++
 tools/usb/usbip/src/utils.h                |  15 ++
 34 files changed, 1627 insertions(+), 306 deletions(-)

-- 
2.1.0


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 01/18] usbip: sysfs_utils: add read_sysfs_attribute
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 02/18] usbip: Add support for client authentication Maximilian Eschenbacher
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Maximilian Eschenbacher,
	Fjodor Schelichow, Johannes Stadlinger

Previous rework of usbip's sysfs access structures called for a
read_sysfs_attribute function to be implemented in sysfs_utils.c

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
---
 tools/usb/usbip/libsrc/sysfs_utils.c | 23 +++++++++++++++++++++++
 tools/usb/usbip/libsrc/sysfs_utils.h |  1 +
 2 files changed, 24 insertions(+)

diff --git a/tools/usb/usbip/libsrc/sysfs_utils.c b/tools/usb/usbip/libsrc/sysfs_utils.c
index 36ac88e..fc6d9f9 100644
--- a/tools/usb/usbip/libsrc/sysfs_utils.c
+++ b/tools/usb/usbip/libsrc/sysfs_utils.c
@@ -29,3 +29,26 @@ int write_sysfs_attribute(const char *attr_path, const char *new_value,
 
 	return 0;
 }
+
+int read_sysfs_attribute(const char *attr_path, char *buffer, size_t buffsize)
+{
+	int fd;
+	int length;
+
+	fd = open(attr_path, O_RDONLY);
+	if (fd < 0) {
+		dbg("error opening attribute %s", attr_path);
+		return -1;
+	}
+
+	length = read(fd, buffer, buffsize);
+	if (length < 0) {
+		dbg("error reading from attribute %s", attr_path);
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+
+	return length;
+}
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.h b/tools/usb/usbip/libsrc/sysfs_utils.h
index 32ac1d1..c1f1b79 100644
--- a/tools/usb/usbip/libsrc/sysfs_utils.h
+++ b/tools/usb/usbip/libsrc/sysfs_utils.h
@@ -4,5 +4,6 @@
 
 int write_sysfs_attribute(const char *attr_path, const char *new_value,
 			  size_t len);
+int read_sysfs_attribute(const char *attr_path, char *buffer, size_t buffsize);
 
 #endif
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 02/18] usbip: Add support for client authentication
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 01/18] usbip: sysfs_utils: add read_sysfs_attribute Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-21  0:42   ` Max Vozeler
  2014-10-03 14:16   ` Valentina Manea
  2014-09-16 23:38 ` [PATCH 03/18] usbip: Add kernel support for client ACLs Maximilian Eschenbacher
                   ` (16 subsequent siblings)
  18 siblings, 2 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This patch adds support for authenticating both client and server using
a pre-shared passphrase using SRP (Secure Remote Password) over TLS (see
RFC 5054) using GnuTLS. Both usbip and usbipd now accept a shared secret
as a command line argument. Currently, the established TLS connection is
only used to perform a secure handshake and dropped before the socket is
passed to the kernel. The code may be extended to exchange a session key
over TLS and pass it to the kernel to perform IPsec.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/configure.ac        |  14 +++
 tools/usb/usbip/doc/usbip.8         |   4 +
 tools/usb/usbip/doc/usbipd.8        |   5 +
 tools/usb/usbip/src/usbip.c         |  30 +++++-
 tools/usb/usbip/src/usbip_attach.c  |   2 +-
 tools/usb/usbip/src/usbip_list.c    |   2 +-
 tools/usb/usbip/src/usbip_network.c | 185 ++++++++++++++++++++++++++++++++++++
 tools/usb/usbip/src/usbip_network.h |  11 ++-
 tools/usb/usbip/src/usbipd.c        | 115 ++++++++++++++++------
 9 files changed, 335 insertions(+), 33 deletions(-)

diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac
index 607d05c..6a8156f 100644
--- a/tools/usb/usbip/configure.ac
+++ b/tools/usb/usbip/configure.ac
@@ -83,6 +83,20 @@ AC_ARG_WITH([tcp-wrappers],
 		AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])],
 	       [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])])
 
+# Checks for the GnuTLS library
+AC_ARG_WITH([gnutls],
+			[AS_HELP_STRING([--with-gnutls],
+							[use the GnuTLS library for authentication])],
+			dnl [ACTION-IF-GIVEN]
+			[if test "$withval" = "yes"; then
+			 PKG_CHECK_MODULES([GNUTLS], [gnutls])
+			 AC_DEFINE([HAVE_GNUTLS], [1], [use gnutls])
+			 CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
+			 LDFLAGS="$LDFLAGS $GNUTLS_LIBS"
+			 fi
+			],
+			)
+
 # Sets directory containing usb.ids.
 AC_ARG_WITH([usbids-dir],
 	    [AS_HELP_STRING([--with-usbids-dir=DIR],
diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
index a6097be..847aa40 100644
--- a/tools/usb/usbip/doc/usbip.8
+++ b/tools/usb/usbip/doc/usbip.8
@@ -27,6 +27,10 @@ Log to syslog.
 \fB\-\-tcp-port PORT\fR
 .IP
 Connect to PORT on remote host (used for attach and list --remote).
+
+\fB\-\-auth\fR
+.IP
+Set the password to be used for client authentication. See usbipd(8) for more information.
 .PP
 
 .SH COMMANDS
diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8
index ac4635d..8beb95a 100644
--- a/tools/usb/usbip/doc/usbipd.8
+++ b/tools/usb/usbip/doc/usbipd.8
@@ -52,6 +52,11 @@ If no FILE specified, use /var/run/usbipd.pid
 \fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR
 .IP
 Listen on TCP/IP port PORT.
+
+.HP
+\fB\-s\fR, \fB\-\-auth\fR
+.IP
+Sets the password to be used for client authentication. If -a is used, the server will only accept connections from authenticated clients. Note: USB traffic will still be unencrypted, this currently only serves for authentication.
 .PP
 
 \fB\-h\fR, \fB\-\-help\fR
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
index d7599d9..cd7e420 100644
--- a/tools/usb/usbip/src/usbip.c
+++ b/tools/usb/usbip/src/usbip.c
@@ -25,6 +25,12 @@
 #include <getopt.h>
 #include <syslog.h>
 
+#include "../config.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
 #include "usbip_common.h"
 #include "usbip_network.h"
 #include "usbip.h"
@@ -35,8 +41,12 @@ static int usbip_version(int argc, char *argv[]);
 static const char usbip_version_string[] = PACKAGE_STRING;
 
 static const char usbip_usage_string[] =
-	"usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
-	"             [help] <command> <args>\n";
+	"usbip "
+#ifdef HAVE_GNUTLS
+	"[--auth PASSWORD] "
+#endif
+	"[--debug] [--log] [--tcp-port PORT]\n"
+	"             [version] [help] <command> <args>\n";
 
 static void usbip_usage(void)
 {
@@ -148,6 +158,7 @@ int main(int argc, char *argv[])
 		{ "debug",    no_argument,       NULL, 'd' },
 		{ "log",      no_argument,       NULL, 'l' },
 		{ "tcp-port", required_argument, NULL, 't' },
+		{ "auth",     required_argument, NULL, 's' },
 		{ NULL,       0,                 NULL,  0  }
 	};
 
@@ -158,12 +169,25 @@ int main(int argc, char *argv[])
 	usbip_use_stderr = 1;
 	opterr = 0;
 	for (;;) {
-		opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
+		opt = getopt_long(argc, argv, "+dls:t:", opts, NULL);
 
 		if (opt == -1)
 			break;
 
 		switch (opt) {
+		case 's':
+#ifdef HAVE_GNUTLS
+			usbip_srp_password = optarg;
+			rc = gnutls_global_init();
+			if (rc < 0) {
+				err("Unable to initialize GnuTLS library: %s",
+				    gnutls_strerror(rc));
+				return EXIT_FAILURE;
+			}
+#else
+			err("usbip has been compiled without GnuTLS support");
+#endif
+			break;
 		case 'd':
 			usbip_use_debug = 1;
 			break;
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index d58a14d..4421ebc 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -175,7 +175,7 @@ static int attach_device(char *host, char *busid)
 	int rc;
 	int rhport;
 
-	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+	sockfd = usbip_net_connect(host);
 	if (sockfd < 0) {
 		err("tcp connect");
 		return -1;
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
index d5ce34a..6042b7e 100644
--- a/tools/usb/usbip/src/usbip_list.c
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -132,7 +132,7 @@ static int list_exported_devices(char *host)
 	int rc;
 	int sockfd;
 
-	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+	sockfd = usbip_net_connect(host);
 	if (sockfd < 0) {
 		err("could not connect to %s:%s: %s", host,
 		    usbip_port_string, gai_strerror(sockfd));
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
index b4c37e7..6b8f949 100644
--- a/tools/usb/usbip/src/usbip_network.c
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -29,11 +29,20 @@
 #include <tcpd.h>
 #endif
 
+#include "../config.h"
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#endif
+
 #include "usbip_common.h"
 #include "usbip_network.h"
 
 int usbip_port = 3240;
 char *usbip_port_string = "3240";
+#ifdef HAVE_GNUTLS
+char *usbip_srp_password;
+#endif
 
 void usbip_setup_port_number(char *arg)
 {
@@ -301,3 +310,179 @@ int usbip_net_tcp_connect(char *hostname, char *service)
 
 	return sockfd;
 }
+
+#ifdef HAVE_GNUTLS
+static gnutls_datum_t usbip_net_srp_salt, usbip_net_srp_verifier;
+static gnutls_srp_server_credentials_t usbip_net_srp_cred;
+
+#define SRP_GROUP gnutls_srp_2048_group_generator
+#define SRP_PRIME gnutls_srp_2048_group_prime
+
+int usbip_net_srp_client_handshake(int sockfd)
+{
+	int ret;
+	gnutls_session_t session;
+	gnutls_srp_client_credentials_t usbip_net_srp_cred;
+
+	ret = gnutls_srp_allocate_client_credentials(&usbip_net_srp_cred);
+	if (ret < 0)
+		return ret;
+
+	gnutls_srp_set_client_credentials(usbip_net_srp_cred, "dummyuser",
+		usbip_srp_password);
+
+	ret = gnutls_init(&session, GNUTLS_CLIENT);
+	if (ret < 0) {
+		gnutls_srp_free_client_credentials(usbip_net_srp_cred);
+		return ret;
+	}
+
+	gnutls_priority_set_direct(session, "NORMAL:+SRP", NULL);
+
+	gnutls_credentials_set(session, GNUTLS_CRD_SRP, usbip_net_srp_cred);
+	gnutls_transport_set_int (session, sockfd);
+
+	do {
+		ret = gnutls_handshake(session);
+	} while (ret < 0 && !gnutls_error_is_fatal(ret));
+
+	gnutls_bye(session, GNUTLS_SHUT_RDWR);
+
+	gnutls_deinit(session);
+	gnutls_srp_free_client_credentials(usbip_net_srp_cred);
+
+	return ret;
+}
+
+int net_srp_server_handshake(int connfd)
+{
+	int ret;
+	gnutls_session_t session;
+
+	if (gnutls_init(&session, GNUTLS_SERVER) != 0)
+		return -1;
+	gnutls_priority_set_direct(session, "NORMAL:-KX-ALL:+SRP", NULL);
+	ret = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
+				     usbip_net_srp_cred);
+	if (!ret)
+		return -1;
+
+	gnutls_transport_set_int(session, connfd);
+
+	do {
+		ret = gnutls_handshake(session);
+	} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
+
+	if (ret < 0)
+		err("GnuTLS handshake failed (%s)", gnutls_strerror(ret));
+	else
+		info("GnuTLS handshake completed");
+
+	if (gnutls_bye(session, GNUTLS_SHUT_RDWR) != 0)
+		err("Unable to shutdown TLS connection.");
+	gnutls_deinit(session);
+
+	return ret;
+}
+
+static int net_srp_callback(gnutls_session_t sess, const char *username,
+	gnutls_datum_t *nsalt, gnutls_datum_t *nverifier, gnutls_datum_t *g,
+	gnutls_datum_t *n)
+{
+	/*
+	 * GnuTLS expects us to allocate all data returned from callbacks
+	 * using gnutls_malloc(), thus, we have to create a fresh copy of
+	 * our static credentials for every connection.
+	 */
+	nsalt->data = gnutls_malloc(usbip_net_srp_salt.size);
+	nverifier->data = gnutls_malloc(usbip_net_srp_verifier.size);
+	if (nsalt->data == NULL || nverifier->data == NULL) {
+		gnutls_free(nsalt->data);
+		gnutls_free(nverifier->data);
+		return -1;
+	}
+	nsalt->size = usbip_net_srp_salt.size;
+	nverifier->size = usbip_net_srp_verifier.size;
+	memcpy(nverifier->data, usbip_net_srp_verifier.data,
+	       usbip_net_srp_verifier.size);
+	memcpy(nsalt->data, usbip_net_srp_salt.data, usbip_net_srp_salt.size);
+
+	*g = SRP_GROUP;
+	*n = SRP_PRIME;
+
+	/* We only have a single session, thus, ignore it */
+	(void) sess;
+
+	if (strcmp(username, "dummyuser"))
+		/* User invalid, stored dummy data in g and n. */
+		return 1;
+
+	return 0;
+}
+
+int usbip_net_init_gnutls(void)
+{
+	int ret;
+
+	gnutls_global_init();
+
+	usbip_net_srp_salt.data = gnutls_malloc(16);
+	if (!usbip_net_srp_salt.data)
+		return GNUTLS_E_MEMORY_ERROR;
+
+	ret = gnutls_rnd(GNUTLS_RND_NONCE, usbip_net_srp_salt.data, 16);
+	if (ret < 0)
+		return ret;
+	usbip_net_srp_salt.size = 16;
+
+	ret = gnutls_srp_allocate_server_credentials(&usbip_net_srp_cred);
+	if (ret < 0)
+		return ret;
+
+	ret = gnutls_srp_verifier("dummyuser", optarg, &usbip_net_srp_salt,
+				  &SRP_GROUP, &SRP_PRIME,
+				  &usbip_net_srp_verifier);
+	if (ret < 0)
+		return ret;
+
+	gnutls_srp_set_server_credentials_function(usbip_net_srp_cred,
+						   net_srp_callback);
+
+	return GNUTLS_E_SUCCESS;
+}
+#endif
+
+/*
+ * Connect to the server. Performs the TCP connection attempt
+ * and - if necessary - the TLS handshake used for authentication.
+ */
+int usbip_net_connect(char *hostname)
+{
+	int sockfd;
+
+	sockfd = usbip_net_tcp_connect(hostname, usbip_port_string);
+	if (sockfd < 0)
+		return sockfd;
+
+#ifdef HAVE_GNUTLS
+	if (usbip_srp_password) {
+		int rc;
+
+		rc = usbip_net_send_op_common(sockfd, OP_REQ_STARTTLS, 0);
+		if (rc < 0) {
+			err("usbip_net_send_op_common failed");
+			return EAI_SYSTEM;
+		}
+
+		rc = usbip_net_srp_client_handshake(sockfd);
+		if (rc < 0) {
+			err("Unable to perform TLS handshake (wrong password?): %s",
+			    gnutls_strerror(rc));
+			close(sockfd);
+			return EAI_SYSTEM;
+		}
+	}
+#endif
+
+	return sockfd;
+}
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
index c1e875c..292d584 100644
--- a/tools/usb/usbip/src/usbip_network.h
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -15,6 +15,7 @@
 
 extern int usbip_port;
 extern char *usbip_port_string;
+extern char *usbip_srp_password;
 void usbip_setup_port_number(char *arg);
 
 /* ---------------------------------------------------------------------- */
@@ -167,6 +168,12 @@ struct op_devlist_reply_extra {
 	usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
 } while (0)
 
+/* ---------------------------------------------------------------------- */
+/* Initiate encrypted connection. */
+#define OP_STARTTLS 0x06
+#define OP_REQ_STARTTLS   (OP_REQUEST | OP_STARTTLS)
+#define OP_REP_STARTTLS   (OP_REPLY   | OP_STARTTLS)
+
 void usbip_net_pack_uint32_t(int pack, uint32_t *num);
 void usbip_net_pack_uint16_t(int pack, uint16_t *num);
 void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
@@ -180,6 +187,8 @@ int usbip_net_set_reuseaddr(int sockfd);
 int usbip_net_set_nodelay(int sockfd);
 int usbip_net_set_keepalive(int sockfd);
 int usbip_net_set_v6only(int sockfd);
-int usbip_net_tcp_connect(char *hostname, char *port);
+int usbip_net_connect(char *hostname);
+int net_srp_server_handshake(int connfd);
+int usbip_net_init_gnutls(void);
 
 #endif /* __USBIP_NETWORK_H */
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index 2f87f2d..23c15d7 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -36,6 +36,11 @@
 #include <tcpd.h>
 #endif
 
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#endif
+
 #include <getopt.h>
 #include <signal.h>
 #include <poll.h>
@@ -64,6 +69,11 @@ static const char usbipd_help_string[] =
 	"	-6, --ipv6\n"
 	"		Bind to IPv6. Default is both.\n"
 	"\n"
+#ifdef HAVE_GNUTLS
+	"	-sPASSWORD, --auth PASSWORD\n"
+	"		Set PASSWORD as key used for authentication.\n"
+	"\n"
+#endif
 	"	-D, --daemon\n"
 	"		Run as a daemon process.\n"
 	"\n"
@@ -83,6 +93,8 @@ static const char usbipd_help_string[] =
 	"	-v, --version\n"
 	"		Show version.\n";
 
+static int need_auth;
+
 static void usbipd_help(void)
 {
 	printf("%s\n", usbipd_help_string);
@@ -239,14 +251,7 @@ static int recv_request_devlist(int connfd)
 
 static int recv_pdu(int connfd)
 {
-	uint16_t code = OP_UNSPEC;
-	int ret;
-
-	ret = usbip_net_recv_op_common(connfd, &code);
-	if (ret < 0) {
-		dbg("could not receive opcode: %#0x", code);
-		return -1;
-	}
+	int auth = !need_auth, cont = 1, ret;
 
 	ret = usbip_host_refresh_device_list();
 	if (ret < 0) {
@@ -254,25 +259,63 @@ static int recv_pdu(int connfd)
 		return -1;
 	}
 
-	info("received request: %#0x(%d)", code, connfd);
-	switch (code) {
-	case OP_REQ_DEVLIST:
-		ret = recv_request_devlist(connfd);
-		break;
-	case OP_REQ_IMPORT:
-		ret = recv_request_import(connfd);
-		break;
-	case OP_REQ_DEVINFO:
-	case OP_REQ_CRYPKEY:
-	default:
-		err("received an unknown opcode: %#0x", code);
-		ret = -1;
-	}
+	/*
+	 * Process opcodes. We might receive more than one, as the
+	 * client might send STARTTLS first
+	 */
+	while (cont) {
+		uint16_t code = OP_UNSPEC;
 
-	if (ret == 0)
-		info("request %#0x(%d): complete", code, connfd);
-	else
-		info("request %#0x(%d): failed", code, connfd);
+		ret = usbip_net_recv_op_common(connfd, &code);
+		if (ret < 0) {
+			dbg("could not receive opcode: %#0x", code);
+			return -1;
+		}
+
+		info("received request: %#0x(%d)", code, connfd);
+
+		/* We require an authenticated encryption */
+		if (!auth && code != OP_REQ_STARTTLS) {
+			usbip_net_send_op_common(connfd, OP_REPLY, ST_NA);
+			return -1;
+		}
+
+		switch (code) {
+#ifdef HAVE_GNUTLS
+		case OP_REQ_STARTTLS:
+			if (!need_auth) {
+				ret = -1;
+				err("Unexpected TLS handshake attempt (client uses password, server doesn't)");
+			} else {
+				ret = net_srp_server_handshake(connfd);
+				if (ret != 0)
+					err("TLS handshake failed");
+				auth = 1;
+			}
+			break;
+#endif
+		case OP_REQ_DEVLIST:
+			ret = recv_request_devlist(connfd);
+			cont = 0;
+			break;
+		case OP_REQ_IMPORT:
+			ret = recv_request_import(connfd);
+			cont = 0;
+			break;
+		case OP_REQ_DEVINFO:
+		case OP_REQ_CRYPKEY:
+		default:
+			err("received an unknown opcode: %#0x", code);
+			ret = -1;
+		}
+
+		if (ret == 0)
+			info("request %#0x(%d): complete", code, connfd);
+		else {
+			info("request %#0x(%d): failed", code, connfd);
+			break;
+		}
+	}
 
 	return ret;
 }
@@ -593,6 +636,7 @@ int main(int argc, char *argv[])
 		{ "tcp-port", required_argument, NULL, 't' },
 		{ "help",     no_argument,       NULL, 'h' },
 		{ "version",  no_argument,       NULL, 'v' },
+		{ "auth",     required_argument, NULL, 's' },
 		{ NULL,	      0,                 NULL,  0  }
 	};
 
@@ -605,6 +649,9 @@ int main(int argc, char *argv[])
 	int daemonize = 0;
 	int ipv4 = 0, ipv6 = 0;
 	int opt, rc = -1;
+#ifdef HAVE_GNUTLS
+	int ret;
+#endif
 
 	pid_file = NULL;
 
@@ -616,7 +663,7 @@ int main(int argc, char *argv[])
 
 	cmd = cmd_standalone_mode;
 	for (;;) {
-		opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
+		opt = getopt_long(argc, argv, "46s:DdP::t:hv", longopts, NULL);
 
 		if (opt == -1)
 			break;
@@ -628,6 +675,20 @@ int main(int argc, char *argv[])
 		case '6':
 			ipv6 = 1;
 			break;
+		case 's':
+#ifdef HAVE_GNUTLS
+			need_auth = 1;
+			ret = usbip_net_init_gnutls();
+			if (ret < 0) {
+				err("Unable to initialize GnuTLS: %s",
+				    gnutls_strerror(ret));
+				return EXIT_FAILURE;
+			}
+			break;
+#else
+			err("usbipd has been compiled without GnuTLS support");
+			break;
+#endif
 		case 'D':
 			daemonize = 1;
 			break;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 03/18] usbip: Add kernel support for client ACLs
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 01/18] usbip: sysfs_utils: add read_sysfs_attribute Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 02/18] usbip: Add support for client authentication Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-21  0:44   ` Max Vozeler
  2014-09-16 23:38 ` [PATCH 04/18] usbip: Add CIDR matching helper functions Maximilian Eschenbacher
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Kurt Kanzenbach, Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This patch adds the possibility to stored ACLs for allowed clients for
each stub device in sysfs. It adds a new sysfs entry called "usbip_acl"
for each stub device, containing a list of CIDR masks of allowed
clients. This file will be used by usbip and usbipd to store the ACL.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Kurt Kanzenbach <ly80toro@cip.cs.fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 drivers/usb/usbip/stub.h     |  5 ++++
 drivers/usb/usbip/stub_dev.c | 60 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/usbip/stub.h b/drivers/usb/usbip/stub.h
index 266e2b0..b2d3d55 100644
--- a/drivers/usb/usbip/stub.h
+++ b/drivers/usb/usbip/stub.h
@@ -60,6 +60,11 @@ struct stub_device {
 	struct list_head unlink_free;
 
 	wait_queue_head_t tx_waitq;
+
+	/* list of allowed IP addrs */
+	char *acls;
+	/* for locking list operations */
+	spinlock_t ip_lock;
 };
 
 /* private data into urb->priv */
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index fac20e0..e6624f1 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -119,6 +119,55 @@ err:
 }
 static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
 
+/*
+ * This function replaces the current ACL list
+ */
+static ssize_t store_acl(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct stub_device *sdev = dev_get_drvdata(dev);
+	int retval;
+
+	if (count >= PAGE_SIZE)
+		return -EINVAL;
+
+	spin_lock_irq(&sdev->ip_lock);
+	kfree(sdev->acls);
+	sdev->acls = kstrdup(buf, GFP_KERNEL);
+	if (!sdev->acls)
+		retval = -ENOMEM;
+	else
+		retval = strlen(sdev->acls);
+	spin_unlock_irq(&sdev->ip_lock);
+
+	return retval;
+}
+
+/*
+ * This functions prints all allowed IP addrs for this dev
+ */
+static ssize_t show_acl(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct stub_device *sdev = dev_get_drvdata(dev);
+	int retval = 0;
+
+	if (!sdev)
+		return -ENODEV;
+
+	spin_lock_irq(&sdev->ip_lock);
+	if (sdev->acls == NULL) {
+		retval = 0;
+	} else {
+		strcpy(buf, sdev->acls);
+		retval = strlen(buf);
+	}
+	spin_unlock_irq(&sdev->ip_lock);
+
+	return retval;
+}
+static DEVICE_ATTR(usbip_acl, S_IWUSR | S_IRUGO, show_acl, store_acl);
+
 static int stub_add_files(struct device *dev)
 {
 	int err = 0;
@@ -134,9 +183,13 @@ static int stub_add_files(struct device *dev)
 	err = device_create_file(dev, &dev_attr_usbip_debug);
 	if (err)
 		goto err_debug;
+	err = device_create_file(dev, &dev_attr_usbip_acl);
+	if (err)
+		goto err_ip;
 
 	return 0;
-
+err_ip:
+	device_remove_file(dev, &dev_attr_usbip_debug);
 err_debug:
 	device_remove_file(dev, &dev_attr_usbip_sockfd);
 err_sockfd:
@@ -150,6 +203,7 @@ static void stub_remove_files(struct device *dev)
 	device_remove_file(dev, &dev_attr_usbip_status);
 	device_remove_file(dev, &dev_attr_usbip_sockfd);
 	device_remove_file(dev, &dev_attr_usbip_debug);
+	device_remove_file(dev, &dev_attr_usbip_acl);
 }
 
 static void stub_shutdown_connection(struct usbip_device *ud)
@@ -287,6 +341,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev)
 	INIT_LIST_HEAD(&sdev->priv_free);
 	INIT_LIST_HEAD(&sdev->unlink_free);
 	INIT_LIST_HEAD(&sdev->unlink_tx);
+	spin_lock_init(&sdev->ip_lock);
 	spin_lock_init(&sdev->priv_lock);
 
 	init_waitqueue_head(&sdev->tx_waitq);
@@ -453,6 +508,9 @@ static void stub_disconnect(struct usb_device *udev)
 
 	usb_put_dev(sdev->udev);
 
+	/* free ACL list */
+	kfree(sdev->acls);
+
 	/* free sdev */
 	busid_priv->sdev = NULL;
 	stub_device_free(sdev);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 04/18] usbip: Add CIDR matching helper functions
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (2 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 03/18] usbip: Add kernel support for client ACLs Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 05/18] usbip: Add ACL support to usbip bind Maximilian Eschenbacher
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This patch adds a few utility functions to match IP addresses against
CIDR masks.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/src/utils.c | 88 +++++++++++++++++++++++++++++++++++++++++++++
 tools/usb/usbip/src/utils.h | 15 ++++++++
 2 files changed, 103 insertions(+)

diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c
index 2b3d6d2..8dae7aa 100644
--- a/tools/usb/usbip/src/utils.c
+++ b/tools/usb/usbip/src/utils.c
@@ -50,3 +50,91 @@ int modify_match_busid(char *busid, int add)
 
 	return 0;
 }
+
+/*
+ * Parses a string of form "ip/prefix" into a subnet mask to dest.
+ * Returns -1 on error, 0 on success
+ */
+int parse_cidr(const char *src, struct subnet *dest)
+{
+	char *ip, *prefix, *saveptr;
+	char *endptr;
+	struct in6_addr ip6;
+	struct in_addr ip4;
+	int bits;
+	long int tmp;
+	char buf[128]; /* For strtok */
+
+	strncpy(buf, src, sizeof(buf));
+	buf[sizeof(buf)-1] = 0;
+
+	ip = strtok_r(buf, "/", &saveptr);
+	prefix = strtok_r(NULL, "/", &saveptr);
+	if (strtok_r(NULL, "/", &saveptr) || !ip ||
+		     strlen(src) > sizeof(buf) - 1)
+		return -1;
+
+	if (inet_pton(AF_INET6, ip, &ip6) == 1) {
+		dest->ai_family = AF_INET6;
+		bits = 128;
+		dest->address.ip6 = ip6;
+	} else if (inet_pton(AF_INET, ip, &ip4) == 1) {
+		dest->ai_family = AF_INET;
+		bits = 32;
+		dest->address.ip4 = ip4;
+	} else {
+		return -1;
+	}
+
+	/*
+	 * We also accept single IPs without an explicitely
+	 * specified prefix
+	 */
+	if (prefix) {
+		tmp = strtol(prefix, &endptr, 10);
+		if (tmp < 0 || tmp > bits || *endptr != '\0')
+			return -1;
+		dest->prefix = tmp;
+	} else {
+		dest->prefix = bits;
+	}
+
+	return 0;
+}
+
+/*
+ * Checks if addr is in range. Expects addr to be a struct in6_addr* if
+ * ai_family == AF_INET6, else struct in_addr*.
+ * Returns 1 if in range, 0 otherwise.
+ */
+int in_range(struct sockaddr_storage *addr, struct subnet range)
+{
+	if (addr->ss_family != range.ai_family)
+		return 0;
+	if (addr->ss_family == AF_INET6) {
+		int i;
+		struct sockaddr_in6 *in6addr = (struct sockaddr_in6 *) addr;
+		unsigned char *ip = in6addr->sin6_addr.s6_addr;
+
+		for (i = 0; i < range.prefix; ++i) {
+			int idx = i/8, mask = 1 << (7 - i%8);
+
+			if ((ip[idx] & mask) != (range.address.ip6.s6_addr[idx]
+			     & mask))
+				return 0;
+		}
+	} else {
+		int i;
+		struct sockaddr_in *inaddr = (struct sockaddr_in *) addr;
+		uint32_t ip = ntohl(inaddr->sin_addr.s_addr);
+		uint32_t comp = ntohl(range.address.ip4.s_addr);
+
+		for (i = 0; i < range.prefix; ++i) {
+			int mask = 1 << (31-i);
+
+			if ((ip & mask) != (comp & mask))
+				return 0;
+		}
+	}
+	return 1;
+}
diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h
index 5916fd3..a3704ef 100644
--- a/tools/usb/usbip/src/utils.h
+++ b/tools/usb/usbip/src/utils.h
@@ -19,7 +19,22 @@
 #ifndef __UTILS_H
 #define __UTILS_H
 
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/ip.h>
+
+struct subnet {
+	int ai_family;
+	int prefix;
+	union {
+		struct in6_addr ip6;
+		struct in_addr ip4;
+	} address;
+};
+
 int modify_match_busid(char *busid, int add);
+int parse_cidr(const char *src, struct subnet *dest);
+int in_range(struct sockaddr_storage *addr, struct subnet range);
 
 #endif /* __UTILS_H */
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 05/18] usbip: Add ACL support to usbip bind
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (3 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 04/18] usbip: Add CIDR matching helper functions Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 06/18] usbip: Add support for ACLs in usbipd Maximilian Eschenbacher
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Maximilian Eschenbacher,
	Fjodor Schelichow, Johannes Stadlinger, Kurt Kanzenbach,
	Dominik Paulus, Tobias Polzer

Add the command line argument -a (--allow) to usbip bind to specify
networks allowed to attach to the device and code to store the ACLs in
sysfs.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Kurt Kanzenbach <ly80toro@cip.cs.fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/doc/usbip.8      |  8 +++++-
 tools/usb/usbip/src/usbip_bind.c | 62 ++++++++++++++++++++++++++++++++--------
 2 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
index 847aa40..c7ba36f 100644
--- a/tools/usb/usbip/doc/usbip.8
+++ b/tools/usb/usbip/doc/usbip.8
@@ -60,9 +60,15 @@ Detach an imported USB device.
 .PP
 
 .HP
-\fBbind\fR \-\-busid=<\fIbusid\fR>
+\fBbind\fR \-\-busid=<\fIbusid\fR> [\-\-allow=<\fICIDR mask\fR>...]
 .IP
 Make a device exportable.
+.br
+\-\-allow accepts CIDR masks like 127.0.0.0/8 or fd00::/64
+.br
+Only hosts in (at least) one of the allowed ranges are accepted. If
+\-\-allow is omitted, 0.0.0.0/0 and ::/0 are added to the list. The list can
+be read/written from corresponding \fBusbip_acl\fR file in sysfs after bind.
 .PP
 
 .HP
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
index fa46141..b888ea3 100644
--- a/tools/usb/usbip/src/usbip_bind.c
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -38,8 +38,9 @@ enum unbind_status {
 
 static const char usbip_bind_usage_string[] =
 	"usbip bind <args>\n"
-	"    -b, --busid=<busid>    Bind " USBIP_HOST_DRV_NAME ".ko to device "
-	"on <busid>\n";
+	"    -b, --busid=<busid>        Bind " USBIP_HOST_DRV_NAME ".ko to "
+	"device on <busid>\n"
+	"    -a, --allow=<CIDR mask>    Restrict device access to <CIDR mask>\n";
 
 void usbip_bind_usage(void)
 {
@@ -47,10 +48,11 @@ void usbip_bind_usage(void)
 }
 
 /* call at unbound state */
-static int bind_usbip(char *busid)
+static int bind_usbip(char *busid, char *allow)
 {
 	char attr_name[] = "bind";
 	char bind_attr_path[SYSFS_PATH_MAX];
+	char ip_attr_path[SYSFS_PATH_MAX];
 	int rc = -1;
 
 	snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
@@ -64,6 +66,19 @@ static int bind_usbip(char *busid)
 		return -1;
 	}
 
+	/*
+	 * store allowed IP ranges
+	 * specified by `usbip bind -b <busid> --allow <CIDR mask>`
+	 */
+	snprintf(ip_attr_path, sizeof(ip_attr_path), "%s/%s/%s/%s/%s/%s/%s",
+		 SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
+		 SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, busid, "usbip_acl");
+	rc = write_sysfs_attribute(ip_attr_path, allow, strlen(allow));
+	if (rc < 0) {
+		err("error writing cidr mask %s", allow);
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -139,7 +154,7 @@ out:
 	return status;
 }
 
-static int bind_device(char *busid)
+static int bind_device(char *busid, char *allow)
 {
 	int rc;
 	struct udev *udev;
@@ -170,7 +185,7 @@ static int bind_device(char *busid)
 		return -1;
 	}
 
-	rc = bind_usbip(busid);
+	rc = bind_usbip(busid, allow);
 	if (rc < 0) {
 		err("could not bind device to %s", USBIP_HOST_DRV_NAME);
 		modify_match_busid(busid, 0);
@@ -186,29 +201,52 @@ int usbip_bind(int argc, char *argv[])
 {
 	static const struct option opts[] = {
 		{ "busid", required_argument, NULL, 'b' },
+		{ "allow", optional_argument, NULL, 'a' },
 		{ NULL,    0,                 NULL,  0  }
 	};
 
-	int opt;
-	int ret = -1;
+	int opt, rc;
+	char allow[4096];
+	char *device = NULL;
+	struct subnet subnet;
+
+	allow[0] = 0;
 
 	for (;;) {
-		opt = getopt_long(argc, argv, "b:", opts, NULL);
+		opt = getopt_long(argc, argv, "a:b:", opts, NULL);
 
 		if (opt == -1)
 			break;
 
 		switch (opt) {
+		case 'a':
+			rc = parse_cidr(optarg, &subnet);
+			if (rc < 0) {
+				err("Invalid subnet specified: %s", optarg);
+				goto err_out;
+			}
+
+			if (strlen(allow) < sizeof(allow) - strlen(optarg) - 2)
+				sprintf(allow + strlen(allow), "%s\n", optarg);
+			else
+				err("ACL length too long.");
+			break;
 		case 'b':
-			ret = bind_device(optarg);
-			goto out;
+			device = optarg;
+			break;
 		default:
 			goto err_out;
 		}
 	}
 
+	/* By default, allow access from all IPs */
+	if (!allow[0])
+		strcpy(allow, "::/0\n0.0.0.0/0\n");
+
+	if (device)
+		return bind_device(device, allow);
+
 err_out:
 	usbip_bind_usage();
-out:
-	return ret;
+	return -1;
 }
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 06/18] usbip: Add support for ACLs in usbipd
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (4 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 05/18] usbip: Add ACL support to usbip bind Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 07/18] usbip: Add proper error reporting Maximilian Eschenbacher
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Kurt Kanzenbach, Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

Interpret the ACLs stored in sysfs in usbipd and reject clients not
matching one of the ACLs.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Kurt Kanzenbach <ly80toro@cip.cs.fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/libsrc/usbip_common.h |  1 +
 tools/usb/usbip/src/Makefile.am       |  2 +-
 tools/usb/usbip/src/usbip_bind.c      |  2 +-
 tools/usb/usbip/src/usbipd.c          | 73 +++++++++++++++++++++++++++++++++++
 4 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h
index 15fe792..824d5a5 100644
--- a/tools/usb/usbip/libsrc/usbip_common.h
+++ b/tools/usb/usbip/libsrc/usbip_common.h
@@ -38,6 +38,7 @@
 
 #define SYSFS_PATH_MAX		256
 #define SYSFS_BUS_ID_SIZE	32
+#define SYSFS_IP_ACLS_MAX	4096
 
 extern int usbip_use_syslog;
 extern int usbip_use_stderr;
diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
index e81a4eb..c100273 100644
--- a/tools/usb/usbip/src/Makefile.am
+++ b/tools/usb/usbip/src/Makefile.am
@@ -8,4 +8,4 @@ usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
 		 usbip_attach.c usbip_detach.c usbip_list.c \
 		 usbip_bind.c usbip_unbind.c usbip_port.c
 
-usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
+usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c utils.c
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
index b888ea3..3f8c7a3 100644
--- a/tools/usb/usbip/src/usbip_bind.c
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -206,7 +206,7 @@ int usbip_bind(int argc, char *argv[])
 	};
 
 	int opt, rc;
-	char allow[4096];
+	char allow[SYSFS_IP_ACLS_MAX];
 	char *device = NULL;
 	struct subnet subnet;
 
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index 23c15d7..7c0a46d 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -49,6 +49,8 @@
 #include "usbip_common.h"
 #include "usbip_network.h"
 #include "list.h"
+#include "utils.h"
+#include "sysfs_utils.h"
 
 #undef  PROGNAME
 #define PROGNAME "usbipd"
@@ -100,6 +102,61 @@ static void usbipd_help(void)
 	printf("%s\n", usbipd_help_string);
 }
 
+/*
+ * Checks whether client IP matches at least one
+ * ACL entry
+ *
+ * Returns:
+ *		1  if matches
+ *		0  if not
+ *		-1 on error
+ */
+static int check_allowed(char *acls, int sockfd)
+{
+	int rc, match;
+	struct sockaddr_storage sa;
+	char *acl_cpy, *iter, *saveptr;
+	socklen_t sa_len = sizeof(sa);
+
+	rc = getpeername(sockfd, (struct sockaddr *) &sa, &sa_len);
+	if (rc || sa_len > sizeof(sa)) {
+		err("getpeername failed: %s", strerror(errno));
+		return -1;
+	}
+
+	/*
+	 * We are going to modify our argument,
+	 * thus, we need to duplicate it.
+	 */
+	acl_cpy = strdup(acls);
+	if (!acl_cpy) {
+		err("strdup(): %s", strerror(errno));
+		return -1;
+	}
+
+	match = 0;
+	iter = strtok_r(acl_cpy, "\n", &saveptr);
+	/*
+	 * Iterate over ACL entries and check for
+	 * matching one.
+	 */
+	while (iter) {
+		struct subnet net;
+
+		if (parse_cidr(iter, &net) < 0) {
+			dbg("parse_cidr() failed");
+		} else if (in_range(&sa, net)) {
+			match = 1;
+			break;
+		}
+
+		iter = strtok_r(NULL, "\n", &saveptr);
+	}
+
+	free(acl_cpy);
+	return match;
+}
+
 static int recv_request_import(int sockfd)
 {
 	struct op_import_request req;
@@ -107,6 +164,8 @@ static int recv_request_import(int sockfd)
 	struct usbip_exported_device *edev;
 	struct usbip_usb_device pdu_udev;
 	struct list_head *i;
+	char sysfs_attr[SYSFS_IP_ACLS_MAX];
+	char ip_attr_path[SYSFS_PATH_MAX];
 	int found = 0;
 	int error = 0;
 	int rc;
@@ -138,6 +197,20 @@ static int recv_request_import(int sockfd)
 		rc = usbip_host_export_device(edev, sockfd);
 		if (rc < 0)
 			error = 1;
+
+		/* check for allowed IPs */
+		snprintf(ip_attr_path, sizeof(ip_attr_path), "%s/%s",
+			 edev->udev.path, "usbip_acl");
+
+		rc = read_sysfs_attribute(ip_attr_path, sysfs_attr,
+					   sizeof(sysfs_attr));
+		if (rc == -1)
+			err("failed to get ip list");
+		else if (check_allowed(sysfs_attr, conn->sockfd) != 1) {
+			info("Access denied to device %s",
+			     edev->udev.busid);
+			error = ERR_PERM;
+		}
 	} else {
 		info("requested device not found: %s", req.busid);
 		error = 1;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 07/18] usbip: Add proper error reporting
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (5 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 06/18] usbip: Add support for ACLs in usbipd Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 08/18] usbip: Handle usbip being started as user Maximilian Eschenbacher
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This patch adds new error codes and features extended error reporting in
op_common packets.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/src/usbip_attach.c  |  4 +--
 tools/usb/usbip/src/usbip_list.c    |  3 ++-
 tools/usb/usbip/src/usbip_network.c | 51 ++++++++++++++++++++++++++++---------
 tools/usb/usbip/src/usbip_network.h | 17 +++++++++++--
 tools/usb/usbip/src/usbipd.c        | 25 ++++++++++--------
 5 files changed, 73 insertions(+), 27 deletions(-)

diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index 4421ebc..51c67a2 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -147,7 +147,7 @@ static int query_import_device(int sockfd, char *busid)
 	/* receive a reply */
 	rc = usbip_net_recv_op_common(sockfd, &code);
 	if (rc < 0) {
-		err("recv op_common");
+		err("recv op_common: %s", usbip_net_strerror(rc));
 		return -1;
 	}
 
@@ -177,7 +177,7 @@ static int attach_device(char *host, char *busid)
 
 	sockfd = usbip_net_connect(host);
 	if (sockfd < 0) {
-		err("tcp connect");
+		err("connection attempt failed");
 		return -1;
 	}
 
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
index 6042b7e..c122f41 100644
--- a/tools/usb/usbip/src/usbip_list.c
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -64,7 +64,8 @@ static int get_exported_devices(char *host, int sockfd)
 
 	rc = usbip_net_recv_op_common(sockfd, &code);
 	if (rc < 0) {
-		dbg("usbip_net_recv_op_common failed");
+		err("usbip_net_recv_op_common failed: %s",
+		    usbip_net_strerror(rc));
 		return -1;
 	}
 
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
index 6b8f949..f68741d 100644
--- a/tools/usb/usbip/src/usbip_network.c
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -182,7 +182,7 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code)
 	rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
 	if (rc < 0) {
 		dbg("usbip_net_recv failed: %d", rc);
-		goto err;
+		return -ERR_SYSERR;
 	}
 
 	PACK_OP_COMMON(0, &op_common);
@@ -190,30 +190,49 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code)
 	if (op_common.version != USBIP_VERSION) {
 		dbg("version mismatch: %d %d", op_common.version,
 		    USBIP_VERSION);
-		goto err;
+		return -ERR_MISMATCH;
 	}
 
 	switch (*code) {
 	case OP_UNSPEC:
 		break;
 	default:
-		if (op_common.code != *code) {
+		/*
+		 * Only accept expected opcode. Exception: OP_REPLY
+		 * flag set may be sent as a reply to all requests,
+		 * if only used for status reporting.
+		 */
+		if (op_common.code != *code && op_common.code != OP_REPLY) {
 			dbg("unexpected pdu %#0x for %#0x", op_common.code,
 			    *code);
-			goto err;
+			return -ERR_UNEXPECTED;
 		}
 	}
 
-	if (op_common.status != ST_OK) {
-		dbg("request failed at peer: %d", op_common.status);
-		goto err;
-	}
-
 	*code = op_common.code;
 
-	return 0;
-err:
-	return -1;
+	return -op_common.status;
+}
+
+const char *usbip_net_strerror(int status)
+{
+	static const char *const errs[] = {
+		/* ERR_OK */ "Success",
+		/* ERR_NA */ "Command failed",
+		/* ERR_MISMATCH */ "Protocol version mismatch",
+		/* ERR_SYSERR */ "System error",
+		/* ERR_UNEXPECTED */ "Unexpected opcode received",
+		/* ERR_AUTHREQ */ "Server requires authentication",
+		/* ERR_PERM */ "Permission denied",
+		/* ERR_NOTFOUND */ "Requested device not found",
+		/* ERR_NOAUTH */ "Server doesn't support authentication"
+	};
+	if (status < 0)
+		status = -status;
+	if (status >= (int) (sizeof(errs) / sizeof(*errs)) ||
+	    status < 0) /* Happens if status was INT_MIN before */
+		return "Invalid";
+	return errs[status];
 }
 
 int usbip_net_set_reuseaddr(int sockfd)
@@ -467,6 +486,7 @@ int usbip_net_connect(char *hostname)
 #ifdef HAVE_GNUTLS
 	if (usbip_srp_password) {
 		int rc;
+		uint16_t code = OP_REP_STARTTLS;
 
 		rc = usbip_net_send_op_common(sockfd, OP_REQ_STARTTLS, 0);
 		if (rc < 0) {
@@ -474,6 +494,13 @@ int usbip_net_connect(char *hostname)
 			return EAI_SYSTEM;
 		}
 
+		rc = usbip_net_recv_op_common(sockfd, &code);
+		if (rc < 0) {
+			err("STARTTLS attempt failed: %s",
+			    usbip_net_strerror(rc));
+			return -1;
+		}
+
 		rc = usbip_net_srp_client_handshake(sockfd);
 		if (rc < 0) {
 			err("Unable to perform TLS handshake (wrong password?): %s",
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
index 292d584..151e815 100644
--- a/tools/usb/usbip/src/usbip_network.h
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -28,8 +28,15 @@ struct op_common {
 	uint16_t code;
 
 	/* add more error code */
-#define ST_OK	0x00
-#define ST_NA	0x01
+#define ERR_OK         0x00
+#define ERR_NA         0x01
+#define ERR_MISMATCH   0x02
+#define ERR_SYSERR     0x03
+#define ERR_UNEXPECTED 0x04
+#define ERR_AUTHREQ    0x05
+#define ERR_PERM       0x06
+#define ERR_NOTFOUND   0x07
+#define ERR_NOAUTH     0x08
 	uint32_t status; /* op_code status (for reply) */
 
 } __attribute__((packed));
@@ -178,10 +185,16 @@ void usbip_net_pack_uint32_t(int pack, uint32_t *num);
 void usbip_net_pack_uint16_t(int pack, uint16_t *num);
 void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
 void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
+const char *usbip_net_strerror(int status);
 
 ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
 ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
 int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
+/*
+ * Receive opcode.
+ * Returns: 0 on success, negative error code (that may be passed to
+ * usbip_net_strerror) on failure.
+ */
 int usbip_net_recv_op_common(int sockfd, uint16_t *code);
 int usbip_net_set_reuseaddr(int sockfd);
 int usbip_net_set_nodelay(int sockfd);
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index 7c0a46d..4ac4206 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -167,7 +167,7 @@ static int recv_request_import(int sockfd)
 	char sysfs_attr[SYSFS_IP_ACLS_MAX];
 	char ip_attr_path[SYSFS_PATH_MAX];
 	int found = 0;
-	int error = 0;
+	int error = ERR_OK;
 	int rc;
 
 	memset(&req, 0, sizeof(req));
@@ -196,7 +196,7 @@ static int recv_request_import(int sockfd)
 		/* export device needs a TCP/IP socket descriptor */
 		rc = usbip_host_export_device(edev, sockfd);
 		if (rc < 0)
-			error = 1;
+			error = ERR_SYSERR;
 
 		/* check for allowed IPs */
 		snprintf(ip_attr_path, sizeof(ip_attr_path), "%s/%s",
@@ -213,17 +213,16 @@ static int recv_request_import(int sockfd)
 		}
 	} else {
 		info("requested device not found: %s", req.busid);
-		error = 1;
+		error = ERR_NOTFOUND;
 	}
 
-	rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
-				      (!error ? ST_OK : ST_NA));
+	rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, error);
 	if (rc < 0) {
 		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
 		return -1;
 	}
 
-	if (error) {
+	if (error != 0) {
 		dbg("import request busid %s: failed", req.busid);
 		return -1;
 	}
@@ -258,7 +257,7 @@ static int send_reply_devlist(int connfd)
 	}
 	info("exportable devices: %d", reply.ndev);
 
-	rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
+	rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ERR_OK);
 	if (rc < 0) {
 		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
 		return -1;
@@ -341,7 +340,8 @@ static int recv_pdu(int connfd)
 
 		ret = usbip_net_recv_op_common(connfd, &code);
 		if (ret < 0) {
-			dbg("could not receive opcode: %#0x", code);
+			dbg("could not receive opcode: %#0x: %s", code,
+			    usbip_net_strerror(ret));
 			return -1;
 		}
 
@@ -349,7 +349,8 @@ static int recv_pdu(int connfd)
 
 		/* We require an authenticated encryption */
 		if (!auth && code != OP_REQ_STARTTLS) {
-			usbip_net_send_op_common(connfd, OP_REPLY, ST_NA);
+			info("Unauthenticated connection attempt");
+			usbip_net_send_op_common(connfd, OP_REPLY, ERR_AUTHREQ);
 			return -1;
 		}
 
@@ -357,9 +358,13 @@ static int recv_pdu(int connfd)
 #ifdef HAVE_GNUTLS
 		case OP_REQ_STARTTLS:
 			if (!need_auth) {
-				ret = -1;
+				usbip_net_send_op_common(connfd, OP_REPLY,
+							 ERR_NOAUTH);
 				err("Unexpected TLS handshake attempt (client uses password, server doesn't)");
+				ret = -1;
 			} else {
+				usbip_net_send_op_common(connfd, OP_REPLY,
+							 ERR_OK);
 				ret = net_srp_server_handshake(connfd);
 				if (ret != 0)
 					err("TLS handshake failed");
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 08/18] usbip: Handle usbip being started as user
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (6 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 07/18] usbip: Add proper error reporting Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 09/18] usbip: Improve debug output Maximilian Eschenbacher
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Maximilian Eschenbacher,
	Fjodor Schelichow, Johannes Stadlinger, Dominik Paulus,
	Tobias Polzer

usbip now prints an error message when started as user and requiring
root access. Also, some debug messages are changed to error messages so
the command line utilities now print less confusing (and more verbose)
error messages when not used correctly.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/src/usbip_attach.c | 3 +++
 tools/usb/usbip/src/usbip_bind.c   | 9 ++++++---
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index 51c67a2..fcc3efb 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -210,6 +210,9 @@ int usbip_attach(int argc, char *argv[])
 	int opt;
 	int ret = -1;
 
+	if (geteuid() != 0)
+		err("not running as root?");
+
 	for (;;) {
 		opt = getopt_long(argc, argv, "r:b:", opts, NULL);
 
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
index 3f8c7a3..6f5d3c2 100644
--- a/tools/usb/usbip/src/usbip_bind.c
+++ b/tools/usb/usbip/src/usbip_bind.c
@@ -102,19 +102,19 @@ static int unbind_other(char *busid)
 	/* Get the device. */
 	dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
 	if (!dev) {
-		dbg("unable to find device with bus ID %s", busid);
+		err("unable to find device with bus ID %s", busid);
 		goto err_close_busid_dev;
 	}
 
 	/* Check what kind of device it is. */
 	bDevClass  = udev_device_get_sysattr_value(dev, "bDeviceClass");
 	if (!bDevClass) {
-		dbg("unable to get bDevClass device attribute");
+		err("unable to get bDevClass device attribute");
 		goto err_close_busid_dev;
 	}
 
 	if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
-		dbg("skip unbinding of hub");
+		err("skip unbinding of hub");
 		goto err_close_busid_dev;
 	}
 
@@ -212,6 +212,9 @@ int usbip_bind(int argc, char *argv[])
 
 	allow[0] = 0;
 
+	if (geteuid() != 0)
+		err("not running as root?");
+
 	for (;;) {
 		opt = getopt_long(argc, argv, "a:b:", opts, NULL);
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 09/18] usbip: Improve debug output
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (7 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 08/18] usbip: Handle usbip being started as user Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 10/18] usbip: Separate protocol/program version Maximilian Eschenbacher
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

For IPv6, IP:Port is unreadable.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/src/usbipd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index 4ac4206..a7db6dc 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -443,7 +443,7 @@ static int do_accept(int listenfd)
 		return -1;
 	}
 #endif
-	info("connection from %s:%s", host, port);
+	info("connection from %s, port %s", host, port);
 
 	return connfd;
 }
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 10/18] usbip: Separate protocol/program version
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (8 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 09/18] usbip: Improve debug output Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 11/18] usbip: TLS for all userspace communication Maximilian Eschenbacher
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

Not all new program versions necessarily introduce
non-backwards-compatible protocol changes. We thus move the definition
of the protocol version from configure.ac to usbip_network.h, where it
logically belongs to.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/configure.ac        | 1 -
 tools/usb/usbip/src/usbip_network.c | 6 +++---
 tools/usb/usbip/src/usbip_network.h | 6 ++++++
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac
index 6a8156f..cee780e 100644
--- a/tools/usb/usbip/configure.ac
+++ b/tools/usb/usbip/configure.ac
@@ -2,7 +2,6 @@ dnl Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.59)
 AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org])
-AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number])
 
 CURRENT=0
 REVISION=1
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
index f68741d..6e6216d 100644
--- a/tools/usb/usbip/src/usbip_network.c
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -157,7 +157,7 @@ int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
 
 	memset(&op_common, 0, sizeof(op_common));
 
-	op_common.version = USBIP_VERSION;
+	op_common.version = PROTOCOL_VERSION;
 	op_common.code    = code;
 	op_common.status  = status;
 
@@ -187,9 +187,9 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code)
 
 	PACK_OP_COMMON(0, &op_common);
 
-	if (op_common.version != USBIP_VERSION) {
+	if (op_common.version != PROTOCOL_VERSION) {
 		dbg("version mismatch: %d %d", op_common.version,
-		    USBIP_VERSION);
+		    PROTOCOL_VERSION);
 		return -ERR_MISMATCH;
 	}
 
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
index 151e815..942d1bb 100644
--- a/tools/usb/usbip/src/usbip_network.h
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -13,6 +13,12 @@
 
 #include <stdint.h>
 
+/*
+ * Protocol version. Incremented only on non-backwards-compatible
+ * changes.
+ */
+#define PROTOCOL_VERSION 0x111
+
 extern int usbip_port;
 extern char *usbip_port_string;
 extern char *usbip_srp_password;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 11/18] usbip: TLS for all userspace communication
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (9 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 10/18] usbip: Separate protocol/program version Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 12/18] usbip: Exchange session keys in userspace Maximilian Eschenbacher
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This patch extends the TLS support to cover all communication in
userspace. The TLS connection is released shortly before the socket is
passed to the kernel.

This requires for additional connection state to be passed between
functions. We thus replaced the sockfd by a struct containing the TLS
context as well as the fd.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/src/usbip_attach.c  |  68 ++++++++++--
 tools/usb/usbip/src/usbip_list.c    |  26 ++---
 tools/usb/usbip/src/usbip_network.c | 210 +++++++++++++++++++++++++-----------
 tools/usb/usbip/src/usbip_network.h |  49 +++++++--
 tools/usb/usbip/src/usbipd.c        | 158 +++++++++++++--------------
 5 files changed, 334 insertions(+), 177 deletions(-)

diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index fcc3efb..4bc08e0 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -28,6 +28,13 @@
 #include <unistd.h>
 #include <errno.h>
 
+#include "../config.h"
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#endif
+
 #include "vhci_driver.h"
 #include "usbip_common.h"
 #include "usbip_network.h"
@@ -86,10 +93,42 @@ static int record_connection(char *host, char *port, char *busid, int rhport)
 	return 0;
 }
 
-static int import_device(int sockfd, struct usbip_usb_device *udev)
+static int import_device(struct usbip_connection *conn,
+			 struct usbip_usb_device *udev)
 {
 	int rc;
 	int port;
+	struct vhci_conf conf;
+
+	conf.use_crypto = 0;
+#ifdef HAVE_GNUTLS
+	if (conn->have_crypto) {
+		dbg("Generating session key and sending it to client");
+
+		rc = gnutls_rnd(GNUTLS_RND_RANDOM, conf.key1,
+				sizeof(conf.key1));
+		if (rc < 0) {
+			err("Session key generation failed: %s",
+			    gnutls_strerror(rc));
+			return -1;
+		}
+		rc = gnutls_rnd(GNUTLS_RND_RANDOM, conf.key2,
+				sizeof(conf.key2));
+		if (rc < 0) {
+			err("Session key generation failed: %s",
+			    gnutls_strerror(rc));
+			return -1;
+		}
+
+		if (usbip_net_send(conn, conf.key1, sizeof(conf.key1)) < 0 ||
+		    usbip_net_send(conn, conf.key2, sizeof(conf.key2)) < 0) {
+			err("Unable to send session key to client");
+			return -1;
+		}
+
+		conf.use_crypto = 1;
+	}
+#endif
 
 	rc = usbip_vhci_driver_open();
 	if (rc < 0) {
@@ -104,8 +143,14 @@ static int import_device(int sockfd, struct usbip_usb_device *udev)
 		return -1;
 	}
 
-	rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
-				      udev->devnum, udev->speed);
+	usbip_net_bye(conn);
+
+	conf.port = port;
+	conf.sockfd = conn->sockfd;
+	conf.devid = get_devid(udev->busnum, udev->devnum);
+	conf.speed = udev->speed;
+
+	rc = usbip_vhci_attach_device(&conf);
 	if (rc < 0) {
 		err("import device");
 		usbip_vhci_driver_close();
@@ -117,7 +162,7 @@ static int import_device(int sockfd, struct usbip_usb_device *udev)
 	return port;
 }
 
-static int query_import_device(int sockfd, char *busid)
+static int query_import_device(struct usbip_connection *conn, char *busid)
 {
 	int rc;
 	struct op_import_request request;
@@ -128,7 +173,7 @@ static int query_import_device(int sockfd, char *busid)
 	memset(&reply, 0, sizeof(reply));
 
 	/* send a request */
-	rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
+	rc = usbip_net_send_op_common(conn, OP_REQ_IMPORT, 0);
 	if (rc < 0) {
 		err("send op_common");
 		return -1;
@@ -138,20 +183,20 @@ static int query_import_device(int sockfd, char *busid)
 
 	PACK_OP_IMPORT_REQUEST(0, &request);
 
-	rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
+	rc = usbip_net_send(conn, &request, sizeof(request));
 	if (rc < 0) {
 		err("send op_import_request");
 		return -1;
 	}
 
 	/* receive a reply */
-	rc = usbip_net_recv_op_common(sockfd, &code);
+	rc = usbip_net_recv_op_common(conn, &code);
 	if (rc < 0) {
 		err("recv op_common: %s", usbip_net_strerror(rc));
 		return -1;
 	}
 
-	rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
+	rc = usbip_net_recv(conn, &reply, sizeof(reply));
 	if (rc < 0) {
 		err("recv op_import_reply");
 		return -1;
@@ -166,7 +211,7 @@ static int query_import_device(int sockfd, char *busid)
 	}
 
 	/* import a device */
-	return import_device(sockfd, &reply.udev);
+	return import_device(conn, &reply.udev);
 }
 
 static int attach_device(char *host, char *busid)
@@ -174,14 +219,15 @@ static int attach_device(char *host, char *busid)
 	int sockfd;
 	int rc;
 	int rhport;
+	struct usbip_connection conn;
 
-	sockfd = usbip_net_connect(host);
+	sockfd = usbip_net_connect(host, &conn);
 	if (sockfd < 0) {
 		err("connection attempt failed");
 		return -1;
 	}
 
-	rhport = query_import_device(sockfd, busid);
+	rhport = query_import_device(&conn, busid);
 	if (rhport < 0) {
 		err("query");
 		return -1;
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
index c122f41..f0264f6 100644
--- a/tools/usb/usbip/src/usbip_list.c
+++ b/tools/usb/usbip/src/usbip_list.c
@@ -45,7 +45,7 @@ void usbip_list_usage(void)
 	printf("usage: %s", usbip_list_usage_string);
 }
 
-static int get_exported_devices(char *host, int sockfd)
+static int get_exported_devices(char *host, struct usbip_connection *conn)
 {
 	char product_name[100];
 	char class_name[100];
@@ -56,13 +56,13 @@ static int get_exported_devices(char *host, int sockfd)
 	unsigned int i;
 	int rc, j;
 
-	rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
+	rc = usbip_net_send_op_common(conn, OP_REQ_DEVLIST, 0);
 	if (rc < 0) {
 		dbg("usbip_net_send_op_common failed");
 		return -1;
 	}
 
-	rc = usbip_net_recv_op_common(sockfd, &code);
+	rc = usbip_net_recv_op_common(conn, &code);
 	if (rc < 0) {
 		err("usbip_net_recv_op_common failed: %s",
 		    usbip_net_strerror(rc));
@@ -70,7 +70,7 @@ static int get_exported_devices(char *host, int sockfd)
 	}
 
 	memset(&reply, 0, sizeof(reply));
-	rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
+	rc = usbip_net_recv(conn, &reply, sizeof(reply));
 	if (rc < 0) {
 		dbg("usbip_net_recv_op_devlist failed");
 		return -1;
@@ -89,7 +89,7 @@ static int get_exported_devices(char *host, int sockfd)
 
 	for (i = 0; i < reply.ndev; i++) {
 		memset(&udev, 0, sizeof(udev));
-		rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
+		rc = usbip_net_recv(conn, &udev, sizeof(udev));
 		if (rc < 0) {
 			dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
 			return -1;
@@ -106,10 +106,10 @@ static int get_exported_devices(char *host, int sockfd)
 		printf("%11s: %s\n", "", class_name);
 
 		for (j = 0; j < udev.bNumInterfaces; j++) {
-			rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
+			rc = usbip_net_recv(conn, &uintf, sizeof(uintf));
 			if (rc < 0) {
 				err("usbip_net_recv failed: usbip_usb_intf[%d]",
-						j);
+				    j);
 
 				return -1;
 			}
@@ -131,23 +131,23 @@ static int get_exported_devices(char *host, int sockfd)
 static int list_exported_devices(char *host)
 {
 	int rc;
-	int sockfd;
+	struct usbip_connection conn;
 
-	sockfd = usbip_net_connect(host);
-	if (sockfd < 0) {
+	rc = usbip_net_connect(host, &conn);
+	if (rc < 0) {
 		err("could not connect to %s:%s: %s", host,
-		    usbip_port_string, gai_strerror(sockfd));
+		    usbip_port_string, usbip_net_strerror(rc));
 		return -1;
 	}
 	dbg("connected to %s:%s", host, usbip_port_string);
 
-	rc = get_exported_devices(host, sockfd);
+	rc = get_exported_devices(host, &conn);
 	if (rc < 0) {
 		err("failed to get device list from %s", host);
 		return -1;
 	}
 
-	close(sockfd);
+	usbip_net_bye(&conn);
 
 	return 0;
 }
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
index 6e6216d..233ad8b 100644
--- a/tools/usb/usbip/src/usbip_network.c
+++ b/tools/usb/usbip/src/usbip_network.c
@@ -24,6 +24,7 @@
 #include <netdb.h>
 #include <netinet/tcp.h>
 #include <unistd.h>
+#include <assert.h>
 
 #ifdef HAVE_LIBWRAP
 #include <tcpd.h>
@@ -113,20 +114,34 @@ void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
 	/* uint8_t members need nothing */
 }
 
-static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
-			      int sending)
+static ssize_t usbip_net_xmit(struct usbip_connection *conn, void *buff,
+			      size_t bufflen, int sending)
 {
-	ssize_t nbytes;
+	ssize_t nbytes = 0;
 	ssize_t total = 0;
 
 	if (!bufflen)
 		return 0;
 
 	do {
-		if (sending)
-			nbytes = send(sockfd, buff, bufflen, 0);
+		if (!conn->have_crypto && sending)
+			nbytes = send(conn->sockfd, buff, bufflen, 0);
+		else if (!conn->have_crypto && !sending)
+			nbytes = recv(conn->sockfd, buff, bufflen, MSG_WAITALL);
+#ifdef HAVE_GNUTLS
+		else if (sending)
+			nbytes = gnutls_record_send(conn->session, buff,
+						    bufflen);
 		else
-			nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
+			nbytes = gnutls_record_recv(conn->session, buff,
+						    bufflen);
+#else
+		/*
+		 * Assertion to let gcc be able to infer proper initialization
+		 * of nbytes.
+		 */
+		assert(!conn->have_crypto);
+#endif
 
 		if (nbytes <= 0)
 			return -1;
@@ -140,17 +155,20 @@ static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
 	return total;
 }
 
-ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
+ssize_t usbip_net_recv(struct usbip_connection *conn, void *buff,
+		       size_t bufflen)
 {
-	return usbip_net_xmit(sockfd, buff, bufflen, 0);
+	return usbip_net_xmit(conn, buff, bufflen, 0);
 }
 
-ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
+ssize_t usbip_net_send(struct usbip_connection *conn, void *buff,
+		       size_t bufflen)
 {
-	return usbip_net_xmit(sockfd, buff, bufflen, 1);
+	return usbip_net_xmit(conn, buff, bufflen, 1);
 }
 
-int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
+int usbip_net_send_op_common(struct usbip_connection *conn, uint32_t code,
+			     uint32_t status)
 {
 	struct op_common op_common;
 	int rc;
@@ -163,7 +181,7 @@ int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
 
 	PACK_OP_COMMON(1, &op_common);
 
-	rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
+	rc = usbip_net_send(conn, &op_common, sizeof(op_common));
 	if (rc < 0) {
 		dbg("usbip_net_send failed: %d", rc);
 		return -1;
@@ -172,14 +190,15 @@ int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
 	return 0;
 }
 
-int usbip_net_recv_op_common(int sockfd, uint16_t *code)
+
+int usbip_net_recv_op_common(struct usbip_connection *conn, uint16_t *code)
 {
 	struct op_common op_common;
 	int rc;
 
 	memset(&op_common, 0, sizeof(op_common));
 
-	rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
+	rc = usbip_net_recv(conn, &op_common, sizeof(op_common));
 	if (rc < 0) {
 		dbg("usbip_net_recv failed: %d", rc);
 		return -ERR_SYSERR;
@@ -225,7 +244,8 @@ const char *usbip_net_strerror(int status)
 		/* ERR_AUTHREQ */ "Server requires authentication",
 		/* ERR_PERM */ "Permission denied",
 		/* ERR_NOTFOUND */ "Requested device not found",
-		/* ERR_NOAUTH */ "Server doesn't support authentication"
+		/* ERR_NOAUTH */ "Server doesn't support authentication",
+		/* ERR_INUSE */ "Requested device is already in use"
 	};
 	if (status < 0)
 		status = -status;
@@ -252,7 +272,8 @@ int usbip_net_set_nodelay(int sockfd)
 	const int val = 1;
 	int ret;
 
-	ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+	ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val,
+		sizeof(val));
 	if (ret < 0)
 		dbg("setsockopt: TCP_NODELAY");
 
@@ -337,59 +358,53 @@ static gnutls_srp_server_credentials_t usbip_net_srp_cred;
 #define SRP_GROUP gnutls_srp_2048_group_generator
 #define SRP_PRIME gnutls_srp_2048_group_prime
 
-int usbip_net_srp_client_handshake(int sockfd)
+int usbip_net_srp_client_handshake(struct usbip_connection *conn)
 {
 	int ret;
-	gnutls_session_t session;
-	gnutls_srp_client_credentials_t usbip_net_srp_cred;
 
-	ret = gnutls_srp_allocate_client_credentials(&usbip_net_srp_cred);
+	ret = gnutls_srp_allocate_client_credentials(&conn->srp_client_cred);
 	if (ret < 0)
 		return ret;
 
-	gnutls_srp_set_client_credentials(usbip_net_srp_cred, "dummyuser",
+	gnutls_srp_set_client_credentials(conn->srp_client_cred, "dummyuser",
 		usbip_srp_password);
 
-	ret = gnutls_init(&session, GNUTLS_CLIENT);
+	ret = gnutls_init(&conn->session, GNUTLS_CLIENT);
 	if (ret < 0) {
-		gnutls_srp_free_client_credentials(usbip_net_srp_cred);
+		gnutls_srp_free_client_credentials(conn->srp_client_cred);
 		return ret;
 	}
 
-	gnutls_priority_set_direct(session, "NORMAL:+SRP", NULL);
+	gnutls_priority_set_direct(conn->session, "NORMAL:+SRP", NULL);
 
-	gnutls_credentials_set(session, GNUTLS_CRD_SRP, usbip_net_srp_cred);
-	gnutls_transport_set_int (session, sockfd);
+	gnutls_credentials_set(conn->session, GNUTLS_CRD_SRP,
+			       conn->srp_client_cred);
+	gnutls_transport_set_int (conn->session, conn->sockfd);
 
 	do {
-		ret = gnutls_handshake(session);
+		ret = gnutls_handshake(conn->session);
 	} while (ret < 0 && !gnutls_error_is_fatal(ret));
 
-	gnutls_bye(session, GNUTLS_SHUT_RDWR);
-
-	gnutls_deinit(session);
-	gnutls_srp_free_client_credentials(usbip_net_srp_cred);
-
 	return ret;
 }
 
-int net_srp_server_handshake(int connfd)
+int usbip_net_srp_server_handshake(struct usbip_connection *conn)
 {
 	int ret;
-	gnutls_session_t session;
 
-	if (gnutls_init(&session, GNUTLS_SERVER) != 0)
+	ret = gnutls_init(&conn->session, GNUTLS_SERVER);
+	if (ret != 0)
 		return -1;
-	gnutls_priority_set_direct(session, "NORMAL:-KX-ALL:+SRP", NULL);
-	ret = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
+	gnutls_priority_set_direct(conn->session, "NORMAL:-KX-ALL:+SRP", NULL);
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_SRP,
 				     usbip_net_srp_cred);
-	if (!ret)
+	if (ret < 0)
 		return -1;
 
-	gnutls_transport_set_int(session, connfd);
+	gnutls_transport_set_int(conn->session, conn->sockfd);
 
 	do {
-		ret = gnutls_handshake(session);
+		ret = gnutls_handshake(conn->session);
 	} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
 
 	if (ret < 0)
@@ -397,9 +412,7 @@ int net_srp_server_handshake(int connfd)
 	else
 		info("GnuTLS handshake completed");
 
-	if (gnutls_bye(session, GNUTLS_SHUT_RDWR) != 0)
-		err("Unable to shutdown TLS connection.");
-	gnutls_deinit(session);
+	conn->have_crypto = 1;
 
 	return ret;
 }
@@ -471,45 +484,120 @@ int usbip_net_init_gnutls(void)
 }
 #endif
 
-/*
- * Connect to the server. Performs the TCP connection attempt
- * and - if necessary - the TLS handshake used for authentication.
- */
-int usbip_net_connect(char *hostname)
+#ifdef HAVE_LIBWRAP
+static int tcpd_auth(int connfd)
 {
-	int sockfd;
+	struct request_info request;
+	int rc;
+
+	request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
+	fromhost(&request);
+	rc = hosts_access(&request);
+	if (rc == 0)
+		return -1;
+
+	return 0;
+}
+#endif
+
+int usbip_net_accept(int listenfd, struct usbip_connection *conn)
+{
+	int connfd;
+	struct sockaddr_storage ss;
+	socklen_t len = sizeof(ss);
+	char host[NI_MAXHOST], port[NI_MAXSERV];
+	int rc;
+
+	memset(&ss, 0, sizeof(ss));
+
+	connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
+	if (connfd < 0) {
+		err("failed to accept connection");
+		return -1;
+	}
 
-	sockfd = usbip_net_tcp_connect(hostname, usbip_port_string);
-	if (sockfd < 0)
-		return sockfd;
+	rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
+			 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+	if (rc)
+		err("getnameinfo: %s", gai_strerror(rc));
+
+#ifdef HAVE_LIBWRAP
+	rc = tcpd_auth(connfd);
+	if (rc < 0) {
+		info("denied access from %s", host);
+		close(connfd);
+		return -1;
+	}
+#endif
+	info("connection from %s, port %s", host, port);
+
+	conn->sockfd = connfd;
+	conn->have_crypto = 0;
+	conn->server = 1;
+
+	return 0;
+}
+
+int usbip_net_connect(char *hostname, struct usbip_connection *conn)
+{
+	conn->sockfd = usbip_net_tcp_connect(hostname, usbip_port_string);
+	if (conn->sockfd < 0) {
+		err("TCP connection attempt failed: %s",
+				gai_strerror(conn->sockfd));
+		return ERR_SYSERR;
+	}
+
+	conn->have_crypto = 0;
+	conn->server = 0;
 
 #ifdef HAVE_GNUTLS
 	if (usbip_srp_password) {
 		int rc;
 		uint16_t code = OP_REP_STARTTLS;
 
-		rc = usbip_net_send_op_common(sockfd, OP_REQ_STARTTLS, 0);
+		rc = usbip_net_send_op_common(conn, OP_REQ_STARTTLS, 0);
 		if (rc < 0) {
+			close(conn->sockfd);
 			err("usbip_net_send_op_common failed");
-			return EAI_SYSTEM;
+			return ERR_SYSERR;
 		}
 
-		rc = usbip_net_recv_op_common(sockfd, &code);
+		rc = usbip_net_recv_op_common(conn, &code);
 		if (rc < 0) {
 			err("STARTTLS attempt failed: %s",
 			    usbip_net_strerror(rc));
-			return -1;
+			close(conn->sockfd);
+			return ERR_SYSERR;
 		}
 
-		rc = usbip_net_srp_client_handshake(sockfd);
+		rc = usbip_net_srp_client_handshake(conn);
 		if (rc < 0) {
 			err("Unable to perform TLS handshake (wrong password?): %s",
-			    gnutls_strerror(rc));
-			close(sockfd);
-			return EAI_SYSTEM;
+				gnutls_strerror(rc));
+			close(conn->sockfd);
+			return ERR_SYSERR;
 		}
+
+		conn->have_crypto = 1;
 	}
 #endif
 
-	return sockfd;
+	return 0;
+}
+
+void usbip_net_bye(struct usbip_connection *conn)
+{
+#ifdef HAVE_GNUTLS
+	if (conn->have_crypto) {
+		gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
+
+		gnutls_deinit(conn->session);
+		if (!conn->server)
+			gnutls_srp_free_client_credentials(conn->srp_client_cred);
+
+		conn->have_crypto = 0;
+	}
+#else
+	(void)conn;
+#endif
 }
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
index 942d1bb..22fddfc 100644
--- a/tools/usb/usbip/src/usbip_network.h
+++ b/tools/usb/usbip/src/usbip_network.h
@@ -9,6 +9,10 @@
 #include "../config.h"
 #endif
 
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
 #include <sys/types.h>
 
 #include <stdint.h>
@@ -24,6 +28,19 @@ extern char *usbip_port_string;
 extern char *usbip_srp_password;
 void usbip_setup_port_number(char *arg);
 
+/*
+ * Connection handle
+ */
+struct usbip_connection {
+#ifdef HAVE_GNUTLS
+	gnutls_session_t session;
+	gnutls_srp_client_credentials_t srp_client_cred;
+#endif
+	int have_crypto;
+	int sockfd;
+	int server;
+};
+
 /* ---------------------------------------------------------------------- */
 /* Common header for all the kinds of PDUs. */
 struct op_common {
@@ -43,6 +60,7 @@ struct op_common {
 #define ERR_PERM       0x06
 #define ERR_NOTFOUND   0x07
 #define ERR_NOAUTH     0x08
+#define ERR_INUSE      0x09
 	uint32_t status; /* op_code status (for reply) */
 
 } __attribute__((packed));
@@ -193,21 +211,40 @@ void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
 void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
 const char *usbip_net_strerror(int status);
 
-ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
-ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
-int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
+ssize_t usbip_net_recv(struct usbip_connection *conn, void *buff,
+		       size_t bufflen);
+ssize_t usbip_net_send(struct usbip_connection *conn, void *buff,
+		       size_t bufflen);
+int usbip_net_send_op_common(struct usbip_connection *conn, uint32_t code,
+			     uint32_t status);
 /*
  * Receive opcode.
  * Returns: 0 on success, negative error code (that may be passed to
  * usbip_net_strerror) on failure.
  */
-int usbip_net_recv_op_common(int sockfd, uint16_t *code);
+int usbip_net_recv_op_common(struct usbip_connection *conn, uint16_t *code);
 int usbip_net_set_reuseaddr(int sockfd);
 int usbip_net_set_nodelay(int sockfd);
 int usbip_net_set_keepalive(int sockfd);
 int usbip_net_set_v6only(int sockfd);
-int usbip_net_connect(char *hostname);
-int net_srp_server_handshake(int connfd);
+/*
+ * Connect to the server. Performs the TCP connection attempt
+ * and - if necessary - the TLS handshake used for authentication.
+ *
+ * Newly generated connection parameters are stored in the - caller
+ * allocated - usbip_connection struct conn.
+ *
+ * Returns:
+ *	0 on success
+ *	negative error code on failure
+ */
+int usbip_net_connect(char *hostname, struct usbip_connection *conn);
+int usbip_net_accept(int listenfd, struct usbip_connection *conn);
+int usbip_net_srp_server_handshake(struct usbip_connection *conn);
+/*
+ * Shuts down the TLS connection, but leaves the socket intact
+ */
+void usbip_net_bye(struct usbip_connection *conn);
 int usbip_net_init_gnutls(void);
 
 #endif /* __USBIP_NETWORK_H */
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
index a7db6dc..122175e 100644
--- a/tools/usb/usbip/src/usbipd.c
+++ b/tools/usb/usbip/src/usbipd.c
@@ -61,6 +61,7 @@
 #define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
 
 static const char usbip_version_string[] = PACKAGE_STRING;
+static int need_auth;
 
 static const char usbipd_help_string[] =
 	"usage: usbipd [options]\n"
@@ -95,8 +96,6 @@ static const char usbipd_help_string[] =
 	"	-v, --version\n"
 	"		Show version.\n";
 
-static int need_auth;
-
 static void usbipd_help(void)
 {
 	printf("%s\n", usbipd_help_string);
@@ -157,7 +156,7 @@ static int check_allowed(char *acls, int sockfd)
 	return match;
 }
 
-static int recv_request_import(int sockfd)
+static int recv_request_import(struct usbip_connection *conn)
 {
 	struct op_import_request req;
 	struct op_common reply;
@@ -173,7 +172,7 @@ static int recv_request_import(int sockfd)
 	memset(&req, 0, sizeof(req));
 	memset(&reply, 0, sizeof(reply));
 
-	rc = usbip_net_recv(sockfd, &req, sizeof(req));
+	rc = usbip_net_recv(conn, &req, sizeof(req));
 	if (rc < 0) {
 		dbg("usbip_net_recv failed: import request");
 		return -1;
@@ -191,12 +190,7 @@ static int recv_request_import(int sockfd)
 
 	if (found) {
 		/* should set TCP_NODELAY for usbip */
-		usbip_net_set_nodelay(sockfd);
-
-		/* export device needs a TCP/IP socket descriptor */
-		rc = usbip_host_export_device(edev, sockfd);
-		if (rc < 0)
-			error = ERR_SYSERR;
+		usbip_net_set_nodelay(conn->sockfd);
 
 		/* check for allowed IPs */
 		snprintf(ip_attr_path, sizeof(ip_attr_path), "%s/%s",
@@ -211,12 +205,22 @@ static int recv_request_import(int sockfd)
 			     edev->udev.busid);
 			error = ERR_PERM;
 		}
+
+		/*
+		 * There is a race condition here: Other clients might
+		 * take it, as this check doesn't lock the device
+		 * However, this seems hardly avoidable here.
+		 */
+		if (edev->status != SDEV_ST_AVAILABLE) {
+			error = ERR_INUSE;
+			found = 0;
+		}
 	} else {
 		info("requested device not found: %s", req.busid);
 		error = ERR_NOTFOUND;
 	}
 
-	rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, error);
+	rc = usbip_net_send_op_common(conn, OP_REP_IMPORT, error);
 	if (rc < 0) {
 		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
 		return -1;
@@ -230,18 +234,47 @@ static int recv_request_import(int sockfd)
 	memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
 	usbip_net_pack_usb_device(1, &pdu_udev);
 
-	rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
+	rc = usbip_net_send(conn, &pdu_udev, sizeof(pdu_udev));
 	if (rc < 0) {
 		dbg("usbip_net_send failed: devinfo");
 		return -1;
 	}
 
+	if (found) {
+		struct host_conf conf = {
+			.sockfd = conn->sockfd,
+			.use_crypto = 0
+		};
+
+#ifdef HAVE_GNUTLS
+		if (conn->have_crypto) {
+			if (usbip_net_recv(conn, conf.key1,
+						 sizeof(conf.key1)) < 0 ||
+			    usbip_net_recv(conn, conf.key2,
+						 sizeof(conf.key2)) < 0) {
+				err("Unable to receive session key");
+				return -1;
+			}
+			conf.use_crypto = 1;
+		}
+#endif
+
+		usbip_net_bye(conn);
+		/* export device needs a TCP/IP socket descriptor */
+		conf.sockfd = conn->sockfd;
+		rc = usbip_host_export_device(edev, &conf);
+		if (rc < 0) {
+			err("usbip_host_export_device");
+			return -1;
+		}
+	}
+
 	dbg("import request busid %s: complete", req.busid);
 
 	return 0;
 }
 
-static int send_reply_devlist(int connfd)
+static int send_reply_devlist(struct usbip_connection *conn)
 {
 	struct usbip_exported_device *edev;
 	struct usbip_usb_device pdu_udev;
@@ -257,14 +290,14 @@ static int send_reply_devlist(int connfd)
 	}
 	info("exportable devices: %d", reply.ndev);
 
-	rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ERR_OK);
+	rc = usbip_net_send_op_common(conn, OP_REP_DEVLIST, ERR_OK);
 	if (rc < 0) {
 		dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
 		return -1;
 	}
 	PACK_OP_DEVLIST_REPLY(1, &reply);
 
-	rc = usbip_net_send(connfd, &reply, sizeof(reply));
+	rc = usbip_net_send(conn, &reply, sizeof(reply));
 	if (rc < 0) {
 		dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
 		return -1;
@@ -276,7 +309,7 @@ static int send_reply_devlist(int connfd)
 		memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
 		usbip_net_pack_usb_device(1, &pdu_udev);
 
-		rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
+		rc = usbip_net_send(conn, &pdu_udev, sizeof(pdu_udev));
 		if (rc < 0) {
 			dbg("usbip_net_send failed: pdu_udev");
 			return -1;
@@ -287,7 +320,7 @@ static int send_reply_devlist(int connfd)
 			memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
 			usbip_net_pack_usb_interface(1, &pdu_uinf);
 
-			rc = usbip_net_send(connfd, &pdu_uinf,
+			rc = usbip_net_send(conn, &pdu_uinf,
 					sizeof(pdu_uinf));
 			if (rc < 0) {
 				err("usbip_net_send failed: pdu_uinf");
@@ -299,20 +332,20 @@ static int send_reply_devlist(int connfd)
 	return 0;
 }
 
-static int recv_request_devlist(int connfd)
+static int recv_request_devlist(struct usbip_connection *conn)
 {
 	struct op_devlist_request req;
 	int rc;
 
 	memset(&req, 0, sizeof(req));
 
-	rc = usbip_net_recv(connfd, &req, sizeof(req));
+	rc = usbip_net_recv(conn, &req, sizeof(req));
 	if (rc < 0) {
 		dbg("usbip_net_recv failed: devlist request");
 		return -1;
 	}
 
-	rc = send_reply_devlist(connfd);
+	rc = send_reply_devlist(conn);
 	if (rc < 0) {
 		dbg("send_reply_devlist failed");
 		return -1;
@@ -321,7 +354,7 @@ static int recv_request_devlist(int connfd)
 	return 0;
 }
 
-static int recv_pdu(int connfd)
+static int recv_pdu(struct usbip_connection *conn)
 {
 	int auth = !need_auth, cont = 1, ret;
 
@@ -338,19 +371,19 @@ static int recv_pdu(int connfd)
 	while (cont) {
 		uint16_t code = OP_UNSPEC;
 
-		ret = usbip_net_recv_op_common(connfd, &code);
+		ret = usbip_net_recv_op_common(conn, &code);
 		if (ret < 0) {
 			dbg("could not receive opcode: %#0x: %s", code,
 			    usbip_net_strerror(ret));
 			return -1;
 		}
 
-		info("received request: %#0x(%d)", code, connfd);
+		info("received request: %#0x", code);
 
 		/* We require an authenticated encryption */
 		if (!auth && code != OP_REQ_STARTTLS) {
 			info("Unauthenticated connection attempt");
-			usbip_net_send_op_common(connfd, OP_REPLY, ERR_AUTHREQ);
+			usbip_net_send_op_common(conn, OP_REPLY, ERR_AUTHREQ);
 			return -1;
 		}
 
@@ -358,14 +391,15 @@ static int recv_pdu(int connfd)
 #ifdef HAVE_GNUTLS
 		case OP_REQ_STARTTLS:
 			if (!need_auth) {
-				usbip_net_send_op_common(connfd, OP_REPLY,
+				usbip_net_send_op_common(conn, OP_REPLY,
 							 ERR_NOAUTH);
 				err("Unexpected TLS handshake attempt (client uses password, server doesn't)");
 				ret = -1;
 			} else {
-				usbip_net_send_op_common(connfd, OP_REPLY,
+				usbip_net_send_op_common(conn, OP_REPLY,
 							 ERR_OK);
-				ret = net_srp_server_handshake(connfd);
+				info("Starting handshake");
+				ret = usbip_net_srp_server_handshake(conn);
 				if (ret != 0)
 					err("TLS handshake failed");
 				auth = 1;
@@ -373,11 +407,11 @@ static int recv_pdu(int connfd)
 			break;
 #endif
 		case OP_REQ_DEVLIST:
-			ret = recv_request_devlist(connfd);
+			ret = recv_request_devlist(conn);
 			cont = 0;
 			break;
 		case OP_REQ_IMPORT:
-			ret = recv_request_import(connfd);
+			ret = recv_request_import(conn);
 			cont = 0;
 			break;
 		case OP_REQ_DEVINFO:
@@ -388,9 +422,9 @@ static int recv_pdu(int connfd)
 		}
 
 		if (ret == 0)
-			info("request %#0x(%d): complete", code, connfd);
+			info("request %#0x: complete", code);
 		else {
-			info("request %#0x(%d): failed", code, connfd);
+			info("request %#0x: failed", code);
 			break;
 		}
 	}
@@ -398,71 +432,23 @@ static int recv_pdu(int connfd)
 	return ret;
 }
 
-#ifdef HAVE_LIBWRAP
-static int tcpd_auth(int connfd)
-{
-	struct request_info request;
-	int rc;
-
-	request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
-	fromhost(&request);
-	rc = hosts_access(&request);
-	if (rc == 0)
-		return -1;
-
-	return 0;
-}
-#endif
-
-static int do_accept(int listenfd)
-{
-	int connfd;
-	struct sockaddr_storage ss;
-	socklen_t len = sizeof(ss);
-	char host[NI_MAXHOST], port[NI_MAXSERV];
-	int rc;
-
-	memset(&ss, 0, sizeof(ss));
-
-	connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
-	if (connfd < 0) {
-		err("failed to accept connection");
-		return -1;
-	}
-
-	rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
-			 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
-	if (rc)
-		err("getnameinfo: %s", gai_strerror(rc));
-
-#ifdef HAVE_LIBWRAP
-	rc = tcpd_auth(connfd);
-	if (rc < 0) {
-		info("denied access from %s", host);
-		close(connfd);
-		return -1;
-	}
-#endif
-	info("connection from %s, port %s", host, port);
-
-	return connfd;
-}
-
 int process_request(int listenfd)
 {
 	pid_t childpid;
-	int connfd;
+	struct usbip_connection conn;
+	int rc;
 
-	connfd = do_accept(listenfd);
-	if (connfd < 0)
+	rc = usbip_net_accept(listenfd, &conn);
+	if (rc < 0)
 		return -1;
 	childpid = fork();
 	if (childpid == 0) {
 		close(listenfd);
-		recv_pdu(connfd);
+		recv_pdu(&conn);
+		usbip_net_bye(&conn);
 		exit(0);
 	}
-	close(connfd);
+	close(conn.sockfd);
 	return 0;
 }
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 12/18] usbip: Exchange session keys in userspace
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (10 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 11/18] usbip: TLS for all userspace communication Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 13/18] usbip: Pass session keys to the kernel Maximilian Eschenbacher
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

In preparation for the kernel crypto support, we exchange two - randomly
generated - session keys between usbip and usbipd to be used for
encrypting all traffic generated in kernelspace. We use two different
128-bit keys, one for sending and one for receiving. Both are generated
by the client (usbip, probably has more entropy available than the
server) and transferred over the already established TLS connection.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 tools/usb/usbip/libsrc/usbip_common.h      | 21 +++++++++++++++++++++
 tools/usb/usbip/libsrc/usbip_host_driver.c |  5 +++--
 tools/usb/usbip/libsrc/usbip_host_driver.h |  3 ++-
 tools/usb/usbip/libsrc/vhci_driver.c       | 19 +++++--------------
 tools/usb/usbip/libsrc/vhci_driver.h       |  9 +++------
 5 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h
index 824d5a5..86d21f2 100644
--- a/tools/usb/usbip/libsrc/usbip_common.h
+++ b/tools/usb/usbip/libsrc/usbip_common.h
@@ -115,6 +115,27 @@ struct usbip_usb_device {
 	uint8_t bNumInterfaces;
 } __attribute__((packed));
 
+
+/*
+ * These structs contain the configuration
+ * data to be passed to the kernel
+ */
+struct host_conf {
+	int sockfd;
+	uint8_t use_crypto;
+	uint8_t key1[16];
+	uint8_t key2[16];
+};
+struct vhci_conf {
+	uint8_t port;
+	int sockfd;
+	uint32_t devid;
+	uint32_t speed;
+	uint8_t use_crypto;
+	uint8_t key1[16];
+	uint8_t key2[16];
+};
+
 #define to_string(s)	#s
 
 void dump_usb_interface(struct usbip_usb_interface *);
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c
index bef08d5..f7c85da 100644
--- a/tools/usb/usbip/libsrc/usbip_host_driver.c
+++ b/tools/usb/usbip/libsrc/usbip_host_driver.c
@@ -221,7 +221,8 @@ int usbip_host_refresh_device_list(void)
 	return 0;
 }
 
-int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
+int usbip_host_export_device(struct usbip_exported_device *edev,
+			     struct host_conf *conf)
 {
 	char attr_name[] = "usbip_sockfd";
 	char sockfd_attr_path[SYSFS_PATH_MAX];
@@ -247,7 +248,7 @@ int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
 	snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
 		 edev->udev.path, attr_name);
 
-	snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+	snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", conf->sockfd);
 
 	ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
 				    strlen(sockfd_buff));
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.h b/tools/usb/usbip/libsrc/usbip_host_driver.h
index 2a31f85..ce4bd6f 100644
--- a/tools/usb/usbip/libsrc/usbip_host_driver.h
+++ b/tools/usb/usbip/libsrc/usbip_host_driver.h
@@ -43,7 +43,8 @@ int usbip_host_driver_open(void);
 void usbip_host_driver_close(void);
 
 int usbip_host_refresh_device_list(void);
-int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd);
+int usbip_host_export_device(struct usbip_exported_device *edev,
+			     struct host_conf *conf);
 struct usbip_exported_device *usbip_host_get_device(int num);
 
 #endif /* __USBIP_HOST_DRIVER_H */
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index ad92047..c0928e2 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -298,8 +298,8 @@ int usbip_vhci_get_free_port(void)
 	return -1;
 }
 
-int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
-		uint32_t speed) {
+int usbip_vhci_attach_device(struct vhci_conf *conf)
+{
 	char buff[200]; /* what size should be ? */
 	char attach_attr_path[SYSFS_PATH_MAX];
 	char attr_attach[] = "attach";
@@ -307,7 +307,7 @@ int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
 	int ret;
 
 	snprintf(buff, sizeof(buff), "%u %d %u %u",
-			port, sockfd, devid, speed);
+			conf->port, conf->sockfd, conf->devid, conf->speed);
 	dbg("writing: %s", buff);
 
 	path = udev_device_get_syspath(vhci_driver->hc_device);
@@ -321,25 +321,16 @@ int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
 		return -1;
 	}
 
-	dbg("attached port: %d", port);
+	dbg("attached port: %d", conf->port);
 
 	return 0;
 }
 
-static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
+unsigned long get_devid(uint8_t busnum, uint8_t devnum)
 {
 	return (busnum << 16) | devnum;
 }
 
-/* will be removed */
-int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
-		uint8_t devnum, uint32_t speed)
-{
-	int devid = get_devid(busnum, devnum);
-
-	return usbip_vhci_attach_device2(port, sockfd, devid, speed);
-}
-
 int usbip_vhci_detach_device(uint8_t port)
 {
 	char detach_attr_path[SYSFS_PATH_MAX];
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h
index fa2316c..20e6be4 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.h
+++ b/tools/usb/usbip/libsrc/vhci_driver.h
@@ -45,15 +45,12 @@ int  usbip_vhci_refresh_device_list(void);
 
 
 int usbip_vhci_get_free_port(void);
-int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
-		uint32_t speed);
-
-/* will be removed */
-int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
-		uint8_t devnum, uint32_t speed);
+int usbip_vhci_attach_device(struct vhci_conf *conf);
 
 int usbip_vhci_detach_device(uint8_t port);
 
 int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev);
 
+unsigned long get_devid(uint8_t busnum, uint8_t devnum);
+
 #endif /* __VHCI_DRIVER_H */
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 13/18] usbip: Pass session keys to the kernel
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (11 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 12/18] usbip: Exchange session keys in userspace Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 14/18] usbip: Wrap kernel_sendmsg()/recvmsg() Maximilian Eschenbacher
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This extends the userspace code to write the generated session keys to
sysfs in hexadecimal encoding after establishing the connection.
The kernel code is modified to parse the session keys.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 drivers/usb/usbip/stub_dev.c               | 36 +++++++++++++++++++++++++----
 drivers/usb/usbip/usbip_common.h           | 10 ++++++++
 drivers/usb/usbip/vhci_sysfs.c             | 37 ++++++++++++++++++++++++++++--
 tools/usb/usbip/libsrc/usbip_common.c      | 15 ++++++++++++
 tools/usb/usbip/libsrc/usbip_common.h      |  2 ++
 tools/usb/usbip/libsrc/usbip_host_driver.c | 14 ++++++++---
 tools/usb/usbip/libsrc/vhci_driver.c       |  8 ++++---
 7 files changed, 110 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index e6624f1..d237351 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -57,18 +57,46 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
 	struct stub_device *sdev = dev_get_drvdata(dev);
-	int sockfd = 0;
+	int sockfd = 0, ret;
 	struct socket *socket;
-	int rv;
+	char sendkey[USBIP_KEYSIZE], recvkey[USBIP_KEYSIZE];
+	char sendkey_hex[2 * USBIP_KEYSIZE + 1];
+	char recvkey_hex[2 * USBIP_KEYSIZE + 1];
 
 	if (!sdev) {
 		dev_err(dev, "sdev is null\n");
 		return -ENODEV;
 	}
 
-	rv = sscanf(buf, "%d", &sockfd);
-	if (rv != 1)
+	/*
+	 * Read symmetric crypto keys. They are randomly
+	 * generated by userspace and passed to the kernel
+	 * via sysfs (encoded in hexadecimal)
+	 */
+	if (sscanf(buf, "%d %d %32s %32s", &sockfd, &sdev->ud.use_crypto,
+		   sendkey_hex, recvkey_hex) < 1) {
+		dev_err(dev, "Invalid write to sysfs: Invalid sockfd\n");
 		return -EINVAL;
+	}
+	if (sdev->ud.use_crypto) {
+		int i;
+
+		dev_info(dev, "Using encrypted data transport\n");
+		for (i = USBIP_KEYSIZE - 1; i >= 0; --i) {
+			sendkey_hex[2 * (i + 1)] = 0;
+			ret = sscanf(sendkey_hex + (2 * i), "%2hhX",
+				     &sendkey[i]);
+			if (ret < 1)
+				return -EINVAL;
+		}
+		for (i = USBIP_KEYSIZE - 1; i >= 0; --i) {
+			recvkey_hex[2 * (i + 1)] = 0;
+			ret = sscanf(recvkey_hex + (2 * i), "%2hhX",
+				     &recvkey[i]);
+			if (ret < 1)
+				return -EINVAL;
+		}
+	}
 
 	if (sockfd != -1) {
 		int err;
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
index 86b0847..69b3f8a 100644
--- a/drivers/usb/usbip/usbip_common.h
+++ b/drivers/usb/usbip/usbip_common.h
@@ -33,6 +33,13 @@
 
 #define USBIP_VERSION "1.0.0"
 
+/*
+ * Length of symmetric keys. Currently, this should be fixed at 16 bytes.
+ * Will break code if changed, look at userspace and stub_dev.c/vhci_sysfs.c
+ * where this constant is used before changing.
+ */
+#define USBIP_KEYSIZE 16
+
 #undef pr_fmt
 
 #ifdef DEBUG
@@ -275,6 +282,9 @@ struct usbip_device {
 		void (*reset)(struct usbip_device *);
 		void (*unusable)(struct usbip_device *);
 	} eh_ops;
+
+	/* Crypto support */
+	int use_crypto;
 };
 
 #define kthread_get_run(threadfn, data, namefmt, ...)			   \
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index 211f43f..fa948ad 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -174,18 +174,51 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 {
 	struct vhci_device *vdev;
 	struct socket *socket;
-	int sockfd = 0;
+	int sockfd = 0, ret;
 	__u32 rhport = 0, devid = 0, speed = 0;
 	int err;
+	unsigned char sendkey[USBIP_KEYSIZE], recvkey[USBIP_KEYSIZE];
+	char sendkey_hex[2*USBIP_KEYSIZE+1], recvkey_hex[2*USBIP_KEYSIZE+1];
+	int use_crypto = 0;
 
 	/*
 	 * @rhport: port number of vhci_hcd
 	 * @sockfd: socket descriptor of an established TCP connection
 	 * @devid: unique device identifier in a remote host
 	 * @speed: usb device speed in a remote host
+	 * @use_crypto: Whether to use an encrypted connection
+	 * @recvkey_hex/@sendkey_hex: Hexadecimal encoded 128bit
+	 *              symmetric encryption keys to be used.
+	 *              Generated randomly for each connection
+	 *              by userspace.
 	 */
-	if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4)
+	sendkey_hex[0] = 0;
+	recvkey_hex[0] = 0;
+	ret = sscanf(buf, "%u %u %u %u %d %32s %32s", &rhport, &sockfd, &devid,
+		     &speed, &use_crypto, sendkey_hex, recvkey_hex);
+	if (ret < 1)
 		return -EINVAL;
+	if (use_crypto && strlen(sendkey_hex) == 32 &&
+			strlen(recvkey_hex) == 32) {
+		int i;
+
+		dev_info(dev, "Using encrypted data transport\n");
+		/* Decode decimal representation */
+		for (i = USBIP_KEYSIZE - 1; i >= 0; --i) {
+			sendkey_hex[2 * (i + 1)] = 0;
+			ret = sscanf(sendkey_hex + (2 * i), "%2hhX",
+				     &sendkey[i]);
+			if (ret < 1)
+				return -EINVAL;
+		}
+		for (i = USBIP_KEYSIZE - 1; i >= 0; --i) {
+			recvkey_hex[2 * (i + 1)] = 0;
+			ret = sscanf(recvkey_hex + (2 * i), "%2hhX",
+				     &recvkey[i]);
+			if (ret < 1)
+				return -EINVAL;
+		}
+	}
 
 	usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
 			     rhport, sockfd, devid, speed);
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
index ac73710..ebca98b 100644
--- a/tools/usb/usbip/libsrc/usbip_common.c
+++ b/tools/usb/usbip/libsrc/usbip_common.c
@@ -283,3 +283,18 @@ void usbip_names_get_class(char *buff, size_t size, uint8_t class,
 
 	snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol);
 }
+
+/*
+ * Converts a 16-byte key to hexadecimal to be pushed to kernelspace
+ *
+ * Output buffer must be at least 33 bytes long
+ */
+char *keytohex(unsigned char *key, char *out)
+{
+	int i;
+
+	out[32] = 0;
+	for (i = 0; i != 16; ++i)
+		sprintf(out + (2 * i), "%02X", key[i]);
+	return out;
+}
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h
index 86d21f2..b185c2c 100644
--- a/tools/usb/usbip/libsrc/usbip_common.h
+++ b/tools/usb/usbip/libsrc/usbip_common.h
@@ -156,4 +156,6 @@ void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
 void usbip_names_get_class(char *buff, size_t size, uint8_t class,
 			   uint8_t subclass, uint8_t protocol);
 
+char *keytohex(unsigned char *key, char *out);
+
 #endif /* __USBIP_COMMON_H */
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c
index f7c85da..9ee218e 100644
--- a/tools/usb/usbip/libsrc/usbip_host_driver.c
+++ b/tools/usb/usbip/libsrc/usbip_host_driver.c
@@ -226,7 +226,7 @@ int usbip_host_export_device(struct usbip_exported_device *edev,
 {
 	char attr_name[] = "usbip_sockfd";
 	char sockfd_attr_path[SYSFS_PATH_MAX];
-	char sockfd_buff[30];
+	char sockfd_buff[512];
 	int ret;
 
 	if (edev->status != SDEV_ST_AVAILABLE) {
@@ -244,12 +244,20 @@ int usbip_host_export_device(struct usbip_exported_device *edev,
 		return -1;
 	}
 
+	{
+		char key1[33], key2[33];
+
+		snprintf(sockfd_buff, sizeof(sockfd_buff), "%d %d %s %s\n",
+			 conf->sockfd, conf->use_crypto,
+			 keytohex(conf->key2, key2),
+			 keytohex(conf->key1, key1));
+		dbg("write: %s", sockfd_buff);
+	}
+
 	/* only the first interface is true */
 	snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
 		 edev->udev.path, attr_name);
 
-	snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", conf->sockfd);
-
 	ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
 				    strlen(sockfd_buff));
 	if (ret < 0) {
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index c0928e2..b34e53a 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -300,14 +300,16 @@ int usbip_vhci_get_free_port(void)
 
 int usbip_vhci_attach_device(struct vhci_conf *conf)
 {
-	char buff[200]; /* what size should be ? */
+	char buff[512], key1[33], key2[33];
 	char attach_attr_path[SYSFS_PATH_MAX];
 	char attr_attach[] = "attach";
 	const char *path;
 	int ret;
 
-	snprintf(buff, sizeof(buff), "%u %d %u %u",
-			conf->port, conf->sockfd, conf->devid, conf->speed);
+	snprintf(buff, sizeof(buff), "%u %u %u %u %d %s %s",
+		 conf->port, conf->sockfd, conf->devid, conf->speed,
+		 conf->use_crypto, keytohex(conf->key1, key1),
+		 keytohex(conf->key2, key2));
 	dbg("writing: %s", buff);
 
 	path = udev_device_get_syspath(vhci_driver->hc_device);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 14/18] usbip: Wrap kernel_sendmsg()/recvmsg()
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (12 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 13/18] usbip: Pass session keys to the kernel Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 15/18] usbip: Add encryption support to kernel Maximilian Eschenbacher
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This adds two simple wrappers around kernel_sendmsg() and
kernel_recvmsg() that can be extended to perform additional
cryptographic operations on the data before sending it.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 drivers/usb/usbip/stub_rx.c      |  2 +-
 drivers/usb/usbip/stub_tx.c      |  6 ++--
 drivers/usb/usbip/usbip_common.c | 64 +++++++++++++++++++++-------------------
 drivers/usb/usbip/usbip_common.h |  7 ++++-
 drivers/usb/usbip/vhci_rx.c      |  2 +-
 drivers/usb/usbip/vhci_tx.c      |  4 +--
 6 files changed, 46 insertions(+), 39 deletions(-)

diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c
index 00e475c..64b61bf5 100644
--- a/drivers/usb/usbip/stub_rx.c
+++ b/drivers/usb/usbip/stub_rx.c
@@ -544,7 +544,7 @@ static void stub_rx_pdu(struct usbip_device *ud)
 	memset(&pdu, 0, sizeof(pdu));
 
 	/* receive a pdu header */
-	ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
+	ret = usbip_recv(ud, &pdu, sizeof(pdu));
 	if (ret != sizeof(pdu)) {
 		dev_err(dev, "recv a header, %d\n", ret);
 		usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c
index dbcabc9..06ccbcb 100644
--- a/drivers/usb/usbip/stub_tx.c
+++ b/drivers/usb/usbip/stub_tx.c
@@ -258,8 +258,7 @@ static int stub_send_ret_submit(struct stub_device *sdev)
 			iovnum++;
 		}
 
-		ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg,
-						iov,  iovnum, txsize);
+		ret = usbip_sendmsg(&sdev->ud, &msg, iov, iovnum, txsize);
 		if (ret != txsize) {
 			dev_err(&sdev->interface->dev,
 				"sendmsg failed!, retval %d for %zd\n",
@@ -333,8 +332,7 @@ static int stub_send_ret_unlink(struct stub_device *sdev)
 		iov[0].iov_len  = sizeof(pdu_header);
 		txsize += sizeof(pdu_header);
 
-		ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
-				     1, txsize);
+		ret = usbip_sendmsg(&sdev->ud, &msg, iov, 1, txsize);
 		if (ret != txsize) {
 			dev_err(&sdev->interface->dev,
 				"sendmsg failed!, retval %d for %zd\n",
diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c
index facaaf0..559fe53 100644
--- a/drivers/usb/usbip/usbip_common.c
+++ b/drivers/usb/usbip/usbip_common.c
@@ -322,7 +322,7 @@ void usbip_dump_header(struct usbip_header *pdu)
 EXPORT_SYMBOL_GPL(usbip_dump_header);
 
 /* Receive data over TCP/IP. */
-int usbip_recv(struct socket *sock, void *buf, int size)
+int usbip_recv(struct usbip_device *ud, void *buf, int size)
 {
 	int result;
 	struct msghdr msg;
@@ -335,33 +335,26 @@ int usbip_recv(struct socket *sock, void *buf, int size)
 
 	usbip_dbg_xmit("enter\n");
 
-	if (!sock || !buf || !size) {
-		pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf,
-		       size);
+	if (!ud || !buf || !size) {
+		pr_err("invalid arg, ud %p buff %p size %d\n", ud, buf, size);
 		return -EINVAL;
 	}
 
-	do {
-		sock->sk->sk_allocation = GFP_NOIO;
-		iov.iov_base    = buf;
-		iov.iov_len     = size;
-		msg.msg_name    = NULL;
-		msg.msg_namelen = 0;
-		msg.msg_control = NULL;
-		msg.msg_controllen = 0;
-		msg.msg_flags      = MSG_NOSIGNAL;
-
-		result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);
-		if (result <= 0) {
-			pr_debug("receive sock %p buf %p size %u ret %d total %d\n",
-				 sock, buf, size, result, total);
-			goto err;
-		}
-
-		size -= result;
-		buf += result;
-		total += result;
-	} while (size > 0);
+	ud->tcp_socket->sk->sk_allocation = GFP_NOIO;
+	iov.iov_base    = buf;
+	iov.iov_len     = size;
+	msg.msg_name    = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags      = MSG_NOSIGNAL;
+
+	result = usbip_recvmsg(ud, &msg, &iov, 1, size, MSG_WAITALL);
+	if (result < 0) {
+		pr_debug("receive sock %p buf %p size %u ret %d total %d\n",
+			 ud->tcp_socket, buf, size, result, total);
+		return result;
+	}
 
 	if (usbip_dbg_flag_xmit) {
 		if (!in_interrupt())
@@ -375,9 +368,6 @@ int usbip_recv(struct socket *sock, void *buf, int size)
 			 osize, result, size, total);
 	}
 
-	return total;
-
-err:
 	return result;
 }
 EXPORT_SYMBOL_GPL(usbip_recv);
@@ -591,6 +581,20 @@ static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso,
 	}
 }
 
+int usbip_recvmsg(struct usbip_device *ud, struct msghdr *msg,
+		  struct kvec *vec, size_t num, size_t size, int flags)
+{
+	return kernel_recvmsg(ud->tcp_socket, msg, vec, num, size, flags);
+}
+EXPORT_SYMBOL_GPL(usbip_recvmsg);
+
+int usbip_sendmsg(struct usbip_device *ud, struct msghdr *msg,
+		  struct kvec *vec, size_t num, size_t size)
+{
+	return kernel_sendmsg(ud->tcp_socket, msg, vec, num, size);
+}
+EXPORT_SYMBOL_GPL(usbip_sendmsg);
+
 /* must free buffer */
 struct usbip_iso_packet_descriptor*
 usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen)
@@ -637,7 +641,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
 	if (!buff)
 		return -ENOMEM;
 
-	ret = usbip_recv(ud->tcp_socket, buff, size);
+	ret = usbip_recv(ud, buff, size);
 	if (ret != size) {
 		dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n",
 			ret);
@@ -741,7 +745,7 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
 	if (!(size > 0))
 		return 0;
 
-	ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
+	ret = usbip_recv(ud, urb->transfer_buffer, size);
 	if (ret != size) {
 		dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
 		if (ud->side == USBIP_STUB) {
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
index 69b3f8a..8b0ac52 100644
--- a/drivers/usb/usbip/usbip_common.h
+++ b/drivers/usb/usbip/usbip_common.h
@@ -308,7 +308,7 @@ struct usbip_device {
 void usbip_dump_urb(struct urb *purb);
 void usbip_dump_header(struct usbip_header *pdu);
 
-int usbip_recv(struct socket *sock, void *buf, int size);
+int usbip_recv(struct usbip_device *ui, void *buf, int size);
 
 void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
 		    int pack);
@@ -328,6 +328,11 @@ void usbip_stop_eh(struct usbip_device *ud);
 void usbip_event_add(struct usbip_device *ud, unsigned long event);
 int usbip_event_happened(struct usbip_device *ud);
 
+int usbip_recvmsg(struct usbip_device *ui, struct msghdr *msg,
+		  struct kvec *vec, size_t num, size_t size, int flags);
+int usbip_sendmsg(struct usbip_device *ui, struct msghdr *msg,
+		  struct kvec *vec, size_t num, size_t size);
+
 static inline int interface_to_busnum(struct usb_interface *interface)
 {
 	struct usb_device *udev = interface_to_usbdev(interface);
diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c
index 00e4a54..38cee58 100644
--- a/drivers/usb/usbip/vhci_rx.c
+++ b/drivers/usb/usbip/vhci_rx.c
@@ -205,7 +205,7 @@ static void vhci_rx_pdu(struct usbip_device *ud)
 	memset(&pdu, 0, sizeof(pdu));
 
 	/* receive a pdu header */
-	ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
+	ret = usbip_recv(ud, &pdu, sizeof(pdu));
 	if (ret < 0) {
 		if (ret == -ECONNRESET)
 			pr_info("connection reset by peer\n");
diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c
index 409fd99..09663e6 100644
--- a/drivers/usb/usbip/vhci_tx.c
+++ b/drivers/usb/usbip/vhci_tx.c
@@ -115,7 +115,7 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
 			txsize += len;
 		}
 
-		ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize);
+		ret = usbip_sendmsg(&vdev->ud, &msg, iov, 3, txsize);
 		if (ret != txsize) {
 			pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
 			       txsize);
@@ -184,7 +184,7 @@ static int vhci_send_cmd_unlink(struct vhci_device *vdev)
 		iov[0].iov_len  = sizeof(pdu_header);
 		txsize += sizeof(pdu_header);
 
-		ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
+		ret = usbip_sendmsg(&vdev->ud, &msg, iov, 1, txsize);
 		if (ret != txsize) {
 			pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
 			       txsize);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 15/18] usbip: Add encryption support to kernel
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (13 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 14/18] usbip: Wrap kernel_sendmsg()/recvmsg() Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 16/18] usbip: Update documentation Maximilian Eschenbacher
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

This adds code performing the actual encryption and authentication
operations in the usbip kernel code. The whole data stream may now be
encrypted and authenticated with AES-GCM and symmetric 128 bit keys.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 drivers/usb/usbip/Kconfig        |   2 +-
 drivers/usb/usbip/stub.h         |   3 +
 drivers/usb/usbip/stub_dev.c     |   8 +
 drivers/usb/usbip/usbip_common.c | 351 ++++++++++++++++++++++++++++++++++++++-
 drivers/usb/usbip/usbip_common.h |  22 +++
 drivers/usb/usbip/vhci_hcd.c     |   4 +-
 drivers/usb/usbip/vhci_sysfs.c   |  10 ++
 7 files changed, 396 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig
index bd99e9e..4ad96ef 100644
--- a/drivers/usb/usbip/Kconfig
+++ b/drivers/usb/usbip/Kconfig
@@ -1,6 +1,6 @@
 config USBIP_CORE
 	tristate "USB/IP support"
-	depends on USB && NET
+	depends on USB && NET && CRYPTO_GCM && CRYPTO_AES && CRYPTO_CRYPTD
 	---help---
 	  This enables pushing USB packets over IP to allow remote
 	  machines direct access to USB devices. It provides the
diff --git a/drivers/usb/usbip/stub.h b/drivers/usb/usbip/stub.h
index b2d3d55..0b982d6 100644
--- a/drivers/usb/usbip/stub.h
+++ b/drivers/usb/usbip/stub.h
@@ -26,6 +26,9 @@
 #include <linux/types.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/scatterlist.h>
 
 #define STUB_BUSID_OTHER 0
 #define STUB_BUSID_REMOV 1
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
index d237351..fdfab0f 100644
--- a/drivers/usb/usbip/stub_dev.c
+++ b/drivers/usb/usbip/stub_dev.c
@@ -21,6 +21,7 @@
 #include <linux/file.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
+#include <linux/kfifo.h>
 
 #include "usbip_common.h"
 #include "stub.h"
@@ -118,6 +119,12 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
 
 		spin_unlock_irq(&sdev->ud.lock);
 
+		if (sdev->ud.use_crypto) {
+			err = usbip_init_crypto(&sdev->ud, sendkey, recvkey);
+			if (err < 0)
+				goto err;
+		}
+
 		sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud,
 						  "stub_rx");
 		sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud,
@@ -272,6 +279,7 @@ static void stub_shutdown_connection(struct usbip_device *ud)
 	}
 
 	/* 3. free used data */
+	usbip_deinit_crypto(ud);
 	stub_device_cleanup_urbs(sdev);
 
 	/* 4. free stub_unlink */
diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c
index 559fe53..3610842 100644
--- a/drivers/usb/usbip/usbip_common.c
+++ b/drivers/usb/usbip/usbip_common.c
@@ -26,6 +26,8 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <net/sock.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
 
 #include "usbip_common.h"
 
@@ -581,17 +583,362 @@ static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso,
 	}
 }
 
+int usbip_init_crypto(struct usbip_device *ud, unsigned char *sendkey, unsigned
+		      char *recvkey)
+{
+	int ret;
+
+	ud->use_crypto = 1;
+
+	ud->tfm_recv = crypto_alloc_aead("gcm(aes)", 0, 0);
+	if (IS_ERR(ud->tfm_recv))
+		return PTR_ERR(ud->tfm_recv);
+	ud->tfm_send = crypto_alloc_aead("gcm(aes)", 0, 0);
+	if (IS_ERR(ud->tfm_send)) {
+		ret = PTR_ERR(ud->tfm_send);
+		goto err_free_recv;
+	}
+	ret = kfifo_alloc(&ud->recv_queue, RECVQ_SIZE, GFP_KERNEL);
+	if (ret)
+		goto err_free_send;
+
+	if (crypto_aead_setkey(ud->tfm_send, sendkey, USBIP_KEYSIZE) ||
+	    crypto_aead_setkey(ud->tfm_recv, recvkey, USBIP_KEYSIZE) ||
+	    crypto_aead_setauthsize(ud->tfm_send, USBIP_AUTHSIZE) ||
+	    crypto_aead_setauthsize(ud->tfm_recv, USBIP_AUTHSIZE)) {
+		ret = -EINVAL;
+		goto err_free_fifo;
+	}
+
+	ud->ctr_send = 0;
+	ud->ctr_recv = 0;
+
+	return 0;
+
+err_free_fifo:
+	kfifo_free(&ud->recv_queue);
+err_free_send:
+	crypto_free_aead(ud->tfm_send);
+err_free_recv:
+	crypto_free_aead(ud->tfm_recv);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usbip_init_crypto);
+
+void usbip_deinit_crypto(struct usbip_device *ud)
+{
+	if (ud->use_crypto) {
+		crypto_free_aead(ud->tfm_send);
+		crypto_free_aead(ud->tfm_recv);
+		kfifo_free(&ud->recv_queue);
+		ud->use_crypto = 0;
+	}
+}
+EXPORT_SYMBOL_GPL(usbip_deinit_crypto);
+
+struct tcrypt_result {
+	struct completion completion;
+	int err;
+};
+
+static void tcrypt_complete(struct crypto_async_request *req, int err)
+{
+	struct tcrypt_result *res = req->data;
+
+	if (err == -EINPROGRESS)
+		return;
+
+	res->err = err;
+	complete(&res->completion);
+}
+
+#define USBIP_ENCRYPT 1
+#define USBIP_DECRYPT 0
+/*
+ * Perform encryption/decryption on one chunk of data.
+ * Uses global crypto state stored in usbip_device.
+ * Parameters:
+ * encrypt: USBIP_ENCRYPT to perform encryption, USBIP_DECRYPT to perform
+ * decryption
+ * packetsize: Size of the encrypted packet, including the authentication tag,
+ * not including the associated data (length field).
+ * plaintext and ciphertext have to be appropiately managed by the caller
+ * (i.e. they must be at least packetsize bytes long).
+ * Returns: 0 on success, negative error code on failure
+ */
+static int usbip_crypt(struct usbip_device *ud, int encrypt,
+		uint32_t packetsize, unsigned char *plaintext,
+		unsigned char *ciphertext)
+{
+	struct crypto_aead *tfm;
+	struct aead_request *req;
+	struct tcrypt_result result;
+	struct scatterlist plain, cipher, assoc;
+	char iv[16];
+	u64 *iv_num;
+	u64 iv_net;
+	const int plainsize = packetsize - USBIP_AUTHSIZE;
+	int ret;
+
+	/* Currently, this is guaranteed by the caller */
+	if (packetsize < USBIP_AUTHSIZE)
+		return -EINVAL;
+
+	memset(iv, 0, sizeof(iv));
+	if (encrypt) {
+		tfm = ud->tfm_send;
+		iv_num = &ud->ctr_send;
+	} else {
+		tfm = ud->tfm_recv;
+		iv_num = &ud->ctr_recv;
+	}
+	iv_net = cpu_to_be64(*iv_num);
+	memcpy(iv, &iv_net, sizeof(iv_net));
+
+	req = aead_request_alloc(tfm, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	init_completion(&result.completion);
+	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				  tcrypt_complete, &result);
+
+	sg_init_one(&cipher, ciphertext, packetsize);
+	sg_init_one(&plain, plaintext, plainsize);
+	crypto_aead_clear_flags(tfm, ~0);
+
+	if (encrypt)
+		aead_request_set_crypt(req, &plain, &cipher, plainsize, iv);
+	else
+		aead_request_set_crypt(req, &cipher, &plain, packetsize, iv);
+	packetsize = cpu_to_be32(packetsize);
+	sg_init_one(&assoc, &packetsize, sizeof(packetsize));
+	/* Associated data: Unencrypted length tag */
+	aead_request_set_assoc(req, &assoc, sizeof(packetsize));
+
+	if (encrypt)
+		ret = crypto_aead_encrypt(req);
+	else
+		ret = crypto_aead_decrypt(req);
+
+	switch (ret) {
+	case 0: /* Success */
+		break;
+	case -EINPROGRESS:
+	case -EBUSY:
+		wait_for_completion(&result.completion);
+		ret = result.err;
+		break;
+	default:
+		aead_request_free(req);
+		return ret;
+	}
+
+	aead_request_free(req);
+
+	(*iv_num)++; /* Increment IV */
+
+	return ret;
+}
+
+/*
+ * Wrapper to kernel_recvmsg. If necessary, also does the necessary decryption.
+ * If decryption is enabled, you _MUST_ pass 1 as parameter for num, i.e.
+ * only receive into a single continuous buffer.
+ */
 int usbip_recvmsg(struct usbip_device *ud, struct msghdr *msg,
 		  struct kvec *vec, size_t num, size_t size, int flags)
 {
-	return kernel_recvmsg(ud->tcp_socket, msg, vec, num, size, flags);
+	int ret;
+	size_t total = 0;
+	unsigned char *plainbuf, *cipherbuf;
+
+	if (!ud->use_crypto)
+		return kernel_recvmsg(ud->tcp_socket, msg, vec, num, size,
+				      flags);
+
+	if (vec[0].iov_len < size)
+		return -EINVAL;
+	if (num != 1)
+		return -EINVAL;
+
+	plainbuf = kmalloc(USBIP_PACKETSIZE, GFP_KERNEL);
+	if (!plainbuf)
+		return -ENOMEM;
+	cipherbuf = kmalloc(USBIP_PACKETSIZE, GFP_KERNEL);
+	if (!cipherbuf) {
+		kfree(plainbuf);
+		return -ENOMEM;
+	}
+
+	while (total < size) {
+		uint32_t packetsize;
+		struct kvec recvvec;
+
+		/*
+		 * We use a global kfifo to buffer unrequested plaintext bytes.
+		 * Flush this buffer first before receiving new data.
+		 */
+		if (kfifo_len(&ud->recv_queue)) {
+			size_t next = min_t(size_t, kfifo_len(&ud->recv_queue),
+					    size - total);
+			/* No error checking necessary - see previous line */
+			ret = kfifo_out(&ud->recv_queue,
+					vec[0].iov_base + total, next);
+			total += next;
+			continue;
+		}
+
+		/* See usbip_sendmsg() for the format of one encrypted packet */
+
+		/*
+		 * Receive size of next crypto packet
+		 */
+		recvvec.iov_base = &packetsize;
+		recvvec.iov_len = sizeof(packetsize);
+
+		ret = kernel_recvmsg(ud->tcp_socket, msg, &recvvec, 1,
+				     sizeof(packetsize), flags);
+		packetsize = be32_to_cpu(packetsize);
+		if (ret < 0) {
+			total = ret;
+			goto err;
+		} else if (ret != sizeof(packetsize)) {
+			total = -EBADMSG;
+			goto err;
+		}
+
+		if (packetsize > USBIP_PACKETSIZE) {
+			total = -EBADMSG;
+			goto err;
+		}
+
+		/*
+		 * Receive the rest of the packet
+		 */
+		recvvec.iov_base = cipherbuf;
+		recvvec.iov_len = packetsize;
+		ret = kernel_recvmsg(ud->tcp_socket, msg, &recvvec, 1,
+				packetsize, flags);
+		if (ret <= 0) {
+			total = ret;
+			goto err;
+		} else if (ret != packetsize) {
+			total = -EBADMSG;
+			goto err;
+		}
+
+		/*
+		 * Decrypt the packet. This will also authenticate the length
+		 * field
+		 */
+		ret = usbip_crypt(ud, 0, packetsize, plainbuf, cipherbuf);
+		if (ret != 0) {
+			total = ret;
+			goto err;
+		}
+
+		/*
+		 * Add this packet to our global buffer (It will be stored in
+		 * the user buffer in the next loop iteration) No error
+		 * checking necessary - we already know the packet is going to
+		 * fit.
+		 */
+		(void) kfifo_in(&ud->recv_queue, plainbuf, packetsize -
+				USBIP_AUTHSIZE);
+	}
+
+err:
+	kfree(plainbuf);
+	kfree(cipherbuf);
+
+	return total;
 }
 EXPORT_SYMBOL_GPL(usbip_recvmsg);
 
 int usbip_sendmsg(struct usbip_device *ud, struct msghdr *msg,
 		  struct kvec *vec, size_t num, size_t size)
 {
-	return kernel_sendmsg(ud->tcp_socket, msg, vec, num, size);
+	int i = 0, ret, offset = 0;
+	size_t total = 0;
+	unsigned char *cipherbuf;
+
+	/* If crypto is disabled, we just wrap the normal kernel calls. */
+	if (!ud->use_crypto)
+		return kernel_sendmsg(ud->tcp_socket, msg, vec, num, size);
+
+	cipherbuf = kmalloc(USBIP_PACKETSIZE, GFP_KERNEL);
+	if (!cipherbuf)
+		return -ENOMEM;
+
+	/*
+	 * The receiver has to decrypt whole packets. To avoid the need
+	 * to allocate large buffers at the receiving side, we split the
+	 * data to be sent in USBIP_PACKETSIZE large chunks that can be
+	 * decrypted separately. See below for the format of each chunk.
+	 */
+
+	/* Iterate over all kvecs, splitting them up as necessary. */
+	for (i = 0; i != num && size; ) {
+		/* Compute the remaining number of bytes to send for
+		 * this kvec */
+		const size_t PLAIN_SIZE = min_t(size_t, vec[i].iov_len - offset,
+				min_t(size_t, size,
+				      USBIP_PACKETSIZE - USBIP_AUTHSIZE));
+		const size_t PACKET_SIZE = PLAIN_SIZE + USBIP_AUTHSIZE;
+		uint32_t packet_size_net = cpu_to_be32(PACKET_SIZE);
+		struct kvec sendvec[2];
+
+		if (PLAIN_SIZE == 0) {
+			++i;
+			offset = 0;
+			continue;
+		}
+
+		/*
+		 * One encrypted packet consists of:
+		 *  - An unencrypted, authenticated length tag (exactly 4
+		 *    bytes) containing the length of the packet.
+		 *  - Up to USBIP_PACKETSIZE - USBIP_AUTHSIZE bytes of user
+		 *    payload, encrypted
+		 *  - Exactly USBIP_AUTHSIZE bytes authentication tag.
+		 * Note: The packet length is also authenticated, but has
+		 * - for obvious reasons - to be sent in plaintext. This
+		 * packet format will be parsed by usbip_recvmsg (see above).
+		 */
+		ret = usbip_crypt(ud, 1, PACKET_SIZE, vec[i].iov_base + offset,
+				  cipherbuf);
+		if (ret != 0) {
+			kfree(cipherbuf);
+			return ret;
+		}
+
+		/* Length field */
+		sendvec[0].iov_base = &packet_size_net;
+		sendvec[0].iov_len = sizeof(packet_size_net);
+		/* Payload and authentication tag */
+		sendvec[1].iov_base = cipherbuf;
+		sendvec[1].iov_len = PACKET_SIZE;
+		ret = kernel_sendmsg(ud->tcp_socket, msg, sendvec,
+				     ARRAY_SIZE(sendvec), sendvec[0].iov_len +
+				     sendvec[1].iov_len);
+		if (ret < 0) {
+			kfree(cipherbuf);
+			return ret;
+		}
+		if (ret != sendvec[0].iov_len + sendvec[1].iov_len) {
+			kfree(cipherbuf);
+			return -EPROTO;
+		}
+		offset += PLAIN_SIZE;
+		size -= PLAIN_SIZE;
+		total += PLAIN_SIZE;
+	}
+
+	kfree(cipherbuf);
+
+	return total;
 }
 EXPORT_SYMBOL_GPL(usbip_sendmsg);
 
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
index 8b0ac52..6831d99 100644
--- a/drivers/usb/usbip/usbip_common.h
+++ b/drivers/usb/usbip/usbip_common.h
@@ -30,15 +30,28 @@
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include <uapi/linux/usbip.h>
+#include <linux/kfifo.h>
 
 #define USBIP_VERSION "1.0.0"
 
 /*
+ * Length of the authentication tag associated with each packet, in bytes. Can
+ * be set to 4, 8, 12, 13, 14, 15 or 16. See crypto_gcm_setauthsize in
+ * crypto/gcm.c. Increasing this will increase crypto protocol overhead.
+ */
+#define USBIP_AUTHSIZE 4
+/*
  * Length of symmetric keys. Currently, this should be fixed at 16 bytes.
  * Will break code if changed, look at userspace and stub_dev.c/vhci_sysfs.c
  * where this constant is used before changing.
  */
 #define USBIP_KEYSIZE 16
+/*
+ * Maximum size of encrypted packets. Decreasing this will increase overhead
+ * and decrease memory usage.
+ */
+#define USBIP_PACKETSIZE 1024
+#define RECVQ_SIZE (2*USBIP_PACKETSIZE)
 
 #undef pr_fmt
 
@@ -285,6 +298,11 @@ struct usbip_device {
 
 	/* Crypto support */
 	int use_crypto;
+	struct crypto_aead *tfm_recv;
+	struct crypto_aead *tfm_send;
+	/* Counters to be used as IVs */
+	u64 ctr_send, ctr_recv;
+	DECLARE_KFIFO_PTR(recv_queue, char);
 };
 
 #define kthread_get_run(threadfn, data, namefmt, ...)			   \
@@ -308,6 +326,10 @@ struct usbip_device {
 void usbip_dump_urb(struct urb *purb);
 void usbip_dump_header(struct usbip_header *pdu);
 
+int usbip_init_crypto(struct usbip_device *ud, unsigned char *sendkey,
+		unsigned char *recvkey);
+void usbip_deinit_crypto(struct usbip_device *ud);
+
 int usbip_recv(struct usbip_device *ui, void *buf, int size);
 
 void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index c02374b..13db326 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -785,7 +785,9 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
 		kthread_stop_put(vdev->ud.tcp_tx);
 		vdev->ud.tcp_tx = NULL;
 	}
-	pr_info("stop threads\n");
+	pr_info("stopped threads\n");
+
+	usbip_deinit_crypto(&vdev->ud);
 
 	/* active connection is closed */
 	if (vdev->ud.tcp_socket) {
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index fa948ad..19d6141 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -20,6 +20,8 @@
 #include <linux/kthread.h>
 #include <linux/file.h>
 #include <linux/net.h>
+#include <linux/crypto.h>
+#include <linux/kfifo.h>
 
 #include "usbip_common.h"
 #include "vhci.h"
@@ -237,6 +239,13 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 	/* begin a lock */
 	spin_lock(&the_controller->lock);
 	vdev = port_to_vdev(rhport);
+	if (use_crypto) {
+		ret = usbip_init_crypto(&vdev->ud, sendkey, recvkey);
+		if (ret < 0) {
+			spin_unlock(&the_controller->lock);
+			return ret;
+		}
+	}
 	spin_lock(&vdev->ud.lock);
 
 	if (vdev->ud.status != VDEV_ST_NULL) {
@@ -247,6 +256,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 		sockfd_put(socket);
 
 		dev_err(dev, "port %d already used\n", rhport);
+		usbip_deinit_crypto(&vdev->ud);
 		return -EINVAL;
 	}
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 16/18] usbip: Update documentation
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (14 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 15/18] usbip: Add encryption support to kernel Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-16 23:38 ` [PATCH 17/18] usbip: Increment version number to 1.2.1 Maximilian Eschenbacher
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Tobias Polzer,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Dominik Paulus

From: Tobias Polzer <tobias.polzer@fau.de>

README was updated and cleaned. It now contains just one example, which
was updated to use encryption. Also, the new crypto behaviour is
documented. The usbip "port" command has been removed from the README,
as it isn't supported by newer userland versions. One dead link was
removed from the checklist section.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
---
 tools/usb/usbip/README       | 72 +++++++++++++++++---------------------------
 tools/usb/usbip/doc/usbip.8  |  2 ++
 tools/usb/usbip/doc/usbipd.8 |  4 ++-
 3 files changed, 33 insertions(+), 45 deletions(-)

diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README
index 831f49f..ebb194b 100644
--- a/tools/usb/usbip/README
+++ b/tools/usb/usbip/README
@@ -12,13 +12,15 @@
     - libudev >= 2.0
 	libudev library
 
-    - libwrap0-dev
+    - libwrap0-dev (optional)
 	tcp wrapper library
 
     - gcc >= 4.0
 
     - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config
 
+    - libgnutls-dev >= 3.0 (libgnutls28-dev on debian) (optional)
+
 [Optional]
     - hwdata
         Contains USB device identification data.
@@ -29,43 +31,38 @@
 	$ ./autogen.sh
 
     1. Compile & install the userspace utilities.
-	$ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=<dir>]
+	$ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=<dir>] [--with-gnutls]
 	$ make install
 
     2. Compile & install USB/IP drivers.
 
 
 [Usage]
-    server:# (Physically attach your USB device.)
-
-    server:# insmod usbip-core.ko
-    server:# insmod usbip-host.ko
-
-    server:# usbipd -D
-	- Start usbip daemon.
-
-    server:# usbip list -l
-	- List driver assignments for USB devices.
 
-    server:# usbip bind --busid 1-2
-	- Bind usbip-host.ko to the device with busid 1-2.
-	- The USB device 1-2 is now exportable to other hosts!
-	- Use `usbip unbind --busid 1-2' to stop exporting the device.
+See usbip(8) and usbipd(8).
 
-    client:# insmod usbip-core.ko
-    client:# insmod vhci-hcd.ko
+[Security considerations]
+By default, all of the usbip network traffic is unencrypted and
+unauthenticated. As it is mostly parsed in staging quality kernel code, you
+should use usbip in this mode only in absolutely trusted environments.
 
-    client:# usbip list --remote <host>
-	- List exported USB devices on the <host>.
+In addition to the usual methods for secure network tunneling - SSH tunnels,
+IPsec, etc. -, usbip version 1.2.1 supports out-of-the-box crypto for all of
+the network traffic. This requires usbip to be compiled with GnuTLS enabled
+(configure switch: --with-gnutls). Crypto support can be enabled by using
+password authentication. If the --auth flag is set, usbip will not only
+authenticate client and server using the shared passphrase, but also encrypt
+and authenticate all of the following traffic. For the userspace traffic,
+GnuTLS is used, the kernel traffic is encrypted and authenticated using AES-GCM
+with 128bit keys. The session keys are randomly generated and exchanged for
+in userspace for each connection.
 
-    client:# usbip attach --remote <host> --busid 1-2
-	- Connect the remote USB device.
-
-    client:# usbip port
-	- Show virtual port status.
-
-    client:# usbip detach --port <port>
-	- Detach the USB device.
+The encryption support has been designed to offer perfect forward secrecy and
+decent security even if using rather weak passwords. Strong passwords are
+mainly needed to provide proper authorization (this is still important, see
+above!) and to secure against man-in-the-middle attacks.
+However, the crypto code still lacks complete review and code auditing. Do not
+rely on it for strong security.
 
 
 [Example]
@@ -76,7 +73,7 @@ Physically attach your USB devices to this host.
 
     trois:# insmod path/to/usbip-core.ko
     trois:# insmod path/to/usbip-host.ko
-    trois:# usbipd -D
+    trois:# usbipd -sVerySecret -D
 
 In another terminal, let's look up what USB devices are physically
 attached to this host.
@@ -139,7 +136,7 @@ exportable on the host.
     deux:# insmod path/to/usbip-core.ko
     deux:# insmod path/to/vhci-hcd.ko
 
-    deux:# usbip list --remote 10.0.0.3
+    deux:# usbip --auth VerySecret list --remote 10.0.0.3
     Exportable USB devices
     ======================
      - 10.0.0.3
@@ -167,20 +164,9 @@ exportable on the host.
 
 Attach a remote USB device:
 
-    deux:# usbip attach --remote 10.0.0.3 --busid 1-1
+    deux:# usbip --auth VerySecret attach --remote 10.0.0.3 --busid 1-1
     port 0 attached
 
-Show the devices attached to this client:
-
-    deux:# usbip port
-    Port 00: <Port in Use> at Full Speed(12Mbps)
-	   Prolific Technology, Inc. : unknown product (067b:3507)
-	   6-1 -> usbip://10.0.0.3:3240/1-1  (remote bus/dev 001/004)
-	   6-1:1.0 used by usb-storage
-			  /sys/class/scsi_device/0:0:0:0/device
-			  /sys/class/scsi_host/host0/device
-			  /sys/block/sda/device
-
 Detach the imported device:
 
     deux:# usbip detach --port 0
@@ -188,8 +174,6 @@ Detach the imported device:
 
 
 [Checklist]
-    - See 'Debug Tips' on the project wiki.
-	- http://usbip.wiki.sourceforge.net/how-to-debug-usbip
     - usbip-host.ko must be bound to the target device.
 	- See /proc/bus/usb/devices and find "Driver=..." lines of the device.
     - Shutdown firewall.
diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
index c7ba36f..b818bde 100644
--- a/tools/usb/usbip/doc/usbip.8
+++ b/tools/usb/usbip/doc/usbip.8
@@ -27,7 +27,9 @@ Log to syslog.
 \fB\-\-tcp-port PORT\fR
 .IP
 Connect to PORT on remote host (used for attach and list --remote).
+.PP
 
+.HP
 \fB\-\-auth\fR
 .IP
 Set the password to be used for client authentication. See usbipd(8) for more information.
diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8
index 8beb95a..3fcd9ed 100644
--- a/tools/usb/usbip/doc/usbipd.8
+++ b/tools/usb/usbip/doc/usbipd.8
@@ -56,7 +56,9 @@ Listen on TCP/IP port PORT.
 .HP
 \fB\-s\fR, \fB\-\-auth\fR
 .IP
-Sets the password to be used for client authentication. If -a is used, the server will only accept connections from authenticated clients. Note: USB traffic will still be unencrypted, this currently only serves for authentication.
+Sets the password to be used for client authentication. If -a is used, the
+server will only accept connections from authenticated clients. This will also
+encrypt the whole usbip traffic, including kernel traffic, using 128bit AES.
 .PP
 
 \fB\-h\fR, \fB\-\-help\fR
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 17/18] usbip: Increment version number to 1.2.1
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (15 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 16/18] usbip: Update documentation Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-17 17:51   ` Denys Vlasenko
  2014-09-16 23:38 ` [PATCH 18/18] usbip: list.h include stddef.h for offsetof Maximilian Eschenbacher
  2014-09-26 11:56 ` [PATCH 00/18] usbip: Crypto and ACLs Valentina Manea
  18 siblings, 1 reply; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Dominik Paulus,
	Maximilian Eschenbacher, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

From: Dominik Paulus <dominik.paulus@fau.de>

Also increment the kernel module version number to match the
userspace version, as compatibility with old userspace utilities
is now at least partially broken.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
---
 drivers/usb/usbip/usbip_common.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
index 6831d99..a5f416e 100644
--- a/drivers/usb/usbip/usbip_common.h
+++ b/drivers/usb/usbip/usbip_common.h
@@ -32,7 +32,7 @@
 #include <uapi/linux/usbip.h>
 #include <linux/kfifo.h>
 
-#define USBIP_VERSION "1.0.0"
+#define USBIP_VERSION "1.2.1"
 
 /*
  * Length of the authentication tag associated with each packet, in bytes. Can
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 18/18] usbip: list.h include stddef.h for offsetof
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (16 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 17/18] usbip: Increment version number to 1.2.1 Maximilian Eschenbacher
@ 2014-09-16 23:38 ` Maximilian Eschenbacher
  2014-09-26 11:56 ` [PATCH 00/18] usbip: Crypto and ACLs Valentina Manea
  18 siblings, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-09-16 23:38 UTC (permalink / raw)
  To: linux-kernel
  Cc: valentina.manea.m, shuah.kh, gregkh, Maximilian Eschenbacher,
	Fjodor Schelichow, Johannes Stadlinger

Remove offsetof macro from list.h and use builtin macro defined in
stddef.h to avoid multiple declaration error in gcc 4.7.

Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
---
 tools/usb/usbip/libsrc/list.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/usb/usbip/libsrc/list.h b/tools/usb/usbip/libsrc/list.h
index 8d0c936..a3dca5a 100644
--- a/tools/usb/usbip/libsrc/list.h
+++ b/tools/usb/usbip/libsrc/list.h
@@ -15,6 +15,8 @@
  * using the generic single-entry routines.
  */
 
+#include <stddef.h>
+
 struct list_head {
 	struct list_head *next, *prev;
 };
@@ -120,7 +122,6 @@ static inline void list_del(struct list_head *entry)
 	for (pos = (head)->next, n = pos->next; pos != (head); \
 		pos = n, n = pos->next)
 
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 
 /**
  * container_of - cast a member of a structure out to the containing structure
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 17/18] usbip: Increment version number to 1.2.1
  2014-09-16 23:38 ` [PATCH 17/18] usbip: Increment version number to 1.2.1 Maximilian Eschenbacher
@ 2014-09-17 17:51   ` Denys Vlasenko
  2014-09-18 15:31     ` Fjodor Schelichow
  0 siblings, 1 reply; 31+ messages in thread
From: Denys Vlasenko @ 2014-09-17 17:51 UTC (permalink / raw)
  To: Maximilian Eschenbacher
  Cc: linux-kernel, valentina.manea.m, shuah.kh, gregkh,
	Dominik Paulus, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

On Wednesday 17 September 2014 01:38, Maximilian Eschenbacher wrote:
> From: Dominik Paulus <dominik.paulus@fau.de>
> 
> Also increment the kernel module version number to match the
> userspace version, as compatibility with old userspace utilities
> is now at least partially broken.
> 
> Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
> Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
> Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
> Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
> Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
> ---
>  drivers/usb/usbip/usbip_common.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
> index 6831d99..a5f416e 100644
> --- a/drivers/usb/usbip/usbip_common.h
> +++ b/drivers/usb/usbip/usbip_common.h
> @@ -32,7 +32,7 @@
>  #include <uapi/linux/usbip.h>
>  #include <linux/kfifo.h>
>  
> -#define USBIP_VERSION "1.0.0"
> +#define USBIP_VERSION "1.2.1"

You can use UTS_RELEASE instead - it would handle the task of identifying
the version of running code as good, or better, than a subsystem-specific
version id.
For one, as this patch attests, subsystem-specific ids tend to become stale...

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 17/18] usbip: Increment version number to 1.2.1
  2014-09-17 17:51   ` Denys Vlasenko
@ 2014-09-18 15:31     ` Fjodor Schelichow
  0 siblings, 0 replies; 31+ messages in thread
From: Fjodor Schelichow @ 2014-09-18 15:31 UTC (permalink / raw)
  To: Denys Vlasenko, Maximilian Eschenbacher
  Cc: linux-kernel, valentina.manea.m, shuah.kh, gregkh,
	Dominik Paulus, Johannes Stadlinger, Tobias Polzer, i4passt

On 09/17/2014 07:51 PM, Denys Vlasenko wrote:
> On Wednesday 17 September 2014 01:38, Maximilian Eschenbacher wrote:
>> From: Dominik Paulus <dominik.paulus@fau.de>
>> diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
>> index 6831d99..a5f416e 100644
>> --- a/drivers/usb/usbip/usbip_common.h
>> +++ b/drivers/usb/usbip/usbip_common.h
>> @@ -32,7 +32,7 @@
>>   #include <uapi/linux/usbip.h>
>>   #include <linux/kfifo.h>
>>
>> -#define USBIP_VERSION "1.0.0"
>> +#define USBIP_VERSION "1.2.1"
>
> You can use UTS_RELEASE instead - it would handle the task of identifying
> the version of running code as good, or better, than a subsystem-specific
> version id.
> For one, as this patch attests, subsystem-specific ids tend to become stale...
>
After a some discussion we decided to change it according to your 
suggestion. Thanks for that!

regards
Fjodor

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 02/18] usbip: Add support for client authentication
  2014-09-16 23:38 ` [PATCH 02/18] usbip: Add support for client authentication Maximilian Eschenbacher
@ 2014-09-21  0:42   ` Max Vozeler
  2014-09-21 12:43     ` Dominik Paulus
  2014-10-03 14:16   ` Valentina Manea
  1 sibling, 1 reply; 31+ messages in thread
From: Max Vozeler @ 2014-09-21  0:42 UTC (permalink / raw)
  To: Maximilian Eschenbacher
  Cc: linux-kernel, valentina.manea.m, shuah.kh, gregkh,
	Dominik Paulus, Fjodor Schelichow, Johannes Stadlinger,
	Tobias Polzer

Hi,

On Tue, Sep 16, 2014 at 11:38:39PM +0000, Maximilian Eschenbacher wrote:
> From: Dominik Paulus <dominik.paulus@fau.de>
> 
> This patch adds support for authenticating both client and server using
> a pre-shared passphrase using SRP (Secure Remote Password) over TLS (see
> RFC 5054) using GnuTLS. Both usbip and usbipd now accept a shared secret
> as a command line argument.

The command line is not a good fit for passing secrets.

There is no way for the caller to provide the passphrase securely
because anything in the command line can be seen by other local users.

I suggest to read the passphrase from a file instead.

> Currently, the established TLS connection is
> only used to perform a secure handshake and dropped before the socket is
> passed to the kernel. The code may be extended to exchange a session key
> over TLS and pass it to the kernel to perform IPsec.
> 
> Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
> Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
> Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
> Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
> Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
> ---
>  tools/usb/usbip/configure.ac        |  14 +++
>  tools/usb/usbip/doc/usbip.8         |   4 +
>  tools/usb/usbip/doc/usbipd.8        |   5 +
>  tools/usb/usbip/src/usbip.c         |  30 +++++-
>  tools/usb/usbip/src/usbip_attach.c  |   2 +-
>  tools/usb/usbip/src/usbip_list.c    |   2 +-
>  tools/usb/usbip/src/usbip_network.c | 185 ++++++++++++++++++++++++++++++++++++
>  tools/usb/usbip/src/usbip_network.h |  11 ++-
>  tools/usb/usbip/src/usbipd.c        | 115 ++++++++++++++++------
>  9 files changed, 335 insertions(+), 33 deletions(-)
> 
> diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac
> index 607d05c..6a8156f 100644
> --- a/tools/usb/usbip/configure.ac
> +++ b/tools/usb/usbip/configure.ac
> @@ -83,6 +83,20 @@ AC_ARG_WITH([tcp-wrappers],
>  		AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])],
>  	       [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])])
>  
> +# Checks for the GnuTLS library
> +AC_ARG_WITH([gnutls],
> +			[AS_HELP_STRING([--with-gnutls],
> +							[use the GnuTLS library for authentication])],
> +			dnl [ACTION-IF-GIVEN]
> +			[if test "$withval" = "yes"; then
> +			 PKG_CHECK_MODULES([GNUTLS], [gnutls])

GnuTLS version 2.12 passes this configure test but then fails during the
build. Please check for the minimum version here:

 +			 PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.0])

> +			 AC_DEFINE([HAVE_GNUTLS], [1], [use gnutls])
> +			 CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
> +			 LDFLAGS="$LDFLAGS $GNUTLS_LIBS"
> +			 fi
> +			],
> +			)
> +
>  # Sets directory containing usb.ids.
>  AC_ARG_WITH([usbids-dir],
>  	    [AS_HELP_STRING([--with-usbids-dir=DIR],
> diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
> index a6097be..847aa40 100644
> --- a/tools/usb/usbip/doc/usbip.8
> +++ b/tools/usb/usbip/doc/usbip.8
> @@ -27,6 +27,10 @@ Log to syslog.
>  \fB\-\-tcp-port PORT\fR
>  .IP
>  Connect to PORT on remote host (used for attach and list --remote).
> +
> +\fB\-\-auth\fR
> +.IP
> +Set the password to be used for client authentication. See usbipd(8) for more information.
>  .PP
>  
>  .SH COMMANDS
> diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8
> index ac4635d..8beb95a 100644
> --- a/tools/usb/usbip/doc/usbipd.8
> +++ b/tools/usb/usbip/doc/usbipd.8
> @@ -52,6 +52,11 @@ If no FILE specified, use /var/run/usbipd.pid
>  \fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR
>  .IP
>  Listen on TCP/IP port PORT.
> +
> +.HP
> +\fB\-s\fR, \fB\-\-auth\fR
> +.IP
> +Sets the password to be used for client authentication. If -a is used, the server will only accept connections from authenticated clients. Note: USB traffic will still be unencrypted, this currently only serves for authentication.
>  .PP
>  
>  \fB\-h\fR, \fB\-\-help\fR
> diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
> index d7599d9..cd7e420 100644
> --- a/tools/usb/usbip/src/usbip.c
> +++ b/tools/usb/usbip/src/usbip.c
> @@ -25,6 +25,12 @@
>  #include <getopt.h>
>  #include <syslog.h>
>  
> +#include "../config.h"
> +
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +#endif
> +
>  #include "usbip_common.h"
>  #include "usbip_network.h"
>  #include "usbip.h"
> @@ -35,8 +41,12 @@ static int usbip_version(int argc, char *argv[]);
>  static const char usbip_version_string[] = PACKAGE_STRING;
>  
>  static const char usbip_usage_string[] =
> -	"usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
> -	"             [help] <command> <args>\n";
> +	"usbip "
> +#ifdef HAVE_GNUTLS
> +	"[--auth PASSWORD] "
> +#endif
> +	"[--debug] [--log] [--tcp-port PORT]\n"
> +	"             [version] [help] <command> <args>\n";
>  
>  static void usbip_usage(void)
>  {
> @@ -148,6 +158,7 @@ int main(int argc, char *argv[])
>  		{ "debug",    no_argument,       NULL, 'd' },
>  		{ "log",      no_argument,       NULL, 'l' },
>  		{ "tcp-port", required_argument, NULL, 't' },
> +		{ "auth",     required_argument, NULL, 's' },
>  		{ NULL,       0,                 NULL,  0  }
>  	};
>  
> @@ -158,12 +169,25 @@ int main(int argc, char *argv[])
>  	usbip_use_stderr = 1;
>  	opterr = 0;
>  	for (;;) {
> -		opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
> +		opt = getopt_long(argc, argv, "+dls:t:", opts, NULL);
>  
>  		if (opt == -1)
>  			break;
>  
>  		switch (opt) {
> +		case 's':
> +#ifdef HAVE_GNUTLS
> +			usbip_srp_password = optarg;
> +			rc = gnutls_global_init();
> +			if (rc < 0) {
> +				err("Unable to initialize GnuTLS library: %s",
> +				    gnutls_strerror(rc));
> +				return EXIT_FAILURE;
> +			}

The initialization may be better placed outside the getopt loop or it
could be called multiple times.

> +#else
> +			err("usbip has been compiled without GnuTLS support");
> +#endif
> +			break;
>  		case 'd':
>  			usbip_use_debug = 1;
>  			break;
> diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
> index d58a14d..4421ebc 100644
> --- a/tools/usb/usbip/src/usbip_attach.c
> +++ b/tools/usb/usbip/src/usbip_attach.c
> @@ -175,7 +175,7 @@ static int attach_device(char *host, char *busid)
>  	int rc;
>  	int rhport;
>  
> -	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
> +	sockfd = usbip_net_connect(host);
>  	if (sockfd < 0) {
>  		err("tcp connect");
>  		return -1;
> diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
> index d5ce34a..6042b7e 100644
> --- a/tools/usb/usbip/src/usbip_list.c
> +++ b/tools/usb/usbip/src/usbip_list.c
> @@ -132,7 +132,7 @@ static int list_exported_devices(char *host)
>  	int rc;
>  	int sockfd;
>  
> -	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
> +	sockfd = usbip_net_connect(host);
>  	if (sockfd < 0) {
>  		err("could not connect to %s:%s: %s", host,
>  		    usbip_port_string, gai_strerror(sockfd));
> diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
> index b4c37e7..6b8f949 100644
> --- a/tools/usb/usbip/src/usbip_network.c
> +++ b/tools/usb/usbip/src/usbip_network.c
> @@ -29,11 +29,20 @@
>  #include <tcpd.h>
>  #endif
>  
> +#include "../config.h"
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +#include <gnutls/crypto.h>
> +#endif
> +
>  #include "usbip_common.h"
>  #include "usbip_network.h"
>  
>  int usbip_port = 3240;
>  char *usbip_port_string = "3240";
> +#ifdef HAVE_GNUTLS
> +char *usbip_srp_password;
> +#endif
>  
>  void usbip_setup_port_number(char *arg)
>  {
> @@ -301,3 +310,179 @@ int usbip_net_tcp_connect(char *hostname, char *service)
>  
>  	return sockfd;
>  }
> +
> +#ifdef HAVE_GNUTLS
> +static gnutls_datum_t usbip_net_srp_salt, usbip_net_srp_verifier;
> +static gnutls_srp_server_credentials_t usbip_net_srp_cred;
> +
> +#define SRP_GROUP gnutls_srp_2048_group_generator
> +#define SRP_PRIME gnutls_srp_2048_group_prime
> +
> +int usbip_net_srp_client_handshake(int sockfd)
> +{
> +	int ret;
> +	gnutls_session_t session;
> +	gnutls_srp_client_credentials_t usbip_net_srp_cred;
> +
> +	ret = gnutls_srp_allocate_client_credentials(&usbip_net_srp_cred);
> +	if (ret < 0)
> +		return ret;
> +
> +	gnutls_srp_set_client_credentials(usbip_net_srp_cred, "dummyuser",
> +		usbip_srp_password);
>
> +	ret = gnutls_init(&session, GNUTLS_CLIENT);
> +	if (ret < 0) {
> +		gnutls_srp_free_client_credentials(usbip_net_srp_cred);
> +		return ret;
> +	}
> +
> +	gnutls_priority_set_direct(session, "NORMAL:+SRP", NULL);
> +
> +	gnutls_credentials_set(session, GNUTLS_CRD_SRP, usbip_net_srp_cred);
> +	gnutls_transport_set_int (session, sockfd);
> +
> +	do {
> +		ret = gnutls_handshake(session);
> +	} while (ret < 0 && !gnutls_error_is_fatal(ret));
> +
> +	gnutls_bye(session, GNUTLS_SHUT_RDWR);
> +
> +	gnutls_deinit(session);
> +	gnutls_srp_free_client_credentials(usbip_net_srp_cred);
> +
> +	return ret;
> +}
> +
> +int net_srp_server_handshake(int connfd)
> +{
> +	int ret;
> +	gnutls_session_t session;
> +
> +	if (gnutls_init(&session, GNUTLS_SERVER) != 0)
> +		return -1;
> +	gnutls_priority_set_direct(session, "NORMAL:-KX-ALL:+SRP", NULL);
> +	ret = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
> +				     usbip_net_srp_cred);
> +	if (!ret)
> +		return -1;
> +
> +	gnutls_transport_set_int(session, connfd);
> +
> +	do {
> +		ret = gnutls_handshake(session);
> +	} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
> +
> +	if (ret < 0)
> +		err("GnuTLS handshake failed (%s)", gnutls_strerror(ret));
> +	else
> +		info("GnuTLS handshake completed");
> +
> +	if (gnutls_bye(session, GNUTLS_SHUT_RDWR) != 0)
> +		err("Unable to shutdown TLS connection.");
> +	gnutls_deinit(session);
> +
> +	return ret;
> +}
> +
> +static int net_srp_callback(gnutls_session_t sess, const char *username,
> +	gnutls_datum_t *nsalt, gnutls_datum_t *nverifier, gnutls_datum_t *g,
> +	gnutls_datum_t *n)
> +{
> +	/*
> +	 * GnuTLS expects us to allocate all data returned from callbacks
> +	 * using gnutls_malloc(), thus, we have to create a fresh copy of
> +	 * our static credentials for every connection.
> +	 */
> +	nsalt->data = gnutls_malloc(usbip_net_srp_salt.size);
> +	nverifier->data = gnutls_malloc(usbip_net_srp_verifier.size);
> +	if (nsalt->data == NULL || nverifier->data == NULL) {

	if (!nsalt->data || !nverifier->data) {

> +		gnutls_free(nsalt->data);
> +		gnutls_free(nverifier->data);
> +		return -1;
> +	}
> +	nsalt->size = usbip_net_srp_salt.size;
> +	nverifier->size = usbip_net_srp_verifier.size;
> +	memcpy(nverifier->data, usbip_net_srp_verifier.data,
> +	       usbip_net_srp_verifier.size);
> +	memcpy(nsalt->data, usbip_net_srp_salt.data, usbip_net_srp_salt.size);
> +
> +	*g = SRP_GROUP;
> +	*n = SRP_PRIME;
> +
> +	/* We only have a single session, thus, ignore it */
> +	(void) sess;
> +
> +	if (strcmp(username, "dummyuser"))
> +		/* User invalid, stored dummy data in g and n. */
> +		return 1;

Could you describe the role of "dummyuser" in a comment? It seems to be
a placeholder for GnuTLS SRP requiring a username.

> +	return 0;
> +}
> +
> +int usbip_net_init_gnutls(void)
> +{
> +	int ret;
> +
> +	gnutls_global_init();
> +
> +	usbip_net_srp_salt.data = gnutls_malloc(16);

This should be freed somewhere.

> +	if (!usbip_net_srp_salt.data)
> +		return GNUTLS_E_MEMORY_ERROR;
> +
> +	ret = gnutls_rnd(GNUTLS_RND_NONCE, usbip_net_srp_salt.data, 16);
> +	if (ret < 0)
> +		return ret;
> +
> +	usbip_net_srp_salt.size = 16;
> +
> +	ret = gnutls_srp_allocate_server_credentials(&usbip_net_srp_cred);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = gnutls_srp_verifier("dummyuser", optarg, &usbip_net_srp_salt,
> +				  &SRP_GROUP, &SRP_PRIME,
> +				  &usbip_net_srp_verifier);
> +	if (ret < 0)
> +		return ret;
> +
> +	gnutls_srp_set_server_credentials_function(usbip_net_srp_cred,
> +						   net_srp_callback);
> +
> +	return GNUTLS_E_SUCCESS;
> +}
> +#endif
> +
> +/*
> + * Connect to the server. Performs the TCP connection attempt
> + * and - if necessary - the TLS handshake used for authentication.
> + */
> +int usbip_net_connect(char *hostname)
> +{
> +	int sockfd;
> +
> +	sockfd = usbip_net_tcp_connect(hostname, usbip_port_string);
> +	if (sockfd < 0)
> +		return sockfd;
> +
> +#ifdef HAVE_GNUTLS
> +	if (usbip_srp_password) {
> +		int rc;
> +
> +		rc = usbip_net_send_op_common(sockfd, OP_REQ_STARTTLS, 0);
> +		if (rc < 0) {
> +			err("usbip_net_send_op_common failed");
> +			return EAI_SYSTEM;
> +		}
> +
> +		rc = usbip_net_srp_client_handshake(sockfd);
> +		if (rc < 0) {
> +			err("Unable to perform TLS handshake (wrong password?): %s",
> +			    gnutls_strerror(rc));
> +			close(sockfd);
> +			return EAI_SYSTEM;
> +		}
> +	}
> +#endif
> +
> +	return sockfd;
> +}
> diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
> index c1e875c..292d584 100644
> --- a/tools/usb/usbip/src/usbip_network.h
> +++ b/tools/usb/usbip/src/usbip_network.h
> @@ -15,6 +15,7 @@
>  
>  extern int usbip_port;
>  extern char *usbip_port_string;
> +extern char *usbip_srp_password;
>  void usbip_setup_port_number(char *arg);
>  
>  /* ---------------------------------------------------------------------- */
> @@ -167,6 +168,12 @@ struct op_devlist_reply_extra {
>  	usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
>  } while (0)
>  
> +/* ---------------------------------------------------------------------- */
> +/* Initiate encrypted connection. */
> +#define OP_STARTTLS 0x06
> +#define OP_REQ_STARTTLS   (OP_REQUEST | OP_STARTTLS)
> +#define OP_REP_STARTTLS   (OP_REPLY   | OP_STARTTLS)
> +
>  void usbip_net_pack_uint32_t(int pack, uint32_t *num);
>  void usbip_net_pack_uint16_t(int pack, uint16_t *num);
>  void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
> @@ -180,6 +187,8 @@ int usbip_net_set_reuseaddr(int sockfd);
>  int usbip_net_set_nodelay(int sockfd);
>  int usbip_net_set_keepalive(int sockfd);
>  int usbip_net_set_v6only(int sockfd);
> -int usbip_net_tcp_connect(char *hostname, char *port);
> +int usbip_net_connect(char *hostname);
> +int net_srp_server_handshake(int connfd);
> +int usbip_net_init_gnutls(void);
>  
>  #endif /* __USBIP_NETWORK_H */
> diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
> index 2f87f2d..23c15d7 100644
> --- a/tools/usb/usbip/src/usbipd.c
> +++ b/tools/usb/usbip/src/usbipd.c
> @@ -36,6 +36,11 @@
>  #include <tcpd.h>
>  #endif
>  
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +#include <gnutls/crypto.h>
> +#endif
> +
>  #include <getopt.h>
>  #include <signal.h>
>  #include <poll.h>
> @@ -64,6 +69,11 @@ static const char usbipd_help_string[] =
>  	"	-6, --ipv6\n"
>  	"		Bind to IPv6. Default is both.\n"
>  	"\n"
> +#ifdef HAVE_GNUTLS
> +	"	-sPASSWORD, --auth PASSWORD\n"
> +	"		Set PASSWORD as key used for authentication.\n"
> +	"\n"
> +#endif
>  	"	-D, --daemon\n"
>  	"		Run as a daemon process.\n"
>  	"\n"
> @@ -83,6 +93,8 @@ static const char usbipd_help_string[] =
>  	"	-v, --version\n"
>  	"		Show version.\n";
>  
> +static int need_auth;
> +
>  static void usbipd_help(void)
>  {
>  	printf("%s\n", usbipd_help_string);
> @@ -239,14 +251,7 @@ static int recv_request_devlist(int connfd)
>  
>  static int recv_pdu(int connfd)
>  {
> -	uint16_t code = OP_UNSPEC;
> -	int ret;
> -
> -	ret = usbip_net_recv_op_common(connfd, &code);
> -	if (ret < 0) {
> -		dbg("could not receive opcode: %#0x", code);
> -		return -1;
> -	}
> +	int auth = !need_auth, cont = 1, ret;
>  	ret = usbip_host_refresh_device_list();
>  	if (ret < 0) {
> @@ -254,25 +259,63 @@ static int recv_pdu(int connfd)
>  		return -1;
>  	}
>  
> -	info("received request: %#0x(%d)", code, connfd);
> -	switch (code) {
> -	case OP_REQ_DEVLIST:
> -		ret = recv_request_devlist(connfd);
> -		break;
> -	case OP_REQ_IMPORT:
> -		ret = recv_request_import(connfd);
> -		break;
> -	case OP_REQ_DEVINFO:
> -	case OP_REQ_CRYPKEY:
> -	default:
> -		err("received an unknown opcode: %#0x", code);
> -		ret = -1;
> -	}
> +	/*
> +	 * Process opcodes. We might receive more than one, as the
> +	 * client might send STARTTLS first
> +	 */
> +	while (cont) {
> +		uint16_t code = OP_UNSPEC;
>  
> -	if (ret == 0)
> -		info("request %#0x(%d): complete", code, connfd);
> -	else
> -		info("request %#0x(%d): failed", code, connfd);
> +		ret = usbip_net_recv_op_common(connfd, &code);
> +		if (ret < 0) {
> +			dbg("could not receive opcode: %#0x", code);
> +			return -1;
> +		}
> +
> +		info("received request: %#0x(%d)", code, connfd);
> +
> +		/* We require an authenticated encryption */
> +		if (!auth && code != OP_REQ_STARTTLS) {
> +			usbip_net_send_op_common(connfd, OP_REPLY, ST_NA);
> +			return -1;
> +		}
> +
> +		switch (code) {
> +#ifdef HAVE_GNUTLS
> +		case OP_REQ_STARTTLS:
> +			if (!need_auth) {
> +				ret = -1;
> +				err("Unexpected TLS handshake attempt (client uses password, server doesn't)");
> +			} else {
> +				ret = net_srp_server_handshake(connfd);
> +				if (ret != 0)
> +					err("TLS handshake failed");
> +				auth = 1;

This marks the connection as authenticated even if the handshake has
failed, which doesn't seem right.

The err() used here is a macro that merely logs the error and moves
on. It does not exit() like the err.h err() functions.

So this should probably be

> +				if (ret != 0)
> +					err("TLS handshake failed");
				else
> +					auth = 1;

instead?

> +			}
> +			break;
> +#endif
> +		case OP_REQ_DEVLIST:
> +			ret = recv_request_devlist(connfd);
> +			cont = 0;
> +			break;
> +		case OP_REQ_IMPORT:
> +			ret = recv_request_import(connfd);
> +			cont = 0;
> +			break;
> +		case OP_REQ_DEVINFO:
> +		case OP_REQ_CRYPKEY:
> +		default:
> +			err("received an unknown opcode: %#0x", code);
> +			ret = -1;
> +		}
> +
> +		if (ret == 0)
> +			info("request %#0x(%d): complete", code, connfd);
> +		else {
> +			info("request %#0x(%d): failed", code, connfd);
> +			break;
> +		}
> +	}
>  
>  	return ret;
>  }
> @@ -593,6 +636,7 @@ int main(int argc, char *argv[])
>  		{ "tcp-port", required_argument, NULL, 't' },
>  		{ "help",     no_argument,       NULL, 'h' },
>  		{ "version",  no_argument,       NULL, 'v' },
> +		{ "auth",     required_argument, NULL, 's' },
>  		{ NULL,	      0,                 NULL,  0  }
>  	};
>  
> @@ -605,6 +649,9 @@ int main(int argc, char *argv[])
>  	int daemonize = 0;
>  	int ipv4 = 0, ipv6 = 0;
>  	int opt, rc = -1;
> +#ifdef HAVE_GNUTLS
> +	int ret;
> +#endif
>  
>  	pid_file = NULL;
>  
> @@ -616,7 +663,7 @@ int main(int argc, char *argv[])
>  
>  	cmd = cmd_standalone_mode;
>  	for (;;) {
> -		opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
> +		opt = getopt_long(argc, argv, "46s:DdP::t:hv", longopts, NULL);
>  
>  		if (opt == -1)
>  			break;
> @@ -628,6 +675,20 @@ int main(int argc, char *argv[])
>  		case '6':
>  			ipv6 = 1;
>  			break;
> +		case 's':
> +#ifdef HAVE_GNUTLS
> +			need_auth = 1;
> +			ret = usbip_net_init_gnutls();
> +			if (ret < 0) {
> +				err("Unable to initialize GnuTLS: %s",
> +				    gnutls_strerror(ret));
> +				return EXIT_FAILURE;
> +			}
> +			break;

Same comment as above (move outside getopt loop).

	Max

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/18] usbip: Add kernel support for client ACLs
  2014-09-16 23:38 ` [PATCH 03/18] usbip: Add kernel support for client ACLs Maximilian Eschenbacher
@ 2014-09-21  0:44   ` Max Vozeler
  2014-09-21 12:42     ` Dominik Paulus
  0 siblings, 1 reply; 31+ messages in thread
From: Max Vozeler @ 2014-09-21  0:44 UTC (permalink / raw)
  To: Maximilian Eschenbacher
  Cc: linux-kernel, valentina.manea.m, shuah.kh, gregkh,
	Dominik Paulus, Fjodor Schelichow, Johannes Stadlinger,
	Kurt Kanzenbach, Tobias Polzer

Hi,

On Tue, Sep 16, 2014 at 11:38:40PM +0000, Maximilian Eschenbacher wrote:
> From: Dominik Paulus <dominik.paulus@fau.de>
> 
> This patch adds the possibility to stored ACLs for allowed clients for
> each stub device in sysfs. It adds a new sysfs entry called "usbip_acl"
> for each stub device, containing a list of CIDR masks of allowed
> clients. This file will be used by usbip and usbipd to store the ACL.

Is there a need to involve the kernel here, couldn't usbip and usbipd
apply the ACLs during connection setup in userspace?

> Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
> Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
> Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
> Signed-off-by: Kurt Kanzenbach <ly80toro@cip.cs.fau.de>
> Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
> Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
> ---
>  drivers/usb/usbip/stub.h     |  5 ++++
>  drivers/usb/usbip/stub_dev.c | 60 +++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 64 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/usbip/stub.h b/drivers/usb/usbip/stub.h
> index 266e2b0..b2d3d55 100644
> --- a/drivers/usb/usbip/stub.h
> +++ b/drivers/usb/usbip/stub.h
> @@ -60,6 +60,11 @@ struct stub_device {
>  	struct list_head unlink_free;
>  
>  	wait_queue_head_t tx_waitq;
> +
> +	/* list of allowed IP addrs */
> +	char *acls;
> +	/* for locking list operations */
> +	spinlock_t ip_lock;

Perhaps name this 'acl_lock' to make more obvious what it covers?

>  };
>  
>  /* private data into urb->priv */
> diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
> index fac20e0..e6624f1 100644
> --- a/drivers/usb/usbip/stub_dev.c
> +++ b/drivers/usb/usbip/stub_dev.c
> @@ -119,6 +119,55 @@ err:
>  }
>  static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
>  
> +/*
> + * This function replaces the current ACL list
> + */
> +static ssize_t store_acl(struct device *dev, struct device_attribute *attr,
> +			const char *buf, size_t count)
> +{
> +	struct stub_device *sdev = dev_get_drvdata(dev);
> +	int retval;
> +
> +	if (count >= PAGE_SIZE)
> +		return -EINVAL;
> +
> +	spin_lock_irq(&sdev->ip_lock);
> +	kfree(sdev->acls);
> +	sdev->acls = kstrdup(buf, GFP_KERNEL);
> +	if (!sdev->acls)
> +		retval = -ENOMEM;
> +	else
> +		retval = strlen(sdev->acls);
> +	spin_unlock_irq(&sdev->ip_lock);
> +
> +	return retval;
> +}
> +
> +/*
> + * This functions prints all allowed IP addrs for this dev
> + */
> +static ssize_t show_acl(struct device *dev, struct device_attribute *attr,
> +		       char *buf)
> +{
> +	struct stub_device *sdev = dev_get_drvdata(dev);
> +	int retval = 0;
> +
> +	if (!sdev)
> +		return -ENODEV;
> +
> +	spin_lock_irq(&sdev->ip_lock);
> +	if (sdev->acls == NULL) {
> +		retval = 0;
> +	} else {
> +		strcpy(buf, sdev->acls);
> +		retval = strlen(buf);
> +	}
> +	spin_unlock_irq(&sdev->ip_lock);
> +
> +	return retval;
> +}
> +static DEVICE_ATTR(usbip_acl, S_IWUSR | S_IRUGO, show_acl, store_acl);
> +
>  static int stub_add_files(struct device *dev)
>  {
>  	int err = 0;
> @@ -134,9 +183,13 @@ static int stub_add_files(struct device *dev)
>  	err = device_create_file(dev, &dev_attr_usbip_debug);
>  	if (err)
>  		goto err_debug;
> +	err = device_create_file(dev, &dev_attr_usbip_acl);
> +	if (err)
> +		goto err_ip;
>  
>  	return 0;
> -
> +err_ip:
> +	device_remove_file(dev, &dev_attr_usbip_debug);
>  err_debug:
>  	device_remove_file(dev, &dev_attr_usbip_sockfd);
>  err_sockfd:
> @@ -150,6 +203,7 @@ static void stub_remove_files(struct device *dev)
>  	device_remove_file(dev, &dev_attr_usbip_status);
>  	device_remove_file(dev, &dev_attr_usbip_sockfd);
>  	device_remove_file(dev, &dev_attr_usbip_debug);
> +	device_remove_file(dev, &dev_attr_usbip_acl);
>  }
>  
>  static void stub_shutdown_connection(struct usbip_device *ud)
> @@ -287,6 +341,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev)
>  	INIT_LIST_HEAD(&sdev->priv_free);
>  	INIT_LIST_HEAD(&sdev->unlink_free);
>  	INIT_LIST_HEAD(&sdev->unlink_tx);
> +	spin_lock_init(&sdev->ip_lock);
>  	spin_lock_init(&sdev->priv_lock);
>  
>  	init_waitqueue_head(&sdev->tx_waitq);
> @@ -453,6 +508,9 @@ static void stub_disconnect(struct usb_device *udev)
>  
>  	usb_put_dev(sdev->udev);
>  
> +	/* free ACL list */
> +	kfree(sdev->acls);
> +
>  	/* free sdev */
>  	busid_priv->sdev = NULL;
>  	stub_device_free(sdev);

Otherwise looks good to me.

	Max

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/18] usbip: Add kernel support for client ACLs
  2014-09-21  0:44   ` Max Vozeler
@ 2014-09-21 12:42     ` Dominik Paulus
  0 siblings, 0 replies; 31+ messages in thread
From: Dominik Paulus @ 2014-09-21 12:42 UTC (permalink / raw)
  To: Max Vozeler
  Cc: Maximilian Eschenbacher, linux-kernel, valentina.manea.m,
	shuah.kh, gregkh, Dominik Paulus, Fjodor Schelichow,
	Johannes Stadlinger, Kurt Kanzenbach, Tobias Polzer

On Sun, Sep 21, 2014 at 02:44:33AM +0200, Max Vozeler wrote:
> Hi,
> 
> On Tue, Sep 16, 2014 at 11:38:40PM +0000, Maximilian Eschenbacher wrote:
> > From: Dominik Paulus <dominik.paulus@fau.de>
> > 
> > This patch adds the possibility to stored ACLs for allowed clients for
> > each stub device in sysfs. It adds a new sysfs entry called "usbip_acl"
> > for each stub device, containing a list of CIDR masks of allowed
> > clients. This file will be used by usbip and usbipd to store the ACL.
> 
> Is there a need to involve the kernel here, couldn't usbip and usbipd
> apply the ACLs during connection setup in userspace?

In fact, they do, sysfs is just used for storing the ACLs. They are
never interpreted by the kernel. Admittedly, this isn't great design,
but currently, the ACLs are specified when binding a device to usbip
using the "usbip bind" utility and interpreted by usbipd when a
connection attempt is made. usbip (configuration utility) and usbipd
(userspace daemon) don't communicate in userspace at all, and moving the
ACLs out of kernel would be considerably more code and more error prone.

Regards,
Dominik

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 02/18] usbip: Add support for client authentication
  2014-09-21  0:42   ` Max Vozeler
@ 2014-09-21 12:43     ` Dominik Paulus
  0 siblings, 0 replies; 31+ messages in thread
From: Dominik Paulus @ 2014-09-21 12:43 UTC (permalink / raw)
  To: Max Vozeler
  Cc: Maximilian Eschenbacher, linux-kernel, valentina.manea.m,
	shuah.kh, gregkh, Dominik Paulus, Fjodor Schelichow,
	Johannes Stadlinger, Tobias Polzer

Hi,

thanks for your feedback!

On Sun, Sep 21, 2014 at 02:42:59AM +0200, Max Vozeler wrote:
> > +	if (strcmp(username, "dummyuser"))
> > +		/* User invalid, stored dummy data in g and n. */
> > +		return 1;
> 
> Could you describe the role of "dummyuser" in a comment? It seems to be
> a placeholder for GnuTLS SRP requiring a username.

It is, SRP is designed for username/password authentication, but we only
do password.

> 
> > +	return 0;
> > +}
> > +
> > +int usbip_net_init_gnutls(void)
> > +{
> > +	int ret;
> > +
> > +	gnutls_global_init();
> > +
> > +	usbip_net_srp_salt.data = gnutls_malloc(16);
> 
> This should be freed somewhere.

Actually, it is used for the whole lifetime of the process.

> > +	/*
> > +	 * Process opcodes. We might receive more than one, as the
> > +	 * client might send STARTTLS first
> > +	 */
> > +	while (cont) {
> > +		uint16_t code = OP_UNSPEC;
> >  
> > -	if (ret == 0)
> > -		info("request %#0x(%d): complete", code, connfd);
> > -	else
> > -		info("request %#0x(%d): failed", code, connfd);
> > +		ret = usbip_net_recv_op_common(connfd, &code);
> > +		if (ret < 0) {
> > +			dbg("could not receive opcode: %#0x", code);
> > +			return -1;
> > +		}
> > +
> > +		info("received request: %#0x(%d)", code, connfd);
> > +
> > +		/* We require an authenticated encryption */
> > +		if (!auth && code != OP_REQ_STARTTLS) {
> > +			usbip_net_send_op_common(connfd, OP_REPLY, ST_NA);
> > +			return -1;
> > +		}
> > +
> > +		switch (code) {
> > +#ifdef HAVE_GNUTLS
> > +		case OP_REQ_STARTTLS:
> > +			if (!need_auth) {
> > +				ret = -1;
> > +				err("Unexpected TLS handshake attempt (client uses password, server doesn't)");
> > +			} else {
> > +				ret = net_srp_server_handshake(connfd);
> > +				if (ret != 0)
> > +					err("TLS handshake failed");
> > +				auth = 1;
> 
> This marks the connection as authenticated even if the handshake has
> failed, which doesn't seem right.
> 
> The err() used here is a macro that merely logs the error and moves
> on. It does not exit() like the err.h err() functions.
> 
> So this should probably be
> 
> > +				if (ret != 0)
> > +					err("TLS handshake failed");
> 				else
> > +					auth = 1;
> 
> instead?

It might be even better to just drop the connection after a failed
handshake, as existing clients aren't going to do more than one
authentication attempt, anyway.

Note that - after patch 11/18 has been applied, too -
net_srp_server_handshake() sets the "have_crypto" flag on the connection
handle, thus, all subsequent network operations are going to fail
anyway, as no TLS session has been established. Thus, the incorrectly
set "auth" flag doesn't have any security implications here.

Regards,
Dominik

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 00/18] usbip: Crypto and ACLs
  2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
                   ` (17 preceding siblings ...)
  2014-09-16 23:38 ` [PATCH 18/18] usbip: list.h include stddef.h for offsetof Maximilian Eschenbacher
@ 2014-09-26 11:56 ` Valentina Manea
  2014-11-07 17:49   ` Greg KH
  18 siblings, 1 reply; 31+ messages in thread
From: Valentina Manea @ 2014-09-26 11:56 UTC (permalink / raw)
  To: Maximilian Eschenbacher; +Cc: linux-kernel, shuah.kh, Greg KH

Hi,

Sorry for the lack of feedback, I've been having a hectic period. I
will review these patches starting tomorrow.

Valentina

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 02/18] usbip: Add support for client authentication
  2014-09-16 23:38 ` [PATCH 02/18] usbip: Add support for client authentication Maximilian Eschenbacher
  2014-09-21  0:42   ` Max Vozeler
@ 2014-10-03 14:16   ` Valentina Manea
  1 sibling, 0 replies; 31+ messages in thread
From: Valentina Manea @ 2014-10-03 14:16 UTC (permalink / raw)
  To: Maximilian Eschenbacher
  Cc: linux-kernel, shuah.kh, Greg KH, Dominik Paulus,
	Fjodor Schelichow, Johannes Stadlinger, Tobias Polzer

* Is it only on my machines or there is a problem with the gnutls
3.3.0 headers? I get an error about offsetof being redefined, since
gnutls.h includes stddef.h, which defines this symbol as well, besides
libsrc/list.h. It works if I include the gnutls stuff after
usbip_host_driver.h in usbipd.c. Did a bit of debugging but I couldn't
pinpoint the cause of this.
* Same as Max said, this doesn't build with gnutls 2.12. I used 3.30
for building so you should add a check for the version in
configure.ac.
* As I can see, the password is "volatile" in server, ie. is lost
after the process ends. Along with what Max said, maybe I should be
stored in a file. On the server side, I suggest giving the user 2
options: either provide the password as you implemented, with a flag,
either get it from stdin and obfuscate the input.
* nit: on net_srp_server_handshake and net_srp_client_handshake, the
parameters are called differently even if the mean the same thing.
please choose either sockfd or connfd.
* Add gnutls as dependency and provide a short example of how to use
this feature in README.

Other than this, looks good. Thanks!

On Wed, Sep 17, 2014 at 2:38 AM, Maximilian Eschenbacher
<maximilian@eschenbacher.email> wrote:
> From: Dominik Paulus <dominik.paulus@fau.de>
>
> This patch adds support for authenticating both client and server using
> a pre-shared passphrase using SRP (Secure Remote Password) over TLS (see
> RFC 5054) using GnuTLS. Both usbip and usbipd now accept a shared secret
> as a command line argument. Currently, the established TLS connection is
> only used to perform a secure handshake and dropped before the socket is
> passed to the kernel. The code may be extended to exchange a session key
> over TLS and pass it to the kernel to perform IPsec.
>
> Signed-off-by: Maximilian Eschenbacher <maximilian@eschenbacher.email>
> Signed-off-by: Fjodor Schelichow <fjodor.schelichow@hotmail.com>
> Signed-off-by: Johannes Stadlinger <johannes.stadlinger@fau.de>
> Signed-off-by: Dominik Paulus <dominik.paulus@fau.de>
> Signed-off-by: Tobias Polzer <tobias.polzer@fau.de>
> ---
>  tools/usb/usbip/configure.ac        |  14 +++
>  tools/usb/usbip/doc/usbip.8         |   4 +
>  tools/usb/usbip/doc/usbipd.8        |   5 +
>  tools/usb/usbip/src/usbip.c         |  30 +++++-
>  tools/usb/usbip/src/usbip_attach.c  |   2 +-
>  tools/usb/usbip/src/usbip_list.c    |   2 +-
>  tools/usb/usbip/src/usbip_network.c | 185 ++++++++++++++++++++++++++++++++++++
>  tools/usb/usbip/src/usbip_network.h |  11 ++-
>  tools/usb/usbip/src/usbipd.c        | 115 ++++++++++++++++------
>  9 files changed, 335 insertions(+), 33 deletions(-)
>
> diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac
> index 607d05c..6a8156f 100644
> --- a/tools/usb/usbip/configure.ac
> +++ b/tools/usb/usbip/configure.ac
> @@ -83,6 +83,20 @@ AC_ARG_WITH([tcp-wrappers],
>                 AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])],
>                [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])])
>
> +# Checks for the GnuTLS library
> +AC_ARG_WITH([gnutls],
> +                       [AS_HELP_STRING([--with-gnutls],
> +                                                       [use the GnuTLS library for authentication])],
> +                       dnl [ACTION-IF-GIVEN]
> +                       [if test "$withval" = "yes"; then
> +                        PKG_CHECK_MODULES([GNUTLS], [gnutls])
> +                        AC_DEFINE([HAVE_GNUTLS], [1], [use gnutls])
> +                        CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
> +                        LDFLAGS="$LDFLAGS $GNUTLS_LIBS"
> +                        fi
> +                       ],
> +                       )
> +
>  # Sets directory containing usb.ids.
>  AC_ARG_WITH([usbids-dir],
>             [AS_HELP_STRING([--with-usbids-dir=DIR],
> diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
> index a6097be..847aa40 100644
> --- a/tools/usb/usbip/doc/usbip.8
> +++ b/tools/usb/usbip/doc/usbip.8
> @@ -27,6 +27,10 @@ Log to syslog.
>  \fB\-\-tcp-port PORT\fR
>  .IP
>  Connect to PORT on remote host (used for attach and list --remote).
> +
> +\fB\-\-auth\fR
> +.IP
> +Set the password to be used for client authentication. See usbipd(8) for more information.
>  .PP
>
>  .SH COMMANDS
> diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8
> index ac4635d..8beb95a 100644
> --- a/tools/usb/usbip/doc/usbipd.8
> +++ b/tools/usb/usbip/doc/usbipd.8
> @@ -52,6 +52,11 @@ If no FILE specified, use /var/run/usbipd.pid
>  \fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR
>  .IP
>  Listen on TCP/IP port PORT.
> +
> +.HP
> +\fB\-s\fR, \fB\-\-auth\fR
> +.IP
> +Sets the password to be used for client authentication. If -a is used, the server will only accept connections from authenticated clients. Note: USB traffic will still be unencrypted, this currently only serves for authentication.
>  .PP
>
>  \fB\-h\fR, \fB\-\-help\fR
> diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
> index d7599d9..cd7e420 100644
> --- a/tools/usb/usbip/src/usbip.c
> +++ b/tools/usb/usbip/src/usbip.c
> @@ -25,6 +25,12 @@
>  #include <getopt.h>
>  #include <syslog.h>
>
> +#include "../config.h"
> +
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +#endif
> +
>  #include "usbip_common.h"
>  #include "usbip_network.h"
>  #include "usbip.h"
> @@ -35,8 +41,12 @@ static int usbip_version(int argc, char *argv[]);
>  static const char usbip_version_string[] = PACKAGE_STRING;
>
>  static const char usbip_usage_string[] =
> -       "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
> -       "             [help] <command> <args>\n";
> +       "usbip "
> +#ifdef HAVE_GNUTLS
> +       "[--auth PASSWORD] "
> +#endif
> +       "[--debug] [--log] [--tcp-port PORT]\n"
> +       "             [version] [help] <command> <args>\n";
>
>  static void usbip_usage(void)
>  {
> @@ -148,6 +158,7 @@ int main(int argc, char *argv[])
>                 { "debug",    no_argument,       NULL, 'd' },
>                 { "log",      no_argument,       NULL, 'l' },
>                 { "tcp-port", required_argument, NULL, 't' },
> +               { "auth",     required_argument, NULL, 's' },
>                 { NULL,       0,                 NULL,  0  }
>         };
>
> @@ -158,12 +169,25 @@ int main(int argc, char *argv[])
>         usbip_use_stderr = 1;
>         opterr = 0;
>         for (;;) {
> -               opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
> +               opt = getopt_long(argc, argv, "+dls:t:", opts, NULL);
>
>                 if (opt == -1)
>                         break;
>
>                 switch (opt) {
> +               case 's':
> +#ifdef HAVE_GNUTLS
> +                       usbip_srp_password = optarg;
> +                       rc = gnutls_global_init();
> +                       if (rc < 0) {
> +                               err("Unable to initialize GnuTLS library: %s",
> +                                   gnutls_strerror(rc));
> +                               return EXIT_FAILURE;
> +                       }
> +#else
> +                       err("usbip has been compiled without GnuTLS support");
> +#endif
> +                       break;
>                 case 'd':
>                         usbip_use_debug = 1;
>                         break;
> diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
> index d58a14d..4421ebc 100644
> --- a/tools/usb/usbip/src/usbip_attach.c
> +++ b/tools/usb/usbip/src/usbip_attach.c
> @@ -175,7 +175,7 @@ static int attach_device(char *host, char *busid)
>         int rc;
>         int rhport;
>
> -       sockfd = usbip_net_tcp_connect(host, usbip_port_string);
> +       sockfd = usbip_net_connect(host);
>         if (sockfd < 0) {
>                 err("tcp connect");
>                 return -1;
> diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
> index d5ce34a..6042b7e 100644
> --- a/tools/usb/usbip/src/usbip_list.c
> +++ b/tools/usb/usbip/src/usbip_list.c
> @@ -132,7 +132,7 @@ static int list_exported_devices(char *host)
>         int rc;
>         int sockfd;
>
> -       sockfd = usbip_net_tcp_connect(host, usbip_port_string);
> +       sockfd = usbip_net_connect(host);
>         if (sockfd < 0) {
>                 err("could not connect to %s:%s: %s", host,
>                     usbip_port_string, gai_strerror(sockfd));
> diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
> index b4c37e7..6b8f949 100644
> --- a/tools/usb/usbip/src/usbip_network.c
> +++ b/tools/usb/usbip/src/usbip_network.c
> @@ -29,11 +29,20 @@
>  #include <tcpd.h>
>  #endif
>
> +#include "../config.h"
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +#include <gnutls/crypto.h>
> +#endif
> +
>  #include "usbip_common.h"
>  #include "usbip_network.h"
>
>  int usbip_port = 3240;
>  char *usbip_port_string = "3240";
> +#ifdef HAVE_GNUTLS
> +char *usbip_srp_password;
> +#endif
>
>  void usbip_setup_port_number(char *arg)
>  {
> @@ -301,3 +310,179 @@ int usbip_net_tcp_connect(char *hostname, char *service)
>
>         return sockfd;
>  }
> +
> +#ifdef HAVE_GNUTLS
> +static gnutls_datum_t usbip_net_srp_salt, usbip_net_srp_verifier;
> +static gnutls_srp_server_credentials_t usbip_net_srp_cred;
> +
> +#define SRP_GROUP gnutls_srp_2048_group_generator
> +#define SRP_PRIME gnutls_srp_2048_group_prime
> +
> +int usbip_net_srp_client_handshake(int sockfd)
> +{
> +       int ret;
> +       gnutls_session_t session;
> +       gnutls_srp_client_credentials_t usbip_net_srp_cred;
> +
> +       ret = gnutls_srp_allocate_client_credentials(&usbip_net_srp_cred);
> +       if (ret < 0)
> +               return ret;
> +
> +       gnutls_srp_set_client_credentials(usbip_net_srp_cred, "dummyuser",
> +               usbip_srp_password);
> +
> +       ret = gnutls_init(&session, GNUTLS_CLIENT);
> +       if (ret < 0) {
> +               gnutls_srp_free_client_credentials(usbip_net_srp_cred);
> +               return ret;
> +       }
> +
> +       gnutls_priority_set_direct(session, "NORMAL:+SRP", NULL);
> +
> +       gnutls_credentials_set(session, GNUTLS_CRD_SRP, usbip_net_srp_cred);
> +       gnutls_transport_set_int (session, sockfd);
> +
> +       do {
> +               ret = gnutls_handshake(session);
> +       } while (ret < 0 && !gnutls_error_is_fatal(ret));
> +
> +       gnutls_bye(session, GNUTLS_SHUT_RDWR);
> +
> +       gnutls_deinit(session);
> +       gnutls_srp_free_client_credentials(usbip_net_srp_cred);
> +
> +       return ret;
> +}
> +
> +int net_srp_server_handshake(int connfd)
> +{
> +       int ret;
> +       gnutls_session_t session;
> +
> +       if (gnutls_init(&session, GNUTLS_SERVER) != 0)
> +               return -1;
> +       gnutls_priority_set_direct(session, "NORMAL:-KX-ALL:+SRP", NULL);
> +       ret = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
> +                                    usbip_net_srp_cred);
> +       if (!ret)
> +               return -1;
> +
> +       gnutls_transport_set_int(session, connfd);
> +
> +       do {
> +               ret = gnutls_handshake(session);
> +       } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
> +
> +       if (ret < 0)
> +               err("GnuTLS handshake failed (%s)", gnutls_strerror(ret));
> +       else
> +               info("GnuTLS handshake completed");
> +
> +       if (gnutls_bye(session, GNUTLS_SHUT_RDWR) != 0)
> +               err("Unable to shutdown TLS connection.");
> +       gnutls_deinit(session);
> +
> +       return ret;
> +}
> +
> +static int net_srp_callback(gnutls_session_t sess, const char *username,
> +       gnutls_datum_t *nsalt, gnutls_datum_t *nverifier, gnutls_datum_t *g,
> +       gnutls_datum_t *n)
> +{
> +       /*
> +        * GnuTLS expects us to allocate all data returned from callbacks
> +        * using gnutls_malloc(), thus, we have to create a fresh copy of
> +        * our static credentials for every connection.
> +        */
> +       nsalt->data = gnutls_malloc(usbip_net_srp_salt.size);
> +       nverifier->data = gnutls_malloc(usbip_net_srp_verifier.size);
> +       if (nsalt->data == NULL || nverifier->data == NULL) {
> +               gnutls_free(nsalt->data);
> +               gnutls_free(nverifier->data);
> +               return -1;
> +       }
> +       nsalt->size = usbip_net_srp_salt.size;
> +       nverifier->size = usbip_net_srp_verifier.size;
> +       memcpy(nverifier->data, usbip_net_srp_verifier.data,
> +              usbip_net_srp_verifier.size);
> +       memcpy(nsalt->data, usbip_net_srp_salt.data, usbip_net_srp_salt.size);
> +
> +       *g = SRP_GROUP;
> +       *n = SRP_PRIME;
> +
> +       /* We only have a single session, thus, ignore it */
> +       (void) sess;
> +
> +       if (strcmp(username, "dummyuser"))
> +               /* User invalid, stored dummy data in g and n. */
> +               return 1;
> +
> +       return 0;
> +}
> +
> +int usbip_net_init_gnutls(void)
> +{
> +       int ret;
> +
> +       gnutls_global_init();
> +
> +       usbip_net_srp_salt.data = gnutls_malloc(16);
> +       if (!usbip_net_srp_salt.data)
> +               return GNUTLS_E_MEMORY_ERROR;
> +
> +       ret = gnutls_rnd(GNUTLS_RND_NONCE, usbip_net_srp_salt.data, 16);
> +       if (ret < 0)
> +               return ret;
> +       usbip_net_srp_salt.size = 16;
> +
> +       ret = gnutls_srp_allocate_server_credentials(&usbip_net_srp_cred);
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = gnutls_srp_verifier("dummyuser", optarg, &usbip_net_srp_salt,
> +                                 &SRP_GROUP, &SRP_PRIME,
> +                                 &usbip_net_srp_verifier);
> +       if (ret < 0)
> +               return ret;
> +
> +       gnutls_srp_set_server_credentials_function(usbip_net_srp_cred,
> +                                                  net_srp_callback);
> +
> +       return GNUTLS_E_SUCCESS;
> +}
> +#endif
> +
> +/*
> + * Connect to the server. Performs the TCP connection attempt
> + * and - if necessary - the TLS handshake used for authentication.
> + */
> +int usbip_net_connect(char *hostname)
> +{
> +       int sockfd;
> +
> +       sockfd = usbip_net_tcp_connect(hostname, usbip_port_string);
> +       if (sockfd < 0)
> +               return sockfd;
> +
> +#ifdef HAVE_GNUTLS
> +       if (usbip_srp_password) {
> +               int rc;
> +
> +               rc = usbip_net_send_op_common(sockfd, OP_REQ_STARTTLS, 0);
> +               if (rc < 0) {
> +                       err("usbip_net_send_op_common failed");
> +                       return EAI_SYSTEM;
> +               }
> +
> +               rc = usbip_net_srp_client_handshake(sockfd);
> +               if (rc < 0) {
> +                       err("Unable to perform TLS handshake (wrong password?): %s",
> +                           gnutls_strerror(rc));
> +                       close(sockfd);
> +                       return EAI_SYSTEM;
> +               }
> +       }
> +#endif
> +
> +       return sockfd;
> +}
> diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
> index c1e875c..292d584 100644
> --- a/tools/usb/usbip/src/usbip_network.h
> +++ b/tools/usb/usbip/src/usbip_network.h
> @@ -15,6 +15,7 @@
>
>  extern int usbip_port;
>  extern char *usbip_port_string;
> +extern char *usbip_srp_password;
>  void usbip_setup_port_number(char *arg);
>
>  /* ---------------------------------------------------------------------- */
> @@ -167,6 +168,12 @@ struct op_devlist_reply_extra {
>         usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
>  } while (0)
>
> +/* ---------------------------------------------------------------------- */
> +/* Initiate encrypted connection. */
> +#define OP_STARTTLS 0x06
> +#define OP_REQ_STARTTLS   (OP_REQUEST | OP_STARTTLS)
> +#define OP_REP_STARTTLS   (OP_REPLY   | OP_STARTTLS)
> +
>  void usbip_net_pack_uint32_t(int pack, uint32_t *num);
>  void usbip_net_pack_uint16_t(int pack, uint16_t *num);
>  void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
> @@ -180,6 +187,8 @@ int usbip_net_set_reuseaddr(int sockfd);
>  int usbip_net_set_nodelay(int sockfd);
>  int usbip_net_set_keepalive(int sockfd);
>  int usbip_net_set_v6only(int sockfd);
> -int usbip_net_tcp_connect(char *hostname, char *port);
> +int usbip_net_connect(char *hostname);
> +int net_srp_server_handshake(int connfd);
> +int usbip_net_init_gnutls(void);
>
>  #endif /* __USBIP_NETWORK_H */
> diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
> index 2f87f2d..23c15d7 100644
> --- a/tools/usb/usbip/src/usbipd.c
> +++ b/tools/usb/usbip/src/usbipd.c
> @@ -36,6 +36,11 @@
>  #include <tcpd.h>
>  #endif
>
> +#ifdef HAVE_GNUTLS
> +#include <gnutls/gnutls.h>
> +#include <gnutls/crypto.h>
> +#endif
> +
>  #include <getopt.h>
>  #include <signal.h>
>  #include <poll.h>
> @@ -64,6 +69,11 @@ static const char usbipd_help_string[] =
>         "       -6, --ipv6\n"
>         "               Bind to IPv6. Default is both.\n"
>         "\n"
> +#ifdef HAVE_GNUTLS
> +       "       -sPASSWORD, --auth PASSWORD\n"
> +       "               Set PASSWORD as key used for authentication.\n"
> +       "\n"
> +#endif
>         "       -D, --daemon\n"
>         "               Run as a daemon process.\n"
>         "\n"
> @@ -83,6 +93,8 @@ static const char usbipd_help_string[] =
>         "       -v, --version\n"
>         "               Show version.\n";
>
> +static int need_auth;
> +
>  static void usbipd_help(void)
>  {
>         printf("%s\n", usbipd_help_string);
> @@ -239,14 +251,7 @@ static int recv_request_devlist(int connfd)
>
>  static int recv_pdu(int connfd)
>  {
> -       uint16_t code = OP_UNSPEC;
> -       int ret;
> -
> -       ret = usbip_net_recv_op_common(connfd, &code);
> -       if (ret < 0) {
> -               dbg("could not receive opcode: %#0x", code);
> -               return -1;
> -       }
> +       int auth = !need_auth, cont = 1, ret;
>
>         ret = usbip_host_refresh_device_list();
>         if (ret < 0) {
> @@ -254,25 +259,63 @@ static int recv_pdu(int connfd)
>                 return -1;
>         }
>
> -       info("received request: %#0x(%d)", code, connfd);
> -       switch (code) {
> -       case OP_REQ_DEVLIST:
> -               ret = recv_request_devlist(connfd);
> -               break;
> -       case OP_REQ_IMPORT:
> -               ret = recv_request_import(connfd);
> -               break;
> -       case OP_REQ_DEVINFO:
> -       case OP_REQ_CRYPKEY:
> -       default:
> -               err("received an unknown opcode: %#0x", code);
> -               ret = -1;
> -       }
> +       /*
> +        * Process opcodes. We might receive more than one, as the
> +        * client might send STARTTLS first
> +        */
> +       while (cont) {
> +               uint16_t code = OP_UNSPEC;
>
> -       if (ret == 0)
> -               info("request %#0x(%d): complete", code, connfd);
> -       else
> -               info("request %#0x(%d): failed", code, connfd);
> +               ret = usbip_net_recv_op_common(connfd, &code);
> +               if (ret < 0) {
> +                       dbg("could not receive opcode: %#0x", code);
> +                       return -1;
> +               }
> +
> +               info("received request: %#0x(%d)", code, connfd);
> +
> +               /* We require an authenticated encryption */
> +               if (!auth && code != OP_REQ_STARTTLS) {
> +                       usbip_net_send_op_common(connfd, OP_REPLY, ST_NA);
> +                       return -1;
> +               }
> +
> +               switch (code) {
> +#ifdef HAVE_GNUTLS
> +               case OP_REQ_STARTTLS:
> +                       if (!need_auth) {
> +                               ret = -1;
> +                               err("Unexpected TLS handshake attempt (client uses password, server doesn't)");
> +                       } else {
> +                               ret = net_srp_server_handshake(connfd);
> +                               if (ret != 0)
> +                                       err("TLS handshake failed");
> +                               auth = 1;
> +                       }
> +                       break;
> +#endif
> +               case OP_REQ_DEVLIST:
> +                       ret = recv_request_devlist(connfd);
> +                       cont = 0;
> +                       break;
> +               case OP_REQ_IMPORT:
> +                       ret = recv_request_import(connfd);
> +                       cont = 0;
> +                       break;
> +               case OP_REQ_DEVINFO:
> +               case OP_REQ_CRYPKEY:
> +               default:
> +                       err("received an unknown opcode: %#0x", code);
> +                       ret = -1;
> +               }
> +
> +               if (ret == 0)
> +                       info("request %#0x(%d): complete", code, connfd);
> +               else {
> +                       info("request %#0x(%d): failed", code, connfd);
> +                       break;
> +               }
> +       }
>
>         return ret;
>  }
> @@ -593,6 +636,7 @@ int main(int argc, char *argv[])
>                 { "tcp-port", required_argument, NULL, 't' },
>                 { "help",     no_argument,       NULL, 'h' },
>                 { "version",  no_argument,       NULL, 'v' },
> +               { "auth",     required_argument, NULL, 's' },
>                 { NULL,       0,                 NULL,  0  }
>         };
>
> @@ -605,6 +649,9 @@ int main(int argc, char *argv[])
>         int daemonize = 0;
>         int ipv4 = 0, ipv6 = 0;
>         int opt, rc = -1;
> +#ifdef HAVE_GNUTLS
> +       int ret;
> +#endif
>
>         pid_file = NULL;
>
> @@ -616,7 +663,7 @@ int main(int argc, char *argv[])
>
>         cmd = cmd_standalone_mode;
>         for (;;) {
> -               opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
> +               opt = getopt_long(argc, argv, "46s:DdP::t:hv", longopts, NULL);
>
>                 if (opt == -1)
>                         break;
> @@ -628,6 +675,20 @@ int main(int argc, char *argv[])
>                 case '6':
>                         ipv6 = 1;
>                         break;
> +               case 's':
> +#ifdef HAVE_GNUTLS
> +                       need_auth = 1;
> +                       ret = usbip_net_init_gnutls();
> +                       if (ret < 0) {
> +                               err("Unable to initialize GnuTLS: %s",
> +                                   gnutls_strerror(ret));
> +                               return EXIT_FAILURE;
> +                       }
> +                       break;
> +#else
> +                       err("usbipd has been compiled without GnuTLS support");
> +                       break;
> +#endif
>                 case 'D':
>                         daemonize = 1;
>                         break;
> --
> 2.1.0
>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 00/18] usbip: Crypto and ACLs
  2014-09-26 11:56 ` [PATCH 00/18] usbip: Crypto and ACLs Valentina Manea
@ 2014-11-07 17:49   ` Greg KH
  2014-11-09 21:10     ` Valentina Manea
  0 siblings, 1 reply; 31+ messages in thread
From: Greg KH @ 2014-11-07 17:49 UTC (permalink / raw)
  To: Valentina Manea; +Cc: Maximilian Eschenbacher, linux-kernel, shuah.kh

On Fri, Sep 26, 2014 at 02:56:56PM +0300, Valentina Manea wrote:
> Hi,
> 
> Sorry for the lack of feedback, I've been having a hectic period. I
> will review these patches starting tomorrow.

Any chance you got to review these?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 00/18] usbip: Crypto and ACLs
  2014-11-07 17:49   ` Greg KH
@ 2014-11-09 21:10     ` Valentina Manea
  2014-11-09 23:33       ` Greg KH
  2014-11-11 17:52       ` Maximilian Eschenbacher
  0 siblings, 2 replies; 31+ messages in thread
From: Valentina Manea @ 2014-11-09 21:10 UTC (permalink / raw)
  To: Greg KH; +Cc: Maximilian Eschenbacher, linux-kernel, shuah.kh

On Fri, Nov 7, 2014 at 7:49 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
>
> Any chance you got to review these?
>
> thanks,
>
> greg k-h

I did review the patch the implemented most stuff and suggested
modifications but didn't get any follow-up for a while now. Should I
modify it myself and resubmit?

Valentina

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 00/18] usbip: Crypto and ACLs
  2014-11-09 21:10     ` Valentina Manea
@ 2014-11-09 23:33       ` Greg KH
  2014-11-11 17:52       ` Maximilian Eschenbacher
  1 sibling, 0 replies; 31+ messages in thread
From: Greg KH @ 2014-11-09 23:33 UTC (permalink / raw)
  To: Valentina Manea; +Cc: Maximilian Eschenbacher, linux-kernel, shuah.kh

On Sun, Nov 09, 2014 at 11:10:03PM +0200, Valentina Manea wrote:
> On Fri, Nov 7, 2014 at 7:49 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > Any chance you got to review these?
> >
> > thanks,
> >
> > greg k-h
> 
> I did review the patch the implemented most stuff and suggested
> modifications but didn't get any follow-up for a while now. Should I
> modify it myself and resubmit?

If you want it to be merged, please do so.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 00/18] usbip: Crypto and ACLs
  2014-11-09 21:10     ` Valentina Manea
  2014-11-09 23:33       ` Greg KH
@ 2014-11-11 17:52       ` Maximilian Eschenbacher
  1 sibling, 0 replies; 31+ messages in thread
From: Maximilian Eschenbacher @ 2014-11-11 17:52 UTC (permalink / raw)
  To: Valentina Manea; +Cc: Greg KH, linux-kernel, shuah.kh

On Sun, Nov 09, 2014 at 11:10:03PM +0200, Valentina Manea wrote:
> On Fri, Nov 7, 2014 at 7:49 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > Any chance you got to review these?
> >
> > thanks,
> >
> > greg k-h
> 
> I did review the patch the implemented most stuff and suggested
> modifications but didn't get any follow-up for a while now. Should I
> modify it myself and resubmit?

We are almost finished implementing the parts you pointed out and will
resubmit in a few days.

Regards,

Maximilian Eschenbacher

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2014-11-11 18:00 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-16 23:38 [PATCH 00/18] usbip: Crypto and ACLs Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 01/18] usbip: sysfs_utils: add read_sysfs_attribute Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 02/18] usbip: Add support for client authentication Maximilian Eschenbacher
2014-09-21  0:42   ` Max Vozeler
2014-09-21 12:43     ` Dominik Paulus
2014-10-03 14:16   ` Valentina Manea
2014-09-16 23:38 ` [PATCH 03/18] usbip: Add kernel support for client ACLs Maximilian Eschenbacher
2014-09-21  0:44   ` Max Vozeler
2014-09-21 12:42     ` Dominik Paulus
2014-09-16 23:38 ` [PATCH 04/18] usbip: Add CIDR matching helper functions Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 05/18] usbip: Add ACL support to usbip bind Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 06/18] usbip: Add support for ACLs in usbipd Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 07/18] usbip: Add proper error reporting Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 08/18] usbip: Handle usbip being started as user Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 09/18] usbip: Improve debug output Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 10/18] usbip: Separate protocol/program version Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 11/18] usbip: TLS for all userspace communication Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 12/18] usbip: Exchange session keys in userspace Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 13/18] usbip: Pass session keys to the kernel Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 14/18] usbip: Wrap kernel_sendmsg()/recvmsg() Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 15/18] usbip: Add encryption support to kernel Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 16/18] usbip: Update documentation Maximilian Eschenbacher
2014-09-16 23:38 ` [PATCH 17/18] usbip: Increment version number to 1.2.1 Maximilian Eschenbacher
2014-09-17 17:51   ` Denys Vlasenko
2014-09-18 15:31     ` Fjodor Schelichow
2014-09-16 23:38 ` [PATCH 18/18] usbip: list.h include stddef.h for offsetof Maximilian Eschenbacher
2014-09-26 11:56 ` [PATCH 00/18] usbip: Crypto and ACLs Valentina Manea
2014-11-07 17:49   ` Greg KH
2014-11-09 21:10     ` Valentina Manea
2014-11-09 23:33       ` Greg KH
2014-11-11 17:52       ` Maximilian Eschenbacher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).