[libvirt] [PATCH v5 3/9] qemu: Add support for TLS X.509 path to TCP chardev backend

John Ferlan jferlan at redhat.com
Thu Aug 4 15:21:21 UTC 2016


When building a chardev device string for tcp, add the necessary pieces to
access provide the TLS X.509 path to qemu.  This includes generating the
'tls-creds-x509' object and then adding the 'tls-creds' parameter to the
VIR_DOMAIN_CHR_TYPE_TCP command line.

Finally add the tests for the qemu command line. This test will make use
of the "new(ish)" /etc/pki/qemu setting for a TLS certificate environment
by *not* "resetting" the chardevTLSx509certdir prior to running the test.
Also use the default "verify" option (which is "no").

Signed-off-by: John Ferlan <jferlan at redhat.com>
---
 src/qemu/qemu_alias.c                              |  16 +++
 src/qemu/qemu_alias.h                              |   3 +
 src/qemu/qemu_command.c                            | 114 ++++++++++++++++++++-
 .../qemuxml2argv-serial-tcp-tlsx509-chardev.args   |  33 ++++++
 tests/qemuxml2argvtest.c                           |   6 ++
 5 files changed, 171 insertions(+), 1 deletion(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args

diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 0102c96..9094f3b 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -560,3 +560,19 @@ qemuDomainGetSecretAESAlias(const char *srcalias,
 
     return alias;
 }
+
+
+/* qemuAliasTLSObjFromChardevAlias
+ * @chardev_alias: Pointer to the chardev alias string
+ *
+ * Generate and return a string to be used as the TLS object alias
+ */
+char *
+qemuAliasTLSObjFromChardevAlias(const char *chardev_alias)
+{
+    char *ret;
+
+    ignore_value(virAsprintf(&ret, "obj%s_tls0", chardev_alias));
+
+    return ret;
+}
diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h
index 505c40e..c366d28 100644
--- a/src/qemu/qemu_alias.h
+++ b/src/qemu/qemu_alias.h
@@ -76,4 +76,7 @@ char *qemuDomainGetMasterKeyAlias(void);
 char *qemuDomainGetSecretAESAlias(const char *srcalias,
                                   bool isLuks);
 
+char *qemuAliasTLSObjFromChardevAlias(const char *chardev_alias)
+    ATTRIBUTE_NONNULL(1);
+
 #endif /* __QEMU_ALIAS_H__*/
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 197537f..33cc451 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -679,6 +679,103 @@ qemuBuildRBDSecinfoURI(virBufferPtr buf,
 }
 
 
+/* qemuBuildTLSx509BackendProps:
+ * @tlspath: path to the TLS credentials
+ * @listen: boolen listen for client or server setting
+ * @verifypeer: boolean to enable peer verification (form of authorization)
+ * @qemuCaps: capabilities
+ * @propsret: json properties to return
+ *
+ * Create a backend string for the tls-creds-x509 object.
+ *
+ * Returns 0 on success, -1 on failure with error set.
+ */
+static int
+qemuBuildTLSx509BackendProps(const char *tlspath,
+                             bool listen,
+                             bool verifypeer,
+                             virQEMUCapsPtr qemuCaps,
+                             virJSONValuePtr *propsret)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *path = NULL;
+    int ret = -1;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_TLS_CREDS_X509)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("tls-creds-x509 not supported in this QEMU binary"));
+        return -1;
+    }
+
+    virQEMUBuildBufferEscapeComma(&buf, tlspath);
+    if (virBufferCheckError(&buf) < 0)
+        goto cleanup;
+    path = virBufferContentAndReset(&buf);
+
+    if (virJSONValueObjectCreate(propsret,
+                                 "s:dir", path,
+                                 "s:endpoint", (listen ? "server": "client"),
+                                 "b:verify-peer", verifypeer,
+                                 NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virBufferFreeAndReset(&buf);
+    VIR_FREE(path);
+    return ret;
+}
+
+
+/* qemuBuildTLSx509CommandLine:
+ * @cmd: Pointer to command
+ * @tlspath: path to the TLS credentials
+ * @listen: boolen listen for client or server setting
+ * @verifypeer: boolean to enable peer verification (form of authorization)
+ * @inalias: Alias for the parent to generate object alias
+ * @qemuCaps: capabilities
+ *
+ * Create the command line for a TLS object
+ *
+ * Returns 0 on success, -1 on failure with error set.
+ */
+static int
+qemuBuildTLSx509CommandLine(virCommandPtr cmd,
+                            const char *tlspath,
+                            bool listen,
+                            bool verifypeer,
+                            const char *inalias,
+                            virQEMUCapsPtr qemuCaps)
+{
+    int ret = -1;
+    char *objalias = NULL;
+    virJSONValuePtr props = NULL;
+    char *tmp = NULL;
+
+    if (qemuBuildTLSx509BackendProps(tlspath, listen, verifypeer,
+                                     qemuCaps, &props) < 0)
+        return -1;
+
+    if (!(objalias = qemuAliasTLSObjFromChardevAlias(inalias)))
+        goto cleanup;
+
+    if (!(tmp = virQEMUBuildObjectCommandlineFromJSON("tls-creds-x509",
+                                                      objalias, props)))
+        goto cleanup;
+
+    virCommandAddArgList(cmd, "-object", tmp, NULL);
+
+    ret = 0;
+
+ cleanup:
+    virJSONValueFree(props);
+    VIR_FREE(objalias);
+    VIR_FREE(tmp);
+    return ret;
+}
+
+
 #define QEMU_DEFAULT_NBD_PORT "10809"
 #define QEMU_DEFAULT_GLUSTER_PORT "24007"
 
@@ -4865,7 +4962,7 @@ qemuBuildChrChardevFileStr(virLogManagerPtr logManager,
 static char *
 qemuBuildChrChardevStr(virLogManagerPtr logManager,
                        virCommandPtr cmd,
-                       virQEMUDriverConfigPtr cfg ATTRIBUTE_UNUSED,
+                       virQEMUDriverConfigPtr cfg,
                        const virDomainDef *def,
                        const virDomainChrSourceDef *dev,
                        const char *alias,
@@ -4948,6 +5045,21 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager,
                           dev->data.tcp.service,
                           telnet ? ",telnet" : "",
                           dev->data.tcp.listen ? ",server,nowait" : "");
+
+            if (cfg->chardevTLS) {
+                char *objalias = NULL;
+
+                if (qemuBuildTLSx509CommandLine(cmd, cfg->chardevTLSx509certdir,
+                                                dev->data.tcp.listen,
+                                                cfg->chardevTLSx509verify,
+                                                alias, qemuCaps) < 0)
+                    goto error;
+
+                if (!(objalias = qemuAliasTLSObjFromChardevAlias(alias)))
+                    goto error;
+                virBufferAsprintf(&buf, ",tls-creds=%s", objalias);
+                VIR_FREE(objalias);
+            }
         break;
 
     case VIR_DOMAIN_CHR_TYPE_UNIX:
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
new file mode 100644
index 0000000..518117b
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
@@ -0,0 +1,33 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-M pc \
+-m 214 \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefconfig \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=readline \
+-no-acpi \
+-boot c \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-chardev udp,id=charserial0,host=127.0.0.1,port=2222,localaddr=127.0.0.1,\
+localport=1111 \
+-device isa-serial,chardev=charserial0,id=serial0 \
+-object tls-creds-x509,id=objserial1_tls0,dir=/etc/pki/qemu,endpoint=client,\
+verify-peer=no \
+-chardev socket,id=charserial1,host=127.0.0.1,port=5555,\
+tls-creds=objserial1_tls0 \
+-device isa-serial,chardev=charserial1,id=serial1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index a5d51a8..8f138e6 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1094,6 +1094,12 @@ mymain(void)
             QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("serial-tcp-telnet-chardev",
             QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
+    driver.config->chardevTLS = 1;
+    DO_TEST("serial-tcp-tlsx509-chardev",
+            QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG,
+            QEMU_CAPS_OBJECT_TLS_CREDS_X509);
+    driver.config->chardevTLS = 0;
+    VIR_FREE(driver.config->chardevTLSx509certdir);
     DO_TEST("serial-many-chardev",
             QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("parallel-tcp-chardev",
-- 
2.7.4




More information about the libvir-list mailing list