zkey: Add 'zkey kms import' command to import keys from a KMS

Allow to import keys that exist in a key management system into the
repository. The key together with its properties is imported.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2020-06-19 10:24:12 +02:00
committed by Jan Höppner
parent bcce1e8d18
commit cd8a733c82
6 changed files with 682 additions and 11 deletions

View File

@@ -1200,6 +1200,7 @@ struct volume_check {
const char *name;
const char *volume;
bool set;
bool nocheck;
};
/**
@@ -1289,7 +1290,7 @@ static int _keystore_volume_check(const char *volume, bool remove, bool set,
goto out;
}
if (remove) {
if (remove || info->nocheck) {
rc = 0;
goto out;
}
@@ -1602,6 +1603,8 @@ static int _keystore_set_default_properties(struct properties *key_props)
* key (optional, can be NULL)
* @param[in] noapqncheck if true, the specified APQN(s) are not checked for
* existence and type.
* @param[i] novolscheck if true, the specified Volume(s) are not checked for
* existence or duplicate use
* @param[in] sector_size the sector size to use with dm-crypt. It must be power
* of two and in range 512 - 4096 bytes. 0 means that
* the sector size is not specified and the system
@@ -1615,7 +1618,7 @@ static int _keystore_create_info_props(struct keystore *keystore,
const char *name,
const char *description,
const char *volumes, const char *apqns,
bool noapqncheck,
bool noapqncheck, bool novolcheck,
size_t sector_size,
const char *volume_type,
const char *key_type,
@@ -1623,7 +1626,7 @@ static int _keystore_create_info_props(struct keystore *keystore,
struct properties **props)
{
struct volume_check vol_check = { .keystore = keystore, .name = name,
.set = 0 };
.set = 0, .nocheck = novolcheck };
struct apqn_check apqn_check = { .noonlinecheck = noapqncheck,
.nomsg = 0,
.cardtype = get_card_type_for_keytype(
@@ -1747,7 +1750,7 @@ static int _keystore_create_info_file(struct keystore *keystore,
int rc;
rc = _keystore_create_info_props(keystore, name, description, volumes,
apqns, noapqncheck, sector_size,
apqns, noapqncheck, false, sector_size,
volume_type, key_type, kms,
&key_props);
if (rc != 0)
@@ -1989,9 +1992,9 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
pr_verbose(keystore, "APQNs for keytype %s: '%s'", key_type, apqns);
rc = _keystore_create_info_props(keystore, name, description, volumes,
apqns, false, sector_size, volume_type,
key_type, kms_info->plugin_name,
&key_props);
apqns, false, false, sector_size,
volume_type, key_type,
kms_info->plugin_name, &key_props);
if (rc != 0)
goto out_free_key_filenames;
@@ -2261,7 +2264,7 @@ int keystore_change_key(struct keystore *keystore, const char *name,
long int sector_size, const char *volume_type)
{
struct volume_check vol_check = { .keystore = keystore, .name = name,
.set = 0 };
.set = 0, .nocheck = 0 };
struct apqn_check apqn_check = { .noonlinecheck = noapqncheck,
.nomsg = 0 };
struct key_filenames file_names = { NULL, NULL, NULL };
@@ -3427,8 +3430,8 @@ int keystore_reencipher_key(struct keystore *keystore, const char *name_filter,
int keystore_copy_key(struct keystore *keystore, const char *name,
const char *newname, const char *volumes, bool local)
{
struct volume_check vol_check = { .keystore = keystore,
.name = newname, .set = 0 };
struct volume_check vol_check = { .keystore = keystore, .name = newname,
.set = 0, .nocheck = 0 };
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames new_names = { NULL, NULL, NULL };
struct properties *key_prop = NULL;
@@ -4887,6 +4890,341 @@ int keystore_msg_for_kms_key(struct keystore *keystore, const char *key_type,
return msg_for_key.num_keys == 0 ? -ENOENT : 0;
}
struct kms_import {
struct keystore *keystore;
bool batch_mode;
bool novolcheck;
unsigned long num_imported;
unsigned long num_skipped;
unsigned long num_failed;
};
/**
* Callback used with the keystore_import_kms_keys() function. Called for each
* key.
*
* @param[in] key1_id the key-ID of the key (1st key of an XTS key)
* @param[in] key1_label the label of the key (1st key of an XTS key)
* @param[in] key2_id the key-ID of the 2nd XTS key, NULL if not XTS
* @param[in] key2_label the label of the 2nd XTS key, NULL if not XTS
* @param[in] xts if true, this is an XTS key pair
* @param[in] name the zkey name of the key
* @param[in] key_type the type of the key (CCA-AESDATA, etc)
* @param[in] key_bits the key size in bits
* @param[in] description the description of the key (can be NULL)
* @param[in] cipher the cipher of the key (can be NULL)
* @param[in] iv_mode the IV-mode of the key (can be NULL)
* @param[in] volumes the associated volumes of the key (can be NULL)
* @param[in] volume_type the volume type of the volume (can be NULL)
* @param[in] sector_size the sector size of the volume (0 means default)
* @param[in] addl_info_argz an argz string containing additional KMS plugin
* specific infos to be displayed, or NULL if none.
* @param[in] addl_info_len length of the argz string in addl_info_argz
* @param[in] private_data the private data pointer
*
* @returns 0 on success, or a negative errno in case of an error.
*/
static int _keystore_process_kms_import(const char *key1_id,
const char *key1_label,
const char *key2_id,
const char *key2_label,
bool xts, const char *name,
const char *UNUSED(key_type),
size_t UNUSED(key_bits),
const char *description,
const char *UNUSED(cipher),
const char *UNUSED(iv_mode),
const char *volumes,
const char *volume_type,
size_t sector_size,
const char *UNUSED(addl_info_argz),
size_t UNUSED(addl_info_len),
void *private_data)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct kms_import *import_data = private_data;
u8 secure_key[2 * MAX_SECURE_KEY_SIZE];
struct properties *key_props = NULL;
char vp[VERIFICATION_PATTERN_LEN];
const char *key_name = name;
struct keystore *keystore;
size_t alt_name_len = 0;
size_t secure_key_size;
bool fatal_err = false;
char *alt_name = NULL;
const char *key_type;
char *apqns = NULL;
int rc;
keystore = import_data->keystore;
rc = _keystore_get_key_filenames(keystore, key_name, &file_names);
if (rc != 0)
goto out;
check_duplicate_key:
rc = _keystore_ensure_keyfiles_not_exist(&file_names, key_name);
if (rc == -EEXIST) {
if (import_data->batch_mode) {
rc = 1;
goto out;
}
printf("%s: Do you want to enter an alternate name [y/N]? ",
program_invocation_short_name);
if (!prompt_for_yes(keystore->verbose)) {
rc = 1;
goto out;
}
prompt_alt_name:
printf("%s: Alternate name: ", program_invocation_short_name);
rc = getline(&alt_name, &alt_name_len, stdin);
if (rc <= 1) {
rc = 1;
goto out;
}
if (alt_name[strlen(alt_name) - 1] == '\n')
alt_name[strlen(alt_name) - 1] = '\0';
key_name = alt_name;
_keystore_free_key_filenames(&file_names);
rc = _keystore_get_key_filenames(keystore, key_name,
&file_names);
if (rc != 0)
goto prompt_alt_name;
goto check_duplicate_key;
} else if (rc != 0) {
goto out;
}
secure_key_size = sizeof(secure_key);
rc = import_kms_key(keystore->kms_info, key1_id, key2_id, xts, key_name,
secure_key, &secure_key_size, keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to import key '%s': %s",
keystore->kms_info->plugin_name, key_name, strerror(-rc));
print_last_kms_error(keystore->kms_info);
if (rc == -ENOTSUP)
fatal_err = true;
goto out;
}
key_type = get_key_type(secure_key, secure_key_size);
if (key_type == NULL) {
warnx("Key '%s' is not a valid secure key", key_name);
free(secure_key);
rc = -EINVAL;
goto out;
}
rc = get_kms_apqns_for_key_type(keystore->kms_info, key_type, true,
&apqns, keystore->verbose);
if (rc != 0) {
if (rc == -ENOTSUP)
warnx("Key-type not supported by the KMS plugin '%s'",
keystore->kms_info->plugin_name);
goto out;
}
pr_verbose(keystore, "APQNs for keytype %s: '%s'", key_type, apqns);
rc = _keystore_create_info_props(keystore, key_name, description,
volumes, apqns, false,
import_data->novolcheck,
sector_size, volume_type, key_type,
keystore->kms_info->plugin_name,
&key_props);
if (rc != 0)
goto out;
rc = properties_set(key_props, xts ? PROP_NAME_KMS_XTS_KEY1_ID :
PROP_NAME_KMS_KEY_ID, key1_id);
if (rc != 0) {
pr_verbose(keystore, "Failed to set key id of key #1: %s",
strerror(-rc));
goto out;
}
rc = properties_set(key_props, xts ? PROP_NAME_KMS_XTS_KEY1_LABEL :
PROP_NAME_KMS_KEY_LABEL, key1_label);
if (rc != 0) {
pr_verbose(keystore, "Failed to set key label of key #1: %s",
strerror(-rc));
goto out;
}
if (xts) {
rc = properties_set(key_props, PROP_NAME_KMS_XTS_KEY2_ID,
key2_id);
if (rc != 0) {
pr_verbose(keystore, "Failed to set key id of key #2: "
"%s", strerror(-rc));
goto out;
}
rc = properties_set(key_props, PROP_NAME_KMS_XTS_KEY2_LABEL,
key2_label);
if (rc != 0) {
pr_verbose(keystore, "Failed to set key label of key "
"#2: %s", strerror(-rc));
goto out;
}
}
rc = write_secure_key(file_names.skey_filename, secure_key,
secure_key_size, keystore->verbose);
if (rc != 0)
goto out;
rc = _keystore_set_file_permission(keystore, file_names.skey_filename);
if (rc != 0)
goto out_remove;
rc = generate_key_verification_pattern(secure_key, secure_key_size,
vp, sizeof(vp),
keystore->verbose);
if (rc != 0) {
warnx("Failed to generate the key verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
fatal_err = true;
goto out_remove;
}
rc = properties_set(key_props, PROP_NAME_KEY_VP, vp);
if (rc != 0) {
pr_verbose(keystore, "Failed to set verification pattern of "
"key: %s", strerror(-rc));
goto out_remove;
}
rc = properties_save(key_props, file_names.info_filename, 1);
if (rc != 0) {
pr_verbose(keystore,
"Key info file '%s' could not be written: %s",
file_names.info_filename, strerror(-rc));
goto out;
}
rc = _keystore_set_file_permission(keystore, file_names.info_filename);
if (rc != 0) {
remove(file_names.info_filename);
goto out_remove;
}
out_remove:
if (rc != 0) {
remove(file_names.skey_filename);
remove(file_names.info_filename);
}
out:
if (rc == 0) {
printf("Successfully imported key '%s'\n", key_name);
import_data->num_imported++;
} else if (rc < 0) {
warnx("Failed to import key '%s': %s", key_name, strerror(-rc));
import_data->num_failed++;
} else {
warnx("Skipping key '%s'", key_name);
import_data->num_skipped++;
}
_keystore_free_key_filenames(&file_names);
if (alt_name != NULL)
free(alt_name);
if (apqns != NULL)
free(apqns);
if (key_props != NULL)
properties_free(key_props);
return fatal_err ? rc : 0;
}
/**
* Imports secure keys from the KMS and adds it to the key store
*
* @param[in] keystore the key store
* @param[in] label_filter the KMS label filter. Can contain wild cards.
* NULL means no name filter.
* @param[in] name_filter the name filter. Can contain wild cards.
* NULL means no name filter.
* @param[in] volume_filter the volume filter. Can contain wild cards, and
* mutliple volume filters separated by commas.
* If the filter does not contain the ':dm-name'
* part, then the volumes are matched without the
* dm-name part. If the filter contains the
* ':dm-name' part, then the filter is matched
* including the dm-name part.
* NULL means no volume filter.
* @param[in] volume_type If not NULL, specifies the volume type.
* @param[in] kms_options an array of KMS options specified, or NULL if no
* KMS options have been specified
* @param[in] num_kms_options the number of options in above array
* @param[in] batch_mode if true, suppress alternate name prompts if a key
* with an already existing name is to be imported.
* @param[in] novolcheck if true, do not check the associated volumes for
* existence and duplicate use
*
* @returns 0 for success or a negative errno in case of an error
*/
int keystore_import_kms_keys(struct keystore *keystore,
const char *label_filter,
const char *name_filter,
const char *volume_filter,
const char *volume_type,
struct kms_option *kms_options,
size_t num_kms_options,
bool batch_mode, bool novolcheck)
{
struct kms_import import_data = { 0 };
int rc;
util_assert(keystore != NULL, "Internal error: keystore is NULL");
if (keystore->kms_info->plugin_lib == NULL) {
warnx("The repository is not bound to a KMS plugin");
return -ENOENT;
}
if (volume_type != NULL &&
!_keystore_valid_volume_type(volume_type)) {
warnx("Invalid volume-type specified");
return -EINVAL;
}
import_data.keystore = keystore;
import_data.batch_mode = batch_mode;
import_data.novolcheck = novolcheck;
import_data.num_imported = 0;
import_data.num_skipped = 0;
import_data.num_failed = 0;
rc = process_kms_keys(keystore->kms_info, label_filter, name_filter,
volume_filter, volume_type,
kms_options, num_kms_options,
_keystore_process_kms_import, &import_data,
keystore->verbose);
if (rc != 0) {
pr_verbose(keystore, "Failed to import kms keys: %s",
strerror(-rc));
} else {
printf("%lu keys imported, %lu keys skipped, %lu keys "
"failed to import\n",
import_data.num_imported, import_data.num_skipped,
import_data.num_failed);
if (import_data.num_failed > 0)
rc = -EIO;
}
return rc;
}
/**
* Frees a keystore object
*

View File

@@ -126,6 +126,15 @@ int keystore_kms_keys_unbind(struct keystore *keystore);
int keystore_msg_for_kms_key(struct keystore *keystore, const char *key_type,
const char *msg);
int keystore_import_kms_keys(struct keystore *keystore,
const char *label_filter,
const char *name_filter,
const char *volume_filter,
const char *volume_type,
struct kms_option *kms_options,
size_t num_kms_options,
bool batch_mode, bool novolcheck);
void keystore_free(struct keystore *keystore);

View File

@@ -2987,3 +2987,129 @@ int list_kms_keys(struct kms_info *kms_info, const char *label_filter,
return rc;
}
/**
* Imports a KMS managed key.
*
* @param[in] kms_info information of the currently bound plugin.
* @param[in] key1_id the id of the key to import (1st key for XTS)
* @param[in] key2_id the id of the 2nd XTS key to import (NULL if not
* XTS)
* @param[in] xts if true, an XTS key is to be imported
* @param[in] name the zkey-name under which the key is imported
* @param[in] key_blob a buffer to return the key blob. The size of the
* buffer is specified in key_blob_length
* @param[out] key_blob_length on entry: the size of the key_blob buffer.
* on exit: the size of the key blob returned.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error.
*/
int import_kms_key(struct kms_info *kms_info, const char *key1_id,
const char *key2_id, bool xts, const char *name,
unsigned char *key_blob, size_t *key_blob_length,
bool verbose)
{
size_t key_blob_size, key_blob_ofs, key_size = 0;
struct kms_property kms_prop;
char *sys_name = NULL;
int rc = 0;
util_assert(kms_info != NULL, "Internal error: kms_info is NULL");
util_assert(key1_id != NULL, "Internal error: key1_id is NULL");
util_assert(xts == false || key2_id != NULL,
"Internal error: key2_id is NULL");
util_assert(key_blob != NULL, "Internal error: key_blob is NULL");
util_assert(key_blob_length != NULL,
"Internal error: key_blob_length is NULL");
if (kms_info->plugin_lib == NULL) {
warnx("The repository is not bound to a KMS plugin");
return -ENOENT;
}
if (kms_info->funcs->kms_import_key == NULL ||
kms_info->funcs->kms_set_key_properties == NULL) {
pr_verbose(verbose, "The KMS plugin does not support to "
"import keys");
return -ENOTSUP;
}
sys_name = _get_system_specific_prop_name(KMS_KEY_PROP_NAME);
if (sys_name == NULL)
return -ENOMEM;
key_blob_size = *key_blob_length;
memset(key_blob, 0, key_blob_size);
rc = kms_info->funcs->kms_import_key(kms_info->handle, key1_id,
key_blob, &key_blob_size);
if (rc != 0) {
pr_verbose(verbose, "KMS plugin failed to import key '%s': %s",
key1_id, strerror(-rc));
goto out;
}
if (is_cca_aes_data_key(key_blob, key_blob_size))
key_size = AESDATA_KEY_SIZE;
else if (is_cca_aes_cipher_key(key_blob, key_blob_size))
key_size = AESCIPHER_KEY_SIZE;
else if (is_ep11_aes_key(key_blob, key_blob_size))
key_size = EP11_KEY_SIZE;
if (key_size == 0 || key_blob_size > key_size) {
pr_verbose(verbose, "Key '%s' has an unknown or unsupported "
"key type", key1_id);
rc = -EIO;
goto out;
}
key_blob_ofs = key_size;
if (xts) {
key_blob_size = key_size;
rc = kms_info->funcs->kms_import_key(kms_info->handle, key2_id,
key_blob + key_blob_ofs,
&key_blob_size);
if (rc != 0) {
pr_verbose(verbose, "KMS plugin failed to import key #2"
"'%s': %s", key2_id, strerror(-rc));
goto out;
}
key_blob_ofs += key_size;
}
*key_blob_length = key_blob_ofs;
kms_prop.name = sys_name;
kms_prop.value = name;
rc = kms_info->funcs->kms_set_key_properties(kms_info->handle, key1_id,
&kms_prop, 1);
if (rc != 0) {
pr_verbose(verbose, "KMS plugin failed to set properties of "
"key '%s': %s", key1_id, strerror(-rc));
goto out;
}
if (xts) {
rc = kms_info->funcs->kms_set_key_properties(kms_info->handle,
key2_id,
&kms_prop, 1);
if (rc != 0) {
pr_verbose(verbose, "KMS plugin failed to set "
"properties of key #2 '%s': %s", key1_id,
strerror(-rc));
goto out;
}
}
out:
if (sys_name != NULL)
free(sys_name);
if (rc != 0)
*key_blob_length = 0;
return rc;
}

View File

@@ -110,4 +110,9 @@ int list_kms_keys(struct kms_info *kms_info, const char *label_filter,
const char *volume_type, struct kms_option *kms_options,
size_t num_kms_options, bool verbose);
int import_kms_key(struct kms_info *kms_info, const char *key1_id,
const char *key2_id, bool xts, const char *name,
unsigned char *key_blob, size_t *key_blob_length,
bool verbose);
#endif

View File

@@ -1065,6 +1065,50 @@ command displays the attributes of the secure keys, such as key label, key name,
whether it is a secure key that can be used for the XTS cipher mode, the textual
description, associated volumes, the volume type, and sector size.
.
.SS "Import secure keys managed by a key management system into the repository"
.
.B zkey kms
.BR import | im
.RB [ \-\-label | \-B
.IR key-label ]
.RB [ \-\-name | \-N
.IR key-name ]
.RB [ \-\-volumes | \-l
.IR volume1[:dmname1][,volume2[:dmname2][,...]] ]
.RB [ \-\-volume-type | \-t
.IR type ]
.RB [ \-\-batch\-mode | \-q ]
.RB [ \-\-no\-volume\-check ]
.RB [ KMS\-plugin\ specific\ options ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B kms import
command to import secure keys managed by a key management system (KMS) into the
secure key repository.
You can filter the list of keys to be imported by key label, key name,
associated volumes, and volume type. You can use wildcards for the key label,
key name, and associated volumes. The device-mapper name of an associated
volume can be omitted. If it is specified, then only those keys are listed that
are associated with the specified volume and device-mapper name.
.PP
A key management system plugin may offer plugin specific options that can be
specified with the \fBkms import\fP command. Use \fBkms import \-\-help\fP
to display the plugin specific options and their meaning.
.PP
If a secure key with the same name as a key to be imported already exists in
the repository, then you are prompted to enter an alternate name. You can skip
the import of that key, or enter an alternate name. If option
\fB\-\-batch\-mode\fP is specified, then already existing keys are skipped.
.PP
If a key to be imported is associated with one or multiple volumes, it is
verified that the volumes are available, and are not already associated with
another secure key in the repository. If one of the volumes or all of them are
not available, or are already associated with another secure key, the import
fails. Use option \fB\-\-no\-volume\-check\fP to omit the volume check, and
import the keys even if the associated volume(s) do not exist.
.
.
.
.SH OPTIONS
@@ -1756,7 +1800,52 @@ has been compiled with LUKS2 support enabled.
.
.
.
.SS "Options for the kms import command"
.TP
.BR \-B ", " \-\-label\~\fIkey-label\fP
Specifies the label of the secure key in the key management system (KMS).
You can use wildcards to select multiple secure keys.
When wildcards are used you must quote the value.
Only keys with labels that match the pattern are imported.
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the key management system (KMS).
You can use wildcards to select multiple secure keys.
When wildcards are used you must quote the value.
Only keys with names that match the pattern are imported.
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with the secure AES key in the key management system (KMS). Only
those keys are imported, which are associated with the specified volumes.
The volume association also contains the device-mapper name, separated by a
colon, used with dm-crypt. You can omit the device-mapper name; if it is
specified then only those keys are listed 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.
.TP
.BR \-t ", " \-\-volume-type\~\fItype\fP
Specifies the volume type of the associated volumes used with dm-crypt. Possible
values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume
type are imported.
This option is only available if
.B zkey
has been compiled with LUKS2 support enabled.
.TP
.BR \-q ", " \-\-batch\-mode
Suppress prompts to skip or to enter an anternate name, if a secure key with the
same name as the secure key to be imported already exists in the repository.
When this option is specified, then keys with an altready existing name are
skipped.
.TP
.BR \-\-no\-volume\-check
Do not check if the volume(s) associated with the to be imported secure key(s)
are available, or are already associated with other secure keys in the
repository.
.
.
.
.SS "General options"
.TP
.BR \-V ", " \-\-verbose

View File

@@ -72,6 +72,7 @@ static struct zkey_globals {
char *volumes;
char *apqns;
bool noapqncheck;
bool novolcheck;
long int sector_size;
char *volume_type;
char *newname;
@@ -128,6 +129,7 @@ static struct zkey_globals {
#define COMMAND_KMS_CONFIGURE "configure"
#define COMMAND_KMS_REENCIPHER "reencipher"
#define COMMAND_KMS_LIST "list"
#define COMMAND_KMS_IMPORT "import"
#define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER"
@@ -150,6 +152,7 @@ static struct zkey_globals {
#define OPT_CRYPTSETUP_OPEN 260
#define OPT_CRYPTSETUP_FORMAT 261
#define OPT_NO_APQN_CHECK 262
#define OPT_NO_VOLUME_CHECK 263
/*
* Configuration of command line options
@@ -961,6 +964,66 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_KMS " " COMMAND_KMS_LIST,
},
#endif
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
.desc = "OPTIONS",
.command = COMMAND_KMS " " COMMAND_KMS_IMPORT,
},
{
.option = { "label", required_argument, NULL, 'B'},
.argument = "LABEL",
.desc = "Label of the secure AES keys as known by the KMS that "
"are to be imported. You can use wildcards to select "
"the keys to be imported.",
.command = COMMAND_KMS " " COMMAND_KMS_IMPORT,
},
{
.option = { "name", required_argument, NULL, 'N'},
.argument = "NAME",
.desc = "Name of the secure AES keys as known by zkey that "
"are to be imported. You can use wildcards to select "
"the keys to be imported.",
.command = COMMAND_KMS " " COMMAND_KMS_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 secure AES key in "
"the KMS. Use this option to import all keys "
"associated with specific volumes. The device-mapper "
"name (DMNAME) is optional. If specified, only those "
"keys are listed where both, the volume and the device-"
"mapper name matches.",
.command = COMMAND_KMS " " COMMAND_KMS_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'. Use this option to import "
"all keys with the specified volumes type.",
.command = COMMAND_KMS " " COMMAND_KMS_IMPORT,
},
#endif
{
.option = {"batch-mode", 0, NULL, 'q'},
.desc = "Suppresses alternate name questions. When importing a "
"key with a name that already exists in the "
"repository, do not prompt for an alternate name, but "
"skip the import of the duplicate key.",
.command = COMMAND_KMS " " COMMAND_KMS_IMPORT,
},
{
.option = {"no-volume-check", 0, NULL, OPT_NO_VOLUME_CHECK},
.desc = "Do not check if the volume(s) associated with the "
"secure key(s) to be imported are available, or are "
"already associated with other secure keys.",
.command = COMMAND_KMS " " COMMAND_KMS_IMPORT,
.flags = UTIL_OPT_FLAG_NOSHORT,
},
/***********************************************************/
OPT_PLACEHOLDER,
OPT_PLACEHOLDER,
@@ -1063,6 +1126,7 @@ static int command_kms_info(void);
static int command_kms_configure(void);
static int command_kms_reencipher(void);
static int command_kms_list(void);
static int command_kms_import(void);
static struct zkey_command zkey_kms_commands[] = {
{
@@ -1150,6 +1214,20 @@ static struct zkey_command zkey_kms_commands[] = {
.need_kms_login = 1,
.kms_plugin_opts_cmd = KMS_COMMAND_LIST,
},
{
.command = COMMAND_KMS_IMPORT,
.abbrev_len = 2,
.function = command_kms_import,
.short_desc = "Imports secure keys managed by a key management "
"system",
.long_desc = "Imports secure keys managed by a key management "
"system (KMS) into the repository",
.need_keystore = 1,
.has_options = 1,
.use_kms_plugin = 1,
.need_kms_login = 1,
.kms_plugin_opts_cmd = KMS_COMMAND_LIST_IMPORT,
},
{ .command = NULL }
};
@@ -2531,6 +2609,29 @@ static int command_kms_list(void)
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
* Command handler for 'kms import'.
*
* Imports secure keys managed by a KMS
*/
static int command_kms_import(void)
{
int rc;
if (g.kms_info.plugin_lib == NULL) {
rc = -ENOENT;
warnx("The repository is not bound to a KMS plugin");
return EXIT_FAILURE;
}
rc = keystore_import_kms_keys(g.keystore, g.label, g.name, g.volumes,
g.volume_type, g.kms_options,
g.num_kms_options, g.batch_mode,
g.novolcheck);
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
@@ -2761,6 +2862,9 @@ int main(int argc, char *argv[])
case OPT_NO_APQN_CHECK:
g.noapqncheck = 1;
break;
case OPT_NO_VOLUME_CHECK:
g.novolcheck = 1;
break;
case 'S':
g.sector_size = strtol(optarg, &endp, 0);
if (*optarg == '\0' || *endp != '\0' ||