Define, parse, and format a key secret element for a chardev tcp backend.
This secret will be used in conjunction with the chartcp_tls_x509_cert_dir
in order to provide the secret to the TLS encrypted TCP chardev.
<secret type='passphrase' usage='keyexample'/>
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
docs/formatdomain.html.in | 29 ++++++++++++
docs/schemas/domaincommon.rng | 21 +++++++++
src/conf/domain_conf.c | 35 +++++++++++++++
src/conf/domain_conf.h | 3 ++
...uxml2argv-serial-tcp-tlsx509-secret-chardev.xml | 42 ++++++++++++++++++
...ml2xmlout-serial-tcp-tlsx509-secret-chardev.xml | 51 ++++++++++++++++++++++
tests/qemuxml2xmltest.c | 1 +
7 files changed, 182 insertions(+)
create mode 100644
tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml
create mode 100644
tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-secret-chardev.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index f660aa6..5803c40 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -6031,6 +6031,35 @@ qemu-kvm -net nic,model=? /dev/null
</devices>
...</pre>
+ <p>
+ <span class="since">Since 2.0.0,</span> some hypervisors
support using
+ a TLS X.509 certificate environment in order to encrypt the TCP. In
+ order to provide the passphrase for the certificates, provide a
+ <code>secret</code> element. The <code>secret</code>
element takes
+ two required attributes <code>type</code> and either
<code>UUID</code>
+ or <code>usage</code>. The supported <code>type</code> is
a "passphrase"
+ secret referenced via either attribute <code>uuid</code> or
+ <code>usage</code>.
+ </p>
+<pre>
+ ...
+ <devices>
+ <serial type="tcp">
+ <source mode="connect" host="0.0.0.0"
service="2445"/>
+ <protocol type="raw"/>
+ <secret type='passphrase' usage='keyexample'/>
+ <target port="1"/>
+ </serial>
+ ...
+ <serial type="tcp">
+ <source mode="bind" host="127.0.0.1"
service="2445"/>
+ <protocol type="raw"/>
+ <target port="1"/>
+ <secret type='passphrase' usage='keyexample'/>
+ </serial>
+ </devices>
+ ...</pre>
+
<h6><a name="elementsCharUDP">UDP network
console</a></h6>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 162c2e0..eb08f3d 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3221,6 +3221,9 @@
<ref name="qemucdevTgtDef"/>
</optional>
<optional>
+ <ref name="qemucdevSecret"/>
+ </optional>
+ <optional>
<ref name="alias"/>
</optional>
<optional>
@@ -3272,6 +3275,24 @@
</element>
</define>
+ <define name="qemucdevSecret">
+ <element name='secret'>
+ <attribute name='type'>
+ <choice>
+ <value>passphrase</value>
+ </choice>
+ </attribute>
+ <choice>
+ <attribute name='uuid'>
+ <ref name="UUID"/>
+ </attribute>
+ <attribute name='usage'>
+ <ref name='genericName'/>
+ </attribute>
+ </choice>
+ </element>
+ </define>
+
<define name="qemucdevSrcTypeChoice">
<choice>
<value>dev</value>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 9443281..f614ff9 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1843,6 +1843,7 @@ virDomainChrSourceDefClear(virDomainChrSourceDefPtr def)
case VIR_DOMAIN_CHR_TYPE_TCP:
VIR_FREE(def->data.tcp.host);
VIR_FREE(def->data.tcp.service);
+ virSecretLookupDefClear(&def->data.tcp.seclookupdef);
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
@@ -1899,6 +1900,10 @@ virDomainChrSourceDefCopy(virDomainChrSourceDefPtr dest,
if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0)
return -1;
+
+ if (virSecretLookupDefCopy(&dest->data.tcp.seclookupdef,
+ &src->data.tcp.seclookupdef) < 0)
+ return -1;
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
@@ -9900,6 +9905,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
char *master = NULL;
char *slave = NULL;
char *append = NULL;
+ xmlNodePtr secret = NULL;
+ char *sectypestr = NULL;
int remaining = 0;
while (cur != NULL) {
@@ -9989,6 +9996,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
} else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
if (!protocol)
protocol = virXMLPropString(cur, "type");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "secret")) {
+ secret = cur;
} else {
remaining++;
}
@@ -10092,6 +10101,25 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
goto error;
}
+ if (secret) {
+
+ if (!(sectypestr = virXMLPropString(secret, "type"))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing TCP chardev secret type"));
+ goto error;
+ }
+ if ((def->data.tcp.sectype =
+ virSecretUsageTypeFromString(sectypestr)) !=
+ VIR_SECRET_USAGE_TYPE_PASSPHRASE) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid TCP chardev secret type
'%s'"),
+ sectypestr);
+ goto error;
+ }
+ if (virSecretLookupParseSecret(secret,
+ &def->data.tcp.seclookupdef) < 0)
+ goto error;
+ }
break;
case VIR_DOMAIN_CHR_TYPE_UDP:
@@ -10166,6 +10194,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
VIR_FREE(append);
VIR_FREE(logappend);
VIR_FREE(logfile);
+ VIR_FREE(sectypestr);
return remaining;
@@ -21065,6 +21094,12 @@ virDomainChrSourceDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, "<protocol type='%s'/>\n",
virDomainChrTcpProtocolTypeToString(
def->data.tcp.protocol));
+ if (def->data.tcp.sectype == VIR_SECRET_USAGE_TYPE_PASSPHRASE) {
+ const char *typestr =
+ virSecretUsageTypeToString(def->data.tcp.sectype);
+ virSecretLookupFormatSecret(buf, typestr,
+ &def->data.tcp.seclookupdef);
+ }
break;
case VIR_DOMAIN_CHR_TYPE_UNIX:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a06281c..8d4a9ec 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -52,6 +52,7 @@
# include "virprocess.h"
# include "virgic.h"
# include "virperf.h"
+# include "virsecret.h"
# include "virtypedparam.h"
/* forward declarations of all device types, required by
@@ -1098,6 +1099,8 @@ struct _virDomainChrSourceDef {
bool listen;
int protocol;
bool tlscreds;
+ int sectype; /* virSecretUsage */
+ virSecretLookupTypeDef seclookupdef;
} tcp;
struct {
char *bindHost;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml
b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml
new file mode 100644
index 0000000..e889072
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml
@@ -0,0 +1,42 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <serial type='udp'>
+ <source mode='bind' host='127.0.0.1'
service='1111'/>
+ <source mode='connect' host='127.0.0.1'
service='2222'/>
+ <target port='0'/>
+ </serial>
+ <serial type='tcp'>
+ <source mode='connect' host='127.0.0.1'
service='5555'/>
+ <protocol type='raw'/>
+ <target port='0'/>
+ <secret type='passphrase' usage='mycluster_myname'/>
+ </serial>
+ <console type='udp'>
+ <source mode='bind' host='127.0.0.1'
service='1111'/>
+ <source mode='connect' host='127.0.0.1'
service='2222'/>
+ <target type='serial' port='0'/>
+ </console>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-secret-chardev.xml
b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-secret-chardev.xml
new file mode 100644
index 0000000..0a6cdbb
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-secret-chardev.xml
@@ -0,0 +1,51 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x2'/>
+ </controller>
+ <controller type='ide' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x01' function='0x1'/>
+ </controller>
+ <controller type='pci' index='0' model='pci-root'/>
+ <serial type='udp'>
+ <source mode='bind' host='127.0.0.1'
service='1111'/>
+ <source mode='connect' host='127.0.0.1'
service='2222'/>
+ <target port='0'/>
+ </serial>
+ <serial type='tcp'>
+ <source mode='connect' host='127.0.0.1'
service='5555'/>
+ <protocol type='raw'/>
+ <secret type='passphrase' usage='mycluster_myname'/>
+ <target port='0'/>
+ </serial>
+ <console type='udp'>
+ <source mode='bind' host='127.0.0.1'
service='1111'/>
+ <source mode='connect' host='127.0.0.1'
service='2222'/>
+ <target type='serial' port='0'/>
+ </console>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x03' function='0x0'/>
+ </memballoon>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 3064458..cef459e 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -484,6 +484,7 @@ mymain(void)
DO_TEST("serial-udp");
DO_TEST("serial-tcp-telnet");
DO_TEST("serial-tcp-tlsx509-chardev");
+ DO_TEST("serial-tcp-tlsx509-secret-chardev");
DO_TEST("serial-many");
DO_TEST("serial-spiceport");
DO_TEST("serial-spiceport-nospice");
--
2.5.5