diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb92f80a6d3d3ab801856446e3b345f05ee52f2e..3367172f04754598671a3a82d1a2fd6c52e96d87 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,8 +6,8 @@ endif(COMMAND cmake_policy)
 
 project (pkcs11 C)
 
-set(PKCS11_PROXY_SRCS gck-rpc-module.c gck-rpc-message.c gck-rpc-util.c egg-buffer.c)
-set(PKCS11_DAEMON_SRCS egg-buffer.c gck-rpc-daemon-standalone.c gck-rpc-dispatch.c gck-rpc-message.c gck-rpc-util.c syscall-reporter.c syscall-names.h)
+set(PKCS11_PROXY_SRCS gck-rpc-module.c gck-rpc-message.c gck-rpc-util.c egg-buffer.c gck-rpc-tls-psk.c)
+set(PKCS11_DAEMON_SRCS egg-buffer.c gck-rpc-daemon-standalone.c gck-rpc-dispatch.c gck-rpc-message.c gck-rpc-util.c syscall-reporter.c syscall-names.h gck-rpc-tls-psk.c)
 
 add_definitions(-Wall)
 add_library(pkcs11-proxy SHARED ${PKCS11_PROXY_SRCS})
@@ -33,8 +33,8 @@ if (WIN32)
   target_link_libraries (pkcs11-proxy ws2_32)
 endif (WIN32)
 
-target_link_libraries (pkcs11-proxy pthread)
-target_link_libraries (pkcs11-daemon dl pthread)
+target_link_libraries (pkcs11-proxy pthread ssl)
+target_link_libraries (pkcs11-daemon dl pthread ssl)
 
 install_targets (/lib pkcs11-proxy)
 install_targets (/bin pkcs11-daemon)
diff --git a/README.rst b/README.rst
index 8f258c7ebb1329571c74536fd2850c93bc8d0b65..fd5bb2ae94fad0d161f743ef97e3c0b27c6bed2e 100644
--- a/README.rst
+++ b/README.rst
@@ -6,5 +6,10 @@ This fork has the following additional features:
 
 - support for running in "inetd mode", useful for calling directly from stunnel
 - seccomp syscall filtering (only tested in inetd-mode)
+- getaddrinfo support for IPv6, fallback and DNS resolution
+- TLS-PSK support to optionally encrypt communication
+
+Plus a number of important bug fixes. This version passes the SoftHSM test
+suite.
 
 An ubuntu PPA that tracks this version is ppa:leifj
diff --git a/USAGE b/USAGE
index c1784c7608ddefe654db621159f5be1bd368992d..f79297522dc0684c2331684553d96ef686de5e4b 100644
--- a/USAGE
+++ b/USAGE
@@ -5,9 +5,10 @@ dependencies and other features.
 
 The proxy tunnels PKCS11-requests over the network.  One possible use
 is to store cryptograhic information on a seperate server.  This way
-the crypto it can be isolated from the rest of the system.  Beware:
-the connection is not encrypted and can easily be sniffed.  You should
-use a secure communication-channel, for example stunnel.
+the crypto can be isolated from the rest of the system.
+
+Example
+=======
 
 Here is an example of using pkcs11-proxy together with SoftHSM (from the
 OpenDNSSEC project).  The benefit of this setup is that no extra hardware
@@ -30,3 +31,52 @@ slots: Slot 0           SoftHSM
   token label:   test token manuf:   SoftHSM token model:   SoftHSM
   token flags:   rng, login required, PIN initialized, token initialized,
   other flags=0x40 serial num  :  1
+
+
+IPv6 and DNS
+============
+
+The PKCS11_DAEMON_SOCKET and PKCS11_PROXY_SOCKET environment variables can
+have both hostnames and IPv6 addresses in them. getaddrinfo(3) is used to
+resolve any DNS name.
+
+$ PKCS11_DAEMON_SOCKET="tcp://server.example.com:2345" ...
+
+If `server.example.com' resolves to more than one IP address (such as one
+IPv4 and one IPv6 address), these will be tried sequentially. Currently,
+no attempt is made to speed up connection establishment using Happy Eyeballs
+(RFC 6555) or similar, so timeouts in case of unreachable addresses could
+be expected to be quite problematic.
+
+IPv6 addresses should be enclosed by square brackets.
+
+$ PKCS11_DAEMON_SOCKET="tcp://[::1]:2345" ...
+
+
+Encryption
+==========
+
+This version supports encrypting the communication between the client and
+proxy using OpenSSL TLS-PSK (pre-shared key). The PSK is read from a file
+that usees the GnuTLS psktool format. This format includes PSK identity
+as well as key.
+
+Currently, there is no way to specify the identity to use on the client
+side (client tells server what identity should be used), and the first
+identity found in the PSK file is used. The server side will correctly
+look up the identity requested by the client in it's PSK file, so it is
+possible to have one unique PSK identity and key per PKCS11 client, and
+have all the identitys and keys in the PSK file for the PKCS11 daemon.
+
+$ cat test.psk
+test:e9622c85018998993fcc16f5ce9c15e9
+$ PKCS11_PROXY_TLS_PSK_FILE="test.psk" \
+  PKCS11_DAEMON_SOCKET="tls://server.example.com:2345" \
+  pkcs11-daemon /usr/lib/libsofthsm.so
+$ PKCS11_PROXY_TLS_PSK_FILE="test.psk" \
+  PKCS11_PROXY_SOCKET="tls://server.example.com:2345" \
+  pkcs11-tool --module=/usr/lib/libpkcs11-proxy.so -L Available
+slots: Slot 0           SoftHSM
+  token label:   test token manuf:   SoftHSM token model:   SoftHSM
+  token flags:   rng, login required, PIN initialized, token initialized,
+  other flags=0x40 serial num  :  1
diff --git a/config.h b/config.h
index 88806d5099a1956ce2a80352fd5a37c33b84ecd1..7ebadeecf181b47e251215e2384a737eb5986b0b 100644
--- a/config.h
+++ b/config.h
@@ -6,6 +6,8 @@
 # define PKCS11PROXY_LISTEN_BACKLOG 128
 # define PKCS11PROXY_MAX_SESSION_COUNT 256
 
+# define PKCS11PROXY_TLS_PSK_CIPHERS "PSK-AES128-CBC-SHA:PSK-AES256-CBC-SHA";
+
 #ifdef __MINGW32__
 
 # include <stdint.h>
diff --git a/gck-rpc-daemon-standalone.c b/gck-rpc-daemon-standalone.c
index 9b89f50c46bd8809553b4271e061f838bc4907be..f0ffdfa720370bbcd595091693655e5d9baa55ce 100644
--- a/gck-rpc-daemon-standalone.c
+++ b/gck-rpc-daemon-standalone.c
@@ -26,6 +26,7 @@
 #include "pkcs11/pkcs11.h"
 
 #include "gck-rpc-layer.h"
+#include "gck-rpc-tls-psk.h"
 
 #include <stdio.h>
 #include <errno.h>
@@ -166,12 +167,12 @@ int main(int argc, char *argv[])
 	CK_C_GetFunctionList func_get_list;
 	CK_FUNCTION_LIST_PTR funcs;
 	void *module;
-	const char *path;
+	const char *path, *tls_psk_keyfile;
 	fd_set read_fds;
 	int sock, ret;
 	CK_RV rv;
 	CK_C_INITIALIZE_ARGS init_args;
-
+	GckRpcTlsPskState *tls;
 
         if (install_syscall_reporter())
                 return 1;
@@ -229,6 +230,27 @@ int main(int argc, char *argv[])
         if (!path)
 	   path = SOCKET_PATH;
 
+	/* Initialize TLS, if appropriate */
+	tls = NULL;
+	if (! strncmp("tls://", path, 6)) {
+		tls_psk_keyfile = getenv("PKCS11_PROXY_TLS_PSK_FILE");
+		if (! tls_psk_keyfile || ! tls_psk_keyfile[0]) {
+			fprintf(stderr, "key file must be specified for tls:// socket.\n");
+			exit(1);
+		}
+
+		tls = calloc(1, sizeof(GckRpcTlsPskState));
+		if (tls == NULL) {
+			fprintf(stderr, "can't allocate memory for TLS-PSK");
+			exit(1);
+		}
+
+		if (! gck_rpc_init_tls_psk(tls, tls_psk_keyfile, NULL, GCK_RPC_TLS_PSK_SERVER)) {
+			fprintf(stderr, "TLS-PSK initialization failed");
+			exit(1);
+		}
+	}
+
         if (strcmp(path,"-") == 0) {
            gck_rpc_layer_inetd(funcs);
         } else {
@@ -254,7 +276,7 @@ int main(int argc, char *argv[])
 		}
 
 		if (FD_ISSET(sock, &read_fds))
-			gck_rpc_layer_accept();
+			gck_rpc_layer_accept(tls);
 	   }
 
 	   gck_rpc_layer_uninitialize();
@@ -267,5 +289,8 @@ int main(int argc, char *argv[])
 
 	dlclose(module);
 
+	if (tls)
+		gck_rpc_close_tls(tls);
+
 	return 0;
 }
diff --git a/gck-rpc-dispatch.c b/gck-rpc-dispatch.c
index a6f76343986527374e91b6fc46f54b86c34fa0b9..c604eca986d30d8a6db8f1dc998ed709015b02a7 100644
--- a/gck-rpc-dispatch.c
+++ b/gck-rpc-dispatch.c
@@ -25,6 +25,7 @@
 
 #include "gck-rpc-layer.h"
 #include "gck-rpc-private.h"
+#include "gck-rpc-tls-psk.h"
 
 #include "pkcs11/pkcs11.h"
 #include "pkcs11/pkcs11g.h"
@@ -71,14 +72,15 @@ typedef struct _CallState {
 	uint64_t appid;
 	int call;
 	int sock;
-        int (*read)(int, unsigned char *,size_t);
-        int (*write)(int, unsigned char *,size_t);
+        int (*read)(void *cs, unsigned char *,size_t);
+        int (*write)(void *cs, unsigned char *,size_t);
 	struct sockaddr_storage addr;
 	socklen_t addrlen;
 	/* XXX Maybe sessions should be a linked list instead, to remove the hard
 	 * upper limit and reduce typical memory use.
 	 */
 	SessionState sessions[PKCS11PROXY_MAX_SESSION_COUNT];
+	GckRpcTlsPskState *tls;
 } CallState;
 
 typedef struct _DispatchState {
@@ -2137,17 +2139,20 @@ static int dispatch_call(CallState * cs)
 	return 1;
 }
 
-static int read_all(int sock, unsigned char *data, size_t len)
+static int read_all(CallState *cs, void *data, size_t len)
 {
 	int r;
 
-	assert(sock >= 0);
+	assert(cs->sock >= 0);
 	assert(data);
 	assert(len > 0);
 
 	while (len > 0) {
 
-                r = recv(sock, (void *)data, len, 0);
+		if (cs->tls)
+			r = gck_rpc_tls_read_all(cs->tls, data, len);
+		else
+			r = recv(cs->sock, data, len, 0);
 
 		if (r == 0) {
 			/* Connection was closed on client */
@@ -2166,17 +2171,20 @@ static int read_all(int sock, unsigned char *data, size_t len)
 	return 1;
 }
 
-static int write_all(int sock, unsigned char *data, size_t len)
+static int write_all(CallState *cs, void *data, size_t len)
 {
 	int r;
 
-	assert(sock >= 0);
+	assert(cs->sock >= 0);
 	assert(data);
 	assert(len > 0);
 
 	while (len > 0) {
 
-                r = send(sock, (void *)data, len, MSG_NOSIGNAL);
+		if (cs->tls)
+			r = gck_rpc_tls_write_all(cs->tls, (void *) data, len);
+		else
+                        r = send(cs->sock, data, len, MSG_NOSIGNAL);
 
 		if (r == -1) {
 			if (errno == EPIPE) {
@@ -2212,8 +2220,16 @@ static void run_dispatch_loop(CallState *cs)
 		hoststr[0] = portstr[0] = '\0';
 	}
 
+	/* Enable TLS for this socket */
+	if (cs->tls) {
+		if (! gck_rpc_start_tls(cs->tls, cs->sock)) {
+			gck_rpc_warn("Can't enable TLS");
+			return ;
+		}
+	}
+
 	/* The client application */
-	if (!cs->read(cs->sock, (unsigned char *)&cs->appid, sizeof (cs->appid))) {
+	if (! cs->read(cs, (void *)&cs->appid, sizeof (cs->appid))) {
 		gck_rpc_warn("Can't read appid\n");
 		return ;
 	}
@@ -2233,7 +2249,7 @@ static void run_dispatch_loop(CallState *cs)
 		call_reset(cs);
 
 		/* Read the number of bytes ... */
-		if (!cs->read(cs->sock, buf, 4))
+		if (! cs->read(cs, buf, 4))
 			break;
 
 		/* Calculate the number of bytes */
@@ -2252,7 +2268,7 @@ static void run_dispatch_loop(CallState *cs)
 		}
 
 		/* ... and read/parse in the actual message */
-		if (!cs->read(cs->sock, cs->req->buffer.buf, len))
+		if (!cs->read(cs, cs->req->buffer.buf, len))
 			break;
 
 		egg_buffer_add_empty(&cs->req->buffer, len);
@@ -2266,8 +2282,8 @@ static void run_dispatch_loop(CallState *cs)
 
 		/* .. send back response length, and then response data */
 		egg_buffer_encode_uint32(buf, cs->resp->buffer.len);
-		if (!cs->write(cs->sock, buf, 4) ||
-		    !cs->write(cs->sock, cs->resp->buffer.buf, cs->resp->buffer.len))
+		if (!cs->write(cs, buf, 4) ||
+		    !cs->write(cs, cs->resp->buffer.buf, cs->resp->buffer.len))
 			break;
 	}
 
@@ -2299,7 +2315,7 @@ static int pkcs11_socket = -1;
 /* The unix socket path, that we listen on */
 static char pkcs11_socket_path[MAXPATHLEN] = { 0, };
 
-void gck_rpc_layer_accept(void)
+void gck_rpc_layer_accept(GckRpcTlsPskState *tls)
 {
 	struct sockaddr_storage addr;
 	DispatchState *ds, **here;
@@ -2342,6 +2358,7 @@ void gck_rpc_layer_accept(void)
         ds->cs.write = &write_all;
 	ds->cs.addr = addr;
 	ds->cs.addrlen = addrlen;
+	ds->cs.tls = tls;
 
 	error = pthread_create(&ds->thread, NULL,
 			       run_dispatch_thread, &(ds->cs));
@@ -2357,14 +2374,26 @@ void gck_rpc_layer_accept(void)
 	pthread_mutex_unlock(&pkcs11_dispatchers_mutex);
 }
 
+static int _inetd_read(CallState *cs, void *data, size_t len)
+{
+	assert(cs->sock >= 0);
+	return read(cs->sock, data, len);
+}
+
+static int _inetd_write(CallState *cs, void *data, size_t len)
+{
+	assert(cs->sock >= 0);
+	return write(cs->sock, data, len);
+}
+
 void gck_rpc_layer_inetd(CK_FUNCTION_LIST_PTR module)
 {
    CallState cs;
 
    memset(&cs, 0, sizeof(cs));
    cs.sock = STDIN_FILENO;
-   cs.read = &read;
-   cs.write = &write;
+   cs.read = &_inetd_read;
+   cs.write = &_inetd_write;
 
    pkcs11_module = module;
 
@@ -2496,7 +2525,8 @@ int gck_rpc_layer_initialize(const char *prefix, CK_FUNCTION_LIST_PTR module)
         }
 #endif
 
-	if (!strncmp("tcp://", prefix, 6)) {
+	if (!strncmp("tcp://", prefix, 6) ||
+	    !strncmp("tls://", prefix, 6)) {
 		/*
 		 * TCP socket
 		 */
diff --git a/gck-rpc-layer.h b/gck-rpc-layer.h
index 5d2766c4fe5e466de380aab99fe04f848da6b80c..8ea653b55f1e86c3862857e841fad39192fa93d9 100644
--- a/gck-rpc-layer.h
+++ b/gck-rpc-layer.h
@@ -3,6 +3,8 @@
 
 #include "pkcs11/pkcs11.h"
 
+#include "gck-rpc-tls-psk.h"
+
 /* ------------------------------------------------------------------
  * DISPATCHER
  */
@@ -14,7 +16,7 @@ int gck_rpc_layer_initialize(const char *prefix, CK_FUNCTION_LIST_PTR funcs);
 void gck_rpc_layer_uninitialize(void);
 
 /* Accept a new connection. Should be called when above fd has read */
-void gck_rpc_layer_accept(void);
+void gck_rpc_layer_accept(GckRpcTlsPskState *tls);
 
 /* Run a single connection off of STDIN - call from inetd or stunnel */
 void gck_rpc_layer_inetd(CK_FUNCTION_LIST_PTR funcs);
diff --git a/gck-rpc-module.c b/gck-rpc-module.c
index 1ce0665af712e9d1fc5569cc11895d35abfd3026..84adf067023bc0c52b93427e4821fa3afed481ea 100644
--- a/gck-rpc-module.c
+++ b/gck-rpc-module.c
@@ -25,6 +25,7 @@
 
 #include "gck-rpc-layer.h"
 #include "gck-rpc-private.h"
+#include "gck-rpc-tls-psk.h"
 
 #include "pkcs11/pkcs11.h"
 
@@ -67,6 +68,8 @@ static uint64_t pkcs11_app_id = 0;
 
 /* The socket to connect to */
 static char pkcs11_socket_path[MAXPATHLEN] = { 0, };
+/* The TLS-PSK keyfile name */
+static char tls_psk_key_filename[MAXPATHLEN] = { 0, };
 
 /* The error used by us when parsing of rpc message fails */
 #define PARSE_ERROR   CKR_DEVICE_ERROR
@@ -113,6 +116,9 @@ static void parse_argument(char *arg)
 	if (strcmp(arg, "socket") == 0)
 		snprintf(pkcs11_socket_path, sizeof(pkcs11_socket_path), "%s",
 			 value);
+	else if (strcmp(arg, "tls_psk_file") == 0)
+		snprintf(tls_psk_key_filename, sizeof(tls_psk_key_filename), "%s",
+			 value);
 	else
 		warning(("unrecognized argument: %s", arg));
 }
@@ -201,6 +207,7 @@ typedef struct _CallState {
 	GckRpcMessage *req;	/* The current request */
 	GckRpcMessage *resp;	/* The current response */
 	int call_status;
+	GckRpcTlsPskState *tls;
 	struct _CallState *next;	/* For pooling of completed sockets */
 } CallState;
 
@@ -251,7 +258,10 @@ static CK_RV call_write(CallState * cs, unsigned char *data, size_t len)
 			return CKR_DEVICE_ERROR;
 		}
 
-                r = send(fd, (void *)data, len, 0);
+		if (cs->tls)
+			r = gck_rpc_tls_write_all(cs->tls, (void *) data, len);
+		else
+			r = send(fd, (void *) data, len, 0);
 
 		if (r == -1) {
 			if (errno == EPIPE) {
@@ -290,7 +300,10 @@ static CK_RV call_read(CallState * cs, unsigned char *data, size_t len)
 			return CKR_DEVICE_ERROR;
 		}
 
-                r = recv(fd, (void *)data, len, 0);
+		if (cs->tls)
+			r = gck_rpc_tls_read_all(cs->tls, (void *) data, len);
+		else
+			r = recv(fd, (void *) data, len, 0);
 
 		if (r == 0) {
 			warning(("couldn't receive data: daemon closed connection"));
@@ -409,7 +422,8 @@ static CK_RV call_connect(CallState * cs)
 
 	memset(&addr, 0, sizeof(addr));
 
-	if (!strncmp("tcp://", pkcs11_socket_path, 6)) {
+	if (! strncmp("tcp://", pkcs11_socket_path, 6) ||
+	    ! strncmp("tls://", pkcs11_socket_path, 6)) {
 		char *host, *port;
 
 		if (! gck_rpc_parse_host_port(pkcs11_socket_path + 6, &host, &port)) {
@@ -424,6 +438,24 @@ static CK_RV call_connect(CallState * cs)
 		}
 
 		free(host);
+
+		if (! strncmp("tls://", pkcs11_socket_path, 6)) {
+			cs->tls = calloc(1, sizeof(GckRpcTlsPskState));
+			if (cs->tls == NULL) {
+				warning(("can't allocate memory for TLS-PSK"));
+				return CKR_HOST_MEMORY;
+			}
+
+			if (! gck_rpc_init_tls_psk(cs->tls, tls_psk_key_filename, NULL, GCK_RPC_TLS_PSK_CLIENT)) {
+				warning(("TLS-PSK initialization failed"));
+				return CKR_DEVICE_ERROR;
+			}
+
+			if (! gck_rpc_start_tls(cs->tls, sock)) {
+				gck_rpc_warn("failed starting TLS");
+				return CKR_DEVICE_ERROR;
+			}
+		}
 	} else {
 		addr.sun_family = AF_UNIX;
 		strncpy(addr.sun_path, pkcs11_socket_path,
@@ -472,6 +504,9 @@ static void call_destroy(void *value)
 		gck_rpc_message_free(cs->req);
 		gck_rpc_message_free(cs->resp);
 
+		if (cs->tls)
+			gck_rpc_close_tls(cs->tls);
+
 		free(cs);
 
 		debug(("destroyed state"));
@@ -1320,7 +1355,8 @@ static CK_RV rpc_C_Initialize(CK_VOID_PTR init_args)
 	if (pkcs11_socket_path[0] == 0) {
 		path = getenv("PKCS11_PROXY_SOCKET");
 		if (path && path[0]) {
-			if (!strncmp("tcp://", path, 6))
+			if ((! strncmp("tcp://", path, 6)) ||
+			    (! strncmp("tls://", path, 6)))
 				snprintf(pkcs11_socket_path,
 					 sizeof(pkcs11_socket_path), "%s",
 					 path);
@@ -1335,6 +1371,23 @@ static CK_RV rpc_C_Initialize(CK_VOID_PTR init_args)
 		}
 	}
 
+	/* If socket path indicates TLS, make sure tls_psk_key_filename is populated. */
+	if (! strncmp("tls://", pkcs11_socket_path, 6)) {
+		if (! tls_psk_key_filename[0]) {
+			path = getenv("PKCS11_PROXY_TLS_PSK_FILE");
+			if (path && path[0]) {
+				snprintf(tls_psk_key_filename, sizeof(tls_psk_key_filename),
+					 "%s", path);
+			}
+		}
+
+		if (! tls_psk_key_filename[0]) {
+			warning(("can't handle tls:// path without a tls-psk file"));
+			ret =  CKR_FUNCTION_NOT_SUPPORTED;
+			goto done;
+		}
+	}
+
 	srand(time(NULL) ^ pid);
 	pkcs11_app_id = (uint64_t) rand() << 32 | rand();
 
diff --git a/gck-rpc-tls-psk.c b/gck-rpc-tls-psk.c
new file mode 100644
index 0000000000000000000000000000000000000000..23d5dd4b34c8f18d4139049ffabf890f7edb3f2f
--- /dev/null
+++ b/gck-rpc-tls-psk.c
@@ -0,0 +1,376 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-rpc-tls-psk.c - TLS-PSK functionality to protect communication
+
+   Copyright (C) 2013, NORDUnet A/S
+
+   pkcs11-proxy is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   pkcs11-proxy is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Fredrik Thulin <fredrik@thulin.net>
+*/
+
+#include "config.h"
+
+#include "gck-rpc-private.h"
+#include "gck-rpc-tls-psk.h"
+
+#include <sys/param.h>
+#include <assert.h>
+
+/* TLS pre-shared key */
+static char tls_psk_identity[128] = { 0, };
+static char tls_psk_key_filename[MAXPATHLEN] = { 0, };
+
+/* -----------------------------------------------------------------------------
+ * LOGGING and DEBUGGING
+ */
+#ifndef DEBUG_OUTPUT
+#define DEBUG_OUTPUT 0
+#endif
+#if DEBUG_OUTPUT
+#define debug(x) gck_rpc_debug x
+#else
+#define debug(x)
+#endif
+#define warning(x) gck_rpc_warn x
+
+
+/* -----------------------------------------------------------------------------
+ * TLS-PSK (pre-shared key) functionality
+ */
+
+/* Utility function to decode a single hex char.
+ *
+ * Returns value as integer, or -1 on invalid hex char (not 0-9, a-f or A-F).
+ */
+static int
+_tls_psk_to_hex(char val)
+{
+	if (val >= '0' && val <= '9')
+		return val - '0';
+	if (val >= 'a' && val <= 'f')
+		return val - 'a' + 10;
+	if (val >= 'A' && val <= 'F')
+		return val - 'A' + 10;
+	return -1;
+}
+
+/* Hex decode the key from an entry in the TLS-PSK key file. Entrys are of the form
+ *
+ *   identity:hex-key\n
+ *
+ * Logging debug/error messages here is a bit problematic since the key is sensitive
+ * and should not be logged to syslog for example. This code avoids logging the key
+ * part and only logs identity.
+ *
+ * Returns 0 on failure, number of bytes in hex-decoded key on success.
+ */
+static int
+_tls_psk_decode_key(const char *identity, const char *hexkey, unsigned char *psk, unsigned int max_psk_len)
+{
+	int psk_len, i;
+
+	/* check that length of the key is even */
+	if ((strlen(hexkey) % 2) != 0) {
+		warning(("un-even length TLS-PSK key"));
+		return 0;
+	}
+
+	memset(psk, 0, max_psk_len);
+	psk_len = 0;
+
+	while (*hexkey && (psk_len < max_psk_len)) {
+		/* decode first half of byte, check for errors */
+		if ((i = _tls_psk_to_hex(*hexkey)) < 0) {
+			warning(("bad TLS-PSK '%.100s' hex char at position %i (%c)",
+				 identity, psk_len + 1, *hexkey));
+			return 0;
+		}
+		*psk = i << 4;
+		hexkey++;
+
+		/* decode second half of byte, check for errors */
+		if ((i = _tls_psk_to_hex(*hexkey)) < 0) {
+		        warning(("bad TLS-PSK '%.100s' hex char at position %i (%c)",
+				 identity, psk_len + 1, *hexkey));
+			return 0;
+		}
+		*psk |= i;
+		hexkey++;
+
+		psk_len++;
+		psk++;
+	}
+	if (*hexkey) {
+		warning(("too long TLS-PSK '%.100s' key (max %i)", identity, max_psk_len));
+		return 0;
+	}
+
+	return psk_len;
+}
+
+/*
+ * Callbacks invoked by OpenSSL PSK initialization.
+ */
+
+/* Server side TLS-PSK initialization callback. Given an identity (chosen by the client),
+ * locate a pre-shared key and put it in psk.
+ *
+ * Returns the number of bytes put in psk, or 0 on failure.
+ */
+static unsigned int
+_tls_psk_server_cb(SSL *ssl, const char *identity,
+		   unsigned char *psk, unsigned int max_psk_len)
+{
+	char line[1024], *hexkey;
+	unsigned int psk_len;
+	FILE *fd;
+	int i;
+
+	debug(("Initializing TLS-PSK with keyfile '%.100s', identity '%.100s'",
+	       tls_psk_key_filename, identity));
+
+	if ((fd = fopen(tls_psk_key_filename, "r")) == NULL) {
+		gck_rpc_warn("can't open TLS-PSK keyfile '%.100s' for reading", tls_psk_key_filename);
+		return 0;
+	}
+
+	/* Format of PSK file is that of GnuTLS psktool.
+	 *
+	 * identity:hex-key
+	 * other:another-hex-key
+	*/
+	psk_len = 0;
+
+	while (fgets(line, sizeof(line) - 1, fd)) {
+		/* Find first colon and replace it with NULL */
+		hexkey = strchr(line, ':');
+		if (! hexkey)
+			continue;
+		*hexkey = 0;
+		hexkey++;
+
+		/* Remove newline(s) at the end */
+		for (i = strlen(hexkey) - 1; i && (hexkey[i] == '\n' || hexkey[i] == '\r'); i--)
+			hexkey[i] = 0;
+
+		if (identity == NULL || ! identity[0] || ! strcmp(line, identity)) {
+			/* If the line starts with identity: or identity is not provided, parse this line. */
+			psk_len = _tls_psk_decode_key(line, hexkey, psk, max_psk_len);
+			if (psk_len)
+				debug(("Loaded TLS-PSK '%.100s' from keyfile '%.100s'",
+				       line, tls_psk_key_filename));
+			else
+				warning(("Failed loading TLS-PSK '%.100s' from keyfile '%.100s'",
+					 line, tls_psk_key_filename));
+			break;
+		}
+	}
+	fclose(fd);
+
+	return psk_len;
+}
+
+/* Client side TLS-PSK initialization callback. Indicate to OpenSSL what identity to
+ * use, and the pre-shared key for that identity.
+ *
+ * Returns the number of bytes put in psk, or 0 on failure.
+ */
+static unsigned int
+_tls_psk_client_cb(SSL *ssl, const char *hint,
+		   char *identity, unsigned int max_identity_len,
+		   unsigned char *psk, unsigned int max_psk_len)
+{
+	/* Client tells server which identity it wants to use in ClientKeyExchange */
+	snprintf(identity, max_identity_len, "%s", tls_psk_identity);
+
+	/* We currently just discard the hint sent to us by the server */
+	return _tls_psk_server_cb(ssl, identity, psk, max_psk_len);
+}
+
+
+/* Initialize OpenSSL and create an SSL CTX. Should be called just once.
+ *
+ * Returns 0 on failure and 1 on success.
+ */
+int
+gck_rpc_init_tls_psk(GckRpcTlsPskState *state, const char *key_filename,
+		     const char *identity, enum gck_rpc_tls_psk_caller caller)
+{
+	char *tls_psk_ciphers = PKCS11PROXY_TLS_PSK_CIPHERS;
+
+	if (state->initialized == 1) {
+		warning(("TLS state already initialized"));
+		return 0;
+	}
+
+	/* Global OpenSSL initialization */
+	SSL_load_error_strings();
+	SSL_library_init();
+	OpenSSL_add_ssl_algorithms();
+
+	assert(caller == GCK_RPC_TLS_PSK_CLIENT || caller == GCK_RPC_TLS_PSK_SERVER);
+
+	if (caller == GCK_RPC_TLS_PSK_CLIENT)
+		state->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+	else
+		state->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+
+	if (state->ssl_ctx == NULL) {
+		gck_rpc_warn("can't initialize SSL_CTX");
+		return 0;
+	}
+
+	/* Set up callback for TLS-PSK initialization */
+	if (caller == GCK_RPC_TLS_PSK_CLIENT)
+		SSL_CTX_set_psk_client_callback(state->ssl_ctx, _tls_psk_client_cb);
+	else
+		SSL_CTX_set_psk_server_callback(state->ssl_ctx, _tls_psk_server_cb);
+
+	/* Disable compression, for security (CRIME Attack). */
+	SSL_CTX_set_options(state->ssl_ctx, SSL_OP_NO_COMPRESSION);
+
+	/* Specify ciphers to use */
+	SSL_CTX_set_cipher_list(state->ssl_ctx, tls_psk_ciphers);
+
+	snprintf(tls_psk_key_filename, sizeof(tls_psk_key_filename), "%s", key_filename);
+	snprintf(tls_psk_identity, sizeof(tls_psk_identity), "%s", identity ? identity : "");
+
+	state->type = caller;
+	state->initialized = 1;
+
+	debug(("Initialized TLS-PSK %s", caller == GCK_RPC_TLS_PSK_CLIENT ? "client" : "server"));
+
+	return 1;
+}
+
+/* Set up SSL for a new socket. Call this after accept() or connect().
+ *
+ * When a socket has been created, call gck_rpc_start_tls() with the TLS state
+ * initialized using gck_rpc_init_tls_psk() and the new socket.
+ *
+ * Returns 1 on success and 0 on failure.
+ */
+int
+gck_rpc_start_tls(GckRpcTlsPskState *state, int sock)
+{
+	int res;
+	char buf[256];
+
+	state->ssl = SSL_new(state->ssl_ctx);
+	if (! state->ssl) {
+		warning(("can't initialize SSL"));
+		return 0;
+	}
+
+	state->bio = BIO_new_socket(sock, BIO_NOCLOSE);
+	if (! state->bio) {
+		warning(("can't initialize SSL BIO"));
+		return 0;
+	}
+
+	SSL_set_bio(state->ssl, state->bio, state->bio);
+
+	/* Set up callback for TLS-PSK initialization */
+	if (state->type == GCK_RPC_TLS_PSK_CLIENT)
+		res = SSL_connect(state->ssl);
+	else
+		res = SSL_accept(state->ssl);
+
+	if (res != 1) {
+		ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
+		warning(("can't start TLS : %i/%i (%s perhaps)",
+			 res, SSL_get_error(state->ssl, res), strerror(errno)));
+		warning(("SSL ERR: %s", buf));
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Un-initialize everything SSL related. Call this on application shut down.
+ */
+void
+gck_rpc_close_tls(GckRpcTlsPskState *state)
+{
+	if (state->ssl_ctx) {
+		SSL_CTX_free(state->ssl_ctx);
+		state->ssl_ctx = NULL;
+	}
+
+	if (state->ssl) {
+		SSL_free(state->ssl);
+		state->ssl = NULL;
+	}
+
+	if (state->bio) {
+		BIO_free(state->bio);
+		state->bio = NULL;
+	}
+}
+
+/* Send data using SSL.
+ *
+ * Returns the number of bytes written.
+ */
+int
+gck_rpc_tls_write_all(GckRpcTlsPskState *state, void *data, unsigned int len)
+{
+	int bytes, error;
+	char buf[256];
+
+	assert(state);
+	assert(data);
+	assert(len > 0);
+
+	bytes = SSL_write(state->ssl, data, len);
+
+	if (bytes <= 0) {
+		while ((error = ERR_get_error())) {
+			ERR_error_string_n(error, buf, sizeof(buf));
+			warning(("SSL_write error: %s", buf));
+		}
+		return 0;
+	}
+
+	return bytes;
+}
+
+/* Read data using SSL.
+ *
+ * Returns the number of bytes read.
+ */
+int
+gck_rpc_tls_read_all(GckRpcTlsPskState *state, void *data, unsigned int len)
+{
+	int bytes, error;
+	char buf[256];
+
+	assert(state);
+	assert(data);
+	assert(len > 0);
+
+	bytes = SSL_read(state->ssl, data, len);
+
+	if (bytes <= 0) {
+		while ((error = ERR_get_error())) {
+			ERR_error_string_n(error, buf, sizeof(buf));
+			warning(("SSL_read error: %s", buf));
+		}
+		return 0;
+	}
+
+	return bytes;
+}
diff --git a/gck-rpc-tls-psk.h b/gck-rpc-tls-psk.h
new file mode 100644
index 0000000000000000000000000000000000000000..b878376ae367f7041bfe0deea54c48a80f9c80c1
--- /dev/null
+++ b/gck-rpc-tls-psk.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+#ifndef GCKRPC_TLS_PSK_H_
+#define GCKRPC_TLS_PSK_H_
+
+#include "openssl/bio.h"
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x10000000
+# error "OpenSSL version >= 1.0.0 required"
+#endif
+
+enum gck_rpc_tls_psk_caller {
+	GCK_RPC_TLS_PSK_CLIENT,
+	GCK_RPC_TLS_PSK_SERVER
+};
+
+typedef struct {
+	int initialized;
+	SSL_CTX *ssl_ctx;
+	BIO *bio;
+	SSL *ssl;
+	enum gck_rpc_tls_psk_caller type;
+} GckRpcTlsPskState;
+
+
+int gck_rpc_init_tls_psk(GckRpcTlsPskState *state, const char *key_filename,
+			 const char *identity, enum gck_rpc_tls_psk_caller caller);
+int gck_rpc_start_tls(GckRpcTlsPskState *state, int sock);
+
+int gck_rpc_tls_write_all(GckRpcTlsPskState *state, void *data, unsigned int len);
+int gck_rpc_tls_read_all(GckRpcTlsPskState *state, void *data, unsigned int len);
+
+void gck_rpc_close_tls(GckRpcTlsPskState *state);
+
+#endif /* GCKRPC_TLS_PSK_H_ */