mirror of
https://github.com/libvirt/libvirt.git
synced 2026-08-10 04:58:12 -05:00
encryption: Add <cipher> and <ivgen> to encryption
For a luks device, allow the configuration of a specific cipher to be used for encrypting the volume. Signed-off-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
@@ -7802,6 +7802,17 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
|
||||
def->startupPolicy = val;
|
||||
}
|
||||
|
||||
if (encryption) {
|
||||
if (encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS &&
|
||||
encryption->encinfo.cipher_name) {
|
||||
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("supplying the <cipher> for a domain is "
|
||||
"unnecessary"));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
def->dst = target;
|
||||
target = NULL;
|
||||
def->src->auth = authdef;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "viruuid.h"
|
||||
#include "virfile.h"
|
||||
#include "virsecret.h"
|
||||
#include "virstring.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
||||
|
||||
@@ -45,6 +46,17 @@ VIR_ENUM_IMPL(virStorageEncryptionFormat,
|
||||
VIR_STORAGE_ENCRYPTION_FORMAT_LAST,
|
||||
"default", "qcow", "luks")
|
||||
|
||||
static void
|
||||
virStorageEncryptionInfoDefFree(virStorageEncryptionInfoDefPtr def)
|
||||
{
|
||||
VIR_FREE(def->cipher_name);
|
||||
VIR_FREE(def->cipher_mode);
|
||||
VIR_FREE(def->cipher_hash);
|
||||
VIR_FREE(def->ivgen_name);
|
||||
VIR_FREE(def->ivgen_hash);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
virStorageEncryptionSecretFree(virStorageEncryptionSecretPtr secret)
|
||||
{
|
||||
@@ -63,6 +75,7 @@ virStorageEncryptionFree(virStorageEncryptionPtr enc)
|
||||
|
||||
for (i = 0; i < enc->nsecrets; i++)
|
||||
virStorageEncryptionSecretFree(enc->secrets[i]);
|
||||
virStorageEncryptionInfoDefFree(&enc->encinfo);
|
||||
VIR_FREE(enc->secrets);
|
||||
VIR_FREE(enc);
|
||||
}
|
||||
@@ -80,6 +93,23 @@ virStorageEncryptionSecretCopy(const virStorageEncryptionSecret *src)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virStorageEncryptionInfoDefCopy(const virStorageEncryptionInfoDef *src,
|
||||
virStorageEncryptionInfoDefPtr dst)
|
||||
{
|
||||
dst->cipher_size = src->cipher_size;
|
||||
if (VIR_STRDUP(dst->cipher_name, src->cipher_name) < 0 ||
|
||||
VIR_STRDUP(dst->cipher_mode, src->cipher_mode) < 0 ||
|
||||
VIR_STRDUP(dst->cipher_hash, src->cipher_hash) < 0 ||
|
||||
VIR_STRDUP(dst->ivgen_name, src->ivgen_name) < 0 ||
|
||||
VIR_STRDUP(dst->ivgen_hash, src->ivgen_hash) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
virStorageEncryptionPtr
|
||||
virStorageEncryptionCopy(const virStorageEncryption *src)
|
||||
{
|
||||
@@ -100,6 +130,9 @@ virStorageEncryptionCopy(const virStorageEncryption *src)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (virStorageEncryptionInfoDefCopy(&src->encinfo, &ret->encinfo) < 0)
|
||||
goto error;
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
@@ -153,6 +186,61 @@ virStorageEncryptionSecretParse(xmlXPathContextPtr ctxt,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virStorageEncryptionInfoParseCipher(xmlNodePtr info_node,
|
||||
virStorageEncryptionInfoDefPtr info)
|
||||
{
|
||||
int ret = -1;
|
||||
char *size_str = NULL;
|
||||
|
||||
if (!(info->cipher_name = virXMLPropString(info_node, "name"))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("cipher info missing 'name' attribute"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((size_str = virXMLPropString(info_node, "size")) &&
|
||||
virStrToLong_uip(size_str, NULL, 10, &info->cipher_size) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("cannot parse cipher size: '%s'"),
|
||||
size_str);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!size_str) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("cipher info missing 'size' attribute"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
info->cipher_mode = virXMLPropString(info_node, "mode");
|
||||
info->cipher_hash = virXMLPropString(info_node, "hash");
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(size_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virStorageEncryptionInfoParseIvgen(xmlNodePtr info_node,
|
||||
virStorageEncryptionInfoDefPtr info)
|
||||
{
|
||||
if (!(info->ivgen_name = virXMLPropString(info_node, "name"))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("missing ivgen info name string"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
info->ivgen_hash = virXMLPropString(info_node, "hash");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static virStorageEncryptionPtr
|
||||
virStorageEncryptionParseXML(xmlXPathContextPtr ctxt)
|
||||
{
|
||||
@@ -196,6 +284,28 @@ virStorageEncryptionParseXML(xmlXPathContextPtr ctxt)
|
||||
VIR_FREE(nodes);
|
||||
}
|
||||
|
||||
if (ret->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
|
||||
xmlNodePtr tmpnode;
|
||||
|
||||
if ((tmpnode = virXPathNode("./cipher[1]", ctxt))) {
|
||||
if (virStorageEncryptionInfoParseCipher(tmpnode, &ret->encinfo) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((tmpnode = virXPathNode("./ivgen[1]", ctxt))) {
|
||||
/* If no cipher node, then fail */
|
||||
if (!ret->encinfo.cipher_name) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("ivgen element found, but cipher is missing"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virStorageEncryptionInfoParseIvgen(tmpnode, &ret->encinfo) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
|
||||
cleanup:
|
||||
@@ -250,6 +360,28 @@ virStorageEncryptionSecretFormat(virBufferPtr buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
virStorageEncryptionInfoDefFormat(virBufferPtr buf,
|
||||
const virStorageEncryptionInfoDef *enc)
|
||||
{
|
||||
virBufferEscapeString(buf, "<cipher name='%s'", enc->cipher_name);
|
||||
virBufferAsprintf(buf, " size='%u'", enc->cipher_size);
|
||||
if (enc->cipher_mode)
|
||||
virBufferEscapeString(buf, " mode='%s'", enc->cipher_mode);
|
||||
if (enc->cipher_hash)
|
||||
virBufferEscapeString(buf, " hash='%s'", enc->cipher_hash);
|
||||
virBufferAddLit(buf, "/>\n");
|
||||
|
||||
if (enc->ivgen_name) {
|
||||
virBufferEscapeString(buf, "<ivgen name='%s'", enc->ivgen_name);
|
||||
if (enc->ivgen_hash)
|
||||
virBufferEscapeString(buf, " hash='%s'", enc->ivgen_hash);
|
||||
virBufferAddLit(buf, "/>\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
virStorageEncryptionFormat(virBufferPtr buf,
|
||||
virStorageEncryptionPtr enc)
|
||||
@@ -270,6 +402,10 @@ virStorageEncryptionFormat(virBufferPtr buf,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (enc->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS &&
|
||||
enc->encinfo.cipher_name)
|
||||
virStorageEncryptionInfoDefFormat(buf, &enc->encinfo);
|
||||
|
||||
virBufferAdjustIndent(buf, -2);
|
||||
virBufferAddLit(buf, "</encryption>\n");
|
||||
|
||||
|
||||
@@ -44,6 +44,18 @@ struct _virStorageEncryptionSecret {
|
||||
virSecretLookupTypeDef seclookupdef;
|
||||
};
|
||||
|
||||
/* It's possible to dictate the cipher and if necessary iv */
|
||||
typedef struct _virStorageEncryptionInfoDef virStorageEncryptionInfoDef;
|
||||
typedef virStorageEncryptionInfoDef *virStorageEncryptionInfoDefPtr;
|
||||
struct _virStorageEncryptionInfoDef {
|
||||
unsigned int cipher_size;
|
||||
char *cipher_name;
|
||||
char *cipher_mode;
|
||||
char *cipher_hash;
|
||||
char *ivgen_name;
|
||||
char *ivgen_hash;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
/* "default" is only valid for volume creation */
|
||||
VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT = 0,
|
||||
@@ -61,6 +73,8 @@ struct _virStorageEncryption {
|
||||
|
||||
size_t nsecrets;
|
||||
virStorageEncryptionSecretPtr *secrets;
|
||||
|
||||
virStorageEncryptionInfoDef encinfo;
|
||||
};
|
||||
|
||||
virStorageEncryptionPtr virStorageEncryptionCopy(const virStorageEncryption *src)
|
||||
|
||||
Reference in New Issue
Block a user