zkey: Add integritytab and integritysetup commands for integrity volumes

The commands 'zkey integritytab' generates /etc/integritytab entries for
volumes of type INTEGRITY.

The 'zkey integritysetup' generates integritysetup commands for formatting
and opening volumes of type INTEGRITY.

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 15:17:17 +01:00
committed by Jan Höppner
parent 8e74293c2d
commit c161c04392
4 changed files with 495 additions and 5 deletions

View File

@@ -4543,8 +4543,8 @@ static int _keystore_execute_cmd(const char *cmd,
return rc;
}
struct crypt_info {
bool integrity;
bool execute;
bool batch_mode;
const char *keyfile;
@@ -4785,6 +4785,104 @@ static int _keystore_process_crypttab(struct keystore *UNUSED(keystore),
return 0;
}
/**
* Processing function for the integritysetup function. Builds a integritysetup
* command line and optionally executes it.
*
* @param[in] keystore the keystore (not used here)
* @param[in] volume the volume to mount
* @param[in] dmname the device mapper name
* @param[in] cipher_spec the cipher specification
* @param[in] key_file_name the key file name
* @param[in] key_file_size the size of the key file in bytes
* @param[in] sector_size the sector size in bytes or 0 if not specified
* @param[in] volume_type the volume type
* @param[in] passphrase_file the passphrase file name (can be NULL)
* @param[in] info processing info
*
* @returns 0 if successful, a negative errno value otherwise
*/
static int _keystore_process_integritysetup(struct keystore *keystore,
const char *volume,
const char *dmname,
const char *cipher_spec,
const char *key_file_name,
size_t key_file_size,
size_t sector_size,
const char *volume_type,
const char *UNUSED(passphrase_file),
struct crypt_info *info)
{
char temp[100];
int rc = 0;
char *cmd;
if (strcasecmp(volume_type, VOLUME_TYPE_INTEGRITY) != 0)
return 0;
sprintf(temp, "--sector-size %lu ", sector_size);
util_asprintf(&cmd,
"integritysetup %s %s%s--integrity %s "
"--integrity-key-file '%s' --integrity-key-size %lu "
"%s%s%s%s",
info->open ? "open" : "format",
info->batch_mode ? "-q " : "",
keystore->verbose ? "-v " : "",
cipher_spec, key_file_name, key_file_size,
sector_size > 0 && !info->open ? temp : "",
volume, info->open ? " " : "",
info->open ? dmname : "");
if (info->execute) {
printf("Executing: %s\n", cmd);
rc = _keystore_execute_cmd(cmd, "integritysetup");
} else {
printf("%s\n", cmd);
}
free(cmd);
return rc;
}
/**
* Processing function for the integritytab function. Builds a integritytab
* entry and prints it.
*
* @param[in] keystore the keystore (not used here)
* @param[in] volume the volume to mount
* @param[in] dmname the device mapper name
* @param[in] cipher_spec the cipher specification
* @param[in] key_file_name the key file name
* @param[in] key_file_size the size of the key file in bytes
* @param[in] sector_size the sector size in bytes or 0 if not specified
* @param[in] volume_type the volume type
* @param[in] passphrase_file the passphrase file name (can be NULL)
* @param[in] info processing info (not used here)
*
* @returns 0 if successful, a negative errno value otherwise
*/
static int _keystore_process_integritytab(struct keystore *UNUSED(keystore),
const char *volume,
const char *dmname,
const char *cipher_spec,
const char *key_file_name,
size_t UNUSED(key_file_size),
size_t UNUSED(sector_size),
const char *volume_type,
const char *UNUSED(passphrase_file),
struct crypt_info *UNUSED(info))
{
if (strcasecmp(volume_type, VOLUME_TYPE_INTEGRITY) != 0)
return 0;
printf("%s\t%s\t%s\tintegrity-algorithm=%s\n", volume, dmname,
key_file_name, cipher_spec);
return 0;
}
/**
* Builds a cipher specification for cryptsetup/crypttab
*
@@ -4820,6 +4918,39 @@ out:
return cipher_spec;
}
/**
* Builds a hmac specification for integritysetup/integritytab
*
* @param properties the key properties
*
* @returns the hmac spec string (must be freed by the caller)
*/
static char *_keystore_build_hmac_spec(struct properties *properties,
size_t bitsize)
{
char *cipher_spec = NULL;
char *cipher = NULL;
char *digest = NULL;
cipher = properties_get(properties, PROP_NAME_CIPHER);
if (cipher == NULL)
goto out;
digest = properties_get(properties, PROP_NAME_DIGEST);
if (digest == NULL)
goto out;
util_asprintf(&cipher_spec, "%s-%s%u", cipher, digest, bitsize / 2);
out:
if (cipher != NULL)
free(cipher);
if (digest != NULL)
free(digest);
return cipher_spec;
}
/**
* Processing function for the cryptsetup and crypttab functions.
* Extracts the required information and calls the secondary processing function
@@ -4847,6 +4978,7 @@ static int _keystore_process_crypt(struct keystore *keystore,
size_t sector_size = 0;
char *volumes = NULL;
u8 *secure_key = NULL;
size_t bitsize = 0;
char *dmname;
char *temp;
int rc = 0;
@@ -4859,9 +4991,16 @@ static int _keystore_process_crypt(struct keystore *keystore,
if (secure_key == NULL)
return -EIO;
cipher_spec = _keystore_build_cipher_spec(properties,
is_xts_key(secure_key,
secure_key_size));
if (info->integrity) {
rc = get_key_bit_size(secure_key, secure_key_size, &bitsize);
if (rc != 0)
goto out;
cipher_spec = _keystore_build_hmac_spec(properties, bitsize);
} else {
cipher_spec = _keystore_build_cipher_spec(properties,
is_xts_key(secure_key,
secure_key_size));
}
if (cipher_spec == NULL) {
rc = -EINVAL;
goto out;
@@ -4965,6 +5104,7 @@ int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter,
util_file_read_i(&info.fips, 10, "/proc/sys/crypto/fips_enabled");
info.integrity = false;
info.execute = execute;
info.open = open;
info.format = format;
@@ -5031,6 +5171,7 @@ int keystore_crypttab(struct keystore *keystore, const char *volume_filter,
return -EINVAL;
}
info.integrity = false;
info.keyfile = keyfile;
info.keyfile_offset = keyfile_offset;
info.keyfile_size = keyfile_size;
@@ -5054,6 +5195,105 @@ int keystore_crypttab(struct keystore *keystore, const char *volume_filter,
return rc;
}
/**
* Generates integritysetup commands for one or multiple volumes.
*
* @param[in] keystore the key store
* @param[in] volume_filter the volume filter. Can contain wild cards, and
* multiple volume filters separated by commas.
* The ':dm-name' part of the volume is optional
* for the volume filter. If not specified, the filter
* checks the volume part only.
* @param[in] execute If TRUE the integritysetup command is executed,
* otherwise it is printed to stdout
* @param[in] batch_mode If TRUE, suppress integritysetup confirmation
* questions
* @param[in] open If TRUE, generate integritysetup open commands
* @returns 0 for success or a negative errno in case of an error
*/
int keystore_integritysetup(struct keystore *keystore,
const char *volume_filter,
bool execute, bool batch_mode, bool open)
{
struct crypt_info info = { 0 };
int rc;
util_assert(keystore != NULL, "Internal error: keystore is NULL");
if (volume_filter == NULL)
volume_filter = "*";
info.integrity = true;
info.execute = execute;
info.open = open;
info.batch_mode = batch_mode;
info.volume_filter = str_list_split(volume_filter);
info.process_func = _keystore_process_integritysetup;
rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL,
VOLUME_TYPE_INTEGRITY,
KEY_TYPE_FILTER_HMAC,
false, false,
_keystore_process_crypt, &info);
str_list_free_string_array(info.volume_filter);
if (rc < 0)
pr_verbose(keystore, "Integritysetup failed with: %s",
strerror(-rc));
else if (rc > 0)
pr_verbose(keystore, "Integritysetup failed with: %d", rc);
else
pr_verbose(keystore,
"Successfully generated integritysetup commands");
return rc;
}
/**
* Generates integritytab entries for one or multiple volumes.
*
* @param[in] keystore the key store
* @param[in] volume_filter the volume filter. Can contain wild cards, and
* multiple volume filters separated by commas.
* The ':dm-name' part of the volume is optional
* for the volume filter. If not specified, the filter
* checks the volume part only.
*
* @returns 0 for success or a negative errno in case of an error
*/
int keystore_integritytab(struct keystore *keystore, const char *volume_filter)
{
struct crypt_info info = { 0 };
int rc;
util_assert(keystore != NULL, "Internal error: keystore is NULL");
if (volume_filter == NULL)
volume_filter = "*";
info.integrity = true;
info.volume_filter = str_list_split(volume_filter);
info.process_func = _keystore_process_integritytab;
rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL,
VOLUME_TYPE_INTEGRITY,
KEY_TYPE_FILTER_HMAC,
false, false,
_keystore_process_crypt, &info);
str_list_free_string_array(info.volume_filter);
if (rc != 0)
pr_verbose(keystore, "Integritysetup failed with: %s",
strerror(-rc));
else
pr_verbose(keystore,
"Successfully generated integritysetup entries");
return rc;
}
/**
* Converts a secure keys in the keystore
*

View File

@@ -130,6 +130,12 @@ int keystore_crypttab(struct keystore *keystore, const char *volume_filter,
const char *volume_type, const char *keyfile,
size_t keyfile_offset, size_t keyfile_size, size_t tries);
int keystore_integritysetup(struct keystore *keystore,
const char *volume_filter,
bool execute, bool batch_mode, bool open);
int keystore_integritytab(struct keystore *keystore, const char *volume_filter);
int keystore_convert_key(struct keystore *keystore, const char *name,
const char *key_type, bool noapqncheck, bool quiet,
bool exportable, int pkey_fd, struct ext_lib *lib);

View File

@@ -735,6 +735,13 @@ options
and
.B \-\-keyfile\-size
to control which part of the key file is used as passphrase.
.PP
.B Note:
Use the
.B integritytab
command to generate integritytab entries for volumes using the \fBintegrity\fP
volume type that are associated with secure HMAC keys contained in the
secure key repository.
.
.SS "Generate cryptsetup commands for volumes associated with secure AES keys"
.
@@ -811,6 +818,88 @@ To avoid cryptsetup confirmation questions, you can specify the
.B \-\-batch\-mode
option. These options are passed to the generated command(s) and behave in the
same way as with \fBcryptsetup\fP.
.PP
.B Note:
Use the
.B integritysetup
command to generate \fBintegritysetup format\fP and \fBintegritysetup open\fP
commands for volumes using the \fBintegrity\fP volume type that are associated
with secure HMAC keys contained in the
secure key repository.
.
.SS "Generate integritytab entries for volumes associated with secure HMAC keys"
.
.B zkey
.BR integritytab | integrityt
.RB [ \-\-volumes | \-l
.IR volume1[:dmname1][,volume2[:dmname2][,...]] ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B integritytab
command to generate integritytab entries using \fBdm\-integrity\fP for volumes
that are associated with secure HMAC keys contained in the secure key
repository. Only HMAC keys with a volume type of \fBintegrity\fP are considered.
Specify the
.B \-\-volumes
option to limit the list
of volumes where integritytab entries are generated for. You can use wildcards.
When wildcards are used you must quote the value.
The device-mapper name of an associated volume can be omitted; if it is
specified then only those volumes with the specified volume and device-mapper
name are selected.
.PP
.B Note:
Use the
.B crypttab
command to generate crypttab entries for volumes using the \fBplain\fP or
\fBluks2\fP volume type that are associated with secure AES keys contained in
the secure key repository.
.
.SS "Generate integritysetup commands for volumes associated with secure HMAC keys"
.
.B zkey
.BR integritysetup | integritys
.RB [ \-\-volumes | \-l
.IR volume1[:dmname1][,volume2[:dmname2][,...]] ]
.RB [ \-\-run | \-r ]
.RB [ \-\-open ]
.RB [ \-\-batch\-mode | \-q ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B integritysetup
command to generate \fBintegritysetup format\fP, or \fBintegritysetup open\fP
commands for volumes that are associated with secure HMAC keys contained in the
secure key repository. Only HMAC keys with a volume type of \fBintegrity\fP are
considered. Specify the
.B \-\-volumes
option to limit the list
of volumes where integritysetup commands are generated for. You can use
wildcards. When wildcards are used you must quote the value.
The device-mapper name of an associated volume can be omitted; if it is
specified then only those volumes with the specified volume and device-mapper
name are selected.
Specify the
.B \-\-run
option to run the generated integritysetup commands. Specify the
.B \-\-open
to generate \fBintegritysetup open\fP commands. By default \fBintegritysetup
format\fP commands are generated.
To avoid integritysetup confirmation questions, you can specify the
.B \-\-batch\-mode
option. These option is passed to the generated command(s) and behave in the
same way as with \fBintegritysetup\fP.
.PP
.B Note:
Use the
.B cryptsetup
command to generate\fBcryptsetup plainOpen\fP, \fBcryptsetup luksOpen\fP, or
\fBcryptsetup luksFormat\fP commands for volumes using the \fBplain\fP or
\fBluks2\fP volume types that are associated with secure AES keys contained in
the secure key repository.
.
.SS "Convert existing AES or HMAC secure keys from one key type to another type"
.
@@ -1965,6 +2054,52 @@ generated cryptsetup command(s).
.
.
.
.SS "Options for the integritytab command"
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with secure HMAC keys in the repository. Only HMAC keys with a
volume type of \fBintegrity\fP are considered.
The volume association also contains the device-mapper name, separated by a
colon, used with \fBdm\-integrity\fP. You can omit the device-mapper name; if
it is specified then only those keys are selected that are associated with the
specified volume and device-mapper name. You can use wildcards to specify
the volumes and device-mapper names.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the integritysetup command"
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with secure HMAC keys in the repository. Only HMAC keys with a
volume type of \fBintegrity\fP are considered.
The volume association also contains the device-mapper name, separated by a
colon, used with \fBdm\-integrity\fP. You can omit the device-mapper name; if
it is specified then only those keys are selected that are associated with the
specified volume and device-mapper name. You can use wildcards to specify
the volumes and device-mapper names.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-r ", " \-\-run
Runs the generated integritysetup commands. When one of the integritysetup
commands fail, no further integritysetup commands are run, and zkey ends with
an error.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-open
Generates \fBintegritysetup open\fP commands. By default \fBintegritysetup
format\fP commands are generated.
.TP
.BR \-q ", " \-\-batch\-mode
Suppress integritysetup confirmation questions. This option is passed to the
generated integritysetup command(s).
.
.
.
.SS "Options for the convert command"
.TP
.BR \-N ", " \-\-name\~\fIkey\-name\fP

View File

@@ -134,6 +134,8 @@ static struct zkey_globals {
#define COMMAND_COPY "copy "
#define COMMAND_CRYPTTAB "crypttab"
#define COMMAND_CRYPTSETUP "cryptsetup"
#define COMMAND_INTEGRITYTAB "integritytab"
#define COMMAND_INTEGRITYSETUP "integritysetup"
#define COMMAND_CONVERT "convert"
#define COMMAND_KMS "kms"
#define COMMAND_KMS_PLUGINS "plugins"
@@ -158,7 +160,7 @@ static struct zkey_globals {
.command = OPT_COMMAND_PLACEHOLDER, \
}
#define ZKEY_COMMAND_MAX_LEN 10
#define ZKEY_COMMAND_MAX_LEN 15
#define ENVVAR_ZKEY_REPOSITORY "ZKEY_REPOSITORY"
#define DEFAULT_KEYSTORE "/etc/zkey/repository"
@@ -970,6 +972,62 @@ static struct util_opt opt_vec[] = {
.flags = UTIL_OPT_FLAG_NOSHORT,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
.desc = "OPTIONS",
.command = COMMAND_INTEGRITYTAB,
},
{
.option = { "volumes", required_argument, NULL, 'l'},
.argument = "VOLUME[:DMNAME][,...]",
.desc = "Comma-separated pairs of volume and device-mapper "
"names that are associated with the secure HMAC key in "
"the repository. Use this option to select the volumes "
"for which a integritytab entry is to be generated. "
"The device-mapper name (DMNAME) is optional. If "
"specified, only those volumes are selected where "
"both, the volume and the device-mapper name matches",
.command = COMMAND_INTEGRITYTAB,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
.desc = "OPTIONS",
.command = COMMAND_INTEGRITYSETUP,
},
{
.option = { "volumes", required_argument, NULL, 'l'},
.argument = "VOLUME[:DMNAME][,...]",
.desc = "Comma-separated pairs of volume and device-mapper "
"names that are associated with the secure HMAC key in "
"the repository. Use this option to select the volumes "
"for which a integritysetup command is to be generated "
"or run. The device-mapper name (DMNAME) is optional. "
"If specified, only those volumes are selected where "
"both, the volume and the device-mapper name matches",
.command = COMMAND_INTEGRITYSETUP,
},
{
.option = {"run", 0, NULL, 'r'},
.desc = "Runs the generated integritysetup command",
.command = COMMAND_INTEGRITYSETUP,
},
{
.option = {"batch-mode", 0, NULL, 'q'},
.desc = "Suppresses integritysetup confirmation questions. "
"This option is passed to the generated integritysetup "
"command(s)",
.command = COMMAND_INTEGRITYSETUP,
},
{
.option = {"open", 0, NULL, OPT_CRYPTSETUP_OPEN},
.desc = "Generates 'integritysetup open' commands. If this "
"option is not specified, 'integritysetup format' "
"commands are generated",
.command = COMMAND_INTEGRITYSETUP,
.flags = UTIL_OPT_FLAG_NOSHORT,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
.desc = "OPTIONS",
@@ -1465,6 +1523,8 @@ static int command_rename(void);
static int command_copy(void);
static int command_crypttab(void);
static int command_cryptsetup(void);
static int command_integritytab(void);
static int command_integritysetup(void);
static int command_convert(void);
static int command_kms_plugins(void);
static int command_kms_bind(void);
@@ -1762,6 +1822,26 @@ static struct zkey_command zkey_commands[] = {
.has_options = 1,
.need_keystore = 1,
},
{
.command = COMMAND_INTEGRITYTAB,
.abbrev_len = 10,
.function = command_integritytab,
.short_desc = "Generate integritytab entries",
.long_desc = "Generate integritytab entries for selected "
"volumes",
.has_options = 1,
.need_keystore = 1,
},
{
.command = COMMAND_INTEGRITYSETUP,
.abbrev_len = 10,
.function = command_integritysetup,
.short_desc = "Generate or run integritysetup commands",
.long_desc = "Generate or run integritysetup commands for "
"selected volumes",
.has_options = 1,
.need_keystore = 1,
},
{
.command = COMMAND_CONVERT,
.abbrev_len = 3,
@@ -2752,6 +2832,35 @@ static int command_cryptsetup(void)
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
* Command handler for 'integritytab'.
*
* Generates integritytab entries for selected volumes
*/
static int command_integritytab(void)
{
int rc;
rc = keystore_integritytab(g.keystore, g.volumes);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
* Command handler for 'integritysetup'.
*
* Generates and runs integritysetup commands for selected volumes
*/
static int command_integritysetup(void)
{
int rc;
rc = keystore_integritysetup(g.keystore, g.volumes, g.run,
g.batch_mode, g.open);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
* Command handler for 'convert'.
*