]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
libvirt: Introduce protected key mgmt ops
authorTony Krowiak <akrowiak@linux.vnet.ibm.com>
Mon, 27 Apr 2015 21:57:27 +0000 (17:57 -0400)
committerMichal Privoznik <mprivozn@redhat.com>
Mon, 18 May 2015 07:53:13 +0000 (09:53 +0200)
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>
docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/libvirt_private.syms

index e0b6ba704ff71b1be3a87d3dbe7b03967d6654e2..eb3aacd4365d7e804d7656bd030f0926c7781bcc 100644 (file)
@@ -6227,6 +6227,45 @@ qemu-kvm -net nic,model=? /dev/null
       being on a file system that lacks security labeling.
     </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>
+&lt;domain&gt;
+  ...
+  &lt;keywrap&gt;
+    &lt;cipher name='aes' state='off'/&gt;
+  &lt;/keywrap&gt;
+  ...
+&lt;/domain&gt;
+</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>
 
     <p>
index c151e92974d298b93d9f4a2c3cab77ffb48bc4c5..64a094b5ad1c49258a21b21b7a0af739ee1dd7fc 100644 (file)
@@ -67,6 +67,9 @@
         <optional>
           <ref name='qemucmdline'/>
         </optional>
+        <optional>
+          <ref name='keywrap'/>
+        </optional>
       </interleave>
     </element>
   </define>
     </element>
   </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:
       - an optional id attribute with a number on the domain element
index 4f1dd990cc66eada93951fd9a939b048aaf9650e..bfdc94e1b917945d0d66964499d71aec91d608af 100644 (file)
@@ -477,6 +477,11 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
               "ich9",
               "usb")
 
+VIR_ENUM_IMPL(virDomainKeyWrapCipherName,
+              VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST,
+              "aes",
+              "dea")
+
 VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
               "virtio",
               "xen",
@@ -834,6 +839,131 @@ virDomainXMLOptionClassDispose(void *obj)
         (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:
@@ -2361,6 +2491,8 @@ void virDomainDefFree(virDomainDefPtr def)
         virDomainShmemDefFree(def->shmems[i]);
     VIR_FREE(def->shmems);
 
+    VIR_FREE(def->keywrap);
+
     if (def->namespaceData && def->ns.free)
         (def->ns.free)(def->namespaceData);
 
@@ -15569,6 +15701,9 @@ virDomainDefParseXML(xmlDocPtr xml,
         VIR_FREE(tmp);
     }
 
+    if (virDomainKeyWrapDefParseXML(def, ctxt) < 0)
+        goto error;
+
     /* Extract custom metadata */
     if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
         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
 virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
 {
@@ -21524,6 +21677,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
             goto error;
     }
 
+    if (def->keywrap)
+        virDomainKeyWrapDefFormat(buf, def->keywrap);
+
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</domain>\n");
 
index 2544cbc2cb993df48014d6005ee04b093adf1c6a..d8a8e31dd398f2ffa716ccd1348d481b77626cff 100644 (file)
@@ -2119,6 +2119,13 @@ struct _virDomainPowerManagement {
     int s4;
 };
 
+typedef struct _virDomainKeyWrapDef virDomainKeyWrapDef;
+typedef virDomainKeyWrapDef *virDomainKeyWrapDefPtr;
+struct _virDomainKeyWrapDef {
+    int aes; /* enum virTristateSwitch */
+    int dea; /* enum virTristateSwitch */
+};
+
 /*
  * Guest VM main configuration
  *
@@ -2255,6 +2262,8 @@ struct _virDomainDef {
     void *namespaceData;
     virDomainXMLNamespace ns;
 
+    virDomainKeyWrapDefPtr keywrap;
+
     /* Application-specific custom metadata */
     xmlNodePtr metadata;
 };
@@ -2263,6 +2272,13 @@ unsigned long long virDomainDefGetMemoryInitial(virDomainDefPtr def);
 void virDomainDefSetMemoryInitial(virDomainDefPtr def, unsigned long long size);
 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 {
     VIR_DOMAIN_TAINT_CUSTOM_ARGV,      /* Custom ARGV passthrough from XML */
     VIR_DOMAIN_TAINT_CUSTOM_MONITOR,   /* Custom monitor commands issued */
@@ -2954,6 +2970,7 @@ VIR_ENUM_DECL(virDomainChrTcpProtocol)
 VIR_ENUM_DECL(virDomainChrSpicevmc)
 VIR_ENUM_DECL(virDomainSoundCodec)
 VIR_ENUM_DECL(virDomainSoundModel)
+VIR_ENUM_DECL(virDomainKeyWrapCipherName)
 VIR_ENUM_DECL(virDomainMemballoonModel)
 VIR_ENUM_DECL(virDomainSmbiosMode)
 VIR_ENUM_DECL(virDomainWatchdogModel)
index 9c468dbe1da40a06418a52ab3ee9fda72916edf6..15e71d5629fbecf845386e1b313ec995ad0c7c64 100644 (file)
@@ -330,6 +330,8 @@ virDomainIOThreadIDDefFree;
 virDomainIOThreadIDDel;
 virDomainIOThreadIDFind;
 virDomainIOThreadSchedDelId;
+virDomainKeyWrapCipherNameTypeFromString;
+virDomainKeyWrapCipherNameTypeToString;
 virDomainLeaseDefFree;
 virDomainLeaseIndex;
 virDomainLeaseInsert;