mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +00:00
libvirt: Introduce protected key mgmt ops
Two new domain configuration XML elements are added to enable/disable the protected key management operations for a guest: <domain> ... <keywrap> <cipher name='aes|dea' state='on|off'/> </keywrap> ... </domain> Signed-off-by: Tony Krowiak <akrowiak@linux.vnet.ibm.com> Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> Signed-off-by: Daniel Hansel <daniel.hansel@linux.vnet.ibm.com> Reviewed-by: Boris Fiuczynski <fiuczy@linux.vnet.ibm.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
99a42f3c0f
commit
73eda71028
@ -6227,6 +6227,45 @@ qemu-kvm -net nic,model=? /dev/null
|
|||||||
being on a file system that lacks security labeling.
|
being on a file system that lacks security labeling.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3><a name="keywrap">Key Wrap</a></h3>
|
||||||
|
|
||||||
|
<p>The content of the optional <code>keywrap</code> element specifies
|
||||||
|
whether the guest will be allowed to perform the S390 cryptographic key
|
||||||
|
management operations. A clear key can be protected by encrypting it
|
||||||
|
under a unique wrapping key that is generated for each guest VM running
|
||||||
|
on the host. Two variations of wrapping keys are generated: one version
|
||||||
|
for encrypting protected keys using the DEA/TDEA algorithm, and another
|
||||||
|
version for keys encrypted using the AES algorithm. If a
|
||||||
|
<code>keywrap</code> element is not included, the guest will be granted
|
||||||
|
access to both AES and DEA/TDEA key wrapping by default.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<domain>
|
||||||
|
...
|
||||||
|
<keywrap>
|
||||||
|
<cipher name='aes' state='off'/>
|
||||||
|
</keywrap>
|
||||||
|
...
|
||||||
|
</domain>
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
At least one <code>cipher</code> element must be nested within the
|
||||||
|
<code>keywrap</code> element.
|
||||||
|
</p>
|
||||||
|
<dl>
|
||||||
|
<dt><code>cipher</code></dt>
|
||||||
|
<dd>The <code>name</code> attribute identifies the algorithm
|
||||||
|
for encrypting a protected key. The values supported for this attribute
|
||||||
|
are <code>aes</code> for encryption under the AES wrapping key, or
|
||||||
|
<code>dea</code> for encryption under the DEA/TDEA wrapping key. The
|
||||||
|
<code>state</code> attribute indicates whether the cryptographic key
|
||||||
|
management operations should be turned on for the specified encryption
|
||||||
|
algorithm. The value can be set to <code>on</code> or <code>off</code>.
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<p>Note: DEA/TDEA is synonymous with DES/TDES.</p>
|
||||||
|
|
||||||
<h2><a name="examples">Example configs</a></h2>
|
<h2><a name="examples">Example configs</a></h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -67,6 +67,9 @@
|
|||||||
<optional>
|
<optional>
|
||||||
<ref name='qemucmdline'/>
|
<ref name='qemucmdline'/>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<ref name='keywrap'/>
|
||||||
|
</optional>
|
||||||
</interleave>
|
</interleave>
|
||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
@ -382,6 +385,24 @@
|
|||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name="keywrap">
|
||||||
|
<element name="keywrap">
|
||||||
|
<oneOrMore>
|
||||||
|
<element name="cipher">
|
||||||
|
<attribute name="name">
|
||||||
|
<choice>
|
||||||
|
<value>aes</value>
|
||||||
|
<value>dea</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="state">
|
||||||
|
<ref name='virOnOff'/>
|
||||||
|
</attribute>
|
||||||
|
</element>
|
||||||
|
</oneOrMore>
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
The Identifiers can be:
|
The Identifiers can be:
|
||||||
- an optional id attribute with a number on the domain element
|
- an optional id attribute with a number on the domain element
|
||||||
|
@ -477,6 +477,11 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
|
|||||||
"ich9",
|
"ich9",
|
||||||
"usb")
|
"usb")
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(virDomainKeyWrapCipherName,
|
||||||
|
VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST,
|
||||||
|
"aes",
|
||||||
|
"dea")
|
||||||
|
|
||||||
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
|
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
|
||||||
"virtio",
|
"virtio",
|
||||||
"xen",
|
"xen",
|
||||||
@ -834,6 +839,131 @@ virDomainXMLOptionClassDispose(void *obj)
|
|||||||
(xmlopt->config.privFree)(xmlopt->config.priv);
|
(xmlopt->config.privFree)(xmlopt->config.priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virDomainKeyWrapCipherDefParseXML:
|
||||||
|
*
|
||||||
|
* @def Domain definition
|
||||||
|
* @node An XML cipher node
|
||||||
|
* @ctxt The XML context
|
||||||
|
*
|
||||||
|
* Parse the attributes from the cipher node and store the state
|
||||||
|
* attribute in @def.
|
||||||
|
*
|
||||||
|
* A cipher node has the form of
|
||||||
|
*
|
||||||
|
* <cipher name='aes|dea' state='on|off'/>
|
||||||
|
*
|
||||||
|
* Returns: 0 if the parse succeeded
|
||||||
|
* -1 otherwise
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
virDomainKeyWrapCipherDefParseXML(virDomainKeyWrapDefPtr keywrap,
|
||||||
|
xmlNodePtr node,
|
||||||
|
xmlXPathContextPtr ctxt)
|
||||||
|
{
|
||||||
|
|
||||||
|
char *name = NULL;
|
||||||
|
char *state = NULL;
|
||||||
|
int state_type;
|
||||||
|
int name_type;
|
||||||
|
int ret = -1;
|
||||||
|
xmlNodePtr oldnode = ctxt->node;
|
||||||
|
|
||||||
|
ctxt->node = node;
|
||||||
|
if (!(name = virXPathString("string(./@name)", ctxt))) {
|
||||||
|
virReportError(VIR_ERR_CONF_SYNTAX, "%s",
|
||||||
|
_("missing name for cipher"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((name_type = virDomainKeyWrapCipherNameTypeFromString(name)) < 0) {
|
||||||
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
||||||
|
_("%s is not a supported cipher name"), name);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(state = virXPathString("string(./@state)", ctxt))) {
|
||||||
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
||||||
|
_("missing state for cipher named %s"), name);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((state_type = virTristateSwitchTypeFromString(state)) < 0) {
|
||||||
|
virReportError(VIR_ERR_CONF_SYNTAX,
|
||||||
|
_("%s is not a supported cipher state"), state);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ((virDomainKeyWrapCipherName) name_type) {
|
||||||
|
case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_AES:
|
||||||
|
if (keywrap->aes != VIR_TRISTATE_SWITCH_ABSENT) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("A domain definition can have no more than "
|
||||||
|
"one cipher node with name %s"),
|
||||||
|
virDomainKeyWrapCipherNameTypeToString(name_type));
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
keywrap->aes = state_type;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_DEA:
|
||||||
|
if (keywrap->dea != VIR_TRISTATE_SWITCH_ABSENT) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("A domain definition can have no more than "
|
||||||
|
"one cipher node with name %s"),
|
||||||
|
virDomainKeyWrapCipherNameTypeToString(name_type));
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
keywrap->dea = state_type;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(name);
|
||||||
|
VIR_FREE(state);
|
||||||
|
ctxt->node = oldnode;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virDomainKeyWrapDefParseXML(virDomainDefPtr def, xmlXPathContextPtr ctxt)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int ret = -1;
|
||||||
|
xmlNodePtr *nodes = NULL;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (!(n = virXPathNodeSet("./keywrap/cipher", ctxt, &nodes)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(def->keywrap) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (virDomainKeyWrapCipherDefParseXML(def->keywrap, nodes[i], ctxt) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!def->keywrap->aes &&
|
||||||
|
!def->keywrap->dea)
|
||||||
|
VIR_FREE(def->keywrap);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (ret < 0)
|
||||||
|
VIR_FREE(def->keywrap);
|
||||||
|
VIR_FREE(nodes);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virDomainXMLOptionNew:
|
* virDomainXMLOptionNew:
|
||||||
@ -2361,6 +2491,8 @@ void virDomainDefFree(virDomainDefPtr def)
|
|||||||
virDomainShmemDefFree(def->shmems[i]);
|
virDomainShmemDefFree(def->shmems[i]);
|
||||||
VIR_FREE(def->shmems);
|
VIR_FREE(def->shmems);
|
||||||
|
|
||||||
|
VIR_FREE(def->keywrap);
|
||||||
|
|
||||||
if (def->namespaceData && def->ns.free)
|
if (def->namespaceData && def->ns.free)
|
||||||
(def->ns.free)(def->namespaceData);
|
(def->ns.free)(def->namespaceData);
|
||||||
|
|
||||||
@ -15569,6 +15701,9 @@ virDomainDefParseXML(xmlDocPtr xml,
|
|||||||
VIR_FREE(tmp);
|
VIR_FREE(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virDomainKeyWrapDefParseXML(def, ctxt) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
/* Extract custom metadata */
|
/* Extract custom metadata */
|
||||||
if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
|
if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
|
||||||
def->metadata = xmlCopyNode(node, 1);
|
def->metadata = xmlCopyNode(node, 1);
|
||||||
@ -20622,6 +20757,24 @@ virDomainLoaderDefFormat(virBufferPtr buf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
virDomainKeyWrapDefFormat(virBufferPtr buf, virDomainKeyWrapDefPtr keywrap)
|
||||||
|
{
|
||||||
|
virBufferAddLit(buf, "<keywrap>\n");
|
||||||
|
virBufferAdjustIndent(buf, 2);
|
||||||
|
|
||||||
|
if (keywrap->aes)
|
||||||
|
virBufferAsprintf(buf, "<cipher name='aes' state='%s'/>\n",
|
||||||
|
virTristateSwitchTypeToString(keywrap->aes));
|
||||||
|
|
||||||
|
if (keywrap->dea)
|
||||||
|
virBufferAsprintf(buf, "<cipher name='dea' state='%s'/>\n",
|
||||||
|
virTristateSwitchTypeToString(keywrap->dea));
|
||||||
|
|
||||||
|
virBufferAdjustIndent(buf, -2);
|
||||||
|
virBufferAddLit(buf, "</keywrap>\n");
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
|
virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
|
||||||
{
|
{
|
||||||
@ -21524,6 +21677,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (def->keywrap)
|
||||||
|
virDomainKeyWrapDefFormat(buf, def->keywrap);
|
||||||
|
|
||||||
virBufferAdjustIndent(buf, -2);
|
virBufferAdjustIndent(buf, -2);
|
||||||
virBufferAddLit(buf, "</domain>\n");
|
virBufferAddLit(buf, "</domain>\n");
|
||||||
|
|
||||||
|
@ -2119,6 +2119,13 @@ struct _virDomainPowerManagement {
|
|||||||
int s4;
|
int s4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _virDomainKeyWrapDef virDomainKeyWrapDef;
|
||||||
|
typedef virDomainKeyWrapDef *virDomainKeyWrapDefPtr;
|
||||||
|
struct _virDomainKeyWrapDef {
|
||||||
|
int aes; /* enum virTristateSwitch */
|
||||||
|
int dea; /* enum virTristateSwitch */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Guest VM main configuration
|
* Guest VM main configuration
|
||||||
*
|
*
|
||||||
@ -2255,6 +2262,8 @@ struct _virDomainDef {
|
|||||||
void *namespaceData;
|
void *namespaceData;
|
||||||
virDomainXMLNamespace ns;
|
virDomainXMLNamespace ns;
|
||||||
|
|
||||||
|
virDomainKeyWrapDefPtr keywrap;
|
||||||
|
|
||||||
/* Application-specific custom metadata */
|
/* Application-specific custom metadata */
|
||||||
xmlNodePtr metadata;
|
xmlNodePtr metadata;
|
||||||
};
|
};
|
||||||
@ -2263,6 +2272,13 @@ unsigned long long virDomainDefGetMemoryInitial(virDomainDefPtr def);
|
|||||||
void virDomainDefSetMemoryInitial(virDomainDefPtr def, unsigned long long size);
|
void virDomainDefSetMemoryInitial(virDomainDefPtr def, unsigned long long size);
|
||||||
unsigned long long virDomainDefGetMemoryActual(virDomainDefPtr def);
|
unsigned long long virDomainDefGetMemoryActual(virDomainDefPtr def);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_AES,
|
||||||
|
VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_DEA,
|
||||||
|
|
||||||
|
VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST
|
||||||
|
} virDomainKeyWrapCipherName;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VIR_DOMAIN_TAINT_CUSTOM_ARGV, /* Custom ARGV passthrough from XML */
|
VIR_DOMAIN_TAINT_CUSTOM_ARGV, /* Custom ARGV passthrough from XML */
|
||||||
VIR_DOMAIN_TAINT_CUSTOM_MONITOR, /* Custom monitor commands issued */
|
VIR_DOMAIN_TAINT_CUSTOM_MONITOR, /* Custom monitor commands issued */
|
||||||
@ -2954,6 +2970,7 @@ VIR_ENUM_DECL(virDomainChrTcpProtocol)
|
|||||||
VIR_ENUM_DECL(virDomainChrSpicevmc)
|
VIR_ENUM_DECL(virDomainChrSpicevmc)
|
||||||
VIR_ENUM_DECL(virDomainSoundCodec)
|
VIR_ENUM_DECL(virDomainSoundCodec)
|
||||||
VIR_ENUM_DECL(virDomainSoundModel)
|
VIR_ENUM_DECL(virDomainSoundModel)
|
||||||
|
VIR_ENUM_DECL(virDomainKeyWrapCipherName)
|
||||||
VIR_ENUM_DECL(virDomainMemballoonModel)
|
VIR_ENUM_DECL(virDomainMemballoonModel)
|
||||||
VIR_ENUM_DECL(virDomainSmbiosMode)
|
VIR_ENUM_DECL(virDomainSmbiosMode)
|
||||||
VIR_ENUM_DECL(virDomainWatchdogModel)
|
VIR_ENUM_DECL(virDomainWatchdogModel)
|
||||||
|
@ -330,6 +330,8 @@ virDomainIOThreadIDDefFree;
|
|||||||
virDomainIOThreadIDDel;
|
virDomainIOThreadIDDel;
|
||||||
virDomainIOThreadIDFind;
|
virDomainIOThreadIDFind;
|
||||||
virDomainIOThreadSchedDelId;
|
virDomainIOThreadSchedDelId;
|
||||||
|
virDomainKeyWrapCipherNameTypeFromString;
|
||||||
|
virDomainKeyWrapCipherNameTypeToString;
|
||||||
virDomainLeaseDefFree;
|
virDomainLeaseDefFree;
|
||||||
virDomainLeaseIndex;
|
virDomainLeaseIndex;
|
||||||
virDomainLeaseInsert;
|
virDomainLeaseInsert;
|
||||||
|
Loading…
Reference in New Issue
Block a user