[Libguestfs] [PATCH v2 nbdkit] tls: Implement Pre-Shared Keys (PSK) authentication.

Richard W.M. Jones rjones at redhat.com
Mon Jun 25 21:33:44 UTC 2018


---
 .gitignore            |   1 +
 docs/nbdkit.pod.in    |  42 ++++++++-
 nbdkit.in             |   2 +-
 src/crypto.c          | 234 +++++++++++++++++++++++++++++++++++---------------
 src/internal.h        |   1 +
 src/main.c            |   8 +-
 tests/Makefile.am     |   8 ++
 tests/make-psk.sh     |  54 ++++++++++++
 tests/test-tls-psk.sh | 118 +++++++++++++++++++++++++
 9 files changed, 394 insertions(+), 74 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5c3d822..c986d76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,7 @@ Makefile.in
 /tests/disk.xz
 /tests/ext2.img
 /tests/file-data
+/tests/keys.psk
 /tests/offset-data
 /tests/partition-disk
 /tests/pki
diff --git a/docs/nbdkit.pod.in b/docs/nbdkit.pod.in
index 42e6e6b..115db3c 100644
--- a/docs/nbdkit.pod.in
+++ b/docs/nbdkit.pod.in
@@ -11,7 +11,7 @@ nbdkit - A toolkit for creating NBD servers
         [--newstyle] [--oldstyle] [-P PIDFILE] [-p PORT] [-r]
         [--run CMD] [-s] [--selinux-label LABEL] [-t THREADS]
         [--tls=off|on|require] [--tls-certificates /path/to/certificates]
-        [--tls-verify-peer]
+        [--tls-psk /path/to/pskfile] [--tls-verify-peer]
         [-U SOCKET] [-u USER] [-v] [-V]
         PLUGIN [key=value [key=value [...]]]
 
@@ -288,6 +288,12 @@ support).  See L</TLS> below.
 Set the path to the TLS certificates directory.  If not specified,
 some built-in paths are checked.  See L</TLS> below for more details.
 
+=item B<--tls-psk> /path/to/pskfile
+
+Set the path to the pre-shared keys (PSK) file.  If used, this
+overrides certificate authentication.  There is no built-in path.  See
+L</TLS> below for more details.
+
 =item B<--tls-verify-peer>
 
 Enables TLS client certificate verification.  The default is I<not> to
@@ -757,6 +763,35 @@ denied.  Also denied are clients which present a valid certificate
 signed by another CA.  Also denied are clients with certificates added
 to the certificate revocation list (F<ca-crl.pem>).
 
+=head2 TLS with Pre-Shared Keys (PSK)
+
+As a simpler alternative to TLS certificates, you may used pre-shared
+keys to authenticate clients.
+
+Create a PSK file containing one or more C<username:key> pairs.  It is
+easiest to use L<psktool(1)> for this:
+
+ mkdir -m 0700 /tmp/keys
+ psktool -u rich -p /tmp/keys/keys.psk
+
+The PSK file contains the hex-encoded random keys in plaintext.  Any
+client which can read this file will be able to connect to the server.
+
+Use the nbdkit I<--tls-psk> option to start the server:
+
+ nbdkit --tls=require --tls-psk=/tmp/keys/keys.psk -e / file file=disk.img
+
+This option overrides X.509 certificate authentication.
+
+Clients must supply one of the usernames in the PSK file and the
+corresponding key in order to connect.  An example of connecting using
+L<qemu-img(1)> is:
+
+ qemu-img info \
+   --object tls-creds-psk,id=tls0,dir=/tmp/keys,username=rich,endpoint=client \
+   --image-opts \
+   file.driver=nbd,file.host=localhost,file.port=10809,file.tls-creds=tls0,file.export=/
+
 =head2 Default TLS behaviour
 
 If nbdkit was compiled without GnuTLS support, then TLS is disabled
@@ -779,6 +814,10 @@ whether or not to use TLS and whether or not to present certificates.
 TLS client certificates are I<not> checked by default unless you
 specify I<--tls-verify-peer>.
 
+If the I<--tls-psk> option is used then TLS is enabled (but I<not>
+required).  To ensure that all clients are authorized you must use
+I<--tls=require>.
+
 Each of these defaults is insecure to some extent (including
 I<--tls=on> which could be subject to a downgrade attack), so if you
 expect TLS then it is best to specify the I<--tls> option that you
@@ -968,6 +1007,7 @@ L<https://en.wikipedia.org/wiki/Fibre_Channel_over_Ethernet>.
 
 L<gnutls_priority_init(3)>,
 L<qemu-img(1)>,
+L<psktool(1)>,
 L<systemd.socket(5)>.
 
 =head1 AUTHORS
diff --git a/nbdkit.in b/nbdkit.in
index e1cb941..51abcbf 100644
--- a/nbdkit.in
+++ b/nbdkit.in
@@ -70,7 +70,7 @@ while [ $# -gt 0 ]; do
             args[$i]="$1"
             shift
             ;;
-        -e | --export* | -g | --group | -i | --ip* | -P | --pid* | -p | --port | --run | --selinux-label | -t | --threads | --tls | --tls-certificates | -U | --unix | -u | --user)
+        -e | --export* | -g | --group | -i | --ip* | -P | --pid* | -p | --port | --run | --selinux-label | -t | --threads | --tls | --tls-certificates | --tls-psk | -U | --unix | -u | --user)
             args[$i]="$1"
             ((++i))
             args[$i]="$2"
diff --git a/src/crypto.c b/src/crypto.c
index 23c5c8f..6af3977 100644
--- a/src/crypto.c
+++ b/src/crypto.c
@@ -37,10 +37,12 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <assert.h>
@@ -51,7 +53,12 @@
 
 #include <gnutls/gnutls.h>
 
+static int crypto_auth = 0;
+#define CRYPTO_AUTH_CERTIFICATES 1
+#define CRYPTO_AUTH_PSK 2
+
 static gnutls_certificate_credentials_t x509_creds;
+static gnutls_psk_server_credentials_t psk_creds;
 
 static void print_gnutls_error (int err, const char *fs, ...)
   __attribute__((format (printf, 2, 3)));
@@ -147,23 +154,9 @@ load_certificates (const char *path)
   return 1;
 }
 
-/* Initialize crypto.  This also handles the command line parameters
- * and loading the server certificate.
- */
-void
-crypto_init (int tls_set_on_cli)
+static int
+start_certificates (void)
 {
-  int err;
-
-  err = gnutls_global_init ();
-  if (err < 0) {
-    print_gnutls_error (err, "initializing GnuTLS");
-    exit (EXIT_FAILURE);
-  }
-
-  if (tls == 0)                 /* --tls=off */
-    return;
-
   /* Try to locate the certificates directory and load them. */
   if (tls_certificates_dir == NULL) {
     const char *home;
@@ -196,49 +189,119 @@ crypto_init (int tls_set_on_cli)
     if (load_certificates (tls_certificates_dir))
       goto found_certificates;
   }
-
-  /* If we get here, we didn't manage to load the certificates.  If
-   * --tls=require was given on the command line then that's a
-   * problem.
-   */
-  if (tls == 2) {               /* --tls=require */
-    fprintf (stderr,
-             "%s: --tls=require but could not load TLS certificates.\n"
-             "Try setting ‘--tls-certificates=/path/to/certificates’ or read\n"
-             "the \"TLS\" section in nbdkit(1).\n",
-             program_name);
-    exit (EXIT_FAILURE);
-  }
-
-  /* If --tls=on was given on the command line, warn before we turn
-   * TLS off.
-   */
-  if (tls == 1 && tls_set_on_cli) { /* explicit --tls=on */
-    fprintf (stderr,
-             "%s: warning: --tls=on but could not load TLS certificates.\n"
-             "TLS will be disabled and TLS connections will be rejected.\n"
-             "Try setting ‘--tls-certificates=/path/to/certificates’ or read\n"
-             "the \"TLS\" section in nbdkit(1).\n",
-             program_name);
-  }
-
-  tls = 0;
-  debug ("TLS disabled: could not load TLS certificates");
-  return;
+  return -1;
 
  found_certificates:
 #ifdef HAVE_GNUTLS_CERTIFICATE_SET_KNOWN_DH_PARAMS
   gnutls_certificate_set_known_dh_params (x509_creds, GNUTLS_SEC_PARAM_MEDIUM);
 #endif
+  return 0;
+}
 
-  debug ("TLS enabled");
+static int
+start_psk (void)
+{
+  int err;
+  CLEANUP_FREE char *abs_psk_file = NULL;
+
+  /* Make sure the path to the PSK file is absolute. */
+  abs_psk_file = realpath (tls_psk, NULL);
+  if (abs_psk_file == NULL) {
+    perror (tls_psk);
+    exit (EXIT_FAILURE);
+  }
+
+  err = gnutls_psk_allocate_server_credentials (&psk_creds);
+  if (err < 0) {
+    print_gnutls_error (err, "allocating PSK credentials");
+    exit (EXIT_FAILURE);
+  }
+
+  /* Note that this function makes a copy of the string so it
+   * is safe to free it afterwards.
+   */
+  gnutls_psk_set_server_credentials_file (psk_creds, abs_psk_file);
+
+  return 0;
+}
+
+/* Initialize crypto.  This also handles the command line parameters
+ * and loading the server certificate.
+ */
+void
+crypto_init (int tls_set_on_cli)
+{
+  int err, r;
+  const char *what;
+
+  err = gnutls_global_init ();
+  if (err < 0) {
+    print_gnutls_error (err, "initializing GnuTLS");
+    exit (EXIT_FAILURE);
+  }
+
+  if (tls == 0)                 /* --tls=off */
+    return;
+
+  /* --tls-psk overrides certificates. */
+  if (tls_psk != NULL) {
+    r = start_psk ();
+    what = "Pre-Shared Keys (PSK)";
+    if (r == 0) crypto_auth = CRYPTO_AUTH_PSK;
+  }
+  else {
+    r = start_certificates ();
+    what = "X.509 certificates";
+    if (r == 0) crypto_auth = CRYPTO_AUTH_CERTIFICATES;
+  }
+
+  if (r == 0) {
+    debug ("TLS enabled using: %s", what);
+  }
+  else {
+    /* If we get here, we didn't manage to load the PSK file /
+     * certificates.  If --tls=require was given on the command line
+     * then that's a problem.
+     */
+    if (tls == 2) {               /* --tls=require */
+      fprintf (stderr,
+               "%s: --tls=require but could not load TLS certificates.\n"
+               "Try setting ‘--tls-certificates=/path/to/certificates’ or read\n"
+               "the \"TLS\" section in nbdkit(1).\n",
+               program_name);
+      exit (EXIT_FAILURE);
+    }
+
+    /* If --tls=on was given on the command line, warn before we turn
+     * TLS off.
+     */
+    if (tls == 1 && tls_set_on_cli) { /* explicit --tls=on */
+      fprintf (stderr,
+               "%s: warning: --tls=on but could not load TLS certificates.\n"
+               "TLS will be disabled and TLS connections will be rejected.\n"
+               "Try setting ‘--tls-certificates=/path/to/certificates’ or read\n"
+               "the \"TLS\" section in nbdkit(1).\n",
+               program_name);
+    }
+
+    tls = 0;
+    debug ("TLS disabled: could not load TLS certificates");
+  }
 }
 
 void
 crypto_free (void)
 {
-  if (tls > 0)
-    gnutls_certificate_free_credentials (x509_creds);
+  if (tls > 0) {
+    switch (crypto_auth) {
+    case CRYPTO_AUTH_CERTIFICATES:
+      gnutls_certificate_free_credentials (x509_creds);
+      break;
+    case CRYPTO_AUTH_PSK:
+      gnutls_psk_free_server_credentials (psk_creds);
+      break;
+    }
+  }
 
   gnutls_global_deinit ();
 }
@@ -335,6 +398,7 @@ int
 crypto_negotiate_tls (struct connection *conn, int sockin, int sockout)
 {
   gnutls_session_t *session;
+  CLEANUP_FREE char *priority = NULL;
   int err;
 
   /* Create the GnuTLS session. */
@@ -351,33 +415,61 @@ crypto_negotiate_tls (struct connection *conn, int sockin, int sockout)
     return -1;
   }
 
-  err = gnutls_priority_set_direct (*session, TLS_PRIORITY, NULL);
-  if (err < 0) {
-    nbdkit_error ("failed to set TLS session priority to %s: %s",
-                  TLS_PRIORITY, gnutls_strerror (err));
-    goto error;
-  }
+  switch (crypto_auth) {
+  case CRYPTO_AUTH_CERTIFICATES:
+    /* Associate the session with the server credentials (key, cert). */
+    err = gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE,
+                                  x509_creds);
+    if (err < 0) {
+      nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err));
+      goto error;
+    }
 
-  /* Associate the session with the server credentials (key, cert). */
-  err = gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE,
-                                x509_creds);
-  if (err < 0) {
-    nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err));
-    goto error;
-  }
-
-  /* If verify peer is enabled, tell GnuTLS to request the client
-   * certificates.  (Note the default is to not request or verify
-   * certificates).
-   */
-  if (tls_verify_peer) {
+    /* If verify peer is enabled, tell GnuTLS to request the client
+     * certificates.  (Note the default is to not request or verify
+     * certificates).
+     */
+    if (tls_verify_peer) {
 #ifdef HAVE_GNUTLS_SESSION_SET_VERIFY_CERT
-    gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUEST);
-    gnutls_session_set_verify_cert (*session, NULL, 0);
+      gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUEST);
+      gnutls_session_set_verify_cert (*session, NULL, 0);
 #else
-    nbdkit_error ("--tls-verify-peer: GnuTLS >= 3.4.6 is required for this feature");
-    goto error;
+      nbdkit_error ("--tls-verify-peer: GnuTLS >= 3.4.6 is required for this feature");
+      goto error;
 #endif
+    }
+
+    priority = strdup (TLS_PRIORITY);
+    if (priority == NULL) {
+      nbdkit_error ("strdup: %m");
+      goto error;
+    }
+    break;
+
+  case CRYPTO_AUTH_PSK:
+    /* Associate the session with the server PSK credentials. */
+    err = gnutls_credentials_set (*session, GNUTLS_CRD_PSK, psk_creds);
+    if (err < 0) {
+      nbdkit_error ("gnutls_credentials_set: %s", gnutls_strerror (err));
+      goto error;
+    }
+
+    if (asprintf (&priority, "%s:+PSK:+DHE-PSK", TLS_PRIORITY) == -1) {
+      nbdkit_error ("asprintf: %m");
+      goto error;
+    }
+    break;
+
+  default:
+    abort ();
+  }
+
+  assert (priority != NULL);
+  err = gnutls_priority_set_direct (*session, priority, NULL);
+  if (err < 0) {
+    nbdkit_error ("failed to set TLS session priority to %s: %s",
+                  priority, gnutls_strerror (err));
+    goto error;
   }
 
   /* Set up GnuTLS so it reads and writes on the raw sockets, and set
diff --git a/src/internal.h b/src/internal.h
index ea3155c..ec19841 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -108,6 +108,7 @@ extern int readonly;
 extern const char *selinux_label;
 extern int tls;
 extern const char *tls_certificates_dir;
+extern const char *tls_psk;
 extern int tls_verify_peer;
 extern char *unixsocket;
 extern int verbose;
diff --git a/src/main.c b/src/main.c
index 8d901cf..6524b85 100644
--- a/src/main.c
+++ b/src/main.c
@@ -89,6 +89,7 @@ const char *selinux_label;      /* --selinux-label */
 int threads;                    /* -t */
 int tls;                        /* --tls : 0=off 1=on 2=require */
 const char *tls_certificates_dir; /* --tls-certificates */
+const char *tls_psk;            /* --tls-psk */
 int tls_verify_peer;            /* --tls-verify-peer */
 char *unixsocket;               /* -U */
 const char *user, *group;       /* -u & -g */
@@ -144,6 +145,7 @@ static const struct option long_options[] = {
   { "threads",    1, NULL, 't' },
   { "tls",        1, NULL, 0 },
   { "tls-certificates", 1, NULL, 0 },
+  { "tls-psk",    1, NULL, 0 },
   { "tls-verify-peer", 0, NULL, 0 },
   { "unix",       1, NULL, 'U' },
   { "user",       1, NULL, 'u' },
@@ -161,7 +163,7 @@ usage (void)
           "       [--newstyle] [--oldstyle] [-P PIDFILE] [-p PORT] [-r]\n"
           "       [--run CMD] [-s] [--selinux-label LABEL] [-t THREADS]\n"
           "       [--tls=off|on|require] [--tls-certificates /path/to/certificates]\n"
-          "       [--tls-verify-peer]\n"
+          "       [--tls-psk /path/to/pskfile] [--tls-verify-peer]\n"
           "       [-U SOCKET] [-u USER] [-v] [-V]\n"
           "       PLUGIN [key=value [key=value [...]]]\n"
           "\n"
@@ -314,6 +316,10 @@ main (int argc, char *argv[])
         tls_certificates_dir = optarg;
         break;
       }
+      else if (strcmp (long_options[option_index].name, "tls-psk") == 0) {
+        tls_psk = optarg;
+        break;
+      }
       else if (strcmp (long_options[option_index].name, "tls-verify-peer") == 0) {
         tls_verify_peer = 1;
         break;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 755fe51..a7a31b9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -37,6 +37,7 @@ MAINTAINERCLEANFILES =
 EXTRA_DIST = \
 	functions.sh \
 	make-pki.sh \
+	make-psk.sh \
 	python-exception.py \
 	README.tests \
 	shebang.pl \
@@ -72,6 +73,7 @@ EXTRA_DIST = \
 	test-start.sh \
 	test-random-sock.sh \
 	test-tls.sh \
+	test-tls-psk.sh \
 	test-version.sh \
 	test-version-filter.sh \
 	test-version-plugin.sh \
@@ -112,6 +114,7 @@ TESTS += \
 	test-captive.sh \
 	test-random-sock.sh \
 	test-tls.sh \
+	test-tls-psk.sh \
 	test-ip.sh \
 	test-socket-activation \
 	test-foreground.sh
@@ -171,6 +174,11 @@ check_DATA += pki/.stamp
 pki/.stamp: $(srcdir)/make-pki.sh
 	$(srcdir)/make-pki.sh
 
+# PSK keys for the TLS-PSK tests.
+check_DATA += keys.psk
+keys.psk: $(srcdir)/make-psk.sh
+	$(srcdir)/make-psk.sh
+
 #----------------------------------------------------------------------
 # Tests of C plugins or tests which require plugins.
 
diff --git a/tests/make-psk.sh b/tests/make-psk.sh
new file mode 100755
index 0000000..5e27ea5
--- /dev/null
+++ b/tests/make-psk.sh
@@ -0,0 +1,54 @@
+#!/bin/bash -
+# nbdkit
+# Copyright (C) 2018 Red Hat Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+set -e
+
+# This creates the PSK keys for the TLS-PSK tests.  However if pkstool
+# doesn't exist, just create an empty directory instead.
+
+if [ ! -f test-tls-psk.sh ]; then
+    echo "$0: script is being run from the wrong directory."
+    echo "Don't try to run this script by hand."
+    exit 1
+fi
+
+rm -f keys.psk
+
+if ! psktool --help >/dev/null 2>&1; then
+    echo "$0: psktool not found, TLS-PSK tests will be skipped."
+    touch keys.psk
+    exit 0
+fi
+
+# Create the keys file.
+psktool -u qemu -p keys.psk
diff --git a/tests/test-tls-psk.sh b/tests/test-tls-psk.sh
new file mode 100755
index 0000000..4f8111a
--- /dev/null
+++ b/tests/test-tls-psk.sh
@@ -0,0 +1,118 @@
+#!/bin/bash -
+# nbdkit
+# Copyright (C) 2018 Red Hat Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+set -e
+set -x
+source ./functions.sh
+
+# Don't fail if certain commands aren't available.
+if ! ss --version; then
+    echo "$0: 'ss' command not available"
+    exit 77
+fi
+if ! command -v qemu-img > /dev/null; then
+    echo "$0: 'qemu-img' command not available"
+    exit 77
+fi
+if ! qemu-img --help | grep -- --object; then
+    echo "$0: 'qemu-img' command does not have the --object option"
+    exit 77
+fi
+
+# Does the qemu-img binary support PSK?
+if LANG=C qemu-img info --object tls-creds-psk,id=id disk |&
+        grep -sq "invalid object type: tls-creds-psk"
+then
+    echo "$0: 'qemu-img' command does not support TLS-PSK"
+    exit 77
+fi
+
+# Does the nbdkit binary support TLS?
+if ! nbdkit --dump-config | grep -sq tls=yes; then
+    echo "$0: nbdkit built without TLS support"
+    exit 77
+fi
+
+# Did we create the PSK keys file?
+# Probably 'certtool' is missing.
+if [ ! -s keys.psk ]; then
+    echo "$0: PSK keys file was not created by the test harness"
+    exit 77
+fi
+
+# Unfortunately qemu cannot do TLS over a Unix domain socket (nbdkit
+# probably can, although it is not tested).  Find an unused port to
+# listen on.
+for port in `seq 50000 65535`; do
+    if ! ss -ltn | grep -sqE ":$port\b"; then break; fi
+done
+echo picked unused port $port
+
+nbdkit -P tls-psk.pid -p $port -n --tls=require --tls-psk=keys.psk example1
+
+# We may have to wait a short time for the pid file to appear.
+for i in `seq 1 10`; do
+    if test -f tls-psk.pid; then
+        break
+    fi
+    sleep 1
+done
+if ! test -f tls-psk.pid; then
+    echo "$0: PID file was not created"
+    exit 1
+fi
+
+pid="$(cat tls-psk.pid)"
+
+# Kill the process on exit.
+cleanup ()
+{
+    status=$?
+
+    kill $pid
+    rm -f tls-psk.pid tls-psk.out
+
+    exit $status
+}
+trap cleanup INT QUIT TERM EXIT ERR
+
+# Run qemu-img against the server.
+LANG=C \
+qemu-img info \
+         --object "tls-creds-psk,id=tls0,endpoint=client,dir=$PWD" \
+         --image-opts "file.driver=nbd,file.host=localhost,file.port=$port,file.tls-creds=tls0" > tls-psk.out
+
+cat tls-psk.out
+
+grep -sq "^file format: raw" tls-psk.out
+grep -sq "^virtual size: 100M" tls-psk.out
-- 
2.16.2




More information about the Libguestfs mailing list