mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
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:
committed by
Steffen Eiden
parent
fdf66dc148
commit
95bf7eb285
112
zkey/keystore.c
112
zkey/keystore.c
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
126
zkey/pvsecrets.c
126
zkey/pvsecrets.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
134
zkey/zkey.1
134
zkey/zkey.1
@@ -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
|
||||
|
||||
157
zkey/zkey.c
157
zkey/zkey.c
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user