zkey: Add the 'pvsecrets import' command

The 'pvsecrets import' command imports a protected virtualization secret
into the zkey key repository. Like other key import or key generation
commands, additional information can be associated with the imported key,
such as a textual description, the volume to encrypt with together with
the volume type, the sector size, and a dummy passphrase. You can not
associate a set of APQNs, since a protected virtualization secret does
not need or use a crypto card.

This command only works when running in a secure execution guest.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jorg Schmidbauer <jschmidb@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2024-02-15 15:14:04 +01:00
committed by Steffen Eiden
parent fdf66dc148
commit 95bf7eb285
6 changed files with 513 additions and 32 deletions

View File

@@ -2259,9 +2259,11 @@ out_free_key_filenames:
}
/**
* Imports a secure key from a file and adds it to the key store
* Imports a secure key from a buffer and adds it to the key store
*
* @param[in] keystore the key store
* @param[in] secure_key the buffer containing the key
* @param[in] secure_key_size the size of the key
* @param[in] name the name of the key
* @param[in] description textual description of the key (optional, can be NULL)
* @param[in] volumes a comma separated list of volumes associated with this
@@ -2274,7 +2276,6 @@ out_free_key_filenames:
* of two and in range 512 - 4096 bytes. 0 means that
* the sector size is not specified and the system
* default is used.
* @param[in] import_file The name of a secure key containing the key to import
* @param[in] volume_type the type of volume
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
@@ -2283,25 +2284,23 @@ out_free_key_filenames:
*
* @returns 0 for success or a negative errno in case of an error
*/
int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
struct ext_lib *lib)
int keystore_import(struct keystore *keystore, unsigned char *secure_key,
size_t secure_key_size, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *volume_type, bool gen_passphrase,
const char *passphrase_file, struct ext_lib *lib)
{
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
size_t secure_key_size;
const char *key_type;
u8 mkvp[MKVP_LENGTH];
int selected = 1;
u8 *secure_key;
int rc;
util_assert(keystore != NULL, "Internal error: keystore is NULL");
util_assert(name != NULL, "Internal error: name is NULL");
util_assert(import_file != NULL, "Internal error: import_file is NULL");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
rc = _keystore_get_key_filenames(keystore, name, &file_names);
if (rc != 0)
@@ -2311,27 +2310,29 @@ int keystore_import_key(struct keystore *keystore, const char *name,
if (rc != 0)
goto out_free_key_filenames;
secure_key = read_secure_key(import_file, &secure_key_size,
keystore->verbose);
if (secure_key == NULL) {
rc = -ENOENT;
goto out_free_key_filenames;
}
key_type = get_key_type(secure_key, secure_key_size);
if (key_type == NULL) {
warnx("Key '%s' is not a valid secure key", name);
free(secure_key);
rc = -EINVAL;
goto out_free_key_filenames;
}
if (!is_secure_key(secure_key, secure_key_size)) {
if (apqns != NULL) {
warnx("No APQNs can be associated with keys of type %s",
key_type);
rc = -EINVAL;
goto out_free_props;
}
goto write_key;
}
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
mkvp, keystore->verbose);
if (rc != 0) {
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
goto out_free_key;
goto out_free_props;
}
rc = cross_check_apqns(apqns, mkvp,
@@ -2340,17 +2341,17 @@ int keystore_import_key(struct keystore *keystore, const char *name,
get_card_type_for_keytype(key_type),
true, keystore->verbose);
if (rc == -EINVAL)
goto out_free_key;
goto out_free_props;
if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) {
warnx("Your master key setup is improper");
goto out_free_key;
goto out_free_props;
}
if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
if (lib->cca->lib_csulcca == NULL) {
rc = load_cca_library(lib->cca, keystore->verbose);
if (rc != 0)
goto out_free_key;
goto out_free_props;
}
rc = select_cca_adapter_by_mkvp(lib->cca, mkvp, apqns,
@@ -2365,7 +2366,7 @@ int keystore_import_key(struct keystore *keystore, const char *name,
warnx("No APQN found that is suitable for "
"working with the secure AES key '%s'", name);
rc = 0;
goto out_free_key;
goto out_free_props;
}
rc = restrict_key_export(lib->cca, secure_key, secure_key_size,
@@ -2375,7 +2376,7 @@ int keystore_import_key(struct keystore *keystore, const char *name,
"key: %s", strerror(-rc));
if (!selected)
print_msg_for_cca_envvars("secure AES key");
goto out_free_key;
goto out_free_props;
}
rc = check_aes_cipher_key(secure_key, secure_key_size);
@@ -2386,15 +2387,14 @@ int keystore_import_key(struct keystore *keystore, const char *name,
if (!prompt_for_yes(keystore->verbose)) {
warnx("Operation aborted");
rc = -ECANCELED;
goto out_free_key;
goto out_free_props;
}
}
}
write_key:
rc = write_secure_key(file_names.skey_filename, secure_key,
secure_key_size, keystore->verbose);
free(secure_key);
secure_key = NULL;
if (rc != 0)
goto out_free_props;
@@ -2414,9 +2414,6 @@ int keystore_import_key(struct keystore *keystore, const char *name,
"Successfully imported a secure key in '%s' and key info in '%s'",
file_names.skey_filename, file_names.info_filename);
out_free_key:
if (secure_key != NULL)
free(secure_key);
out_free_props:
if (key_props != NULL)
properties_free(key_props);
@@ -2431,6 +2428,59 @@ out_free_key_filenames:
return rc;
}
/**
* Imports a secure key from a file and adds it to the key store
*
* @param[in] keystore the key store
* @param[in] name the name of the key
* @param[in] description textual description of the key (optional, can be NULL)
* @param[in] volumes a comma separated list of volumes associated with this
* key (optional, can be NULL)
* @param[in] apqns a comma separated list of APQNs associated with this
* key (optional, can be NULL)
* @param[in] noapqncheck if true, the specified APQN(s) are not checked for
* existence and type.
* @param[in] sector_size the sector size to use with dm-crypt. It must be a
* power of two and in range 512 - 4096 bytes. 0 means
* that the sector size is not specified and the system
* default is used.
* @param[in] import_file The name of a secure key containing the key to import
* @param[in] volume_type the type of volume
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] lib the external library struct
*
* @returns 0 for success or a negative errno in case of an error
*/
int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
struct ext_lib *lib)
{
size_t secure_key_size;
u8 *secure_key;
int rc;
util_assert(import_file != NULL, "Internal error: import_file is NULL");
secure_key = read_secure_key(import_file, &secure_key_size,
keystore->verbose);
if (secure_key == NULL)
return -ENOENT;
rc = keystore_import(keystore, secure_key, secure_key_size, name,
description, volumes, apqns, noapqncheck,
sector_size, volume_type, gen_passphrase,
passphrase_file, lib);
if (secure_key != NULL)
free(secure_key);
return rc;
}
/**
* Changes properties of a key in the keystore.

View File

@@ -3,7 +3,7 @@
*
* Keystore handling functions
*
* Copyright IBM Corp. 2018, 2020
* Copyright IBM Corp. 2018, 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -65,6 +65,13 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
struct kms_option *kms_options,
size_t num_kms_options);
int keystore_import(struct keystore *keystore, unsigned char *secure_key,
size_t secure_key_size, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *volume_type, bool gen_passphrase,
const char *passphrase_file, struct ext_lib *lib);
int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,

View File

@@ -552,3 +552,129 @@ int pvsecrets_list(int uv_fd, bool all, bool hex, const char *type_filter,
return rc;
}
struct build_secret_key_blob_data {
unsigned char id[UV_SECRET_ID_LEN];
char name[UV_SECRET_ID_LEN];
struct pvsecrettoken token;
bool found;
};
/**
* Callback used to generate a pvsecrets key blob for a specific secret ID.
* Called for each secret.
*
* @param idx the index of the secret
* @param type the type of the secret
* @param id the ID of the secret
* @param cb_private callback private data
*
* @returns 0 on success, a negative errno in case of an error
*/
static int pvsecrets_build_key_blob_cb(u16 UNUSED(idx), u16 type, u32 len,
const u8 id[UV_SECRET_ID_LEN],
void *cb_private)
{
struct build_secret_key_blob_data *build_blob_data = cb_private;
if (build_blob_data->found)
return 0;
if (memcmp(id, build_blob_data->name, UV_SECRET_ID_LEN) != 0 &&
memcmp(id, build_blob_data->id, UV_SECRET_ID_LEN) != 0)
return 0;
memset(&build_blob_data->token, 0, sizeof(build_blob_data->token));
build_blob_data->token.hdr.type = TOKEN_TYPE_NON_CCA;
build_blob_data->token.hdr.version = TOKEN_VERSION_PVSECRET;
build_blob_data->token.secret_type = type;
build_blob_data->token.secret_len = len;
memcpy(build_blob_data->token.secretid, id, UV_SECRET_ID_LEN);
build_blob_data->found = true;
return 0;
}
/**
* Imports a protected virtualization secure key from the UV and adds it to the
* key store
*
* @param keystore the key store
* @param uv_fd the file descriptor of the ultravisor device
* @param secret_id the secret id as 32 byte hex string. Can be NULL if
* secret_name is non-NULL.
* @param secret_name the secret name. Can be NULL if secret_id is non-NULL.
* @param name the name of the key in the repository
* @param description textual description of the key (optional, can be NULL)
* @param volumes a comma separated list of volumes associated with this
* key (optional, can be NULL)
* @param volume_type the type of volume
* @param sector_size the sector size to use with dm-crypt. It must be a
* power of two and in range 512 - 4096 bytes. 0 means
* that the sector size is not specified and the system
* default is used.
* @param gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error
*/
int pvsecrets_import(struct keystore *keystore, int uv_fd,
const char *secret_id, const char *secret_name,
const char *name, const char *description,
const char *volumes, const char *volume_type,
long sector_size, bool gen_passphrase,
const char *passphrase_file, bool verbose)
{
struct build_secret_key_blob_data build_blob_data = { 0 };
int rc;
util_assert(keystore != NULL, "Internal error: keystore is NULL");
util_assert(uv_fd != -1, "Internal error: uv_fd is -1");
util_assert(secret_id != NULL || secret_name != NULL,
"Internal error: secret_id and secrest_name is NULL");
util_assert(name != NULL, "Internal error: name is NULL");
rc = get_secret_id_from_hex_or_name(secret_id, secret_name,
build_blob_data.id,
build_blob_data.name);
if (rc < 0)
return rc;
if (rc > 0)
return -EINVAL;
rc = uv_list_secrets(uv_fd, pvsecrets_build_key_blob_cb,
&build_blob_data, verbose);
if (rc != 0) {
warnx("Failed to import the pvsecret with %s '%s': %s",
secret_id != NULL ? "id" : "name",
secret_id != NULL ? secret_id : secret_name,
strerror(-rc));
return rc;
}
if (!build_blob_data.found) {
warnx("The pvsecret with %s '%s' does not exist",
secret_id != NULL ? "id" : "name",
secret_id != NULL ? secret_id : secret_name);
return -ENOENT;
}
if (!is_pvsecret_type_supported(build_blob_data.token.secret_type)) {
warnx("The type of the pvsecret with %s '%s' is not supported "
"by zkey: %s", secret_id != NULL ? "id" : "name",
secret_id != NULL ? secret_id : secret_name,
get_pvsecret_type_name(
build_blob_data.token.secret_type));
return -EINVAL;
}
rc = keystore_import(keystore, (unsigned char *)&build_blob_data.token,
sizeof(build_blob_data.token), name, description,
volumes, NULL, false, sector_size, volume_type,
gen_passphrase, passphrase_file, NULL);
return rc;
}

View File

@@ -16,6 +16,7 @@
#include "lib/zt_common.h"
#include "pkey.h"
#include "keystore.h"
/*
* Definitions for the /dev/uv kernel module interface
@@ -89,5 +90,11 @@ int uv_open_device(bool verbose);
int pvsecrets_list(int uv_fd, bool all, bool hex, const char *type_filter,
const char *secret_id, const char *secret_name,
bool verbose);
int pvsecrets_import(struct keystore *keystore, int uv_fd,
const char *secret_id, const char *secret_name,
const char *name, const char *description,
const char *volumes, const char *volume_type,
long sector_size, bool gen_passphrase,
const char *passphrase_file, bool verbose);
#endif

View File

@@ -1208,6 +1208,64 @@ are supported by the \fBzkey\fP tool. To list all pvsecret types, specify the
This command is only available when running in a secure execution guest.
Only the \fBroot\fP user is allowed to perform this command.
.
.SS "Import protected virtualization secrets into the repository"
.
.B zkey pvsecrets
.BR import | im
.RB [ \-\-pvsecret\-id | \-I
.IR pvsecret\-id ]
.RB [ \-\-pvsecret\-name | \-e
.IR pvsecret\-name ]
.B \-\-name | \-N
.IR key\-name
.RB [ \-\-description | \-d
.IR description ]
.RB [ \-\-volumes | \-l
.IR volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-sector\-size | \-S
.IR bytes ]
.RB [ \-\-volume\-type | \-t
.IR type ]
.RB [ \-\-gen\-dummy\-passphrase ]
.RB [ \-\-set\-dummy\-passphrase
.IR passphrase\-file ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B pvsecrets import
command to import a protected virtualization (PV) secret into the repository.
Either the \fB\-\-pvsecret\-id\fP option or the \fB\-\-pvsecret\-name\fP
option can be specified. If the pvsecret name is specified, then the
\fB\-\-name\fP option can be omitted. The name of the protected virtualization
secret key object in the repository will then be the same as the pvsecret name.
.PP
You can use the YAML file that was created when using the \fBpvsecret create\fP
command for adding the protected virtualization secret:
\fB\-\-pvsecret\-id "$(yq .id \fP\fIYAML\-FILE\fP\fB)"\fP or
\fB\-\-pvsecret\-name "$(yq .name \fP\fIYAML\-FILE\fP\fB)"\fP.
You might have to install the \fByq\fP package first.
.PP
A protected virtualization secret key object does not contain the key material,
but only a reference (i.e. the secret ID) to the key in the ultravisor.
When such a protected virtualization secret key object is used with
\fBdm\-crypt\fP and the \fBPAES\fP kernel cipher, the key material (i.e. a
protected key) is retrieved from the ultravisor and the crypto operation is
performed with it.
.PP
When importing a protected virtualization secret in a key repository,
additional information can be associated with it using the
.B \-\-description
,
.B \-\-volumes
, or the
.B \-\-sector\-size
options. APQNs can not be associated, because protected virtualization secrets
do not require a crypto card.
.PP
This command is only available when running in a secure execution guest.
Only the \fBroot\fP user is allowed to perform this command.
.
.
.
.
@@ -2117,6 +2175,82 @@ can be specified, but not both.
.
.
.
.SS "Options for the pvsecrets import command"
.TP
.BR \-I ", " \-\-pvsecret\-id\~\fIpvsecret\-id\fP
ID of the protected virtualization (PV) secret to import. The pvsecret ID is a
32 byte hex string, optionally prefixed by \fB0x\fP. You can use the YAML file
that was created when using the \fBpvsecret create\fP command for adding the
protected virtualization secret:
\fB\-\-pvsecret\-id "$(yq .id \fP\fIYAML\-FILE\fP\fB)"\fP.
You might have to install the \fByq\fP package first.
Either the \fB\-\-pvsecret\-id\fP option or the \fB\-\-pvsecret\-name\fP option
can be specified, but not both.
.TP
.BR \-e ", " \-\-pvsecret\-name\~\fIpvsecret\-name\fP
Name of the protected virtualization (PV) secret to import. You can use the YAML
file that was created when using the \fBpvsecret create\fP command for adding
the protected virtualization secret:
\fB\-\-pvsecret\-name "$(yq .name \fP\fIYAML\-FILE\fP\fB)"\fP.
You might have to install the \fByq\fP package first.
Either the \fB\-\-pvsecret\-id\fP option or the \fB\-\-pvsecret\-name\fP option
can be specified, but not both. If the \fB\-\-pvsecret\-name\fP option is
specified, then the \fB\-\-name\fP option can be omitted. The name of the
protected virtualization secret key object in the repository will then be the
same as the pvsecret name.
.TP
.BR \-N ", " \-\-name\~\fIkey\-name\fP
Specifies the name of the protected virtualization secret key object in the key
repository. If the \fB\-\-pvsecret\-name\fP option is specified, then the
\fB\-\-name\fP option can be omitted. The name of the protected virtualization
secret in the repository will then be the same as the pvsecret name.
.TP
.BR \-d ", " \-\-description\~\fIdescription\fP
Specifies a textual description for the protected virtualization secret in the
key repository.
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1[,volume2:dmname2[,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with the protected virtualization secret in the repository. These
volumes are to be encrypted using \fBdm\-crypt\fP with the protected
virtualization secret. 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 key.
.TP
.BR \-S ", " \-\-sector\-size\~\fIbytes\fP
Specifies the sector size in bytes used with \fBdm\-crypt\fP. It must be a power
of two and in the range of 512 to 4096 bytes. If omitted, the system default
sector size is used.
.TP
.BR \-t ", " \-\-volume\-type\~\fItype\fP
Specifies the volume type of the associated volumes used with \fBdm\-crypt\fP.
Possible values are \fBplain\fP and \fBluks2\fP. If omitted, \fBluks2\fP is
used. This option is only available if
.B zkey
has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled,
the default volume type is \fBplain\fP.
.TP
.BR \-\-gen\-dummy\-passphrase
Generate a dummy passphrase randomly and associate it with the protected
virtualization secret used to encrypt LUKS2 volume(s). The LUKS2 passphrase is
of less or no relevance for the security of the volume(s), when a protected
virtualization secret is used to encrypt the volume(s), and can therefore be
stored insecurely inside the key repository. If for a certain usage the
passphrase is of relevance for security, then do not use this option. This
option can only be specified for keys with a volume type of \fBluks2\fP.
.TP
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
Set a dummy passphrase that is read from the specified file and associate it
with the protected virtualization secret used to encrypt LUKS2 volume(s).
The LUKS2 passphrase is of less or no relevance for the security of the
volume(s), when an protected virtualization secret is used to encrypt the
volume(s), and can therefore be stored insecurely inside the key repository.
If for a certain usage the passphrase is of relevance for security, then do
not use this option. This option can only be specified for keys with a volume
type of \fBluks2\fP.
.
.
.
.SS "General options"
.TP
.BR \-V ", " \-\-verbose

View File

@@ -145,6 +145,7 @@ static struct zkey_globals {
#define COMMAND_KMS_REFRESH "refresh"
#define COMMAND_PVSECRETS "pvsecrets"
#define COMMAND_PVSECRETS_LIST "list"
#define COMMAND_PVSECRETS_IMPORT "import"
#define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER"
@@ -1234,6 +1235,103 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
.desc = "OPTIONS",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
{
.option = { "pvsecret-id", required_argument, NULL, 'I'},
.argument = "PVSECRET-ID",
.desc = "ID of the protected virtualization (PV) secret to "
"import. Either '--pvsecret-id/-I' or "
"'--pvsecret-name/-e' can be specified, but not both.",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
{
.option = { "pvsecret-name", required_argument, NULL, 'e'},
.argument = "PVSECRET-NAME",
.desc = "Name of the protected virtualization (PV) secret to "
"import. Either '--pvsecret-name/-e' or "
"'--pvsecret-id/-I' can be specified, but not both. "
"If the '--pvsecret-name/-e' option is specified, but "
"the '--name/-N' option is omitted, then the imported "
"protected virtualisation secret will be named the "
"same as the pvsecret name.",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
{
.option = { "name", required_argument, NULL, 'N'},
.argument = "NAME",
.desc = "Name of the imported protected virtualisation secret "
"in the repository. If the '--name/-N' option is "
"omitted, but the '--pvsecret-name/-e' is specified, "
"then the imported protected virtualisation secret "
"will be named the same as the pvsecret name.",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
{
.option = { "description", required_argument, NULL, 'd'},
.argument = "DESCRIPTION",
.desc = "Textual description of the protected virtualisation "
"secret in the repository",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
{
.option = { "volumes", required_argument, NULL, 'l'},
.argument = "VOLUME:DMNAME[,...]",
.desc = "Comma-separated pairs of volume and device-mapper "
"names that are associated with the protected "
"virtualisation secret in the repository",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
{
.option = { "sector-size", required_argument, NULL, 'S'},
.argument = "512|4096",
.desc = "The sector size used with dm-crypt. It must be a power "
"of two and in range 512 - 4096 bytes. If this option "
"is omitted, the system default sector size (512) is "
"used",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
#ifdef HAVE_LUKS2_SUPPORT
{
.option = { "volume-type", required_argument, NULL, 't'},
.argument = "type",
.desc = "The type of the associated volume(s). Possible values "
"are 'plain' and 'luks2'. When this option is omitted, "
"the default is 'luks2'",
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
#endif
{
.option = { "gen-dummy-passphrase", 0, NULL,
OPT_GEN_DUMMY_PASSPHRASE},
.desc = "Generate a dummy passphrase and associate it with the "
"protected virtualisation secret used to encrypt LUKS2 "
"volume(s). The LUKS2 passphrase is of less or no "
"relevance for the security of the volume(s), when an "
"protected virtualisation secret is used to encrypt "
"the volume(s), and can therefore be stored insecurely "
"inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
{
.option = { "set-dummy-passphrase", required_argument, NULL,
OPT_SET_DUMMY_PASSPHRASE},
.argument = "passphrase-file",
.desc = "Set a dummy passphrase to be associated with the "
"protected virtualisation secret used to encrypt LUKS2 "
"volume(s). The LUKS2 passphrase is of less or no "
"relevance for the security of the volume(s), when a "
"protected virtualisation secret is used to encrypt "
"the volume(s), and can therefore be stored insecurely "
"inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_IMPORT,
},
/***********************************************************/
OPT_PLACEHOLDER,
OPT_PLACEHOLDER,
OPT_PLACEHOLDER,
@@ -1339,6 +1437,7 @@ static int command_kms_list(void);
static int command_kms_import(void);
static int command_kms_refresh(void);
static int command_pvsecrets_list(void);
static int command_pvsecrets_import(void);
static struct zkey_command zkey_kms_commands[] = {
{
@@ -1469,6 +1568,19 @@ static struct zkey_command zkey_pvsecrets_commands[] = {
.has_options = 1,
.need_uv_device = 1,
},
{
.command = COMMAND_PVSECRETS_IMPORT,
.abbrev_len = 2,
.function = command_pvsecrets_import,
.short_desc = "Imports a protected virtualization (PV) secret",
.long_desc = "Imports a protected virtualization (PV) secret "
"into the repository. This command is only "
"available when running in a secure execution "
"guest.",
.has_options = 1,
.need_keystore = 1,
.need_uv_device = 1,
},
{ .command = NULL }
};
@@ -3006,6 +3118,51 @@ static int command_pvsecrets_list(void)
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
* Command handler for 'pvsecrets import'.
*
* Import a protected virtualization secret into the repository
*/
static int command_pvsecrets_import(void)
{
int rc;
if (g.secret_id == NULL && g.secret_name == NULL) {
misc_print_required_parm("--pvsecret-id/-I or "
"--pvsecret-name/-e");
return EXIT_FAILURE;
}
if (g.secret_id != NULL && g.secret_name != NULL) {
warnx("Either '--pvsecret-id/-I' or '--pvsecret-name/-e' can "
"be specified, but not both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.secret_name == NULL && g.name == NULL) {
misc_print_required_parm("--name/-N");
return EXIT_FAILURE;
}
if (g.sector_size < 0)
g.sector_size = 0;
if (g.gen_passphrase && g.passphrase_file != NULL) {
warnx("Either '--gen-dummy-passphrase' or "
"'--set-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = pvsecrets_import(g.keystore, g.uv_fd, g.secret_id, g.secret_name,
g.name != NULL ? g.name : g.secret_name,
g.description, g.volumes, g.volume_type,
g.sector_size, g.gen_passphrase,
g.passphrase_file, g.verbose);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/**
* Opens the keystore. The keystore directory is either the
* default directory or as specified in an environment variable