mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Normally, secure keys generated by zkey are intentionally export restricted. Export restricted keys can not be wrapped with a key encrypting key (KEK). However, keys that are generated inside a Secure Execution for Linux guest that shall also be used outside of the Secure Execution for Linux guest can only be transported to outside the Secure Execution for Linux guest by wrapping them with a KEK and unwrapping them outside of the Secure Execution for Linux guest. For that such keys must be exportable. Add an option to generate and import exportable secure keys, which then can be wrapped, and thus transported to outside of a Secure Execution for Linux guest. This applies to keys of type 'CCA-AESCIPHER' and 'EP11-AES'. Keys of type 'CCA-AESDATA' are always exportable, and can not be export restricted. For keys of type 'EP11-AES' additionally allow to set the 'wrap-with-trusted' attribute. This restricts the key so that it only can be wrapped with a trusted key encrypting key. For keys of type 'EP11-AES' to be exportable, the access control point (ACP) XCP_CPB_ALLOW_COMBINED_EXTRACT must be 'ON' on all APQNs used. This access control point is only supported on newer EP11 firmware levels. If the access control point is 'OFF' or not supported by the EP11 firmware, then the IOCTL to generate the key fails with a generic error (Input/output error - EIO). The zkey tool prints an appropriate error message in that case. Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com> Reviewed-by: Finn Callies <fcallies@linux.ibm.com> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
3736 lines
104 KiB
C
3736 lines
104 KiB
C
/*
|
|
* zkey - Generate, re-encipher, and validate secure keys
|
|
*
|
|
* Copyright IBM Corp. 2017, 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.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <dlfcn.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/util_base.h"
|
|
#include "lib/util_libc.h"
|
|
#include "lib/util_opt.h"
|
|
#include "lib/util_panic.h"
|
|
#include "lib/util_prg.h"
|
|
#include "lib/zt_common.h"
|
|
|
|
#include "cca.h"
|
|
#include "ep11.h"
|
|
#include "keystore.h"
|
|
#include "misc.h"
|
|
#include "pkey.h"
|
|
#include "utils.h"
|
|
#include "kms.h"
|
|
#include "pvsecrets.h"
|
|
|
|
/*
|
|
* Program configuration
|
|
*/
|
|
static const struct util_prg prg = {
|
|
.desc = "Manage secure AES keys",
|
|
.command_args = "COMMAND [SECURE-KEY-FILE]",
|
|
.args = "",
|
|
.copyright_vec = {
|
|
{
|
|
.owner = "IBM Corp.",
|
|
.pub_first = 2017,
|
|
.pub_last = 2024,
|
|
},
|
|
UTIL_PRG_COPYRIGHT_END
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Global variables for program options
|
|
*/
|
|
static struct zkey_globals {
|
|
char *pos_arg;
|
|
char *clearkeyfile;
|
|
char *outputfile;
|
|
bool xts;
|
|
bool verbose;
|
|
long int keybits;
|
|
bool tonew;
|
|
bool fromold;
|
|
bool complete;
|
|
bool inplace;
|
|
bool staged;
|
|
char *name;
|
|
char *description;
|
|
char *volumes;
|
|
char *apqns;
|
|
bool noapqncheck;
|
|
bool novolcheck;
|
|
long int sector_size;
|
|
char *volume_type;
|
|
char *newname;
|
|
char *key_type;
|
|
char *label;
|
|
bool local;
|
|
bool gen_passphrase;
|
|
char *passphrase_file;
|
|
bool remove_passphrase;
|
|
bool exportable;
|
|
bool wrap_with_trusted;
|
|
bool kms_bound;
|
|
bool run;
|
|
bool batch_mode;
|
|
char *keyfile;
|
|
long long keyfile_offset;
|
|
long long keyfile_size;
|
|
long long tries;
|
|
bool force;
|
|
bool open;
|
|
bool format;
|
|
bool refresh_properties;
|
|
bool all;
|
|
bool hex;
|
|
char *secret_type;
|
|
char *secret_id;
|
|
char *secret_name;
|
|
struct ext_lib lib;
|
|
struct cca_lib cca;
|
|
struct ep11_lib ep11;
|
|
int pkey_fd;
|
|
int uv_fd;
|
|
struct keystore *keystore;
|
|
struct kms_info kms_info;
|
|
int first_kms_option;
|
|
struct kms_option *kms_options;
|
|
size_t num_kms_options;
|
|
} g = {
|
|
.pkey_fd = -1,
|
|
.uv_fd = -1,
|
|
.sector_size = -1,
|
|
.lib.cca = &g.cca,
|
|
.lib.ep11 = &g.ep11,
|
|
};
|
|
|
|
/*
|
|
* Available commands
|
|
*/
|
|
#define COMMAND_GENERATE "generate"
|
|
#define COMMAND_REENCIPHER "reencipher"
|
|
#define COMMAND_VALIDATE "validate"
|
|
#define COMMAND_IMPORT "import"
|
|
#define COMMAND_EXPORT "export"
|
|
#define COMMAND_LIST "list "
|
|
#define COMMAND_REMOVE "remove"
|
|
#define COMMAND_CHANGE "change"
|
|
#define COMMAND_RENAME "rename"
|
|
#define COMMAND_COPY "copy "
|
|
#define COMMAND_CRYPTTAB "crypttab"
|
|
#define COMMAND_CRYPTSETUP "cryptsetup"
|
|
#define COMMAND_CONVERT "convert"
|
|
#define COMMAND_KMS "kms"
|
|
#define COMMAND_KMS_PLUGINS "plugins"
|
|
#define COMMAND_KMS_BIND "bind"
|
|
#define COMMAND_KMS_UNBIND "unbind"
|
|
#define COMMAND_KMS_INFO "info"
|
|
#define COMMAND_KMS_CONFIGURE "configure"
|
|
#define COMMAND_KMS_REENCIPHER "reencipher"
|
|
#define COMMAND_KMS_LIST "list"
|
|
#define COMMAND_KMS_IMPORT "import"
|
|
#define COMMAND_KMS_REFRESH "refresh"
|
|
#define COMMAND_PVSECRETS "pvsecrets"
|
|
#define COMMAND_PVSECRETS_LIST "list"
|
|
#define COMMAND_PVSECRETS_IMPORT "import"
|
|
|
|
#define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER"
|
|
|
|
#define OPT_PLACEHOLDER \
|
|
{ \
|
|
.option = { "", 0, NULL, ' ' }, \
|
|
.desc = OPT_COMMAND_PLACEHOLDER, \
|
|
.command = OPT_COMMAND_PLACEHOLDER, \
|
|
}
|
|
|
|
#define ZKEY_COMMAND_MAX_LEN 10
|
|
|
|
#define ENVVAR_ZKEY_REPOSITORY "ZKEY_REPOSITORY"
|
|
#define DEFAULT_KEYSTORE "/etc/zkey/repository"
|
|
|
|
#define OPT_CRYPTSETUP_KEYFILE 256
|
|
#define OPT_CRYPTSETUP_KEYFILE_OFFSET 257
|
|
#define OPT_CRYPTSETUP_KEYFILE_SIZE 258
|
|
#define OPT_CRYPTSETUP_TRIES 259
|
|
#define OPT_CRYPTSETUP_OPEN 260
|
|
#define OPT_CRYPTSETUP_FORMAT 261
|
|
#define OPT_NO_APQN_CHECK 262
|
|
#define OPT_NO_VOLUME_CHECK 263
|
|
#define OPT_REFRESH_PROPERTIES 264
|
|
#define OPT_GEN_DUMMY_PASSPHRASE 265
|
|
#define OPT_SET_DUMMY_PASSPHRASE 266
|
|
#define OPT_REMOVE_DUMMY_PASSPHRASE 267
|
|
#define OPT_EXPORTABLE 268
|
|
#define OPT_WRAP_WITH_TRUSTED 269
|
|
|
|
/*
|
|
* Configuration of command line options
|
|
*/
|
|
static struct util_opt opt_vec[] = {
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = {"xts", 0, NULL, 'x'},
|
|
.desc = "Generate a secure AES key for the XTS cipher mode",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = { "keybits", required_argument, NULL, 'k'},
|
|
.argument = "SIZE",
|
|
.desc = "Size of the AES key to be generated in bits. "
|
|
"Valid sizes are 128, 192, and 256 bits. Secure keys "
|
|
"for use with the XTS cipher mode can only use keys "
|
|
" of 128 or 256 bits. Default is 256 bits",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = { "clearkey", required_argument, NULL, 'c'},
|
|
.argument = "CLEAR-KEY-FILE",
|
|
.desc = "Name of a file containing the clear AES key in "
|
|
"binary. If option --keybits/-k is omitted, then the "
|
|
"size of the CLEAR-KEY-FILE determines the size "
|
|
"of the AES key. If option --keybits/-k is specified, "
|
|
"then the size of the CLEAR-KEY-FILE must match the "
|
|
"specified key size. Valid file sizes are 16, 24, or "
|
|
"32 bytes, and 32, or 64 bytes for keys to be used "
|
|
"with XTS mode ciphers",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES key in the repository. If "
|
|
"option --name/-N is specified, then the generated "
|
|
"secure AES key is stored in the repository. Parameter "
|
|
"SECURE-KEY-FILE is not used when option --name/-N is "
|
|
"specified",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = { "description", required_argument, NULL, 'd'},
|
|
.argument = "DESCRIPTION",
|
|
.desc = "Textual description of the secure AES key in the "
|
|
"repository",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.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 repository",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = { "apqns", required_argument, NULL, 'a'},
|
|
.argument = "CARD.DOMAIN[,...]",
|
|
.desc = "Comma-separated pairs of crypto cards and domains "
|
|
"that are associated with the secure AES key in the "
|
|
"repository",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
|
|
.desc = "Do not check if the specified APQN(s) are available. "
|
|
"Use this option to associate APQN(s) with a secure "
|
|
"AES key that are currently not available.",
|
|
.command = COMMAND_GENERATE,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = { "sector-size", required_argument, NULL, 'S'},
|
|
.argument = "bytes",
|
|
.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_GENERATE,
|
|
},
|
|
#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_GENERATE,
|
|
},
|
|
#endif
|
|
{
|
|
.option = { "key-type", required_argument, NULL, 'K'},
|
|
.argument = "type",
|
|
.desc = "The type of the key. Possible values are '"
|
|
KEY_TYPE_CCA_AESDATA"', '"KEY_TYPE_CCA_AESCIPHER"' "
|
|
"and '"KEY_TYPE_EP11_AES"'. When this option is "
|
|
"omitted, the default is '"KEY_TYPE_CCA_AESDATA"'",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = { "local", 0, NULL, 'L'},
|
|
.desc = "Generate the key locally. This is the default when no "
|
|
"KMS plugin is bound to the repository. If the "
|
|
"repository is bound to a KMS plugin, then keys are "
|
|
"generated by the KMS per default.",
|
|
.command = COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.option = { "gen-dummy-passphrase", 0, NULL,
|
|
OPT_GEN_DUMMY_PASSPHRASE},
|
|
.desc = "Generate a dummy passphrase and associate it with the "
|
|
"secure AES key used to encrypt LUKS2 volume(s). The "
|
|
"LUKS2 passphrase is of less or no relevance for the "
|
|
"security of the volume(s), when an secure AES key 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_GENERATE,
|
|
},
|
|
{
|
|
.option = { "set-dummy-passphrase", required_argument, NULL,
|
|
OPT_SET_DUMMY_PASSPHRASE},
|
|
.argument = "passphrase-file",
|
|
.desc = "Set a dummy passphrase to be associated with the "
|
|
"secure AES key used to encrypt LUKS2 volume(s). The "
|
|
"LUKS2 passphrase is of less or no relevance for the "
|
|
"security of the volume(s), when an secure AES key 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_GENERATE,
|
|
},
|
|
{
|
|
.option = {"exportable", 0, NULL, OPT_EXPORTABLE},
|
|
.desc = "Generate a secure AES key that is not export "
|
|
"restricted. Exportable keys can be exported by means "
|
|
"of wrapping them with a key encryption key (KEK). By "
|
|
"default keys of type " KEY_TYPE_CCA_AESCIPHER " and "
|
|
KEY_TYPE_EP11_AES " are export restricted, and thus can "
|
|
"not be wrapped by a KEK. Keys of type "
|
|
KEY_TYPE_CCA_AESDATA " are always exportable, and can "
|
|
"not be export restricted.",
|
|
.command = COMMAND_GENERATE,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"wrap-with-trusted", 0, NULL, OPT_WRAP_WITH_TRUSTED},
|
|
.desc = "Generate a secure AES key that can only be wrapped "
|
|
"with a trusted key encryption key (KEK). This option "
|
|
"is only valid for keys of type " KEY_TYPE_EP11_AES
|
|
" and only if option '--exportable' is also specified.",
|
|
.command = COMMAND_GENERATE,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = { "output", required_argument, NULL, 'f'},
|
|
.argument = "OUTPUT-FILE",
|
|
.desc = "Name of the output file to which the re-enciphered "
|
|
"secure key is written. If this option is omitted, "
|
|
"then the re-enciphered secure key will be replaced "
|
|
"in the SECURE-KEY-FILE",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"to-new", 0, NULL, 'n'},
|
|
.desc = "Re-enciphers a secure AES key that is currently "
|
|
"enciphered with the master key in the CURRENT "
|
|
"register with the master key in the NEW register",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"from-old", 0, NULL, 'o'},
|
|
.desc = "Re-enciphers a secure AES key that is currently "
|
|
"enciphered with the master key in the OLD register "
|
|
"with the master key in the CURRENT register",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"complete", 0, NULL, 'p'},
|
|
.desc = "Completes a staged re-enciphering. Use this option "
|
|
"after the new master key has been set (made "
|
|
"active)",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"in-place", 0, NULL, 'i'},
|
|
.desc = "Forces an in-place re-enchipering of a secure AES "
|
|
"key. Re-enciphering from OLD to CURRENT is performed "
|
|
"in-place per default",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"staged", 0, NULL, 's'},
|
|
.desc = "Forces that the re-enciphering of a secure AES key is "
|
|
"performed in staged mode. Re-enciphering from CURRENT "
|
|
"to NEW is performed in staged mode per default",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES keys in the repository that "
|
|
"are to be re-enciphered. You can use wild-cards to "
|
|
"select the keys to re-encipher.",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.option = { "apqns", required_argument, NULL, 'a'},
|
|
.argument = "CARD.DOMAIN[,...]",
|
|
.desc = "Comma-separated pairs of crypto cards and domains "
|
|
"that are associated with the secure AES key in the "
|
|
"repository. Use this option to re-encipher all keys "
|
|
"associated with specific crypto cards",
|
|
.command = COMMAND_REENCIPHER,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_VALIDATE,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES keys in the repository that "
|
|
"are to be validated. You can use wild-cards to select "
|
|
"the keys to validate.",
|
|
.command = COMMAND_VALIDATE,
|
|
},
|
|
{
|
|
.option = { "apqns", required_argument, NULL, 'a'},
|
|
.argument = "CARD.DOMAIN[,...]",
|
|
.desc = "Comma-separated pairs of crypto cards and domains "
|
|
"that are associated with the secure AES key in the "
|
|
"repository. Use this option to validate all keys "
|
|
"associated with specific crypto cards",
|
|
.command = COMMAND_VALIDATE,
|
|
},
|
|
{
|
|
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
|
|
.desc = "Do not check if the associated APQN(s) are available",
|
|
.command = COMMAND_VALIDATE,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_IMPORT,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the imported secure AES key in the repository",
|
|
.command = COMMAND_IMPORT,
|
|
},
|
|
{
|
|
.option = { "description", required_argument, NULL, 'd'},
|
|
.argument = "DESCRIPTION",
|
|
.desc = "Textual description of the secure AES key in the "
|
|
"repository",
|
|
.command = COMMAND_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 repository",
|
|
.command = COMMAND_IMPORT,
|
|
},
|
|
{
|
|
.option = { "apqns", required_argument, NULL, 'a'},
|
|
.argument = "CARD.DOMAIN[,...]",
|
|
.desc = "Comma-separated pairs of crypto cards and domains "
|
|
"that are associated with the secure AES key in the "
|
|
"repository",
|
|
.command = COMMAND_IMPORT,
|
|
},
|
|
{
|
|
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
|
|
.desc = "Do not check if the specified APQN(s) are available. "
|
|
"Use this option to associate APQN(s) with a secure "
|
|
"AES key that are currently not available.",
|
|
.command = COMMAND_IMPORT,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = { "sector-size", required_argument, NULL, 'S'},
|
|
.argument = "512|4096",
|
|
.desc = "The sector size used with dm-crypt. It must be power "
|
|
"of two and in range 512 - 4096 bytes. If this option "
|
|
"is omitted, the system default sector size (512) is "
|
|
"used",
|
|
.command = COMMAND_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_IMPORT,
|
|
},
|
|
#endif
|
|
{
|
|
.option = { "gen-dummy-passphrase", 0, NULL,
|
|
OPT_GEN_DUMMY_PASSPHRASE},
|
|
.desc = "Generate a dummy passphrase and associate it with the "
|
|
"secure AES key used to encrypt LUKS2 volume(s). The "
|
|
"LUKS2 passphrase is of less or no relevance for the "
|
|
"security of the volume(s), when an secure AES key 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_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 "
|
|
"secure AES key used to encrypt LUKS2 volume(s). The "
|
|
"LUKS2 passphrase is of less or no relevance for the "
|
|
"security of the volume(s), when an secure AES key 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_IMPORT,
|
|
},
|
|
{
|
|
.option = {"exportable", 0, NULL, OPT_EXPORTABLE},
|
|
.desc = "Allow to import a secure AES key that is not export "
|
|
"restricted. Exportable keys can be exported by means "
|
|
"of wrapping them with a key encryption key (KEK). By "
|
|
"default keys of type " KEY_TYPE_CCA_AESCIPHER " and "
|
|
KEY_TYPE_EP11_AES " are export restricted, and thus can "
|
|
"not be wrapped by a KEK. Keys of type "
|
|
KEY_TYPE_CCA_AESDATA " are always exportable, and can "
|
|
"not be export restricted.",
|
|
.command = COMMAND_IMPORT,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_EXPORT,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES key in the repository that is "
|
|
"to be exported",
|
|
.command = COMMAND_EXPORT,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_LIST,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES keys in the repository that "
|
|
"are to be listed. You can use wild-cards to select "
|
|
"the keys to list.",
|
|
.command = COMMAND_LIST,
|
|
},
|
|
{
|
|
.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 repository. Use this option to list 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_LIST,
|
|
},
|
|
{
|
|
.option = { "apqns", required_argument, NULL, 'a'},
|
|
.argument = "CARD.DOMAIN[,...]",
|
|
.desc = "Comma-separated pairs of crypto cards and domains "
|
|
"that are associated with the secure AES key in the "
|
|
"repository. Use this option to list all keys "
|
|
"associated with specific crypto cards",
|
|
.command = COMMAND_LIST,
|
|
},
|
|
#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 list all "
|
|
"keys with the specified volumes type.",
|
|
.command = COMMAND_LIST,
|
|
},
|
|
#endif
|
|
{
|
|
.option = { "key-type", required_argument, NULL, 'K'},
|
|
.argument = "type",
|
|
.desc = "The type of the key. Possible values are '"
|
|
KEY_TYPE_CCA_AESDATA "', '" KEY_TYPE_CCA_AESCIPHER
|
|
"', '" KEY_TYPE_EP11_AES "', and '"
|
|
KEY_TYPE_PVSECRET_AES "'. Use this option to list all "
|
|
"keys with the specified key type.",
|
|
.command = COMMAND_LIST,
|
|
},
|
|
{
|
|
.option = { "local", 0, NULL, 'L'},
|
|
.desc = "List local keys only. Local keys are not bound to a "
|
|
"KMS plugin.",
|
|
.command = COMMAND_LIST,
|
|
},
|
|
{
|
|
.option = { "kms-bound", 0, NULL, 'M'},
|
|
.desc = "List KMS-bound keys only. KMS-bound keys are bound to "
|
|
"a KMS plugin.",
|
|
.command = COMMAND_LIST,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_REMOVE,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES key in the repository that is "
|
|
"to be removed",
|
|
.command = COMMAND_REMOVE,
|
|
},
|
|
{
|
|
.option = {"force", 0, NULL, 'F'},
|
|
.desc = "Do not prompt for a confirmation when removing a key",
|
|
.command = COMMAND_REMOVE,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES key in the repository that is "
|
|
"to be changed",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
{
|
|
.option = { "description", required_argument, NULL, 'd'},
|
|
.argument = "DESCRIPTION",
|
|
.desc = "Textual description of the secure AES key in the "
|
|
"repository",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
{
|
|
.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 repository. To add pairs of volume and device-"
|
|
"mapper names to the key specify '+VOLUME:DMNAME[,...]'. "
|
|
"To remove pairs of volume and device-mapper names "
|
|
"from the key specify '-VOLUME:DMNAME[,...]'",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
{
|
|
.option = { "apqns", required_argument, NULL, 'a'},
|
|
.argument = "[+|-]CARD.DOMAIN[,...]",
|
|
.desc = "Comma-separated pairs of crypto cards and domains "
|
|
"that are associated with the secure AES key in the "
|
|
"repository. To add pairs of crypto cards and domains "
|
|
"to the key specify '+CARD.DOMAIN[,...]'. To remove "
|
|
"pairs of crypto cards and domains from the key "
|
|
"specify '-CARD.DOMAIN[,...]'",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
{
|
|
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
|
|
.desc = "Do not check if the specified APQN(s) are available. "
|
|
"Use this option to associate APQN(s) with a secure "
|
|
"AES key that are currently not available.",
|
|
.command = COMMAND_CHANGE,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = { "sector-size", required_argument, NULL, 'S'},
|
|
.argument = "0|512|4096",
|
|
.desc = "The sector size used with dm-crypt. It must be power "
|
|
"of two and in range 512 - 4096 bytes. Specify 0 to "
|
|
"use the system default sector size (512)",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
#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'",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
#endif
|
|
{
|
|
.option = { "gen-dummy-passphrase", 0, NULL,
|
|
OPT_GEN_DUMMY_PASSPHRASE},
|
|
.desc = "Generate a dummy passphrase and associate it with the "
|
|
"secure AES key used to encrypt LUKS2 volume(s). The "
|
|
"LUKS2 passphrase is of less or no relevance for the "
|
|
"security of the volume(s), when an secure AES key 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_CHANGE,
|
|
},
|
|
{
|
|
.option = { "set-dummy-passphrase", required_argument, NULL,
|
|
OPT_SET_DUMMY_PASSPHRASE},
|
|
.argument = "passphrase-file",
|
|
.desc = "Set a dummy passphrase to be associated with the "
|
|
"secure AES key used to encrypt LUKS2 volume(s). The "
|
|
"LUKS2 passphrase is of less or no relevance for the "
|
|
"security of the volume(s), when an secure AES key 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_CHANGE,
|
|
},
|
|
{
|
|
.option = { "remove-dummy-passphrase", 0, NULL,
|
|
OPT_REMOVE_DUMMY_PASSPHRASE},
|
|
.desc = "Remove an associated dummy passphrase used with LUKS2 "
|
|
"volume(s).",
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
{
|
|
.option = {"force", 0, NULL, 'F'},
|
|
.desc = "Do not prompt for a confirmation when removing an "
|
|
"associated dummy passphrase",
|
|
.command = COMMAND_CHANGE,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_RENAME,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES key in the repository that is "
|
|
"to be renamed",
|
|
.command = COMMAND_RENAME,
|
|
},
|
|
{
|
|
.option = { "new-name", required_argument, NULL, 'w'},
|
|
.argument = "NEW-NAME",
|
|
.desc = "New name of the secure AES key in the repository",
|
|
.command = COMMAND_RENAME,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_COPY,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES key in the repository that is "
|
|
"to be copied",
|
|
.command = COMMAND_COPY,
|
|
},
|
|
{
|
|
.option = { "new-name", required_argument, NULL, 'w'},
|
|
.argument = "NEW-NAME",
|
|
.desc = "New name of the secure AES key in the repository",
|
|
.command = COMMAND_COPY,
|
|
},
|
|
{
|
|
.option = { "volumes", required_argument, NULL, 'l'},
|
|
.argument = "VOLUME:DMNAME[,...]",
|
|
.desc = "Comma-separated pairs of volume and device-mapper "
|
|
"names that are associated with the copied secure AES "
|
|
"key in the repository. If option '--volumes/-l' is "
|
|
"omitted, no volumes are associated with the copied "
|
|
"key, because only one key can be associated to a "
|
|
"specific volume.",
|
|
.command = COMMAND_COPY,
|
|
},
|
|
{
|
|
.option = { "local", 0, NULL, 'L'},
|
|
.desc = "Copy the key to a local key. This is the default when "
|
|
"no KMS plugin is bound to the repository. If the "
|
|
"repository is bound to a KMS plugin, then keys are "
|
|
"bound to the KMS per default, and KMS-bound key can "
|
|
"only be copied to local keys.",
|
|
.command = COMMAND_COPY,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_CRYPTTAB,
|
|
},
|
|
{
|
|
.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 repository. Use this option to select the volumes "
|
|
"for which a crypttab 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_CRYPTTAB,
|
|
},
|
|
#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 select "
|
|
"the keys by its volume type for which a crypttab "
|
|
"entry is to be generated",
|
|
.command = COMMAND_CRYPTTAB,
|
|
},
|
|
{
|
|
.option = {"key-file", required_argument, NULL,
|
|
OPT_CRYPTSETUP_KEYFILE},
|
|
.argument = "FILE-NAME",
|
|
.desc = "Read the passphrase from the specified file. "
|
|
"The specified file is passed to the generated "
|
|
"crypttab entry for LUKS2 volumes",
|
|
.command = COMMAND_CRYPTTAB,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"keyfile-offset", required_argument, NULL,
|
|
OPT_CRYPTSETUP_KEYFILE_OFFSET},
|
|
.argument = "BYTES",
|
|
.desc = "Specifies the number of bytes to skip in the file "
|
|
"specified with option '--key-file'. "
|
|
"The specified offset is passed to the generated "
|
|
"crypttab entry for LUKS2 volumes. Not all "
|
|
"distributions support the 'keyfile-offset' option in "
|
|
"crypttab entries",
|
|
.command = COMMAND_CRYPTTAB,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"keyfile-size", required_argument, NULL,
|
|
OPT_CRYPTSETUP_KEYFILE_SIZE},
|
|
.argument = "BYTES",
|
|
.desc = "Specifies the number of bytes to read from the file "
|
|
"specified with option '--key-file'. "
|
|
"The specified size is passed to the generated "
|
|
"crypttab entry for LUKS2 volumes. Not all "
|
|
"distributions support the 'keyfile-size' option in "
|
|
"crypttab entries",
|
|
.command = COMMAND_CRYPTTAB,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"tries", required_argument, NULL,
|
|
OPT_CRYPTSETUP_TRIES},
|
|
.argument = "NUMBER",
|
|
.desc = "Specifies how often the interactive input of the "
|
|
"passphrase can be retried. "
|
|
"The specified number is passed to the generated "
|
|
"crypttab entry for LUKS2 volumes",
|
|
.command = COMMAND_CRYPTTAB,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
#endif
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
},
|
|
{
|
|
.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 repository. Use this option to select the volumes "
|
|
"for which a cryptsetup 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_CRYPTSETUP,
|
|
},
|
|
#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 select "
|
|
"the keys by its volume type for which a crypttab "
|
|
"entry is to be generated",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
},
|
|
#endif
|
|
{
|
|
.option = {"run", 0, NULL, 'r'},
|
|
.desc = "Runs the generated cryptsetup command",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
},
|
|
#ifdef HAVE_LUKS2_SUPPORT
|
|
{
|
|
.option = {"key-file", required_argument, NULL,
|
|
OPT_CRYPTSETUP_KEYFILE},
|
|
.argument = "FILE-NAME",
|
|
.desc = "Read the passphrase from the specified file. "
|
|
"This option is passed to the generated command(s) for "
|
|
"LUKS2 volumes",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"keyfile-offset", required_argument, NULL,
|
|
OPT_CRYPTSETUP_KEYFILE_OFFSET},
|
|
.argument = "BYTES",
|
|
.desc = "Specifies the number of bytes to skip in the file "
|
|
"specified with option '--key-file'. "
|
|
"This option is passed to the generated command(s) for "
|
|
"LUKS2 volumes",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"keyfile-size", required_argument, NULL,
|
|
OPT_CRYPTSETUP_KEYFILE_SIZE},
|
|
.argument = "BYTES",
|
|
.desc = "Specifies the number of bytes to read from the file "
|
|
"specified with option '--key-file'. "
|
|
"This option is passed to the generated command(s) for "
|
|
"LUKS2 volumes",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"tries", required_argument, NULL,
|
|
OPT_CRYPTSETUP_TRIES},
|
|
.argument = "NUMBER",
|
|
.desc = "Specifies how often the interactive input of the "
|
|
"passphrase can be retried. "
|
|
"This option is passed to the generated command(s) for "
|
|
"LUKS2 volumes",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
#endif
|
|
{
|
|
.option = {"batch-mode", 0, NULL, 'q'},
|
|
.desc = "Suppresses cryptsetup confirmation questions. "
|
|
"This option is passed to the generated cryptsetup "
|
|
"command(s)",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
},
|
|
#ifdef HAVE_LUKS2_SUPPORT
|
|
{
|
|
.option = {"open", 0, NULL, OPT_CRYPTSETUP_OPEN},
|
|
.desc = "Generates luksOpen or plainOpen commands. For the "
|
|
"plain volume type, this is the default",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"format", 0, NULL, OPT_CRYPTSETUP_FORMAT},
|
|
.desc = "Generates luksFormat commands. For the LUKS2 volume "
|
|
"type, this is the default. If specified for the "
|
|
"plain volume type, then no command is generated",
|
|
.command = COMMAND_CRYPTSETUP,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
#endif
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_CONVERT,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES key in the repository that is "
|
|
"to be converted",
|
|
.command = COMMAND_CONVERT,
|
|
},
|
|
{
|
|
.option = { "key-type", required_argument, NULL, 'K'},
|
|
.argument = "type",
|
|
.desc = "The type of the key to convert the secure key to. "
|
|
"Possible values are '"KEY_TYPE_CCA_AESCIPHER"'. ",
|
|
.command = COMMAND_CONVERT,
|
|
},
|
|
{
|
|
.option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
|
|
.desc = "Do not check if the associated APQN(s) are available",
|
|
.command = COMMAND_CONVERT,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
{
|
|
.option = {"force", 0, NULL, 'F'},
|
|
.desc = "Do not prompt for a confirmation when converting a "
|
|
"key",
|
|
.command = COMMAND_CONVERT,
|
|
},
|
|
{
|
|
.option = {"exportable", 0, NULL, OPT_EXPORTABLE},
|
|
.desc = "Convert to an secure AES key that is not export "
|
|
"restricted. Exportable keys can be exported by means "
|
|
"of wrapping them with a key encryption key (KEK).",
|
|
.command = COMMAND_CONVERT,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_CONFIGURE,
|
|
},
|
|
{
|
|
.option = { "apqns", required_argument, NULL, 'a'},
|
|
.argument = "[+|-]CARD.DOMAIN[,...]",
|
|
.desc = "Comma-separated pairs of crypto cards and domains "
|
|
"that are associated with the key management system "
|
|
"(KMS) plugin that the repository is bound to, and all "
|
|
"keys generated with the KMS. To add pairs of crypto "
|
|
"cards and domains to the key, specify "
|
|
"'+CARD.DOMAIN[,...]'. To remove pairs of crypto cards "
|
|
"and domains from the key specify '-CARD.DOMAIN[,...]'",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_CONFIGURE,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"to-new", 0, NULL, 'n'},
|
|
.desc = "Re-enciphers KMS plugin internal secure keys that are "
|
|
"currently enciphered with the master key in the "
|
|
"CURRENT register with the master key in the NEW "
|
|
"register.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"from-old", 0, NULL, 'o'},
|
|
.desc = "Re-enciphers KMS plugin internal secure keys that are "
|
|
"currently enciphered with the master key in the OLD "
|
|
"register with the master key in the CURRENT register.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"complete", 0, NULL, 'p'},
|
|
.desc = "Completes a staged re-enciphering. Use this option "
|
|
"after the new master key has been set (made "
|
|
"active).",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"in-place", 0, NULL, 'i'},
|
|
.desc = "Forces an in-place re-enchipering of the KMS plugin "
|
|
"internal secure keys. Re-enciphering from OLD to "
|
|
"CURRENT is performed in-place per default.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REENCIPHER,
|
|
},
|
|
{
|
|
.option = {"staged", 0, NULL, 's'},
|
|
.desc = "Forces that the re-enciphering of the KMS plugin "
|
|
"internal secure keys is performed in staged mode. "
|
|
"Re-enciphering from CURRENT to NEW is performed in "
|
|
"staged mode per default.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REENCIPHER,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_LIST,
|
|
},
|
|
{
|
|
.option = { "label", required_argument, NULL, 'B'},
|
|
.argument = "LABEL",
|
|
.desc = "Label of the secure AES keys as known by the KMS that "
|
|
"are to be listed. You can use wildcards to select "
|
|
"the keys to be listed.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_LIST,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES keys as known by zkey that "
|
|
"are to be listed. You can use wildcards to select "
|
|
"the keys to be listed.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_LIST,
|
|
},
|
|
{
|
|
.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 list 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_LIST,
|
|
},
|
|
#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 list all "
|
|
"keys with the specified volumes type.",
|
|
.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,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REFRESH,
|
|
},
|
|
{
|
|
.option = { "name", required_argument, NULL, 'N'},
|
|
.argument = "NAME",
|
|
.desc = "Name of the secure AES keys in the repository that "
|
|
"are to be refreshed. You can use wildcards to select "
|
|
"the keys to be refreshed.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REFRESH,
|
|
},
|
|
{
|
|
.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 repository. Use this option to refresh all keys "
|
|
"associated with specific volumes. The device-mapper "
|
|
"name (DMNAME) is optional. If specified, only those "
|
|
"keys are refreshed where both, the volume and the "
|
|
"device-mapper name matches",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REFRESH,
|
|
},
|
|
#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 refresh "
|
|
"all keys with the specified volumes type.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REFRESH,
|
|
},
|
|
#endif
|
|
{
|
|
.option = { "key-type", required_argument, NULL, 'K'},
|
|
.argument = "type",
|
|
.desc = "The type of the key. Possible values are '"
|
|
KEY_TYPE_CCA_AESDATA"', '"KEY_TYPE_CCA_AESCIPHER"' "
|
|
"and '"KEY_TYPE_EP11_AES"'. Use this option to refresh "
|
|
"all keys with the specified key type.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REFRESH,
|
|
},
|
|
{
|
|
.option = {"refresh-properties", 0, NULL, 'P'},
|
|
.desc = "Also refresh the properties of the secure AES key "
|
|
"and update them with the values from the KMS.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REFRESH,
|
|
},
|
|
{
|
|
.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 refreshed are available, or are "
|
|
"already associated with other secure keys.",
|
|
.command = COMMAND_KMS " " COMMAND_KMS_REFRESH,
|
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
|
},
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "OPTIONS",
|
|
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
|
|
},
|
|
{
|
|
.option = {"all", 0, NULL, 'A'},
|
|
.desc = "List all protected virtualization (PV) secret types, "
|
|
"not only those that can be used with zkey.",
|
|
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
|
|
},
|
|
{
|
|
.option = {"hex", 0, NULL, 'H'},
|
|
.desc = "Show all protected virtualization (PV) secret IDs in "
|
|
"hex, even if the ID contains only printable "
|
|
"characters.",
|
|
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
|
|
},
|
|
{
|
|
.option = { "pvsecret-type", required_argument, NULL, 'T'},
|
|
.argument = "PVSECRET-TYPE",
|
|
.desc = "Type of the protected virtualization (PV) secret to "
|
|
"list. If omitted, all pvsecret types are listed.",
|
|
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
|
|
},
|
|
{
|
|
.option = { "pvsecret-id", required_argument, NULL, 'I'},
|
|
.argument = "PVSECRET-ID",
|
|
.desc = "ID of the protected virtualization (PV) secret to "
|
|
"list. Either '--pvsecret-id/-I' or "
|
|
"'--pvsecret-name/-e' can be specified, but not both.",
|
|
.command = COMMAND_PVSECRETS " " COMMAND_PVSECRETS_LIST,
|
|
},
|
|
{
|
|
.option = { "pvsecret-name", required_argument, NULL, 'e'},
|
|
.argument = "PVSECRET-NAME",
|
|
.desc = "Name of the protected virtualization (PV) secret to "
|
|
"list. Either '--pvsecret-name/-e' or "
|
|
"'--pvsecret-id/-I' can be specified, but not both.",
|
|
.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,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
OPT_PLACEHOLDER,
|
|
/***********************************************************/
|
|
{
|
|
.flags = UTIL_OPT_FLAG_SECTION,
|
|
.desc = "COMMON OPTIONS"
|
|
},
|
|
{
|
|
.option = {"verbose", 0, NULL, 'V'},
|
|
.desc = "Print additional information messages during "
|
|
"processing",
|
|
},
|
|
UTIL_OPT_HELP,
|
|
UTIL_OPT_VERSION,
|
|
UTIL_OPT_END
|
|
};
|
|
|
|
#define ZKEY_COMMAND_STR_LEN 80
|
|
|
|
/*
|
|
* Table of supported commands
|
|
*/
|
|
struct zkey_command {
|
|
char *command;
|
|
unsigned int abbrev_len;
|
|
int (*function)(void);
|
|
int need_cca_library;
|
|
int need_ep11_library;
|
|
int need_pkey_device;
|
|
int need_uv_device;
|
|
char *short_desc;
|
|
char *long_desc;
|
|
int has_options;
|
|
char *pos_arg;
|
|
int pos_arg_optional;
|
|
char *pos_arg_alternate;
|
|
char **arg_alternate_value;
|
|
int need_keystore;
|
|
int use_kms_plugin;
|
|
char *kms_plugin_opts_cmd;
|
|
int need_kms_login;
|
|
struct zkey_command *sub_commands;
|
|
};
|
|
|
|
static int command_generate(void);
|
|
static int command_reencipher(void);
|
|
static int command_validate(void);
|
|
static int command_import(void);
|
|
static int command_export(void);
|
|
static int command_list(void);
|
|
static int command_remove(void);
|
|
static int command_change(void);
|
|
static int command_rename(void);
|
|
static int command_copy(void);
|
|
static int command_crypttab(void);
|
|
static int command_cryptsetup(void);
|
|
static int command_convert(void);
|
|
static int command_kms_plugins(void);
|
|
static int command_kms_bind(void);
|
|
static int command_kms_unbind(void);
|
|
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 int command_kms_refresh(void);
|
|
static int command_pvsecrets_list(void);
|
|
static int command_pvsecrets_import(void);
|
|
|
|
static struct zkey_command zkey_kms_commands[] = {
|
|
{
|
|
.command = COMMAND_KMS_PLUGINS,
|
|
.abbrev_len = 2,
|
|
.function = command_kms_plugins,
|
|
.short_desc = "Lists key management system plugins",
|
|
.long_desc = "Lists available key management system (KMS) "
|
|
"plugins.",
|
|
.has_options = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_KMS_BIND,
|
|
.abbrev_len = 2,
|
|
.function = command_kms_bind,
|
|
.short_desc = "Binds the repository to a key management system "
|
|
"plugin",
|
|
.long_desc = "Binds the repository to the specified key "
|
|
"management system (KMS) plugin.",
|
|
.need_keystore = 1,
|
|
.has_options = 1,
|
|
.pos_arg = "[KMS-PLUGIN]",
|
|
},
|
|
{
|
|
.command = COMMAND_KMS_UNBIND,
|
|
.abbrev_len = 3,
|
|
.function = command_kms_unbind,
|
|
.short_desc = "Unbinds the repository from a key management "
|
|
"system plugin",
|
|
.long_desc = "Unbinds the repository from the current key "
|
|
"management system (KMS) plugin, and turns all "
|
|
"KMS-bound keys into local keys",
|
|
.need_keystore = 1,
|
|
.has_options = 1,
|
|
.use_kms_plugin = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_KMS_INFO,
|
|
.abbrev_len = 2,
|
|
.function = command_kms_info,
|
|
.short_desc = "Displays information about a key management "
|
|
"system plugin",
|
|
.long_desc = "Displays information about the current key "
|
|
"management system (KMS) plugin",
|
|
.need_keystore = 1,
|
|
.has_options = 1,
|
|
.use_kms_plugin = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_KMS_CONFIGURE,
|
|
.abbrev_len = 3,
|
|
.function = command_kms_configure,
|
|
.short_desc = "Configures a key management system plugin",
|
|
.long_desc = "Configures or re-configures the current key "
|
|
"management system (KMS) plugin",
|
|
.need_keystore = 1,
|
|
.has_options = 1,
|
|
.use_kms_plugin = 1,
|
|
.kms_plugin_opts_cmd = KMS_COMMAND_CONFIGURE,
|
|
},
|
|
{
|
|
.command = COMMAND_KMS_REENCIPHER,
|
|
.abbrev_len = 2,
|
|
.function = command_kms_reencipher,
|
|
.short_desc = "Re-enciphers secure keys used by a key "
|
|
"management system plugin",
|
|
.long_desc = "Re-enciphers secure keys internally used by a "
|
|
"key management system (KMS) plugin",
|
|
.need_keystore = 1,
|
|
.has_options = 1,
|
|
.use_kms_plugin = 1,
|
|
.kms_plugin_opts_cmd = KMS_COMMAND_REENCIPHER,
|
|
},
|
|
{
|
|
.command = COMMAND_KMS_LIST,
|
|
.abbrev_len = 2,
|
|
.function = command_kms_list,
|
|
.short_desc = "Lists secure keys managed by a key management "
|
|
"system",
|
|
.long_desc = "Lists secure keys managed by a key management "
|
|
"system (KMS)",
|
|
.need_keystore = 1,
|
|
.has_options = 1,
|
|
.use_kms_plugin = 1,
|
|
.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 = COMMAND_KMS_REFRESH,
|
|
.abbrev_len = 3,
|
|
.function = command_kms_refresh,
|
|
.short_desc = "Refreshes secure keys that are bound to a key "
|
|
"management system",
|
|
.long_desc = "Refreshes secure keys that are bound to a key "
|
|
"management system (KMS)",
|
|
.need_keystore = 1,
|
|
.has_options = 1,
|
|
.use_kms_plugin = 1,
|
|
.need_kms_login = 1,
|
|
},
|
|
{ .command = NULL }
|
|
};
|
|
|
|
static struct zkey_command zkey_pvsecrets_commands[] = {
|
|
{
|
|
.command = COMMAND_PVSECRETS_LIST,
|
|
.abbrev_len = 2,
|
|
.function = command_pvsecrets_list,
|
|
.short_desc = "Lists protected virtualization (PV) secrets",
|
|
.long_desc = "Lists available protected virtualization (PV) "
|
|
"secrets. This command is only available when "
|
|
"running in a secure execution guest. Only the "
|
|
"'root' user is allowed to perform this command",
|
|
.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 }
|
|
};
|
|
|
|
static struct zkey_command zkey_commands[] = {
|
|
{
|
|
.command = COMMAND_GENERATE,
|
|
.abbrev_len = 3,
|
|
.function = command_generate,
|
|
.need_pkey_device = 1,
|
|
.short_desc = "Generate a secure AES key",
|
|
.long_desc = "Generate a secure AES key either by "
|
|
"random or from a specified clear key and store "
|
|
"it either into SECURE-KEY-FILE or into the "
|
|
"repository",
|
|
.has_options = 1,
|
|
.pos_arg = "[SECURE-KEY-FILE]",
|
|
.pos_arg_optional = 1,
|
|
.pos_arg_alternate = "--name/-N",
|
|
.arg_alternate_value = &g.name,
|
|
.use_kms_plugin = 1,
|
|
.kms_plugin_opts_cmd = KMS_COMMAND_GENERATE,
|
|
},
|
|
{
|
|
.command = COMMAND_REENCIPHER,
|
|
.abbrev_len = 2,
|
|
.function = command_reencipher,
|
|
/* Will load the CCA or EP11 library on demand */
|
|
.need_pkey_device = 1,
|
|
.short_desc = "Re-encipher an existing secure AES key",
|
|
.long_desc = "Re-encipher an existing secure AES "
|
|
"key that is either contained in SECURE-KEY-FILE "
|
|
"or is stored in the repository with another "
|
|
"master key",
|
|
.has_options = 1,
|
|
.pos_arg = "[SECURE-KEY-FILE]",
|
|
.pos_arg_optional = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_VALIDATE,
|
|
.abbrev_len = 3,
|
|
.function = command_validate,
|
|
.need_pkey_device = 1,
|
|
.short_desc = "Validate an existing secure AES key",
|
|
.long_desc = "Validate an existing secure AES key that is "
|
|
"either contained in SECURE-KEY-FILE or is stored "
|
|
"in the repository and print information about "
|
|
"the key",
|
|
.has_options = 1,
|
|
.pos_arg = "[SECURE-KEY-FILE]",
|
|
.pos_arg_optional = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_IMPORT,
|
|
.abbrev_len = 2,
|
|
.function = command_import,
|
|
.short_desc = "Import a secure AES key",
|
|
.long_desc = "Import a secure AES key from a file into the "
|
|
"repository",
|
|
.has_options = 1,
|
|
.pos_arg = "SECURE-KEY-FILE",
|
|
.need_keystore = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_EXPORT,
|
|
.abbrev_len = 2,
|
|
.function = command_export,
|
|
.short_desc = "Export a secure AES key",
|
|
.long_desc = "Export a secure AES key from the repository to "
|
|
"a file",
|
|
.has_options = 1,
|
|
.pos_arg = "SECURE-KEY-FILE",
|
|
.need_keystore = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_LIST,
|
|
.abbrev_len = 2,
|
|
.function = command_list,
|
|
.short_desc = "List keys in the repository",
|
|
.long_desc = "List secure AES key in the repository",
|
|
.has_options = 1,
|
|
.need_keystore = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_REMOVE,
|
|
.abbrev_len = 3,
|
|
.function = command_remove,
|
|
.short_desc = "Remove a secure AES key",
|
|
.long_desc = "Remove a secure AES key from the repository",
|
|
.has_options = 1,
|
|
.need_keystore = 1,
|
|
.use_kms_plugin = 1,
|
|
.kms_plugin_opts_cmd = KMS_COMMAND_REMOVE,
|
|
},
|
|
{
|
|
.command = COMMAND_CHANGE,
|
|
.abbrev_len = 2,
|
|
.function = command_change,
|
|
.short_desc = "Change a secure AES key",
|
|
.long_desc = "Change the properties of a secure AES key in "
|
|
"the repository",
|
|
.has_options = 1,
|
|
.need_keystore = 1,
|
|
.use_kms_plugin = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_RENAME,
|
|
.abbrev_len = 3,
|
|
.function = command_rename,
|
|
.short_desc = "Rename a secure AES key",
|
|
.long_desc = "Rename a secure AES key in the repository",
|
|
.has_options = 1,
|
|
.need_keystore = 1,
|
|
.use_kms_plugin = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_COPY,
|
|
.abbrev_len = 2,
|
|
.function = command_copy,
|
|
.short_desc = "Copy a secure AES key",
|
|
.long_desc = "Copy a secure AES key in the repository",
|
|
.has_options = 1,
|
|
.need_keystore = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_CRYPTTAB,
|
|
.abbrev_len = 6,
|
|
.function = command_crypttab,
|
|
.short_desc = "Generate crypttab entries",
|
|
.long_desc = "Generate crypttab entries for selected volumes",
|
|
.has_options = 1,
|
|
.need_keystore = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_CRYPTSETUP,
|
|
.abbrev_len = 6,
|
|
.function = command_cryptsetup,
|
|
.short_desc = "Generate or run cryptsetup commands",
|
|
.long_desc = "Generate or run cryptsetup commands for "
|
|
"selected volumes",
|
|
.has_options = 1,
|
|
.need_keystore = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_CONVERT,
|
|
.abbrev_len = 3,
|
|
.function = command_convert,
|
|
.need_cca_library = 1,
|
|
.need_pkey_device = 1,
|
|
.short_desc = "Convert a secure AES key",
|
|
.long_desc = "Convert an existing secure AES key that is "
|
|
"either contained in SECURE-KEY-FILE or is stored "
|
|
"in the repository from one key type to another "
|
|
"type.",
|
|
.has_options = 1,
|
|
.pos_arg = "[SECURE-KEY-FILE]",
|
|
.pos_arg_optional = 1,
|
|
},
|
|
{
|
|
.command = COMMAND_KMS,
|
|
.abbrev_len = 2,
|
|
.short_desc = "key management system (KMS) support",
|
|
.long_desc = "Provides subcommands for key management system "
|
|
"(KMS) support.",
|
|
.has_options = 1,
|
|
.sub_commands = zkey_kms_commands,
|
|
},
|
|
{
|
|
.command = COMMAND_PVSECRETS,
|
|
.abbrev_len = 2,
|
|
.short_desc = "Protected virtualization (PV) support",
|
|
.long_desc = "Provides subcommands for working with protected "
|
|
"virtualization (PV) secrets. Protected "
|
|
"virtualization secrets can be made available to "
|
|
"a secure execution guest and can be used only "
|
|
"within that guest. Thus, these subcommands are "
|
|
"only available when running in a secure "
|
|
"execution guest. Only the 'root' user is allowed "
|
|
"to perform these subcommands.",
|
|
.has_options = 1,
|
|
.sub_commands = zkey_pvsecrets_commands,
|
|
},
|
|
{ .command = NULL }
|
|
};
|
|
|
|
#define pr_verbose(fmt...) if (g.verbose) \
|
|
warnx(fmt)
|
|
|
|
static void print_usage_sub_command_list(const struct zkey_command *sub_command)
|
|
{
|
|
struct zkey_command *sub_cmd = (struct zkey_command *)sub_command;
|
|
char command_str[ZKEY_COMMAND_STR_LEN];
|
|
unsigned int i;
|
|
|
|
printf("SUBCOMMANDS\n");
|
|
while (sub_cmd->command) {
|
|
strcpy(command_str, sub_cmd->command);
|
|
for (i = 0; i < sub_cmd->abbrev_len; i++)
|
|
command_str[i] =
|
|
toupper(command_str[i]);
|
|
printf(" %-*s %s\n", ZKEY_COMMAND_MAX_LEN,
|
|
command_str, sub_cmd->short_desc);
|
|
sub_cmd++;
|
|
}
|
|
}
|
|
|
|
static void print_usage_command(const struct zkey_command *command,
|
|
const struct zkey_command *sub_command)
|
|
{
|
|
char sub_command_str[ZKEY_COMMAND_STR_LEN];
|
|
char command_str[ZKEY_COMMAND_STR_LEN];
|
|
const struct zkey_command *cmd;
|
|
unsigned int i;
|
|
|
|
strncpy(command_str, command->command, sizeof(command_str) - 1);
|
|
for (i = 0; i < command->abbrev_len; i++)
|
|
command_str[i] = toupper(command_str[i]);
|
|
|
|
if (sub_command != NULL) {
|
|
strncpy(sub_command_str, sub_command->command,
|
|
sizeof(sub_command_str) - 1);
|
|
for (i = 0; i < sub_command->abbrev_len; i++)
|
|
sub_command_str[i] = toupper(sub_command_str[i]);
|
|
|
|
printf("Usage: %s %s %s", program_invocation_short_name,
|
|
command_str, sub_command_str);
|
|
} else {
|
|
printf("Usage: %s %s", program_invocation_short_name,
|
|
command_str);
|
|
if (command->sub_commands != NULL)
|
|
printf(" SUBCOMMAND");
|
|
}
|
|
|
|
cmd = sub_command != NULL ? sub_command : command;
|
|
|
|
if (cmd->pos_arg != NULL)
|
|
printf(" %s", cmd->pos_arg);
|
|
if (cmd->has_options)
|
|
printf(" [OPTIONS]");
|
|
|
|
if (prg.args)
|
|
printf(" %s", prg.args);
|
|
printf("\n\n");
|
|
util_print_indented(cmd->long_desc, 0);
|
|
|
|
if (cmd->has_options)
|
|
printf("\n");
|
|
|
|
if (sub_command == NULL && command->sub_commands != NULL)
|
|
print_usage_sub_command_list(command->sub_commands);
|
|
}
|
|
|
|
static void print_usage_command_list(void)
|
|
{
|
|
struct zkey_command *cmd = zkey_commands;
|
|
char command_str[ZKEY_COMMAND_STR_LEN];
|
|
unsigned int i;
|
|
|
|
util_prg_print_help();
|
|
|
|
printf("COMMANDS\n");
|
|
while (cmd->command) {
|
|
strcpy(command_str, cmd->command);
|
|
for (i = 0; i < cmd->abbrev_len; i++)
|
|
command_str[i] = toupper(command_str[i]);
|
|
printf(" %-*s %s\n", ZKEY_COMMAND_MAX_LEN, command_str,
|
|
cmd->short_desc);
|
|
cmd++;
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
/*
|
|
* --help printout
|
|
*/
|
|
static void print_help(const struct zkey_command *command,
|
|
const struct zkey_command *sub_command)
|
|
{
|
|
/* Print usage */
|
|
if (command == NULL)
|
|
print_usage_command_list();
|
|
else
|
|
print_usage_command(command, sub_command);
|
|
|
|
/* Print parameter help */
|
|
util_opt_print_help();
|
|
|
|
if (command == NULL) {
|
|
printf("\n");
|
|
printf("For more information use '%s COMMAND --help'.\n",
|
|
program_invocation_short_name);
|
|
} else if (command->sub_commands != NULL && sub_command == NULL) {
|
|
printf("\n");
|
|
printf("For more information use '%s %s SUBCOMMAND --help'.\n",
|
|
program_invocation_short_name, command->command);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'generate with clear key'
|
|
*
|
|
* Generate a secure key from the specified clear key.
|
|
*/
|
|
static int command_generate_clear(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = generate_secure_key_clear(g.pkey_fd, g.pos_arg,
|
|
g.keybits, g.xts,
|
|
g.clearkeyfile, g.key_type,
|
|
NULL, g.exportable, g.wrap_with_trusted,
|
|
g.verbose);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'generate by random'.
|
|
*
|
|
* Generate a secure key by random using the pkey kernel module.
|
|
*/
|
|
static int command_generate_random(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = generate_secure_key_random(g.pkey_fd, g.pos_arg,
|
|
g.keybits, g.xts, g.key_type,
|
|
NULL, g.exportable, g.wrap_with_trusted,
|
|
g.verbose);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'generate in repository'.
|
|
*
|
|
* Generate a secure key and store it in the repository.
|
|
*/
|
|
static int command_generate_repository(void)
|
|
{
|
|
int rc;
|
|
|
|
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;
|
|
}
|
|
|
|
if (g.kms_info.plugin_lib != NULL && !g.local) {
|
|
if (g.apqns != NULL) {
|
|
warnx("Option '--apqns|-a' is not valid for "
|
|
"generating a key in a KMS-bound repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (g.clearkeyfile != NULL) {
|
|
warnx("Option '--clearkey|-c' is not valid for "
|
|
"generating a key in a KMS-bound repository, "
|
|
"unless option '--local|-L' is also specified");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (g.exportable) {
|
|
warnx("Option '--exportable' is not supported for "
|
|
"generating a key in a KMS-bound repository");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.wrap_with_trusted) {
|
|
warnx("Option '--wrap-with-trusted' is not supported "
|
|
"for generating a key in a KMS-bound repository");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = perform_kms_login(&g.kms_info, g.verbose);
|
|
if (rc != 0)
|
|
rc = EXIT_FAILURE;
|
|
|
|
rc = keystore_generate_key_kms(g.keystore, g.name,
|
|
g.description, g.volumes,
|
|
g.sector_size, g.keybits, g.xts,
|
|
g.volume_type, g.key_type,
|
|
g.gen_passphrase,
|
|
g.passphrase_file,
|
|
g.kms_options,
|
|
g.num_kms_options);
|
|
goto out;
|
|
}
|
|
|
|
if (g.key_type == NULL)
|
|
g.key_type = KEY_TYPE_CCA_AESDATA;
|
|
|
|
if (g.wrap_with_trusted) {
|
|
if (!g.exportable) {
|
|
warnx("Option '--wrap-with-trusted' is only valid "
|
|
"together with the '--exportable' option");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (strcasecmp(g.key_type, KEY_TYPE_EP11_AES) != 0) {
|
|
warnx("Option '--wrap-with-trusted' is only valid for "
|
|
"keys of type '%s'", KEY_TYPE_EP11_AES);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes,
|
|
g.apqns, g.noapqncheck, g.sector_size,
|
|
g.keybits, g.xts, g.clearkeyfile,
|
|
g.volume_type, g.key_type, g.gen_passphrase,
|
|
g.passphrase_file, g.exportable,
|
|
g.wrap_with_trusted, g.pkey_fd);
|
|
|
|
out:
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Command handler for 'generate'.
|
|
*
|
|
* Generate a new secure key either by random or from the specified clear key.
|
|
*/
|
|
static int command_generate(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.pos_arg != NULL && g.name != NULL) {
|
|
warnx(" Option '--name|-N' is not valid for generating a key "
|
|
"outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.apqns == NULL && g.noapqncheck) {
|
|
warnx("Option '--no-apqn-check' is only valid together with "
|
|
"the '--apqns|-a' option");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.name != NULL)
|
|
return command_generate_repository();
|
|
if (g.key_type == NULL)
|
|
g.key_type = KEY_TYPE_CCA_AESDATA;
|
|
if (!is_secure_key_type(g.key_type)) {
|
|
warnx("Keys of type '%s' can not be generated. Use 'zkey "
|
|
"pvsecret import' instead", g.key_type);
|
|
return -EXIT_FAILURE;
|
|
}
|
|
if (g.wrap_with_trusted) {
|
|
if (!g.exportable) {
|
|
warnx("Option '--wrap-with-trusted' is only valid "
|
|
"together with the '--exportable' option");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (strcasecmp(g.key_type, KEY_TYPE_EP11_AES) != 0) {
|
|
warnx("Option '--wrap-with-trusted' is only valid for "
|
|
"keys of type '%s'", KEY_TYPE_EP11_AES);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
if (g.pos_arg != NULL) {
|
|
if (g.volumes != NULL) {
|
|
warnx("Option '--volumes|-l' is not valid for "
|
|
"generating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.apqns != NULL) {
|
|
warnx("Option '--apqns|-a' is not valid for "
|
|
"generating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.noapqncheck) {
|
|
warnx("Option '--no-apqn-check' is not valid for "
|
|
"generating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.description != NULL) {
|
|
warnx("Option '--description|-d' is not valid for "
|
|
"generating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.local) {
|
|
warnx("Option '--local|-L' is not valid for "
|
|
"generating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.gen_passphrase) {
|
|
warnx("Option '--gen-dummy-passphrase' is not valid "
|
|
"for generating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.passphrase_file != NULL) {
|
|
warnx("Option '--sen-dummy-passphrase' is not valid "
|
|
"for generating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = cross_check_apqns(NULL, NULL,
|
|
get_min_card_level_for_keytype(g.key_type),
|
|
get_min_fw_version_for_keytype(g.key_type),
|
|
get_card_type_for_keytype(g.key_type),
|
|
true, g.verbose);
|
|
if (rc == -EINVAL)
|
|
return EXIT_FAILURE;
|
|
if (rc != 0 && rc != -ENOTSUP) {
|
|
warnx("Your master key setup is improper");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return g.clearkeyfile ? command_generate_clear()
|
|
: command_generate_random();
|
|
}
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Command handler for 'reencipher'.
|
|
*
|
|
* Re-encipher the specified secure key with the NEW or CURRENT CCA master key.
|
|
*/
|
|
static int command_reencipher_file(void)
|
|
{
|
|
size_t secure_key_size;
|
|
int rc, is_old_mk;
|
|
u8 *secure_key;
|
|
bool selected;
|
|
|
|
if (g.name != NULL) {
|
|
warnx("Option '--name|-N' is not valid for "
|
|
"re-enciphering a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.apqns != NULL) {
|
|
warnx("Option '--apqns|-a' is not valid for "
|
|
"re-enciphering a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.inplace) {
|
|
warnx("Option '--in-place|-i' is not valid for "
|
|
"re-enciphering a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.staged) {
|
|
warnx("Option '--staged|-s' is not valid for "
|
|
"re-enciphering a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.complete) {
|
|
warnx("Option '--complete|-p' is not valid for "
|
|
"re-enciphering a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* Read the secure key to be re-enciphered */
|
|
secure_key = read_secure_key(g.pos_arg, &secure_key_size, g.verbose);
|
|
if (secure_key == NULL)
|
|
return EXIT_FAILURE;
|
|
|
|
if (!is_secure_key(secure_key, secure_key_size)) {
|
|
warnx("A key of type %s can not be re-enciphered",
|
|
get_key_type(secure_key, secure_key_size));
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL,
|
|
&is_old_mk, NULL, g.verbose);
|
|
if (rc != 0) {
|
|
warnx("The secure key in file '%s' is not valid", g.pos_arg);
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
if (!g.fromold && !g.tonew) {
|
|
/* Autodetect reencipher option */
|
|
if (is_old_mk) {
|
|
g.fromold = 1;
|
|
util_print_indented("The secure key is currently "
|
|
"enciphered with the OLD "
|
|
"master key and is being "
|
|
"re-enciphered with the CURRENT "
|
|
"master key\n", 0);
|
|
} else {
|
|
g.tonew = 1;
|
|
util_print_indented("The secure key is currently "
|
|
"enciphered with the CURRENT "
|
|
"master key and is being "
|
|
"re-enciphered with the NEW "
|
|
"master key\n", 0);
|
|
}
|
|
}
|
|
|
|
/* Re-encipher the secure key */
|
|
if (g.fromold) {
|
|
if (!is_old_mk) {
|
|
warnx("The secure key is already enciphered "
|
|
"with the CURRENT master key");
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
pr_verbose("Secure key will be re-enciphered from OLD to the "
|
|
"CURRENT master key");
|
|
|
|
rc = reencipher_secure_key(&g.lib, secure_key, secure_key_size,
|
|
NULL, REENCIPHER_OLD_TO_CURRENT,
|
|
&selected, g.verbose);
|
|
if (rc != 0) {
|
|
if (rc == -ENODEV) {
|
|
warnx("No APQN found that is suitable for "
|
|
"re-enciphering the secure AES volume "
|
|
"key");
|
|
} else {
|
|
warnx("Re-encipher from OLD to CURRENT "
|
|
"master key has failed\n");
|
|
if (!selected &&
|
|
!is_ep11_aes_key(secure_key,
|
|
secure_key_size) &&
|
|
!is_ep11_aes_key_with_header(secure_key,
|
|
secure_key_size))
|
|
print_msg_for_cca_envvars(
|
|
"secure AES key");
|
|
}
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
if (g.tonew) {
|
|
pr_verbose("Secure key will be re-enciphered from CURRENT "
|
|
"to the NEW master key");
|
|
|
|
rc = reencipher_secure_key(&g.lib, secure_key, secure_key_size,
|
|
NULL, REENCIPHER_CURRENT_TO_NEW,
|
|
&selected, g.verbose);
|
|
if (rc != 0) {
|
|
if (rc == -ENODEV) {
|
|
warnx("No APQN found that is suitable for "
|
|
"re-enciphering the secure AES volume "
|
|
"key and has the NEW master key loaded");
|
|
} else {
|
|
warnx("Re-encipher from CURRENT to NEW "
|
|
"master key has failed\n");
|
|
if (!selected &&
|
|
!is_ep11_aes_key(secure_key,
|
|
secure_key_size) &&
|
|
!is_ep11_aes_key_with_header(secure_key,
|
|
secure_key_size))
|
|
print_msg_for_cca_envvars(
|
|
"secure AES key");
|
|
}
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
pr_verbose("Secure key was re-enciphered successfully");
|
|
|
|
/* Write the migrated secure key */
|
|
rc = write_secure_key(g.outputfile ? g.outputfile : g.pos_arg,
|
|
secure_key, secure_key_size, g.verbose);
|
|
if (rc != 0)
|
|
rc = EXIT_FAILURE;
|
|
out:
|
|
free(secure_key);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'reencipher in repository'.
|
|
*
|
|
* Re-encipher the specified secure key with the NEW or CURRENT master key.
|
|
*/
|
|
static int command_reencipher_repository(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.outputfile) {
|
|
warnx("Option '--output|-o' is not valid for "
|
|
"re-enciphering a key in the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.inplace && g.staged) {
|
|
warnx("Either '--in-place|-i' or '--staged|-s' can be "
|
|
"specified, but not both");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.complete) {
|
|
if (g.inplace) {
|
|
warnx("Option '--in-place|-i' is not valid together "
|
|
"with '--complete|-p'");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.staged) {
|
|
warnx("Option '--staged|-s' is not valid together "
|
|
"with '--complete|-p'");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
rc = keystore_reencipher_key(g.keystore, g.name, g.apqns, g.fromold,
|
|
g.tonew, g.inplace, g.staged, g.complete,
|
|
g.pkey_fd, &g.lib);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'reencipher'.
|
|
*
|
|
* Re-encipher the specified secure key with the NEW or CURRENT master key.
|
|
*/
|
|
static int command_reencipher(void)
|
|
{
|
|
if (g.pos_arg != NULL)
|
|
return command_reencipher_file();
|
|
else
|
|
return command_reencipher_repository();
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'validate'.
|
|
*
|
|
* Validates the specified secure key and prints out information about it.
|
|
*/
|
|
static int command_validate_file(void)
|
|
{
|
|
char vp[VERIFICATION_PATTERN_LEN];
|
|
size_t secure_key_size;
|
|
size_t clear_key_size;
|
|
const char *key_type;
|
|
u8 mkvp[MKVP_LENGTH];
|
|
u8 *secure_key;
|
|
int is_old_mk;
|
|
int rc;
|
|
|
|
if (g.name != NULL) {
|
|
warnx("Option '--name|-N' is not valid for "
|
|
"validating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.apqns != NULL) {
|
|
warnx("Option '--apqns|-a' is not valid for "
|
|
"validating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.noapqncheck) {
|
|
warnx("Option '--no-apqn-check' is not valid for "
|
|
"validating a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* Read the secure key to be re-enciphered */
|
|
secure_key = read_secure_key(g.pos_arg, &secure_key_size, g.verbose);
|
|
if (secure_key == NULL)
|
|
return EXIT_FAILURE;
|
|
|
|
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size,
|
|
&clear_key_size, &is_old_mk, NULL, g.verbose);
|
|
if (rc != 0) {
|
|
warnx("The secure key in file '%s' is not valid", g.pos_arg);
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
rc = generate_key_verification_pattern(secure_key,
|
|
secure_key_size, vp, sizeof(vp),
|
|
g.verbose);
|
|
if (rc != 0) {
|
|
warnx("Failed to generate the verification pattern: %s",
|
|
strerror(-rc));
|
|
warnx("Make sure that kernel module 'paes_s390' is loaded and "
|
|
"that the 'paes' cipher is available");
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
if (is_secure_key(secure_key, secure_key_size)) {
|
|
rc = get_master_key_verification_pattern(secure_key,
|
|
secure_key_size,
|
|
mkvp, g.verbose);
|
|
if (rc != 0) {
|
|
warnx("Failed to get the master key verification "
|
|
"pattern: %s", strerror(-rc));
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
key_type = get_key_type(secure_key, secure_key_size);
|
|
|
|
printf("Validation of secure key in file '%s':\n", g.pos_arg);
|
|
printf(" Status: Valid\n");
|
|
printf(" Secure key size: %lu bytes\n", secure_key_size);
|
|
printf(" Key type: %s\n", key_type);
|
|
printf(" Clear key size: %lu bits\n", clear_key_size);
|
|
printf(" XTS type key: %s\n",
|
|
is_xts_key(secure_key, secure_key_size) ? "Yes" : "No");
|
|
if (is_secure_key(secure_key, secure_key_size)) {
|
|
printf(" Enciphered with: %s master key (MKVP: %s)\n",
|
|
is_old_mk ? "OLD" : "CURRENT",
|
|
printable_mkvp(get_card_type_for_keytype(key_type),
|
|
mkvp));
|
|
}
|
|
printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
|
vp);
|
|
printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
|
&vp[VERIFICATION_PATTERN_LEN / 2]);
|
|
|
|
if (is_secure_key(secure_key, secure_key_size)) {
|
|
rc = cross_check_apqns(NULL, mkvp,
|
|
get_min_card_level_for_keytype(key_type),
|
|
get_min_fw_version_for_keytype(key_type),
|
|
get_card_type_for_keytype(key_type),
|
|
true, g.verbose);
|
|
if (rc == -EINVAL)
|
|
return EXIT_FAILURE;
|
|
if (rc != 0 && rc != -ENOTSUP) {
|
|
warnx("Your master key setup is improper");
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
free(secure_key);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'validate in repository'.
|
|
*
|
|
* Validates the specified secure key and prints out information about it.
|
|
*/
|
|
static int command_validate_repository(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = keystore_validate_key(g.keystore, g.name, g.apqns, g.noapqncheck,
|
|
g.pkey_fd);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'validate'.
|
|
*
|
|
* Validates the specified secure key and prints out information about it.
|
|
*/
|
|
static int command_validate(void)
|
|
{
|
|
if (g.pos_arg != NULL)
|
|
return command_validate_file();
|
|
else
|
|
return command_validate_repository();
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'import'.
|
|
*
|
|
* Imports a secure key from a file into the key repository.
|
|
*/
|
|
static int command_import(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.name == NULL) {
|
|
misc_print_required_parm("--name/-N");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (g.sector_size < 0)
|
|
g.sector_size = 0;
|
|
|
|
if (g.apqns == NULL && g.noapqncheck) {
|
|
warnx("Option '--no-apqn-check' is only valid together with "
|
|
"the '--apqns|-a' option");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
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 = keystore_import_key(g.keystore, g.name, g.description, g.volumes,
|
|
g.apqns, g.noapqncheck, g.sector_size,
|
|
g.pos_arg, g.volume_type, g.gen_passphrase,
|
|
g.passphrase_file, g.exportable, &g.lib);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'export'.
|
|
*
|
|
* Exports a secure key from the repository to a file
|
|
*/
|
|
static int command_export(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.name == NULL) {
|
|
misc_print_required_parm("--name/-N");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_export_key(g.keystore, g.name, g.pos_arg);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'list'.
|
|
*
|
|
* Lists keys stored in the repository
|
|
*/
|
|
static int command_list(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.local && g.kms_bound) {
|
|
warnx("Either '--local|-L' or '--kms-bound|-M' can be "
|
|
"specified, but not both");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns,
|
|
g.volume_type, g.key_type, g.local,
|
|
g.kms_bound);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'remove'.
|
|
*
|
|
* Remove a key from the repository
|
|
*/
|
|
static int command_remove(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.name == NULL) {
|
|
misc_print_required_parm("--name/-N");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_remove_key(g.keystore, g.name, g.force, g.kms_options,
|
|
g.num_kms_options);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'change'.
|
|
*
|
|
* Changes the properties of a key in the repository
|
|
*/
|
|
static int command_change(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.name == NULL) {
|
|
misc_print_required_parm("--name/-N");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.apqns == NULL && g.noapqncheck) {
|
|
warnx("Option '--no-apqn-check' is only valid together with "
|
|
"the '--apqns|-a' option");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
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;
|
|
}
|
|
if (g.gen_passphrase && g.remove_passphrase) {
|
|
warnx("Either '--gen-dummy-passphrase' or "
|
|
"'--remove-dummy-passphrase' can be specified, but not "
|
|
"both");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.passphrase_file != NULL && g.remove_passphrase) {
|
|
warnx("Either '--set-dummy-passphrase' or "
|
|
"'--remove-dummy-passphrase' can be specified, but not "
|
|
"both");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.force && !g.remove_passphrase) {
|
|
warnx("Option '--force|-F' is only valid together with "
|
|
"the '--remove-dummy-passphrase' option");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes,
|
|
g.apqns, g.noapqncheck, g.sector_size,
|
|
g.volume_type, g.gen_passphrase,
|
|
g.passphrase_file, g.remove_passphrase,
|
|
g.force);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'rname'.
|
|
*
|
|
* renames a key in the repository
|
|
*/
|
|
static int command_rename(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.name == NULL) {
|
|
misc_print_required_parm("--name/-N");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.newname == NULL) {
|
|
misc_print_required_parm("--new-name/-w");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_rename_key(g.keystore, g.name, g.newname);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'copy'.
|
|
*
|
|
* Copies a key in the repository
|
|
*/
|
|
static int command_copy(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.name == NULL) {
|
|
misc_print_required_parm("--name/-N");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.newname == NULL) {
|
|
misc_print_required_parm("--new-name/-w");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_copy_key(g.keystore, g.name, g.newname, g.volumes,
|
|
g.local);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'crypttab'.
|
|
*
|
|
* Generates crypttab entries for selected volumes
|
|
*/
|
|
static int command_crypttab(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = keystore_crypttab(g.keystore, g.volumes, g.volume_type, g.keyfile,
|
|
g.keyfile_offset, g.keyfile_size, g.tries);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'cryptsetup'.
|
|
*
|
|
* Generates and runs cryptsetup commands for selected volumes
|
|
*/
|
|
static int command_cryptsetup(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.open && g.format) {
|
|
warnx("Either '--open' or '--format' can be specified, but "
|
|
"not both");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_cryptsetup(g.keystore, g.volumes, g.run, g.volume_type,
|
|
g.keyfile, g.keyfile_offset, g.keyfile_size,
|
|
g.tries, g.batch_mode, g.open, g.format);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'convert'.
|
|
*
|
|
* Converts secure keys from one key type to another
|
|
*/
|
|
static int command_convert_file(void)
|
|
{
|
|
u8 output_key[2 * MAX_SECURE_KEY_SIZE];
|
|
unsigned int output_key_size;
|
|
size_t secure_key_size;
|
|
u8 mkvp[MKVP_LENGTH];
|
|
int rc, is_old_mk;
|
|
int selected = 1;
|
|
u8 *secure_key;
|
|
int min_level;
|
|
|
|
if (g.name != NULL) {
|
|
warnx("Option '--name|-N' is not valid for "
|
|
"converting a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.noapqncheck) {
|
|
warnx("Option '--no-apqn-check' is not valid for "
|
|
"converting a key outside of the repository");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
min_level = get_min_card_level_for_keytype(g.key_type);
|
|
if (min_level < 0) {
|
|
warnx("Invalid key-type specified: %s", g.key_type);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = cross_check_apqns(NULL, NULL, min_level,
|
|
get_min_fw_version_for_keytype(g.key_type),
|
|
get_card_type_for_keytype(g.key_type),
|
|
true, g.verbose);
|
|
if (rc == -EINVAL)
|
|
return EXIT_FAILURE;
|
|
if (rc != 0 && rc != -ENOTSUP) {
|
|
warnx("Your master key setup is improper");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* Read the secure key to be re-enciphered */
|
|
secure_key = read_secure_key(g.pos_arg, &secure_key_size, g.verbose);
|
|
if (secure_key == NULL)
|
|
return EXIT_FAILURE;
|
|
|
|
if (!is_cca_aes_data_key(secure_key, secure_key_size)) {
|
|
warnx("Only secure keys of type %s can "
|
|
"be converted. The secure key '%s' is of type %s",
|
|
KEY_TYPE_CCA_AESDATA, g.pos_arg,
|
|
get_key_type(secure_key, secure_key_size));
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL,
|
|
&is_old_mk, NULL, g.verbose);
|
|
if (rc != 0) {
|
|
warnx("The secure key in file '%s' is not valid", g.pos_arg);
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
|
mkvp, g.verbose);
|
|
if (rc != 0) {
|
|
warnx("Failed to get the master key verification pattern: %s",
|
|
strerror(-rc));
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
if (strcasecmp(get_key_type(secure_key, secure_key_size),
|
|
g.key_type) == 0) {
|
|
warnx("The secure key in file '%s' is already of type %s",
|
|
g.pos_arg, get_key_type(secure_key, secure_key_size));
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
if (is_cca_aes_data_key(secure_key, secure_key_size)) {
|
|
if (strcasecmp(g.key_type, KEY_TYPE_CCA_AESCIPHER) != 0) {
|
|
warnx("The secure key in file '%s' can not be "
|
|
"converted into type %s", g.pos_arg, g.key_type);
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
} else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
|
|
warnx("The secure key in file '%s' is already of type %s",
|
|
g.pos_arg, KEY_TYPE_CCA_AESCIPHER);
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
} else {
|
|
warnx("The secure key in file '%s' has an unsupported key type",
|
|
g.pos_arg);
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
|
FLAG_SEL_CCA_MATCH_CUR_MKVP,
|
|
g.verbose);
|
|
if (rc == -ENOTSUP) {
|
|
rc = 0;
|
|
selected = 0;
|
|
}
|
|
if (rc != 0) {
|
|
warnx("No APQN found that is suitable for "
|
|
"converting the secure AES key in file '%s'", g.pos_arg);
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
if (!g.force) {
|
|
util_print_indented("ATTENTION: Converting a secure key is "
|
|
"irreversible, and might have an effect "
|
|
"on the volumes encrypted with it!", 0);
|
|
printf("%s: Convert key in file '%s' [y/N]? ",
|
|
program_invocation_short_name, g.pos_arg);
|
|
if (!prompt_for_yes(g.verbose)) {
|
|
warnx("Operation aborted");
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
memset(output_key, 0, sizeof(output_key));
|
|
output_key_size = sizeof(output_key);
|
|
rc = convert_aes_data_to_cipher_key(&g.cca, secure_key, secure_key_size,
|
|
output_key, &output_key_size,
|
|
g.verbose);
|
|
if (rc != 0) {
|
|
warnx("Converting the secure key from %s to %s has failed",
|
|
get_key_type(secure_key, secure_key_size), g.key_type);
|
|
if (!selected)
|
|
print_msg_for_cca_envvars("secure AES key");
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
if (!g.exportable) {
|
|
rc = restrict_key_export(&g.cca, output_key, output_key_size,
|
|
g.verbose);
|
|
if (rc != 0) {
|
|
warnx("Export restricting the converted secure key "
|
|
"has failed");
|
|
if (!selected)
|
|
print_msg_for_cca_envvars("secure AES key");
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
pr_verbose("Secure key was converted successfully");
|
|
|
|
/* Write the converted secure key */
|
|
rc = write_secure_key(g.outputfile ? g.outputfile : g.pos_arg,
|
|
output_key, output_key_size, g.verbose);
|
|
if (rc != 0)
|
|
rc = EXIT_FAILURE;
|
|
out:
|
|
free(secure_key);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'convert in repository'.
|
|
*
|
|
* Converts secure keys from one key type to another
|
|
*/
|
|
static int command_convert_repository(void)
|
|
{
|
|
int rc;
|
|
|
|
if (g.name == NULL) {
|
|
misc_print_required_parm("--name/-N");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_convert_key(g.keystore, g.name, g.key_type, g.noapqncheck,
|
|
g.force, g.exportable, g.pkey_fd, &g.lib);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'convert'.
|
|
*
|
|
* Converts secure keys from one key type to another
|
|
*/
|
|
static int command_convert(void)
|
|
{
|
|
if (g.key_type == NULL) {
|
|
misc_print_required_parm("--key-type/-K");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (strcasecmp(g.key_type, KEY_TYPE_CCA_AESCIPHER) != 0) {
|
|
warnx("Secure keys can only be converted into key type %s",
|
|
KEY_TYPE_CCA_AESCIPHER);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (g.pos_arg != NULL)
|
|
return command_convert_file();
|
|
else
|
|
return command_convert_repository();
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms plugins'.
|
|
*
|
|
* List KMS plugins
|
|
*/
|
|
static int command_kms_plugins(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = list_kms_plugins(g.verbose);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms bind'.
|
|
*
|
|
* Bind repository to a KMS plugin
|
|
*/
|
|
static int command_kms_bind(void)
|
|
{
|
|
int rc;
|
|
|
|
rc = bind_kms_plugin(g.keystore, g.pos_arg, g.verbose);
|
|
|
|
if (rc == 0)
|
|
util_print_indented("The KMS plugin requires configuration, "
|
|
"run 'zkey kms configure [OPTIONS]' to "
|
|
"complete the KMS binding process", 0);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms unbind'.
|
|
*
|
|
* Unbind repository from a KMS plugin
|
|
*/
|
|
static int command_kms_unbind(void)
|
|
{
|
|
char *msg;
|
|
int rc;
|
|
|
|
if (g.kms_info.plugin_lib == NULL) {
|
|
rc = -ENOENT;
|
|
warnx("The repository is not bound to a KMS plugin");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
util_asprintf(&msg, "%s: Unbind this repository from KMS plugin '%s' "
|
|
"and turn all KMS-bound keys into local keys [y/N]? ",
|
|
program_invocation_short_name, g.kms_info.plugin_name);
|
|
util_print_indented(msg, 0);
|
|
free(msg);
|
|
if (!prompt_for_yes(g.verbose)) {
|
|
warnx("Operation aborted");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = keystore_kms_keys_unbind(g.keystore);
|
|
if (rc != 0) {
|
|
warnx("Failed to turn KMS-bound keys into local keys: %s",
|
|
strerror(-rc));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
rc = unbind_kms_plugin(&g.kms_info, g.keystore, g.verbose);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms info'.
|
|
*
|
|
* Prints information about a KMS plugin
|
|
*/
|
|
static int command_kms_info(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 = print_kms_info(&g.kms_info);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms configure'.
|
|
*
|
|
* Configures or re-configures a KMS plugin
|
|
*/
|
|
static int command_kms_configure(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 = configure_kms_plugin(g.keystore, g.apqns, g.kms_options,
|
|
g.num_kms_options, g.first_kms_option >= 0,
|
|
g.verbose);
|
|
if (rc == -EAGAIN) {
|
|
util_print_indented("The KMS plugin has accepted the "
|
|
"configuration so far, but requires further"
|
|
" configuration. Run 'zkey kms info' to "
|
|
"find out which KMS plugin settings still "
|
|
"require configuration, and run 'zkey kms "
|
|
"configure' again with the appropriate "
|
|
"options to complete the KMS "
|
|
"configuration process", 0);
|
|
rc = 0;
|
|
}
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms reencipher'.
|
|
*
|
|
* Reenciphers secure keys internally used by a KMS plugin
|
|
*/
|
|
static int command_kms_reencipher(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;
|
|
}
|
|
|
|
if (g.inplace && g.staged) {
|
|
warnx("Either '--in-place|-i' or '--staged|-s' can be "
|
|
"specified, but not both");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.complete) {
|
|
if (g.inplace) {
|
|
warnx("Option '--in-place|-i' is not valid together "
|
|
"with '--complete|-p'");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (g.staged) {
|
|
warnx("Option '--staged|-s' is not valid together "
|
|
"with '--complete|-p'");
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
rc = reencipher_kms(&g.kms_info, g.fromold, g.tonew, g.inplace,
|
|
g.staged, g.complete, g.kms_options,
|
|
g.num_kms_options, g.verbose);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms list'.
|
|
*
|
|
* List secure keys managed by a KMS
|
|
*/
|
|
static int command_kms_list(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 = list_kms_keys(&g.kms_info, g.label, g.name, g.volumes,
|
|
g.volume_type, g.kms_options, g.num_kms_options,
|
|
g.verbose);
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'kms refresh'.
|
|
*
|
|
* Refreshes secure keys managed by a KMS
|
|
*/
|
|
static int command_kms_refresh(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_refresh_kms_keys(g.keystore, g.name, g.volumes,
|
|
g.volume_type, g.key_type,
|
|
g.refresh_properties, g.novolcheck);
|
|
|
|
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Command handler for 'pvsecrets list'.
|
|
*
|
|
* Lists available protected virtualization secrets
|
|
*/
|
|
static int command_pvsecrets_list(void)
|
|
{
|
|
int rc;
|
|
|
|
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;
|
|
}
|
|
|
|
rc = pvsecrets_list(g.uv_fd, g.all, g.hex, g.secret_type, g.secret_id,
|
|
g.secret_name, g.verbose);
|
|
|
|
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
|
|
*/
|
|
static int open_keystore(void)
|
|
{
|
|
char *directory;
|
|
|
|
directory = secure_getenv(ENVVAR_ZKEY_REPOSITORY);
|
|
if (directory == NULL)
|
|
directory = DEFAULT_KEYSTORE;
|
|
|
|
g.keystore = keystore_new(directory, &g.kms_info, g.verbose);
|
|
|
|
return g.keystore == NULL ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
}
|
|
|
|
|
|
static bool is_command(struct zkey_command *command, const char *str)
|
|
{
|
|
char command_str[ZKEY_COMMAND_STR_LEN];
|
|
size_t str_len = strlen(str);
|
|
|
|
util_assert(sizeof(command_str) > strlen(command->command),
|
|
"Buffer 'command_str' too small for %s", command->command);
|
|
if (str_len < command->abbrev_len)
|
|
return false;
|
|
if (str_len > strlen(command->command))
|
|
return false;
|
|
strncpy(command_str, command->command, str_len);
|
|
if (strncasecmp(str, command_str, str_len) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Find the command in the command table
|
|
*/
|
|
static struct zkey_command *find_command(const struct zkey_command *commands,
|
|
const char *command)
|
|
{
|
|
struct zkey_command *cmd = (struct zkey_command *)commands;
|
|
|
|
while (cmd->command) {
|
|
if (is_command(cmd, command))
|
|
return cmd;
|
|
cmd++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Check if positional arguments are specified as needed by the command
|
|
*/
|
|
static int check_positional_arg(struct zkey_command *command)
|
|
{
|
|
if (command->pos_arg_optional) {
|
|
if (g.pos_arg == NULL &&
|
|
command->arg_alternate_value != NULL &&
|
|
*command->arg_alternate_value == NULL) {
|
|
misc_print_required_parms(command->pos_arg,
|
|
command->pos_arg_alternate);
|
|
return EXIT_FAILURE;
|
|
}
|
|
} else {
|
|
if (g.pos_arg == NULL) {
|
|
misc_print_required_parm(command->pos_arg);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Entry point
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char command_str[2 * ZKEY_COMMAND_STR_LEN + 2];
|
|
struct zkey_command *sub_command = NULL;
|
|
struct zkey_command *command = NULL;
|
|
struct zkey_command *cmd = NULL;
|
|
int arg_count = argc;
|
|
char **args = argv;
|
|
char *endp;
|
|
int rc, c;
|
|
|
|
util_prg_init(&prg);
|
|
|
|
/* Get command and subcommand if one is specified */
|
|
if (arg_count >= 2 && strncmp(args[1], "-", 1) != 0) {
|
|
command = find_command(zkey_commands, args[1]);
|
|
if (command == NULL) {
|
|
misc_print_invalid_command(args[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
arg_count--;
|
|
args = &args[1];
|
|
|
|
if (arg_count >= 2 && strncmp(args[1], "-", 1) != 0 &&
|
|
command->sub_commands != NULL) {
|
|
sub_command = find_command(command->sub_commands,
|
|
args[1]);
|
|
if (sub_command == NULL) {
|
|
misc_print_invalid_command(args[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
arg_count--;
|
|
args = &args[1];
|
|
}
|
|
|
|
if (arg_count >= 2 && strncmp(args[1], "-", 1) != 0) {
|
|
g.pos_arg = args[1];
|
|
arg_count--;
|
|
args = &args[1];
|
|
}
|
|
}
|
|
|
|
if (sub_command != NULL) {
|
|
snprintf(command_str, sizeof(command_str), "%s %s",
|
|
command->command, sub_command->command);
|
|
util_prg_set_command(command_str);
|
|
util_opt_set_command(command_str);
|
|
} else {
|
|
util_prg_set_command(command ? command->command : NULL);
|
|
util_opt_set_command(command ? command->command : NULL);
|
|
}
|
|
|
|
if (sub_command != NULL && command->sub_commands != NULL)
|
|
cmd = sub_command;
|
|
else
|
|
cmd = command;
|
|
|
|
if (cmd != NULL && cmd->use_kms_plugin) {
|
|
rc = check_for_kms_plugin(&g.kms_info, g.verbose);
|
|
if (rc != 0)
|
|
return EXIT_FAILURE;
|
|
|
|
if (cmd->kms_plugin_opts_cmd) {
|
|
rc = get_kms_options(&g.kms_info, opt_vec,
|
|
OPT_COMMAND_PLACEHOLDER,
|
|
cmd->kms_plugin_opts_cmd,
|
|
sub_command != NULL ?
|
|
command_str : cmd->command,
|
|
&g.first_kms_option,
|
|
g.verbose);
|
|
if (rc != 0)
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
util_opt_init(opt_vec, NULL);
|
|
|
|
while (1) {
|
|
c = util_opt_getopt_long(arg_count, args);
|
|
if (c == -1)
|
|
break;
|
|
|
|
if (cmd != NULL && cmd->kms_plugin_opts_cmd) {
|
|
rc = handle_kms_option(&g.kms_info, opt_vec,
|
|
g.first_kms_option,
|
|
sub_command != NULL ?
|
|
command_str : cmd->command,
|
|
c, optarg, &g.kms_options,
|
|
&g.num_kms_options, g.verbose);
|
|
if (rc != 0 && rc != -ENOENT) {
|
|
warnx("Failed to process KMS plugin option: "
|
|
"'%c': %s", c, strerror(-rc));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (rc == 0)
|
|
continue;
|
|
}
|
|
|
|
switch (c) {
|
|
case 'x':
|
|
g.xts = 1;
|
|
break;
|
|
case 'k':
|
|
g.keybits = strtol(optarg, &endp, 0);
|
|
if (*optarg == '\0' || *endp != '\0' ||
|
|
g.keybits <= 0 ||
|
|
(g.keybits == LONG_MAX && errno == ERANGE)) {
|
|
warnx("Invalid value for '--keybits'|'-c': "
|
|
"'%s'", optarg);
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
case 'c':
|
|
g.clearkeyfile = optarg;
|
|
break;
|
|
case 'f':
|
|
g.outputfile = optarg;
|
|
break;
|
|
case 'n':
|
|
g.tonew = 1;
|
|
break;
|
|
case 'o':
|
|
g.fromold = 1;
|
|
break;
|
|
case 'p':
|
|
g.complete = 1;
|
|
break;
|
|
case 'i':
|
|
g.inplace = 1;
|
|
break;
|
|
case 's':
|
|
g.staged = 1;
|
|
break;
|
|
case 'N':
|
|
g.name = optarg;
|
|
break;
|
|
case 'd':
|
|
g.description = optarg;
|
|
break;
|
|
case 'l':
|
|
g.volumes = optarg;
|
|
break;
|
|
case 'a':
|
|
g.apqns = optarg;
|
|
break;
|
|
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' ||
|
|
g.sector_size < 0 ||
|
|
(g.sector_size == LONG_MAX && errno == ERANGE)) {
|
|
warnx("Invalid value for '--sector-size'|'-S': "
|
|
"'%s'", optarg);
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
#ifdef HAVE_LUKS2_SUPPORT
|
|
case 't':
|
|
g.volume_type = optarg;
|
|
break;
|
|
#endif
|
|
case 'w':
|
|
g.newname = optarg;
|
|
break;
|
|
case 'r':
|
|
g.run = 1;
|
|
break;
|
|
case 'K':
|
|
g.key_type = optarg;
|
|
break;
|
|
case 'F':
|
|
g.force = 1;
|
|
break;
|
|
case 'V':
|
|
g.verbose = 1;
|
|
break;
|
|
#ifdef HAVE_LUKS2_SUPPORT
|
|
case OPT_CRYPTSETUP_KEYFILE:
|
|
g.keyfile = optarg;
|
|
break;
|
|
case OPT_CRYPTSETUP_KEYFILE_OFFSET:
|
|
g.keyfile_offset = strtoll(optarg, &endp, 0);
|
|
if (*optarg == '\0' || *endp != '\0' ||
|
|
g.keyfile_offset < 0 ||
|
|
(g.keyfile_offset == LLONG_MAX &&
|
|
errno == ERANGE)) {
|
|
warnx("Invalid value for '--keyfile-offset': "
|
|
"'%s'", optarg);
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
case OPT_CRYPTSETUP_KEYFILE_SIZE:
|
|
g.keyfile_size = strtoll(optarg, &endp, 0);
|
|
if (*optarg == '\0' || *endp != '\0' ||
|
|
g.keyfile_size <= 0 ||
|
|
(g.keyfile_size == LLONG_MAX && errno == ERANGE)) {
|
|
warnx("Invalid value for '--keyfile-size': "
|
|
"'%s'", optarg);
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
case OPT_CRYPTSETUP_TRIES:
|
|
g.tries = strtoll(optarg, &endp, 0);
|
|
if (*optarg == '\0' || *endp != '\0' ||
|
|
g.tries <= 0 ||
|
|
(g.tries == LLONG_MAX && errno == ERANGE)) {
|
|
warnx("Invalid value for '--tries': '%s'",
|
|
optarg);
|
|
util_prg_print_parse_error();
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
#endif
|
|
case 'q':
|
|
g.batch_mode = 1;
|
|
break;
|
|
#ifdef HAVE_LUKS2_SUPPORT
|
|
case OPT_CRYPTSETUP_OPEN:
|
|
g.open = 1;
|
|
break;
|
|
case OPT_CRYPTSETUP_FORMAT:
|
|
g.format = 1;
|
|
break;
|
|
#endif
|
|
case 'L':
|
|
g.local = 1;
|
|
break;
|
|
case 'M':
|
|
g.kms_bound = 1;
|
|
break;
|
|
case 'B':
|
|
g.label = optarg;
|
|
break;
|
|
case 'P':
|
|
g.refresh_properties = 1;
|
|
break;
|
|
case OPT_GEN_DUMMY_PASSPHRASE:
|
|
g.gen_passphrase = 1;
|
|
break;
|
|
case OPT_SET_DUMMY_PASSPHRASE:
|
|
g.passphrase_file = optarg;
|
|
break;
|
|
case OPT_REMOVE_DUMMY_PASSPHRASE:
|
|
g.remove_passphrase = 1;
|
|
break;
|
|
case OPT_EXPORTABLE:
|
|
g.exportable = 1;
|
|
break;
|
|
case OPT_WRAP_WITH_TRUSTED:
|
|
g.wrap_with_trusted = 1;
|
|
break;
|
|
case 'A':
|
|
g.all = 1;
|
|
break;
|
|
case 'H':
|
|
g.hex = 1;
|
|
break;
|
|
case 'T':
|
|
g.secret_type = optarg;
|
|
break;
|
|
case 'I':
|
|
g.secret_id = optarg;
|
|
break;
|
|
case 'e':
|
|
g.secret_name = optarg;
|
|
break;
|
|
case 'h':
|
|
print_help(command, sub_command);
|
|
return EXIT_SUCCESS;
|
|
case 'v':
|
|
util_prg_print_version();
|
|
return EXIT_SUCCESS;
|
|
default:
|
|
util_opt_print_parse_error(c, args);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (optind < arg_count) {
|
|
util_prg_print_arg_error(args[optind]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (cmd == NULL) {
|
|
misc_print_missing_command();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (cmd->sub_commands != NULL) {
|
|
misc_print_missing_sub_command();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (cmd->pos_arg != NULL) {
|
|
if (check_positional_arg(cmd) != EXIT_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (cmd->need_keystore ||
|
|
(cmd->pos_arg_optional && g.pos_arg == NULL)) {
|
|
rc = open_keystore();
|
|
if (rc != EXIT_SUCCESS)
|
|
goto out;
|
|
}
|
|
|
|
if (cmd->need_cca_library) {
|
|
rc = load_cca_library(&g.cca, g.verbose);
|
|
if (rc != 0) {
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
if (cmd->need_ep11_library) {
|
|
rc = load_ep11_library(&g.ep11, g.verbose);
|
|
if (rc != 0) {
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
if (cmd->need_pkey_device) {
|
|
g.pkey_fd = open_pkey_device(g.verbose);
|
|
if (g.pkey_fd == -1) {
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
if (cmd->need_uv_device) {
|
|
g.uv_fd = uv_open_device(g.verbose);
|
|
if (g.uv_fd == -1) {
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (g.kms_info.plugin_lib != NULL) {
|
|
rc = init_kms_plugin(&g.kms_info, g.verbose);
|
|
if (rc != 0) {
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
|
|
if (cmd->need_kms_login) {
|
|
rc = perform_kms_login(&g.kms_info, g.verbose);
|
|
if (rc != 0) {
|
|
rc = EXIT_FAILURE;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
umask(0077);
|
|
|
|
rc = cmd->function();
|
|
|
|
out:
|
|
free_kms_plugin(&g.kms_info);
|
|
if (g.cca.lib_csulcca)
|
|
dlclose(g.cca.lib_csulcca);
|
|
if (g.ep11.lib_ep11)
|
|
dlclose(g.ep11.lib_ep11);
|
|
if (g.pkey_fd >= 0)
|
|
close(g.pkey_fd);
|
|
if (g.uv_fd >= 0)
|
|
close(g.uv_fd);
|
|
if (g.keystore)
|
|
keystore_free(g.keystore);
|
|
if (g.kms_options != NULL)
|
|
free(g.kms_options);
|
|
return rc;
|
|
}
|