zkey: Allow to associate a LUKS volume to an AES key and a HMAC key

For combined integrity protected with encryption, a LUKS2 volume can be
associated to exactly one AES type key and also to exactly one HMAC type
key.

For other volume types, a volume can only be associated to exactly one
key, either an AES type key, or an HMAC type key.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2024-03-11 14:42:58 +01:00
committed by Jan Höppner
parent ddf30feb89
commit 355700d606
2 changed files with 156 additions and 17 deletions

View File

@@ -1239,8 +1239,11 @@ struct volume_check {
struct keystore *keystore;
const char *name;
const char *volume;
const char *key_type;
const char *volume_type;
bool set;
bool nocheck;
unsigned int num_combined;
};
/**
@@ -1258,21 +1261,92 @@ struct volume_check {
*/
static int _keystore_volume_check_process(struct keystore *UNUSED(keystore),
const char *name,
struct properties *UNUSED(properties),
struct properties *properties,
struct key_filenames
*UNUSED(file_names),
void *private)
{
struct volume_check *info = (struct volume_check *)private;
char *key_type, *volume_type;
int rc = 0;
key_type = _keystore_get_key_type(properties);
volume_type = _keystore_get_volume_type(properties);
if (info->set) {
if (strcmp(name, info->name) == 0)
return 0;
goto out;
}
if (is_hmac_key_type(info->key_type) &&
strcasecmp(info->volume_type, VOLUME_TYPE_LUKS2) == 0) {
/* HMAC key with LUKS2: accept up to one AES key with LUKS2 */
if (!is_aes_key_type(key_type)) {
warnx("Key '%s' is already associated with volume '%s'",
name, info->volume);
rc = -EINVAL;
goto out;
}
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0) {
warnx("Key '%s' is already associated with volume "
"'%s' but the volume type not LUKS2", name,
info->volume);
rc = -EINVAL;
goto out;
}
if (info->num_combined > 0) {
warnx("More than one AES key is already associated "
"with volume '%s'", info->volume);
rc = -EINVAL;
goto out;
}
info->num_combined++;
goto out;
}
if (is_aes_key_type(info->key_type) &&
strcasecmp(info->volume_type, VOLUME_TYPE_LUKS2) == 0) {
/* AES key with LUKS2: accept up to one HMAC key with LUKS2 */
if (!is_hmac_key_type(key_type)) {
warnx("Key '%s' is already associated with volume '%s'",
name, info->volume);
rc = -EINVAL;
goto out;
}
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0) {
warnx("Key '%s' is already associated with volume "
"'%s' but the volume type not LUKS2", name,
info->volume);
rc = -EINVAL;
goto out;
}
if (info->num_combined > 0) {
warnx("More than one HMAC key is already associated "
"with volume '%s'", info->volume);
rc = -EINVAL;
goto out;
}
info->num_combined++;
goto out;
}
warnx("Key '%s' is already associated with volume '%s'", name,
info->volume);
return -EINVAL;
rc = -EINVAL;
out:
if (key_type != NULL)
free(key_type);
if (volume_type != NULL)
free(volume_type);
return rc;
}
/**
@@ -1841,6 +1915,15 @@ static int _keystore_create_info_props(struct keystore *keystore,
*props = NULL;
if (volume_type == NULL)
volume_type = is_hmac_key_type(key_type) ?
DEFAULT_INTERITY_VOLUME_TYPE :
DEFAULT_VOLUME_TYPE;
if (!_keystore_valid_volume_type(key_type, volume_type)) {
warnx("Invalid volume-type specified");
return -EINVAL;
}
key_props = properties_new();
if (is_aes_key_type(key_type))
rc = _keystore_set_default_aes_properties(key_props);
@@ -1864,6 +1947,8 @@ static int _keystore_create_info_props(struct keystore *keystore,
goto out;
}
vol_check.key_type = key_type;
vol_check.volume_type = volume_type;
rc = _keystore_change_association(key_props, PROP_NAME_VOLUMES,
volumes != NULL ? volumes : "",
"volume", _keystore_volume_check,
@@ -1891,15 +1976,6 @@ static int _keystore_create_info_props(struct keystore *keystore,
goto out;
}
if (volume_type == NULL)
volume_type = is_hmac_key_type(key_type) ?
DEFAULT_INTERITY_VOLUME_TYPE :
DEFAULT_VOLUME_TYPE;
if (!_keystore_valid_volume_type(key_type, volume_type)) {
warnx("Invalid volume-type specified");
rc = -EINVAL;
goto out;
}
rc = properties_set2(key_props, PROP_NAME_VOLUME_TYPE, volume_type,
true);
if (rc != 0) {
@@ -2615,7 +2691,9 @@ int keystore_change_key(struct keystore *keystore, const char *name,
const char **passphrase_upd = NULL;
char *apqns_prop, *key_type = NULL;
char *upd_volume_type = NULL;
char *old_volume_type = NULL;
const char *null_ptr = NULL;
char *prop_volumes = NULL;
char *upd_volumes = NULL;
size_t secure_key_size;
u8 *secure_key = NULL;
@@ -2650,6 +2728,15 @@ int keystore_change_key(struct keystore *keystore, const char *name,
}
key_type = _keystore_get_key_type(key_props);
old_volume_type = _keystore_get_volume_type(key_props);
if (volume_type != NULL) {
if (!_keystore_valid_volume_type(key_type, volume_type)) {
warnx("Invalid volume-type specified");
rc = -EINVAL;
goto out;
}
}
if (description != NULL) {
rc = properties_set(key_props, PROP_NAME_DESCRIPTION,
@@ -2661,6 +2748,10 @@ int keystore_change_key(struct keystore *keystore, const char *name,
}
if (volumes != NULL) {
vol_check.key_type = key_type;
vol_check.volume_type = volume_type != NULL ?
volume_type : old_volume_type;
rc = _keystore_change_association(key_props, PROP_NAME_VOLUMES,
volumes, "volume",
_keystore_volume_check,
@@ -2746,6 +2837,23 @@ int keystore_change_key(struct keystore *keystore, const char *name,
goto out;
}
prop_volumes = properties_get(key_props, PROP_NAME_VOLUMES);
vol_check.volume = prop_volumes;
vol_check.key_type = key_type;
vol_check.volume_type = volume_type;
vol_check.set = true;
vol_check.nocheck = false;
vol_check.num_combined = 0;
rc = _keystore_process_filtered(keystore, NULL, prop_volumes,
NULL, NULL, NULL, false, false,
_keystore_volume_check_process,
&vol_check);
free(prop_volumes);
if (rc != 0)
goto out;
rc = properties_set2(key_props, PROP_NAME_VOLUME_TYPE,
volume_type, true);
if (rc != 0) {
@@ -2840,6 +2948,8 @@ out:
free(secure_key);
if (key_type != NULL)
free(key_type);
if (old_volume_type != NULL)
free(old_volume_type);
if (rc != 0)
pr_verbose(keystore, "Failed to change key '%s': %s",
@@ -3899,8 +4009,10 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
struct key_filenames file_names = { 0 };
struct key_filenames new_names = { 0 };
struct properties *key_prop = NULL;
char *volume_type = NULL;
size_t secure_key_size;
bool kms_bound = false;
char *key_type = NULL;
u8 *secure_key;
int rc;
@@ -3939,6 +4051,9 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
goto out;
}
key_type = _keystore_get_key_type(key_prop);
volume_type = _keystore_get_volume_type(key_prop);
secure_key = read_secure_key(file_names.skey_filename,
&secure_key_size, keystore->verbose);
if (secure_key == NULL) {
@@ -3965,6 +4080,9 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
goto out;
if (volumes != NULL) {
vol_check.key_type = key_type;
vol_check.volume_type = volume_type;
rc = _keystore_change_association(key_prop, PROP_NAME_VOLUMES,
volumes,
"volume",
@@ -4036,6 +4154,10 @@ out:
_keystore_free_key_filenames(&new_names);
if (key_prop != NULL)
properties_free(key_prop);
if (key_type != NULL)
free(key_type);
if (volume_type != NULL)
free(volume_type);
if (rc != 0)
pr_verbose(keystore, "Failed to copy key '%s'to '%s': %s",
@@ -5836,6 +5958,8 @@ static int _keystore_refresh_kms_key(struct keystore *keystore,
}
if (volumes != NULL) {
vol_check.key_type = key_type;
vol_check.volume_type = volume_type;
rc = _keystore_change_association(properties, PROP_NAME_VOLUMES,
volumes, "volume",
_keystore_volume_check,

View File

@@ -51,10 +51,14 @@ a textual description of the key, can be associated with a secure key.
You can associate a secure key with one or multiple cryptographic adapters
(APQNs) that are set up with the same CCA or EP11 master key.
You can also associate a secure key with one or multiple volumes
(block devices), which are encrypted using \fBdm\-crypt\fP with the secure key.
The volume association also contains the device-mapper name, separated by a
colon, used with \fBdm\-crypt\fP. A specific volume can only be associated with
one secure key.
(block devices), which are encrypted using \fBdm\-crypt\fP or are integrity
protected using \fBdm\-integrity\fP with the secure key. The volume association
also contains the device-mapper name, separated by a colon, used with
\fBdm\-crypt\fP or \fBdm\-integrity\fP. A specific volume can only be associated
with one secure key. Keys of type AES are used for disk encryption, while keys
of type HMAC are used for integrity protection. Combined encryption and
integrity protetion is possible with \fBLUKS2\fP. Here, the same volume can be
associated to an AES-type key and an HMAC-type key.
.PP
The generated secure key is saved in a file, and contains an AES secure key with
a length of 128, 192, or 256 bits, or two concatenated AES secure keys with a
@@ -1358,6 +1362,9 @@ encrypted using \fBdm\-crypt\fP with the secure AES key. The volume association
also contains the device-mapper name, separated by a colon, used with
\fBdm\-crypt\fP.
A specific volume can only be associated with a single secure key.
For combined encryption and integrity protection of a volume associate the same
volume to an AES-type key and an HMAC-type key. Both keys must use the
\fBluks2\fP volume type.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP
@@ -1535,6 +1542,9 @@ integrity protected using \fBdm\-integrity\fP with the secure HMAC key. The
volume association also contains the device-mapper name, separated by a colon,
used with \fBdm\-crypt\fP or \fBdm\-integrity\fP.
A specific volume can only be associated with a single secure key.
For combined encryption and integrity protection of a volume associate the same
volume to an AES-type key and an HMAC-type key. Both keys must use the
\fBluks2\fP volume type.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP
@@ -1699,6 +1709,9 @@ To remove a volume from the associated volumes, prefix the volume with a
You cannot mix \fI+\fP and \fI\-\fP in one specification. You can either add or
remove (or set) the associations with one command.
A specific volume can only be associated with a single secure key.
For combined encryption and integrity protection of a volume associate the same
volume to an AES-type key and an HMAC-type key. Both keys must use the
\fBluks2\fP volume type.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fI[+|\-]card1.domain1[,card2.domain2[,...]]\fP
@@ -2226,7 +2239,9 @@ virtualization secret, or are to be integrity protected using
\fBdm\-integrity\fP with the protected virtualization secret. The volume
association also contains the device-mapper name, separated by a colon, used
with \fBdm\-crypt\fP or \fBdm\-integrity\fP. A specific volume can only be
associated with a single key.
associated with a single key. For combined encryption and integrity protection
of a volume associate the same volume to an AES-type key and an HMAC-type key.
Both keys must use the \fBluks2\fP volume type.
.TP
.BR \-S ", " \-\-sector\-size\~\fIbytes\fP
Specifies the sector size in bytes used with \fBdm\-crypt\fP or