.. _network_005ftls:

TLS setup for network services
------------------------------

Almost all network services in QEMU have the ability to use TLS for
session data encryption, along with x509 certificates for simple client
authentication. What follows is a description of how to generate
certificates suitable for usage with QEMU, and applies to the VNC
server, character devices with the TCP backend, NBD server and client,
and migration server and client.

At a high level, QEMU requires certificates and private keys to be
provided in PEM format. Aside from the core fields, the certificates
should include various extension data sets, including v3 basic
constraints data, key purpose, key usage and subject alt name.

The GnuTLS package includes a command called ``certtool`` which can be
used to easily generate certificates and keys in the required format
with expected data present. Alternatively a certificate management
service may be used.

At a minimum it is necessary to setup a certificate authority, and issue
certificates to each server. If using x509 certificates for
authentication, then each client will also need to be issued a
certificate.

Assuming that the QEMU network services will only ever be exposed to
clients on a private intranet, there is no need to use a commercial
certificate authority to create certificates. A self-signed CA is
sufficient, and in fact likely to be more secure since it removes the
ability of malicious 3rd parties to trick the CA into mis-issuing certs
for impersonating your services. The only likely exception where a
commercial CA might be desirable is if enabling the VNC websockets
server and exposing it directly to remote browser clients. In such a
case it might be useful to use a commercial CA to avoid needing to
install custom CA certs in the web browsers.

.. _tls_cert_file_naming:

Certificate file naming
~~~~~~~~~~~~~~~~~~~~~~~

In a simple setup, where all QEMU instances on a machine share the
same TLS configuration, it is suggested that QEMU certificates be
kept in either ``/etc/pki/qemu`` or, for unprivileged users, in
``$HOME/.pki/qemu``. Where different QEMU subsystems require
different certificate configurations, sub-dirs of these locations
may be chosen.

The default file names that QEMU will traditionally load are:

* ``ca-cert.pem`` - mandatory; for both client and server configurations
* ``ca-crl.pem`` - optional; for server configurations only
* ``server-cert.pem`` - mandatory; for server configurations only
* ``server-key.pem`` - mandatory; for server configurations only
* ``client-cert.pem`` - optional; for client configurations only
* ``client-key.pem`` - optional; for client configurations only
* ``dh-params.pem`` - optional; for server configurations only

Since QEMU 10.2.0, there is support for loading upto four additional
identities:

* ``server-cert-[IDX].pem`` - optional; for server configurations only
* ``server-key-[IDX].pem`` - optional; for server configurations only
* ``client-cert-[IDX].pem`` - optional; for client configurations only
* ``client-key-[IDX].pem`` - optional; for client configurations only

where ``-[IDX]`` is one of the digits 0-3. Loading will terminate at
the first absent index. The index based certificate files may be used
as a replacement for, or in addition to, the traditional non-index
based certificate files. The traditional certificate files will be
loaded first, if present, then the index based certificates. Where
multiple certificates are compatible with a TLS session, the first
loaded certificate will preferred. IOW file naming can influence
which certificates are used for a session.

The use of multiple sets of certificates is intended to allow an
incremental transition to certificates using different cryptographic
algorithms. This allows a newly deployed QEMU to introduce use of
stronger cryptographic algorithms that will be preferred when talking
to other newly deployed QEMU instances, while retaining compatibility
with certificates issued to a historically deployed QEMU. This is
notably useful to support live migration from an old QEMU deployed
on older operating system releases, which may support fewer crypto
algorithm choices than the current OS.

The certificate creation commands below will be illustrated using
the traditional naming scheme, but their args can be substituted
to use the indexed naming in the obvious manner.

.. _tls_005fgenerate_005fca:

Setup the Certificate Authority
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This step only needs to be performed once per organization /
organizational unit. First the CA needs a private key. This key must be
kept VERY secret and secure. If this key is compromised the entire trust
chain of the certificates issued with it is lost.

::

   # certtool --generate-privkey > ca-key.pem

To generate a self-signed certificate requires one core piece of
information, the name of the organization. A template file ``ca.info``
should be populated with the desired data to avoid having to deal with
interactive prompts from certtool::

   # cat > ca.info <<EOF
   cn = Name of your organization
   ca
   cert_signing_key
   EOF
   # certtool --generate-self-signed \
              --load-privkey ca-key.pem \
              --template ca.info \
              --outfile ca-cert.pem

The ``ca`` keyword in the template sets the v3 basic constraints
extension to indicate this certificate is for a CA, while
``cert_signing_key`` sets the key usage extension to indicate this will
be used for signing other keys. The generated ``ca-cert.pem`` file
should be copied to all servers and clients wishing to utilize TLS
support in the VNC server. The ``ca-key.pem`` must not be
disclosed/copied anywhere except the host responsible for issuing
certificates.

.. _tls_005fgenerate_005fserver:

Issuing server certificates
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Each server (or host) needs to be issued with a key and certificate.
When connecting the certificate is sent to the client which validates it
against the CA certificate. The core pieces of information for a server
certificate are the hostnames and/or IP addresses that will be used by
clients when connecting. The hostname / IP address that the client
specifies when connecting will be validated against the hostname(s) and
IP address(es) recorded in the server certificate, and if no match is
found the client will close the connection.

Thus it is recommended that the server certificate include both the
fully qualified and unqualified hostnames. If the server will have
permanently assigned IP address(es), and clients are likely to use them
when connecting, they may also be included in the certificate. Both IPv4
and IPv6 addresses are supported. Historically certificates only
included 1 hostname in the ``CN`` field, however, usage of this field
for validation is now deprecated. Instead modern TLS clients will
validate against the Subject Alt Name extension data, which allows for
multiple entries. In the future usage of the ``CN`` field may be
discontinued entirely, so providing SAN extension data is strongly
recommended.

On the host holding the CA, create template files containing the
information for each server, and use it to issue server certificates.

::

   # cat > server-hostNNN.info <<EOF
   organization = Name  of your organization
   cn = hostNNN.foo.example.com
   dns_name = hostNNN
   dns_name = hostNNN.foo.example.com
   ip_address = 10.0.1.87
   ip_address = 192.8.0.92
   ip_address = 2620:0:cafe::87
   ip_address = 2001:24::92
   tls_www_server
   signing_key
   EOF
   # certtool --generate-privkey > server-hostNNN-key.pem
   # certtool --generate-certificate \
              --load-ca-certificate ca-cert.pem \
              --load-ca-privkey ca-key.pem \
              --load-privkey server-hostNNN-key.pem \
              --template server-hostNNN.info \
              --outfile server-hostNNN-cert.pem

The ``dns_name`` and ``ip_address`` fields in the template are setting
the subject alt name extension data. The ``tls_www_server`` keyword is
the key purpose extension to indicate this certificate is intended for
usage in a web server. Although QEMU network services are not in fact
HTTP servers (except for VNC websockets), setting this key purpose is
still recommended. The ``signing_key`` keyword is the key usage extension
to indicate this certificate is intended for usage in the data session.

The ``server-hostNNN-key.pem`` and ``server-hostNNN-cert.pem`` files
should now be securely copied to the server for which they were
generated, and renamed to ``server-key.pem`` and ``server-cert.pem``
when added to the ``/etc/pki/qemu`` directory on the target host. The
``server-key.pem`` file is security sensitive and should be kept
protected with file mode 0600 to prevent disclosure.

.. _tls_005fgenerate_005fclient:

Issuing client certificates
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The QEMU x509 TLS credential setup defaults to enabling client
verification using certificates, providing a simple authentication
mechanism. If this default is used, each client also needs to be issued
a certificate. The client certificate contains enough metadata to
uniquely identify the client with the scope of the certificate
authority. The client certificate would typically include fields for
organization, state, city, building, etc.

Once again on the host holding the CA, create template files containing
the information for each client, and use it to issue client
certificates.

::

   # cat > client-hostNNN.info <<EOF
   country = GB
   state = London
   locality = City Of London
   organization = Name of your organization
   cn = hostNNN.foo.example.com
   tls_www_client
   signing_key
   EOF
   # certtool --generate-privkey > client-hostNNN-key.pem
   # certtool --generate-certificate \
              --load-ca-certificate ca-cert.pem \
              --load-ca-privkey ca-key.pem \
              --load-privkey client-hostNNN-key.pem \
              --template client-hostNNN.info \
              --outfile client-hostNNN-cert.pem

The subject alt name extension data is not required for clients, so
the ``dns_name`` and ``ip_address`` fields are not included. The
``tls_www_client`` keyword is the key purpose extension to indicate this
certificate is intended for usage in a web client. Although QEMU network
clients are not in fact HTTP clients, setting this key purpose is still
recommended. The ``signing_key`` keyword is the key usage extension to
indicate this certificate is intended for usage in the data session.

The ``client-hostNNN-key.pem`` and ``client-hostNNN-cert.pem`` files
should now be securely copied to the client for which they were
generated, and renamed to ``client-key.pem`` and ``client-cert.pem``
when added to the ``/etc/pki/qemu`` directory on the target host. The
``client-key.pem`` file is security sensitive and should be kept
protected with file mode 0600 to prevent disclosure.

If a single host is going to be using TLS in both a client and server
role, it is possible to create a single certificate to cover both roles.
This would be quite common for the migration and NBD services, where a
QEMU process will be started by accepting a TLS protected incoming
migration, and later itself be migrated out to another host. To generate
a single certificate, simply include the template data from both the
client and server instructions in one.

::

   # cat > both-hostNNN.info <<EOF
   country = GB
   state = London
   locality = City Of London
   organization = Name of your organization
   cn = hostNNN.foo.example.com
   dns_name = hostNNN
   dns_name = hostNNN.foo.example.com
   ip_address = 10.0.1.87
   ip_address = 192.8.0.92
   ip_address = 2620:0:cafe::87
   ip_address = 2001:24::92
   tls_www_server
   tls_www_client
   signing_key
   EOF
   # certtool --generate-privkey > both-hostNNN-key.pem
   # certtool --generate-certificate \
              --load-ca-certificate ca-cert.pem \
              --load-ca-privkey ca-key.pem \
              --load-privkey both-hostNNN-key.pem \
              --template both-hostNNN.info \
              --outfile both-hostNNN-cert.pem

When copying the PEM files to the target host, save them twice, once as
``server-cert.pem`` and ``server-key.pem``, and again as
``client-cert.pem`` and ``client-key.pem``.

.. _tls_005fcreds_005fsetup:

TLS x509 credential configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

QEMU has a standard mechanism for loading x509 credentials that will be
used for network services and clients. It requires specifying the
``tls-creds-x509`` class name to the ``--object`` command line argument
for the system emulators. Each set of credentials loaded should be given
a unique string identifier via the ``id`` parameter. A single set of TLS
credentials can be used for multiple network backends, so VNC,
migration, NBD, character devices can all share the same credentials.
Note, however, that credentials for use in a client endpoint must be
loaded separately from those used in a server endpoint.

When specifying the object, the ``dir`` parameters specifies which
directory contains the credential files. This directory is expected to
contain files with the names mentioned previously, ``ca-cert.pem``,
``server-key.pem``, ``server-cert.pem``, ``client-key.pem`` and
``client-cert.pem`` as appropriate.

While it is possible to include a set of pre-generated Diffie-Hellman
(DH) parameters in a file ``dh-params.pem``, this facility is now
deprecated and will be removed in a future release. When omitted the
DH parameters will be automatically negotiated in accordance with
RFC7919.

The ``endpoint`` parameter indicates whether the credentials will be
used for a network client or server, and determines which PEM files are
loaded.

The ``verify`` parameter determines whether x509 certificate validation
should be performed. This defaults to enabled, meaning clients will
always validate the server hostname against the certificate subject alt
name fields and/or CN field. It also means that servers will request
that clients provide a certificate and validate them. Verification
should never be turned off for client endpoints, however, it may be
turned off for server endpoints if an alternative mechanism is used to
authenticate clients. For example, the VNC server can use SASL to
authenticate clients instead.

To load server credentials with client certificate validation enabled

.. parsed-literal::

   |qemu_system| -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server

while to load client credentials use

.. parsed-literal::

   |qemu_system| -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client

Network services which support TLS will all have a ``tls-creds``
parameter which expects the ID of the TLS credentials object. For
example with VNC:

.. parsed-literal::

   |qemu_system| -vnc 0.0.0.0:0,tls-creds=tls0

.. _tls_005fpsk:

TLS certificates for Post-Quantum Cryptography
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Given a new enough gnutls release, suitably integrated & configured with the
operating system crypto policies, QEMU is able to support post-quantum
cryptography on TLS enabled services, either exclusively or in a hybrid mode.

In exclusive mode, only a single set of certificates need to be configured
for QEMU, with PQC compliant algorithms. Such a QEMU configuration will only
be able to interoperate with other services (including other QEMU's) that
also have PQC enabled. This can result in compatibility concerns during the
period of transition over to PQC compliant algorithms.

In hybrid mode, multiple sets of certificates need to be configured for QEMU,
at least one set with traditional (non-PQC compliant) algorithms, and at least
one other set with modern (PQC compliant) algorithms. At time of the TLS
handshake, the GNUTLS algorithm priorities should ensure that PQC compliant
algorithms are negotiated if both sides of the connection support PQC. If one
side lacks PQC, the TLS handshake should fallback to the non-PQC algorithms.
This can assist with interoperability during the transition to PQC, but has a
potential weakness wrt downgrade attacks forcing use of non-PQC algorithms.
Exclusive PQC mode should be preferred where both peers in the TLS connections
are known to support PQC.

Key generation parameters
^^^^^^^^^^^^^^^^^^^^^^^^^

To create certificates with PQC compliant algorithms, the ``--key-type``
argument must be passed to ``certtool`` when creating private keys. No
extra arguments are required for the other ``certtool`` commands, as
their behaviour will be determined by the private key type.

The typical PQC compliant algorithms to use are ``ML-DSA-44``, ``ML-DSA-65``
and ``ML-DSA-87``, with ``ML-DSA-65`` being a suitable default choice in
the absence of explicit requirements.

Taking the example earlier, for creating a key for a client certificate,
to use ``ML-DSA-65`` the command line would be modified to look like::

   # certtool --generate-privkey --key-type=mldsa65 > client-hostNNN-key.pem

The equivalent modification applies to the creation of the private keys
used for server certs, or root/intermediate CA certs.

For hybrid mode, the additional indexed certificate naming must be used.
If multiple configured certificates are compatible with the mutually
supported crypto algorithms between the client and server, then the
first matching certificate will be used.

IOW, to ensure that PQC certificates are preferred, they must use a
non-index based filename, or use an index that is smaller than any
non-PQC certificates. ie, ``server-cert.pem`` for PQC and ``server-cert-0.pem``
for non-PQC, or ``server-cert-0.pem`` for PQC and ``server-cert-1.pem`` for
non-PQC.

Force disabling PQC via crypto priority
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In the OS configuration for system crypto algorithm priorities has
enabled PQC, this can (optionally) be overridden in QEMU configuration
disable use of PQC using the ``priority`` parameter to the ``tls-creds-x509``
object::

  NO_MLDSA="-SIGN-ML-DSA-65:-SIGN-ML-DSA-44:-SIGN-ML-DSA-87"
  NO_MLKEM="-GROUP-X25519-MLKEM768:-GROUP-SECP256R1-MLKEM768:-GROUP-SECP384R1-MLKEM1024"
  # qemu-nbd --object tls-creds-x509,id=tls0,endpoint=server,dir=....,priority=@SYSTEM:$NO_MLDSA:$NO_MLKEM


TLS Pre-Shared Keys (PSK)
~~~~~~~~~~~~~~~~~~~~~~~~~

Instead of using certificates, you may also use TLS Pre-Shared Keys
(TLS-PSK). This can be simpler to set up than certificates but is less
scalable.

Use the GnuTLS ``psktool`` program to generate a ``keys.psk`` file
containing one or more usernames and random keys::

   mkdir -m 0700 /tmp/keys
   psktool -u rich -p /tmp/keys/keys.psk

TLS-enabled servers such as ``qemu-nbd`` can use this directory like so::

   qemu-nbd \
     -t -x / \
     --object tls-creds-psk,id=tls0,endpoint=server,dir=/tmp/keys \
     --tls-creds tls0 \
     image.qcow2

When connecting from a qemu-based client you must specify the directory
containing ``keys.psk`` and an optional username (defaults to "qemu")::

   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=/
