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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list