qemu: Add support for TLS X.509 path to TCP chardev backend

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@redhat.com>
This commit is contained in:
John Ferlan 2016-06-09 18:30:55 -04:00
parent 3f60a9c32f
commit ce61c16450
5 changed files with 171 additions and 1 deletions

View File

@ -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;
}

View File

@ -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__*/

View File

@ -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"
@ -4868,7 +4965,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,
@ -4951,6 +5048,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:

View File

@ -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

View File

@ -1112,6 +1112,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",