Add libLUKS2.

This commit is contained in:
Milan Broz
2017-08-25 20:26:20 +02:00
parent 00b103c85c
commit 9f2727bb77
27 changed files with 9281 additions and 404 deletions

View File

@@ -22,6 +22,7 @@
*/
#include "cryptsetup.h"
#include <uuid/uuid.h>
static const char *opt_cipher = NULL;
static const char *opt_hash = NULL;
@@ -43,6 +44,8 @@ static long opt_new_keyfile_size = 0;
static long opt_keyfile_offset = 0;
static long opt_new_keyfile_offset = 0;
static int opt_key_slot = CRYPT_ANY_SLOT;
static int opt_token = CRYPT_ANY_TOKEN;
static int opt_token_only = 0;
static uint64_t opt_size = 0;
static uint64_t opt_offset = 0;
static uint64_t opt_skip = 0;
@@ -69,10 +72,21 @@ static int opt_veracrypt_query_pim = 0;
static int opt_deferred_remove = 0;
//FIXME: check uint32 overflow for long type
static const char *opt_pbkdf = NULL;
static long opt_pbkdf_memory = 1024;
static long opt_pbkdf_parallel = 2;
static long opt_pbkdf_memory = DEFAULT_LUKS2_MEMORY_KB;
static long opt_pbkdf_parallel = DEFAULT_LUKS2_PARALLEL_THREADS;
static long opt_pbkdf_iterations = 0;
static int opt_iteration_time = 0;
static int opt_disable_locks = 0;
static int opt_disable_keyring = 0;
static const char *opt_priority = NULL; /* normal */
static const char *opt_integrity = NULL; /* none */
static int opt_integrity_nojournal = 0;
static int opt_integrity_no_wipe = 0;
static const char *opt_key_description = NULL;
static int opt_sector_size = 512;
static int opt_persistent = 0;
static const char *opt_label = NULL;
static const char *opt_subsystem = NULL;
static const char **action_argv;
static int action_argc;
@@ -86,6 +100,23 @@ static const char *uuid_or_device_header(const char **data_device)
return uuid_or_device(opt_header_device ?: action_argv[0]);
}
static const char *luksType(const char *type)
{
if (type && !strcmp(type, "luks2"))
return CRYPT_LUKS2;
if (type && !strcmp(type, "luks1"))
return CRYPT_LUKS1;
if (type && !strcmp(type, "luks"))
return CRYPT_LUKS; /* NULL */
if (type && *type)
return type;
return CRYPT_LUKS; /* NULL */
}
static int _verify_passphrase(int def)
{
/* Batch mode switch off verify - if not overrided by -y */
@@ -117,6 +148,13 @@ static void _set_activation_flags(uint32_t *flags)
if (opt_perf_submit_from_crypt_cpus)
*flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
if (opt_integrity_nojournal)
*flags |= CRYPT_ACTIVATE_NO_JOURNAL;
/* In persistent mode, we use what is set on command line */
if (opt_persistent)
*flags |= CRYPT_ACTIVATE_IGNORE_PERSISTENT;
}
static int action_open_plain(void)
@@ -449,12 +487,45 @@ static int action_close(void)
static int action_resize(void)
{
struct crypt_device *cd = NULL;
int r;
size_t passwordLen;
struct crypt_active_device cad;
char *password = NULL;
struct crypt_device *cd = NULL;
r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device);
if (r == 0)
r = crypt_resize(cd, action_argv[0], opt_size);
if (r == 0) {
r = crypt_get_active_device(cd, action_argv[0], &cad);
if (!r && (cad.flags & CRYPT_ACTIVATE_KEYRING_KEY)) {
if (opt_disable_keyring) {
r = -EINVAL;
log_err(_("Resize of active device requires volume key in keyring but --disable-keyring option is set.\n"));
goto out;
}
/* try load VK in kernel keyring using token */
r = crypt_activate_by_token(cd, NULL, opt_token, NULL, CRYPT_ACTIVATE_KEYRING_KEY);
if (r < 0) {
if (opt_token_only)
goto out;
r = tools_get_key(NULL, &password, &passwordLen,
opt_keyfile_offset, opt_keyfile_size, opt_key_file,
opt_timeout, _verify_passphrase(0), 0, cd);
if (r < 0)
goto out;
r = crypt_activate_by_passphrase(cd, NULL, opt_key_slot, password, passwordLen, CRYPT_ACTIVATE_KEYRING_KEY);
crypt_safe_free(password);
}
}
if (r >= 0)
r = crypt_resize(cd, action_argv[0], opt_size);
}
out:
crypt_free(cd);
return r;
@@ -464,6 +535,7 @@ static int action_status(void)
{
crypt_status_info ci;
struct crypt_active_device cad;
struct crypt_params_integrity ip = {};
struct crypt_device *cd = NULL;
char *backing_file;
const char *device;
@@ -504,8 +576,17 @@ static int action_status(void)
if (r < 0)
goto out;
r = crypt_get_integrity_info(cd, &ip);
if (r < 0 && r != -ENOTSUP)
goto out;
log_std(" cipher: %s-%s\n", crypt_get_cipher(cd), crypt_get_cipher_mode(cd));
log_std(" keysize: %d bits\n", crypt_get_volume_key_size(cd) * 8);
log_std(" key location: %s\n", (cad.flags & CRYPT_ACTIVATE_KEYRING_KEY) ? "keyring" : "dm-crypt");
if (ip.integrity)
log_std(" integrity: %s\n", ip.integrity);
if (ip.integrity_key_size)
log_std(" integrity keysize: %d bits\n", ip.integrity_key_size * 8);
device = crypt_get_device_name(cd);
log_std(" device: %s\n", device);
if (crypt_loop_device(device)) {
@@ -513,6 +594,7 @@ static int action_status(void)
log_std(" loop: %s\n", backing_file);
free(backing_file);
}
log_std(" sector size: %d\n", crypt_get_sector_size(cd));
log_std(" offset: %" PRIu64 " sectors\n", cad.offset);
log_std(" size: %" PRIu64 " sectors\n", cad.size);
if (cad.iv_offset)
@@ -569,7 +651,7 @@ static int action_benchmark_kdf(const char *kdf, const char *hash, size_t key_si
} else {
struct crypt_pbkdf_type pbkdf = {
.type = kdf,
.time_ms = opt_iteration_time ?: 800,
.time_ms = opt_iteration_time ?: DEFAULT_LUKS2_ITER_TIME,
.max_memory_kb = opt_pbkdf_memory,
.parallel_threads = opt_pbkdf_parallel,
};
@@ -765,6 +847,14 @@ static int set_pbkdf_params(struct crypt_device *cd, const char *dev_type)
pbkdf.type = CRYPT_KDF_PBKDF2;
pbkdf.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
pbkdf.time_ms = opt_iteration_time ?: DEFAULT_LUKS1_ITER_TIME;
} else if (!strcmp(dev_type, CRYPT_LUKS2)) {
pbkdf.type = opt_pbkdf ?: DEFAULT_LUKS2_PBKDF;
pbkdf.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
pbkdf.time_ms = opt_iteration_time ?: DEFAULT_LUKS2_ITER_TIME;
if (strcmp(pbkdf.type, CRYPT_KDF_PBKDF2)) {
pbkdf.max_memory_kb = opt_pbkdf_memory;
pbkdf.parallel_threads = opt_pbkdf_parallel;
}
} else
return 0;
@@ -784,9 +874,8 @@ static int action_luksRepair(void)
if ((r = crypt_init(&cd, action_argv[0])))
goto out;
/* Currently only LUKS1 allows repair */
crypt_set_log_callback(cd, quiet_log, NULL);
r = crypt_load(cd, CRYPT_LUKS1, NULL);
r = crypt_load(cd, luksType(opt_type), NULL);
crypt_set_log_callback(cd, tool_log, NULL);
if (r == 0) {
log_verbose(_("No known problems detected for LUKS header.\n"));
@@ -796,18 +885,53 @@ static int action_luksRepair(void)
r = yesDialog(_("Really try to repair LUKS device header?"),
NULL) ? 0 : -EINVAL;
if (r == 0)
r = crypt_repair(cd, CRYPT_LUKS1, NULL);
r = crypt_repair(cd, luksType(opt_type), NULL);
out:
crypt_free(cd);
return r;
}
static int _wipe_data_device(struct crypt_device *cd)
{
char tmp_name[64], tmp_path[128], tmp_uuid[40];
uuid_t tmp_uuid_bin;
int r;
if (!opt_batch_mode)
log_std(_("Wiping device to initialize integrity checksum.\n"
"You can interrupt this by pressing CTRL+c "
"(rest of not wiped device will contain invalid checksum).\n"));
/* Activate the device a temporary one */
uuid_generate(tmp_uuid_bin);
uuid_unparse(tmp_uuid_bin, tmp_uuid);
if (snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid) < 0)
return -EINVAL;
if (snprintf(tmp_path, sizeof(tmp_path), "%s/%s", crypt_get_dir(), tmp_name) < 0)
return -EINVAL;
r = crypt_activate_by_volume_key(cd, tmp_name, NULL, 0,
CRYPT_ACTIVATE_PRIVATE | CRYPT_ACTIVATE_NO_JOURNAL);
if (r < 0)
return r;
/* Wipe the device */
set_int_handler(0);
r = crypt_wipe(cd, tmp_path, CRYPT_WIPE_ZERO, 0, 0, DEFAULT_WIPE_BLOCK,
0, &tools_wipe_progress, NULL);
if (crypt_deactivate(cd, tmp_name))
log_err(_("Cannot deactivate temporary device %s.\n"), tmp_path);
set_int_block(0);
return r;
}
static int action_luksFormat(void)
{
int r = -EINVAL, keysize;
int r = -EINVAL, keysize, integrity_keysize = 0, luks_version;
const char *header_device;
char *msg = NULL, *key = NULL, cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *password = NULL;
char *msg = NULL, *key = NULL, *password = NULL;
char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN], integrity[MAX_CIPHER_LEN];
size_t passwordLen;
struct crypt_device *cd = NULL;
struct crypt_params_luks1 params = {
@@ -815,6 +939,25 @@ static int action_luksFormat(void)
.data_alignment = opt_align_payload,
.data_device = opt_header_device ? action_argv[0] : NULL,
};
struct crypt_params_luks2 params2 = {
.data_alignment = params.data_alignment,
.data_device = params.data_device,
.sector_size = opt_sector_size,
.label = opt_label,
.subsystem = opt_subsystem
};
if (!opt_type)
return -EINVAL;
else if (!strcmp(opt_type, "luks2"))
luks_version = 2;
else
luks_version = 1;
if (opt_sector_size > 512 && luks_version == 1) {
log_err(_("Unsupported encryption sector size.\n"));
return -EINVAL;
}
header_device = opt_header_device ?: action_argv[0];
@@ -836,6 +979,16 @@ static int action_luksFormat(void)
goto out;
}
if (luks_version == 2 && opt_integrity) {
r = crypt_parse_integrity_mode(opt_integrity, integrity, &integrity_keysize);
if (r < 0) {
log_err(_("No known integrity specification pattern detected.\n"));
goto out;
}
params2.integrity = integrity;
/* FIXME: we use default integrity_params (set to NULL) */
}
/* Never call pwquality if using null cipher */
if (tools_is_cipher_null(cipher))
opt_force_password = 1;
@@ -846,7 +999,7 @@ static int action_luksFormat(void)
goto out;
}
keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8;
keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8 + integrity_keysize;
if (opt_random)
crypt_set_rng_type(cd, CRYPT_RNG_RANDOM);
@@ -865,14 +1018,21 @@ static int action_luksFormat(void)
goto out;
}
r = set_pbkdf_params(cd, CRYPT_LUKS1);
if (luks_version == 1)
r = set_pbkdf_params(cd, CRYPT_LUKS1);
else
r = set_pbkdf_params(cd, CRYPT_LUKS2);
if (r) {
log_err(_("Failed to set pbkdf parameters.\n"));
goto out;
}
r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
opt_uuid, key, keysize, &params);
if (luks_version == 1)
r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
opt_uuid, key, keysize, &params);
else
r = crypt_format(cd, CRYPT_LUKS2, cipher, cipher_mode,
opt_uuid, key, keysize, &params2);
check_signal(&r);
if (r < 0)
goto out;
@@ -880,6 +1040,11 @@ static int action_luksFormat(void)
r = crypt_keyslot_add_by_volume_key(cd, opt_key_slot,
key, keysize,
password, passwordLen);
if (r < 0)
goto out;
if (opt_integrity && !opt_integrity_no_wipe)
r = _wipe_data_device(cd);
out:
crypt_free(cd);
crypt_safe_free(key);
@@ -905,7 +1070,7 @@ static int action_open_luks(void)
if ((r = crypt_init(&cd, header_device)))
goto out;
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
if (data_device &&
@@ -928,6 +1093,10 @@ static int action_open_luks(void)
r = crypt_activate_by_volume_key(cd, activated_name,
key, keysize, activate_flags);
} else {
r = crypt_activate_by_token(cd, activated_name, opt_token, NULL, activate_flags);
if (r >= 0 || opt_token_only)
goto out;
tries = (opt_key_file && !tools_is_stdin(opt_key_file)) ? 1 : opt_tries;
do {
r = tools_get_key(NULL, &password, &passwordLen,
@@ -945,6 +1114,11 @@ static int action_open_luks(void)
} while ((r == -EPERM || r == -ERANGE) && (--tries > 0));
}
out:
if (r >= 0 && opt_persistent &&
crypt_persistent_flags_set(cd, CRYPT_FLAGS_ACTIVATION, activate_flags))
log_err(_("Device activated but cannot make flags persistent.\n"));
crypt_safe_free(key);
crypt_safe_free(password);
crypt_free(cd);
@@ -959,7 +1133,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
crypt_keyslot_info ki;
char *password = NULL;
size_t passwordLen;
int i, r;
int i, max, r;
ki = crypt_keyslot_status(cd, key_slot);
if (ki == CRYPT_SLOT_ACTIVE_LAST && !opt_batch_mode && !key_file &&
@@ -969,7 +1143,7 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
r = tools_get_key(msg_pass, &password, &passwordLen,
keyfile_offset, keyfile_size, key_file, opt_timeout,
_verify_passphrase(0), 0, cd);
if(r < 0)
if (r < 0)
goto out;
if (ki == CRYPT_SLOT_ACTIVE_LAST) {
@@ -978,13 +1152,18 @@ static int verify_keyslot(struct crypt_device *cd, int key_slot,
password, passwordLen, 0);
} else {
/* try all other keyslots */
for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1); i++) {
r = crypt_keyslot_max(crypt_get_type(cd));
if (r < 0)
goto out;
max = r;
for (i = 0; i < max ; i++) {
if (i == key_slot)
continue;
ki = crypt_keyslot_status(cd, key_slot);
if (ki == CRYPT_SLOT_ACTIVE)
r = crypt_activate_by_passphrase(cd, NULL, i,
password, passwordLen, 0);
ki = crypt_keyslot_status(cd, i);
if (ki == CRYPT_SLOT_ACTIVE || ki == CRYPT_SLOT_ACTIVE_LAST)
r = crypt_activate_by_passphrase(cd, NULL, i,
password, passwordLen, 0);
if (r == i)
break;
}
@@ -1011,21 +1190,9 @@ static int action_luksKillSlot(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
switch (crypt_keyslot_status(cd, opt_key_slot)) {
case CRYPT_SLOT_ACTIVE_LAST:
case CRYPT_SLOT_ACTIVE:
log_verbose(_("Key slot %d selected for deletion.\n"), opt_key_slot);
break;
case CRYPT_SLOT_INACTIVE:
log_err(_("Key %d not active. Can't wipe.\n"), opt_key_slot);
case CRYPT_SLOT_INVALID:
r = -EINVAL;
goto out;
}
if (!opt_batch_mode || opt_key_file || !isatty(STDIN_FILENO)) {
r = verify_keyslot(cd, opt_key_slot,
_("This is the last keyslot. Device will become unusable after purging this key."),
@@ -1059,7 +1226,7 @@ static int action_luksRemoveKey(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
r = tools_get_key(_("Enter passphrase to be deleted: "),
@@ -1109,7 +1276,7 @@ static int action_luksAddKey(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
/* Never call pwquality if using null cipher */
@@ -1194,7 +1361,7 @@ static int action_luksChangeKey(void)
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
goto out;
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
/* Never call pwquality if using null cipher */
@@ -1253,7 +1420,7 @@ static int action_isLuks(void)
goto out;
crypt_set_log_callback(cd, quiet_log, NULL);
r = crypt_load(cd, CRYPT_LUKS1, NULL);
r = crypt_load(cd, luksType(opt_type), NULL);
out:
crypt_free(cd);
return r;
@@ -1270,7 +1437,7 @@ static int action_luksUUID(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
if (opt_uuid)
@@ -1347,7 +1514,7 @@ static int action_luksDump(void)
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
goto out;
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
if (opt_dump_master_key)
@@ -1382,7 +1549,7 @@ static int action_luksResume(void)
if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(opt_header_device))))
goto out;
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
tries = (opt_key_file && !tools_is_stdin(opt_key_file)) ? 1 : opt_tries;
@@ -1421,7 +1588,7 @@ static int action_luksBackup(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
r = crypt_header_backup(cd, CRYPT_LUKS1, opt_header_backup_file);
r = crypt_header_backup(cd, NULL, opt_header_backup_file);
out:
crypt_free(cd);
return r;
@@ -1441,7 +1608,7 @@ static int action_luksRestore(void)
goto out;
crypt_set_confirm_callback(cd, yesDialog, NULL);
r = crypt_header_restore(cd, CRYPT_LUKS1, opt_header_backup_file);
r = crypt_header_restore(cd, NULL, opt_header_backup_file);
out:
crypt_free(cd);
return r;
@@ -1452,7 +1619,9 @@ static int action_open(void)
if (!opt_type)
return -EINVAL;
if (!strcmp(opt_type, "luks") || !strcmp(opt_type, "luks1")) {
if (!strcmp(opt_type, "luks") ||
!strcmp(opt_type, "luks1") ||
!strcmp(opt_type, "luks2")) {
if (action_argc < 2 && !opt_test_passphrase)
goto args;
return action_open_luks();
@@ -1482,14 +1651,14 @@ static int action_luksErase(void)
struct crypt_device *cd = NULL;
crypt_keyslot_info ki;
char *msg = NULL;
int i, r;
int i, max, r;
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
goto out;
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS1, NULL)))
if ((r = crypt_load(cd, luksType(opt_type), NULL)))
goto out;
if(asprintf(&msg, _("This operation will erase all keyslots on device %s.\n"
@@ -1504,7 +1673,12 @@ static int action_luksErase(void)
goto out;
}
for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1); i++) {
/* Safety check */
max = crypt_keyslot_max(crypt_get_type(cd));
if (max <= 0)
return -EINVAL;
for (i = 0; i < max; i++) {
ki = crypt_keyslot_status(cd, i);
if (ki == CRYPT_SLOT_ACTIVE || ki == CRYPT_SLOT_ACTIVE_LAST) {
r = crypt_keyslot_destroy(cd, i);
@@ -1518,6 +1692,182 @@ out:
return r;
}
static int action_luksConvert(void)
{
struct crypt_device *cd = NULL;
char *msg = NULL;
const char *to_type, *from_type;
int r;
if (!strcmp(opt_type, "luks2")) {
to_type = CRYPT_LUKS2;
} else if (!strcmp(opt_type, "luks1")) {
to_type = CRYPT_LUKS1;
} else {
log_err(_("Missing LUKS target type, option --type is required.\n"));
return -EINVAL;
}
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
return r;
crypt_set_confirm_callback(cd, yesDialog, NULL);
if ((r = crypt_load(cd, CRYPT_LUKS, NULL)) ||
!(from_type = crypt_get_type(cd))) {
crypt_free(cd);
return r;
}
if (!strcmp(from_type, to_type)) {
log_err(_("Device is already %s type.\n"), to_type);
crypt_free(cd);
return -EINVAL;
}
if (asprintf(&msg, _("This operation will convert %s to %s format.\n"),
uuid_or_device_header(NULL), to_type) == -1) {
crypt_free(cd);
return -ENOMEM;
}
if (yesDialog(msg, NULL))
r = crypt_convert(cd, to_type, NULL);
else
r = -EPERM;
free(msg);
crypt_free(cd);
return r;
}
static int _config_priority(struct crypt_device *cd)
{
crypt_keyslot_info cs;
crypt_keyslot_priority priority = CRYPT_SLOT_PRIORITY_INVALID;
if (!strcmp("normal", opt_priority))
priority = CRYPT_SLOT_PRIORITY_NORMAL;
else if (!strcmp("prefer", opt_priority))
priority = CRYPT_SLOT_PRIORITY_PREFER;
else if (!strcmp("ignore", opt_priority))
priority = CRYPT_SLOT_PRIORITY_IGNORE;
cs = crypt_keyslot_status(cd, opt_key_slot);
if (cs != CRYPT_SLOT_INVALID)
return crypt_keyslot_set_priority(cd, opt_key_slot, priority);
return -EINVAL;
}
static int _config_labels(struct crypt_device *cd)
{
return crypt_set_label(cd, opt_label, opt_subsystem);
}
static int action_luksConfig(void)
{
struct crypt_device *cd = NULL;
int r;
if (!opt_priority && !opt_label && !opt_subsystem) {
log_err(_("Option --priority, --label or --subsystem is missing.\n"));
return -EINVAL;
}
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
return r;
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL)))
goto out;
if (opt_priority && (r = _config_priority(cd)))
goto out;
if ((opt_label || opt_subsystem) && (r = _config_labels(cd)))
goto out;
out:
crypt_free(cd);
return r;
}
static int _token_add(struct crypt_device *cd)
{
int r, token;
crypt_token_info token_info;
const struct crypt_token_params_luks2_keyring params = {
.key_description = opt_key_description
};
if (opt_token != CRYPT_ANY_TOKEN) {
token_info = crypt_token_status(cd, opt_token, NULL);
if (token_info < CRYPT_TOKEN_INACTIVE) {
log_err(_("Token %d is invalid.\n"), opt_token);
return -EINVAL;
} else if (token_info > CRYPT_TOKEN_INACTIVE) {
log_err(_("Token %d in use.\n"), opt_token);
return -EINVAL;
}
}
r = crypt_token_luks2_keyring_set(cd, opt_token, &params);
if (r < 0)
return r;
token = r;
r = crypt_token_assign_keyslot(cd, token, opt_key_slot);
if (r < 0) {
log_err(_("Failed to assign token %d to keyslot %d.\n"), token, opt_key_slot);
(void) crypt_token_json_set(cd, token, NULL);
}
return r;
}
static int action_token(void)
{
int add, r;
struct crypt_device *cd = NULL;
if (!strcmp(action_argv[0], "add")) {
if (!opt_key_description) {
log_err(_("--key-description parameter is mandatory for token add action.\n"));
return -EINVAL;
}
add = 1;
} else if (!strcmp(action_argv[0], "remove")) {
if (opt_token == CRYPT_ANY_TOKEN) {
log_err(_("Missing --token option specifying token for removal.\n"));
return -EINVAL;
}
add = 0;
} else {
log_err(_("Invalid token operation %s.\n"), action_argv[0]);
return -EINVAL;
}
if ((r = crypt_init(&cd, uuid_or_device(opt_header_device ?: action_argv[1]))))
return r;
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL))) {
crypt_free(cd);
return r;
}
r = add ? _token_add(cd) : crypt_token_json_set(cd, opt_token, NULL);
if (r < 0) {
if (add)
log_err(_("Failed to add keyring token %d.\n"), opt_token);
else
log_err(_("Failed to remove token %d.\n"), opt_token);
}
crypt_free(cd);
return r;
}
static struct action_type {
const char *type;
int (*handler)(void);
@@ -1533,6 +1883,8 @@ static struct action_type {
{ "benchmark", action_benchmark, 0, 0, N_("[--cipher <cipher>]"), N_("benchmark cipher") },
{ "repair", action_luksRepair, 1, 1, N_("<device>"), N_("try to repair on-disk metadata") },
{ "erase", action_luksErase , 1, 1, N_("<device>"), N_("erase all keyslots (remove encryption key)") },
{ "convert", action_luksConvert, 1, 1, N_("<device>"), N_("convert LUKS from/to LUKS2 format") },
{ "config", action_luksConfig, 1, 1, N_("<device>"), N_("set permanent configuration options for LUKS2") },
{ "luksFormat", action_luksFormat, 1, 1, N_("<device> [<new key file>]"), N_("formats a LUKS device") },
{ "luksAddKey", action_luksAddKey, 1, 1, N_("<device> [<new key file>]"), N_("add key to LUKS device") },
{ "luksRemoveKey",action_luksRemoveKey,1, 1, N_("<device> [<key file>]"), N_("removes supplied key or key file from LUKS device") },
@@ -1546,6 +1898,7 @@ static struct action_type {
{ "luksResume", action_luksResume, 1, 1, N_("<device>"), N_("Resume suspended LUKS device.") },
{ "luksHeaderBackup", action_luksBackup,1,1, N_("<device>"), N_("Backup LUKS device header and keyslots") },
{ "luksHeaderRestore",action_luksRestore,1,1,N_("<device>"), N_("Restore LUKS device header and keyslots") },
{ "token", action_token, 2, 0, N_("<add|remove> <device>"), N_("Add or remove keyring token") },
{}
};
@@ -1582,9 +1935,12 @@ static void help(poptContext popt_context,
log_std(_("\nDefault compiled-in key and passphrase parameters:\n"
"\tMaximum keyfile size: %dkB, "
"Maximum interactive passphrase length %d (characters)\n"
"Default PBKDF2 iteration time for LUKS: %d (ms)\n"),
"Default PBKDF2 iteration time for LUKS: %d (ms)\n"
"Default PBKDF for LUKS2: %s\n"
"\tIteration time: %d, Memory required: %dkB, Parallel threads: %d\n"),
DEFAULT_KEYFILE_SIZE_MAXKB, DEFAULT_PASSPHRASE_SIZE_MAX,
DEFAULT_LUKS1_ITER_TIME);
DEFAULT_LUKS1_ITER_TIME, DEFAULT_LUKS2_PBKDF, DEFAULT_LUKS2_ITER_TIME,
DEFAULT_LUKS2_MEMORY_KB, DEFAULT_LUKS2_PARALLEL_THREADS);
log_std(_("\nDefault compiled-in device cipher parameters:\n"
"\tloop-AES: %s, Key %d bits\n"
@@ -1689,6 +2045,19 @@ int main(int argc, const char **argv)
{ "pbkdf-memory", '\0', POPT_ARG_LONG, &opt_pbkdf_memory, 0, N_("PBKDF memory cost limit"), N_("kilobytes") },
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("PBKDF parallel cost "), N_("threads") },
{ "pbkdf-force-iterations",'\0',POPT_ARG_LONG, &opt_pbkdf_iterations, 0, N_("PBKDF iterations cost (forced, disables benchmark)"), NULL },
{ "priority", '\0', POPT_ARG_STRING, &opt_priority, 0, N_("Keyslot priority (ignore/normal/prefer)"), NULL },
{ "disable-locks", '\0', POPT_ARG_NONE, &opt_disable_locks, 0, N_("Disable locking of on-disk metadata"), NULL },
{ "disable-keyring", '\0', POPT_ARG_NONE, &opt_disable_keyring, 0, N_("Disable loading volume keys via kernel keyring"), NULL },
{ "integrity", 'I', POPT_ARG_STRING, &opt_integrity, 0, N_("Data integrity algorithm (LUKS2 only)"), NULL },
{ "integrity-no-journal",'\0',POPT_ARG_NONE, &opt_integrity_nojournal, 0, N_("Disable journal for integrity device."), NULL },
{ "integrity-no-wipe", '\0', POPT_ARG_NONE, &opt_integrity_no_wipe, 0, N_("Do not wipe device after format"), NULL },
{ "token-only", '\0', POPT_ARG_NONE, &opt_token_only, 0, N_("Do not ask for passphrase if activation by token fails"), NULL },
{ "token-id", '\0', POPT_ARG_INT, &opt_token, 0, N_("Token number (default: any)"), NULL },
{ "key-description", '\0', POPT_ARG_STRING, &opt_key_description, 0, N_("Key description"), NULL },
{ "sector-size", '\0', POPT_ARG_INT, &opt_sector_size, 0, N_("Encryption sector size (default: 512 bytes)"), NULL },
{ "persistent", '\0', POPT_ARG_NONE, &opt_persistent, 0, N_("Set activation flags persistent for device."), NULL },
{ "label", '\0', POPT_ARG_STRING, &opt_label, 0, N_("Set label for the LUKS2 device."), NULL },
{ "subsystem", '\0', POPT_ARG_STRING, &opt_subsystem, 0, N_("Set subsystem label for the LUKS2 device."), NULL },
POPT_TABLEEND
};
poptContext popt_context;
@@ -1801,6 +2170,9 @@ int main(int argc, const char **argv)
} else if (!strcmp(aname, "luksErase")) {
aname = "erase";
opt_type = "luks";
} else if (!strcmp(aname, "luksConfig")) {
aname = "config";
opt_type = "luks2";
}
for(action = action_types; action->type; action++)
@@ -1831,6 +2203,11 @@ int main(int argc, const char **argv)
_("Option --allow-discards is allowed only for open operation.\n"),
poptGetInvocationName(popt_context));
if (opt_persistent && strcmp(aname, "open"))
usage(popt_context, EXIT_FAILURE,
_("Option --persistent is allowed only for open operation.\n"),
poptGetInvocationName(popt_context));
if (opt_key_size &&
strcmp(aname, "luksFormat") &&
strcmp(aname, "open") &&
@@ -1840,8 +2217,24 @@ int main(int argc, const char **argv)
"To limit read from keyfile use --keyfile-size=(bytes)."),
poptGetInvocationName(popt_context));
if (opt_integrity && strcmp(aname, "luksFormat"))
usage(popt_context, EXIT_FAILURE,
_("Option --integrity is allowed only for luksFormat (LUKS2).\n"),
poptGetInvocationName(popt_context));
if (opt_integrity_no_wipe && !opt_integrity)
usage(popt_context, EXIT_FAILURE,
_("Option --integrity-no-wipe"
" can be used only for format action with integrity extension.\n"),
poptGetInvocationName(popt_context));
if ((opt_label || opt_subsystem) && strcmp(aname, "luksFormat") && strcmp(aname, "config"))
usage(popt_context, EXIT_FAILURE,
_("Options --label and --subsystem are allowed only for luksFormat and config LUKS2 operations.\n"),
poptGetInvocationName(popt_context));
if (opt_test_passphrase && (strcmp(aname, "open") ||
(strcmp(opt_type, "luks") && strcmp(opt_type, "tcrypt"))))
(strncmp(opt_type, "luks", 4) && strcmp(opt_type, "tcrypt"))))
usage(popt_context, EXIT_FAILURE,
_("Option --test-passphrase is allowed only for open of LUKS and TCRYPT devices.\n"),
poptGetInvocationName(popt_context));
@@ -1853,8 +2246,7 @@ int main(int argc, const char **argv)
if (!strcmp(aname, "luksKillSlot") && action_argc > 1)
opt_key_slot = atoi(action_argv[1]);
if (opt_key_slot != CRYPT_ANY_SLOT &&
(opt_key_slot < 0 || opt_key_slot >= crypt_keyslot_max(CRYPT_LUKS1)))
if (opt_key_slot != CRYPT_ANY_SLOT && opt_key_slot < 0)
usage(popt_context, EXIT_FAILURE, _("Key slot is invalid."),
poptGetInvocationName(popt_context));
@@ -1945,9 +2337,19 @@ int main(int argc, const char **argv)
}
}
if (opt_priority && strcmp(opt_priority, "normal") && strcmp(opt_priority, "prefer") && strcmp(opt_priority, "ignore"))
usage(popt_context, EXIT_FAILURE,
_("Option --priority can be only ignore/normal/prefer.\n"),
poptGetInvocationName(popt_context));
if (!strcmp(aname, "config") && opt_priority && opt_key_slot == CRYPT_ANY_SLOT)
usage(popt_context, EXIT_FAILURE,
_("Keyslot specification is required.\n"),
poptGetInvocationName(popt_context));
if (opt_pbkdf && crypt_parse_pbkdf(opt_pbkdf, &opt_pbkdf))
usage(popt_context, EXIT_FAILURE,
_("PBKDF can be only pbkdf2 or argon2i/argon2id.\n"),
_("Password-based key derivation function (PBKDF) can be only pbkdf2 or argon2i/argon2id.\n"),
poptGetInvocationName(popt_context));
if (opt_pbkdf_iterations && opt_iteration_time)
@@ -1955,12 +2357,27 @@ int main(int argc, const char **argv)
_("PBKDF forced iterations cannot be combined with iteration time option.\n"),
poptGetInvocationName(popt_context));
if ((opt_sector_size != 512 && strcmp(aname, "luksFormat")) || opt_sector_size < 512
|| opt_sector_size > 4096 || (opt_sector_size & (opt_sector_size - 1)))
usage(popt_context, EXIT_FAILURE,
_("Unsupported encryption sector size.\n"),
poptGetInvocationName(popt_context));
if (opt_debug) {
opt_verbose = 1;
crypt_set_debug_level(-1);
dbg_version_and_cmd(argc, argv);
}
if (opt_disable_locks && crypt_metadata_locking(NULL, 0)) {
log_std(_("Cannot disable metadata locking.\n"));
poptFreeContext(popt_context);
exit(EXIT_FAILURE);
}
if (opt_disable_keyring)
(void) crypt_volume_key_keyring(NULL, 0);
r = run_action(action);
poptFreeContext(popt_context);
return r;