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(a)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