Browse files

Add TLS support.

Thanks: Daniel Berrangé
  • Loading branch information...
rwmjones committed Sep 26, 2017
1 parent 6566a94 commit c5e76492309020bde4ba590caf65d77d350659bf
Showing with 1,145 additions and 8 deletions.
  1. +1 −0 .gitignore
  2. +6 −2 README
  3. +22 −1
  4. +249 −0 docs/nbdkit.pod
  5. +1 −1
  6. +4 −1 src/
  7. +110 −3 src/connections.c
  8. +443 −0 src/crypto.c
  9. +17 −0 src/internal.h
  10. +64 −0 src/main.c
  11. +2 −0 src/protocol.h
  12. +7 −0 tests/
  13. +111 −0 tests/
  14. +108 −0 tests/
@@ -43,6 +43,7 @@
@@ -34,8 +34,12 @@ To build the man pages, you will need to install:
- pod2man (included with perl)
There are some *optional* libraries you may want to install for the
There are some *optional* libraries you may want to install for
plugins or extra features.
For TLS support:
- gnutls >= 3.3.0
For the gzip plugin:
@@ -1,5 +1,5 @@
# nbdkit
# Copyright (C) 2013-2016 Red Hat Inc.
# Copyright (C) 2013-2017 Red Hat Inc.
# All rights reserved.
# Redistribution and use in source and binary forms, with or without
@@ -133,6 +133,27 @@ AC_CHECK_HEADERS([selinux/selinux.h sys/prctl.h])
dnl Check support for setsockcreatecon_raw (part of SELinux).
AC_CHECK_LIB([selinux], [setsockcreatecon_raw], [], [:])
dnl Check for GnuTLS (optional, for TLS support).
PKG_CHECK_MODULES([GNUTLS], [gnutls >= 3.3.0], [
AC_DEFINE([HAVE_GNUTLS],[1],[gnutls found at compile time.])
], [
AC_MSG_WARN([gnutls not found or < 3.3.0, TLS support will be disabled.])
AS_IF([test "$GNUTLS_LIBS" != ""],[
AC_MSG_CHECKING([for default TLS session priority string])
[default TLS session priority string @<:@default=NORMAL@:>@])],
[Default TLS session priority string])
dnl Check for valgrind.
@@ -11,6 +11,8 @@ nbdkit - A toolkit for creating NBD servers
[-g GROUP] [-i IPADDR]
[--newstyle] [--oldstyle] [-P PIDFILE] [-p PORT] [-r]
[--run CMD] [-s] [--selinux-label LABEL]
[--tls=off|on|require] [--tls-certificates /path/to/certificates]
[-U SOCKET] [-u USER] [-v] [-V]
PLUGIN [key=value [key=value [...]]]
@@ -224,6 +226,25 @@ Unix domain sockets:
nbdkit --selinux-label system_u:object_r:svirt_t:s0 ...
=item B<--tls=off>
=item B<--tls=on>
=item B<--tls=require>
Disable, enable or require TLS (authentication and encryption
support). See L</TLS> below.
=item B<--tls-certificates> /path/to/certificates
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-verify-peer>
Enables TLS client certificate verification. The default is I<not> to
check the client's certificate.
=item B<-U> SOCKET
=item B<--unix> SOCKET
@@ -437,6 +458,7 @@ Some common clients and the protocol they require:
qemu >= 2.6 client can talk either protocol
nbd-client < 3.10 client can talk either protocol
nbd-client >= 3.10 newstyle
any TLS (encrypted) client newstyle
If you use qemu E<le> 2.5 without the exportname field against a
newstyle server, it will give the error:
@@ -458,6 +480,233 @@ document says should be the case (which isn't based in reality), then
you should always use newstyle when using port 10809, and use oldstyle
on all other ports.
=head1 TLS
TLS (authentication and encryption, sometimes incorrectly called
"SSL") is supported if nbdkit was compiled with GnuTLS. This allows
the server to verify that the client is allowed access, and to encrypt
the contents of the protocol in transit over the network.
TLS can be disabled or enabled by specifying either I<--tls=off> or
I<--tls=on>. With I<--tls=off>, if a client tries to use TLS to
connect, it will be rejected by the server (in other words, as if the
server doesn't support TLS).
I<--tls=on> means that the client may choose to connect either with or
without TLS.
Because I<--tls=on> is subject to downgrade attacks where a malicious
proxy pretends not to support TLS in order to force either the client
or server to communicate in plaintext, you can also specify
I<--tls=require>, where the server enables TLS B<and> rejects all
non-TLS connection attempts.
=head2 TLS with X.509 certificates
When nbdkit starts up, it loads TLS certificates from some built-in
paths, or from the directory specified by the I<--tls-certificates>
Without I<--tls-certificates>, if nbdkit is started as a non-root user
(note this does not include use of the I<-u> or I<-g> options), nbdkit
looks in each of these paths in turn:
Without I<--tls-certificates>, if nbdkit is started as root, nbkit
looks in:
(Use C<nbdkit --dump-config> and look at the
C<root_tls_certificates_dir> setting to get the actual directory built
into the binary.)
You can override both directories above by using
I<--tls-certificates /path/to/certificates>.
In this directory, nbdkit expects to find several files:
=over 4
=item F<ca-cert.pem>
The Certificate Authority certificate.
=item F<server-cert.pem>
The server certificate.
=item F<server-key.pem>
The server private key.
=item F<ca-crl.pem>
(Optional) The certificate revocation list.
=head3 Setting up the Certificate Authority
This step only needs to be done once per organization. It may be that
your organization already has a CA.
$ certtool --generate-privkey > ca-key.pem
$ chmod 0600 ca-key.pem
The F<ca-key.pem> file is the CA private key and is I<extremely>
sensitive data. With possession of this key, anyone can create
certificates pretending to be your organization!
To create the CA certificate file:
$ cat > <<EOF
cn = Name of your organization
$ certtool --generate-self-signed \
--load-privkey ca-key.pem \
--template \
--outfile ca-cert.pem
=head3 Issuing a server certificate for the nbdkit server
Each nbdkit server (or host) needs a secret key and certificate.
$ certtool --generate-privkey > server-key.pem
$ chmod 0600 server-key.pem
The server key file is sensitive. Setting the mode to C<0600> helps
to prevent other users on the same machine from reading it.
The server DNS name (C<cn> below) must be the fully qualified hostname
— and the only hostname — that the client connects to.
$ cat > <<EOF
organization = Name of your organization
cn =
$ certtool --generate-certificate \
--load-ca-certificate ca-cert.pem \
--load-ca-privkey ca-key.pem \
--load-privkey server-key.pem \
--template \
--outfile server-cert.pem
=head3 Issuing and checking client certificates
You don't need to create client certificates unless you want to check
and limit which clients can connect to nbdkit. nbdkit B<does not>
check client certificates unless you specify the I<--tls-verify-peer>
option on the command line.
For each client you should generate a private key and a client
$ certtool --generate-privkey > client-key.pem
$ chmod 0600 client-key.pem
The client key file is sensitive.
The client DNS name (C<cn> below) is the client's name that nbdkit
sees and checks.
$ cat > <<EOF
country = US
state = New York
locality = New York
organization = Name of your organization
cn =
$ certtool --generate-certificate \
--load-ca-certificate ca-cert.pem \
--load-ca-privkey ca-key.pem \
--load-privkey client-key.pem \
--template \
--outfile client-cert.pem
Client certificates do I<not> need to be present anywhere on the
nbdkit host. You don't need to copy them into nbdkit's TLS
certificates directory. The security comes from the fact that the
client must present a client certificate signed by the Certificate
Authority, and nbdkit can check this because it has the F<ca-cert.pem>
To enable checking of client certificates, specify the
I<--tls-verify-peer> option on the command line. Clients which don't
present a valid certificate (eg. not signed, incorrect signature) are
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 Default TLS behaviour
If nbdkit was compiled without GnuTLS support, then TLS is disabled
and TLS connections will be rejected (as if I<--tls=off> was specified
on the command line). Also it is impossible to turn on TLS in this
scenario. You can tell if nbdkit was compiled without GnuTLS support
because C<nbdkit --dump-config> will contain C<tls=no>.
If TLS certificates cannot be loaded either from the built-in path or
from the directory specified by I<--tls-certificates>, then TLS
defaults to disabled. Turning TLS on will give a warning
(I<--tls=on>) or error (I<--tls=require>) about the missing
If TLS certificates can be loaded from the built-in path or from the
I<--tls-certificates> directory, then TLS will by default be enabled
(like I<--tls=on>), but it is not required. Clients can choose
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>.
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
require, and if you want to check client certificates, specify the
I<--tls-verify-peer> option.
=head2 Choice of TLS algorithms
TLS has a bewildering choice of algorithms that can be used. To
enable you to choose a default set of algorithms, there is a configure
setting C<--with-tls-priority>. This defaults to C<NORMAL> which, to
quote the GnuTLS documentation:
=over 4
"C<NORMAL> means all C<secure> ciphersuites. The 256-bit ciphers are
included as a fallback only. The ciphers are sorted by security
You could also set the TLS priority so that it can be configured from
a file at runtime:
./configure --with-tls-priority=@SYSTEM
means use the policy from F</etc/crypto-policies/config>.
./configure --with-tls-priority=@NBDKIT,SYSTEM
means use the policy from
F</etc/crypto-policies/local.d/nbdkit.config> and fall back to
F</etc/crypto-policies/config> if the first file does not exist.
More information can be found in L<gnutls_priority_init(3)>.
You can query information about nbdkit and available plugins from the
@@ -65,7 +65,7 @@ verbose=
while [ $# -gt 0 ]; do
case "$1" in
# Flags that take an argument. We must not rewrite the argument.
-e | --export* | -g | --group | -i | --ip* | -P | --pid* | -p | --port | --run | --selinux-label | -U | --unix | -u | --user)
-e | --export* | -g | --group | -i | --ip* | -P | --pid* | -p | --port | --run | --selinux-label | --tls | --tls-certificates | -U | --unix | -u | --user)
@@ -37,6 +37,7 @@ sbin_PROGRAMS = nbdkit
nbdkit_SOURCES = \
cleanup.c \
connections.c \
crypto.c \
errors.c \
internal.h \
main.c \
@@ -57,8 +58,10 @@ nbdkit_CPPFLAGS = \
nbdkit_CFLAGS = \
-pthread \
nbdkit_LDADD = \
nbdkit_LDFLAGS = \
-pthread \
Oops, something went wrong.

0 comments on commit c5e7649

Please sign in to comment.