summaryrefslogtreecommitdiffstats
path: root/src/cryptsetup.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 08:35:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 08:35:41 +0000
commitf7458043ae6a2d2d54b911fac52e50341646bef2 (patch)
tree6c58e084cd8728490fd5bb8eead07db0be0038f4 /src/cryptsetup.c
parentAdding upstream version 2:2.6.1. (diff)
downloadcryptsetup-f7458043ae6a2d2d54b911fac52e50341646bef2.tar.xz
cryptsetup-f7458043ae6a2d2d54b911fac52e50341646bef2.zip
Adding upstream version 2:2.7.0.upstream/2%2.7.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cryptsetup.c')
-rw-r--r--src/cryptsetup.c637
1 files changed, 556 insertions, 81 deletions
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index e387c1c..a46e2dd 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -3,8 +3,8 @@
*
* Copyright (C) 2004 Jana Saout <jana@saout.de>
* Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
- * Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2009-2023 Milan Broz
+ * Copyright (C) 2009-2024 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2009-2024 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -28,9 +28,13 @@
#include "utils_luks.h"
static char *keyfiles[MAX_KEYFILES];
+static char *keyring_links[MAX_KEYRING_LINKS];
+static char *vks_in_keyring[MAX_VK_IN_KEYRING];
static char *keyfile_stdin = NULL;
static int keyfiles_count = 0;
+static int keyring_links_count = 0;
+static int vks_in_keyring_count = 0;
int64_t data_shift = 0;
const char *device_type = "luks";
@@ -57,6 +61,10 @@ void tools_cleanup(void)
while (keyfiles_count)
free(keyfiles[--keyfiles_count]);
+ while (keyring_links_count)
+ free(keyring_links[--keyring_links_count]);
+ while (vks_in_keyring_count)
+ free(vks_in_keyring[--vks_in_keyring_count]);
total_keyfiles = 0;
}
@@ -89,27 +97,49 @@ static int _set_keyslot_encryption_params(struct crypt_device *cd)
return crypt_keyslot_set_encryption(cd, ARG_STR(OPT_KEYSLOT_CIPHER_ID), ARG_UINT32(OPT_KEYSLOT_KEY_SIZE_ID) / 8);
}
-static int _try_token_pin_unlock(struct crypt_device *cd,
- int token_id,
- const char *activated_name,
- const char *token_type,
- uint32_t activate_flags,
- int tries,
- bool activation)
+static int _try_token_unlock(struct crypt_device *cd,
+ int keyslot,
+ int token_id,
+ const char *activated_name,
+ const char *token_type,
+ uint32_t activate_flags,
+ int tries,
+ bool activation,
+ bool token_only)
{
+ int r;
+ struct crypt_keyslot_context *kc;
size_t pin_len;
char msg[64], *pin = NULL;
- int r;
assert(tries >= 1);
assert(token_id >= 0 || token_id == CRYPT_ANY_TOKEN);
+ assert(keyslot >= 0 || keyslot == CRYPT_ANY_SLOT);
+
+ r = crypt_keyslot_context_init_by_token(cd, token_id, token_type, NULL, 0, NULL, &kc);
+ if (r < 0)
+ return r;
+
+ if (activation)
+ r = crypt_activate_by_keyslot_context(cd, activated_name, keyslot, kc, CRYPT_ANY_SLOT, NULL, activate_flags);
+ else
+ r = crypt_resume_by_keyslot_context(cd, activated_name, keyslot, kc);
+
+ tools_keyslot_msg(r, UNLOCKED);
+ tools_token_error_msg(r, token_type, token_id, false);
+
+ /* Token requires PIN (-ENOANO). Ask for it if there is evident preference for tokens */
+ if (r != -ENOANO || (!token_only && !token_type && token_id == CRYPT_ANY_TOKEN))
+ goto out;
if (token_id == CRYPT_ANY_TOKEN)
r = snprintf(msg, sizeof(msg), _("Enter token PIN: "));
else
r = snprintf(msg, sizeof(msg), _("Enter token %d PIN: "), token_id);
- if (r < 0 || (size_t)r >= sizeof(msg))
- return -EINVAL;
+ if (r < 0 || (size_t)r >= sizeof(msg)) {
+ r = -EINVAL;
+ goto out;
+ }
do {
r = tools_get_key(msg, &pin, &pin_len, 0, 0, NULL,
@@ -117,20 +147,26 @@ static int _try_token_pin_unlock(struct crypt_device *cd,
if (r < 0)
break;
+ r = crypt_keyslot_context_set_pin(cd, pin, pin_len, kc);
+ if (r < 0) {
+ crypt_safe_free(pin);
+ break;
+ }
+
if (activation)
- r = crypt_activate_by_token_pin(cd, activated_name, token_type,
- token_id, pin, pin_len, NULL,
- activate_flags);
+ r = crypt_activate_by_keyslot_context(cd, activated_name, keyslot,
+ kc, CRYPT_ANY_SLOT, NULL, activate_flags);
else
- r = crypt_resume_by_token_pin(cd, activated_name, token_type,
- token_id, pin, pin_len, NULL);
+ r = crypt_resume_by_keyslot_context(cd, activated_name, keyslot, kc);
+
crypt_safe_free(pin);
pin = NULL;
tools_keyslot_msg(r, UNLOCKED);
- tools_token_error_msg(r, ARG_STR(OPT_TOKEN_TYPE_ID), token_id, true);
+ tools_token_error_msg(r, token_type, token_id, true);
check_signal(&r);
} while (r == -ENOANO && (--tries > 0));
-
+out:
+ crypt_keyslot_context_free(kc);
return r;
}
@@ -151,6 +187,7 @@ static int action_open_plain(void)
size_t passwordLen, key_size_max, signatures = 0,
key_size = (ARG_UINT32(OPT_KEY_SIZE_ID) ?: DEFAULT_PLAIN_KEYBITS) / 8;
uint32_t activate_flags = 0;
+ bool compat_warning = false;
int r;
r = crypt_parse_name_and_mode(ARG_STR(OPT_CIPHER_ID) ?: DEFAULT_CIPHER(PLAIN),
@@ -160,6 +197,23 @@ static int action_open_plain(void)
goto out;
}
+ /*
+ * Warn user if no cipher options and passphrase hashing is not specified.
+ * For keyfile, password hashing is not used, no need to print warning for missing --hash.
+ * Keep this enabled even in batch mode to fix scripts and avoid data corruption.
+ */
+ if (!ARG_SET(OPT_CIPHER_ID) || !ARG_SET(OPT_KEY_SIZE_ID)) {
+ log_err(_("WARNING: Using default options for cipher (%s-%s, key size %u bits) that could be incompatible with older versions."),
+ cipher, cipher_mode, key_size * 8);
+ compat_warning = true;
+ }
+ if (!ARG_SET(OPT_HASH_ID) && !ARG_SET(OPT_KEY_FILE_ID)) {
+ log_err(_("WARNING: Using default options for hash (%s) that could be incompatible with older versions."), params.hash);
+ compat_warning = true;
+ }
+ if (compat_warning)
+ log_err(_("For plain mode, always use options --cipher, --key-size and if no keyfile is used, then also --hash."));
+
/* FIXME: temporary hack, no hashing for keyfiles in plain mode */
if (ARG_SET(OPT_KEY_FILE_ID) && !tools_is_stdin(ARG_STR(OPT_KEY_FILE_ID))) {
params.hash = NULL;
@@ -204,11 +258,14 @@ static int action_open_plain(void)
goto out;
/* Skip blkid scan when activating plain device with offset */
- if (!ARG_UINT64(OPT_OFFSET_ID)) {
+ if (!ARG_UINT64(OPT_OFFSET_ID) && !ARG_SET(OPT_DISABLE_BLKID_ID)) {
/* Print all present signatures in read-only mode */
r = tools_detect_signatures(action_argv[0], PRB_FILTER_NONE, &signatures, ARG_SET(OPT_BATCH_MODE_ID));
- if (r < 0)
+ if (r < 0) {
+ if (r == -EIO)
+ log_err(_("Blkid scan failed for %s."), action_argv[0]);
goto out;
+ }
}
if (signatures && !ARG_SET(OPT_BATCH_MODE_ID)) {
@@ -829,6 +886,15 @@ static int action_resize(void)
else if (ARG_SET(OPT_SIZE_ID))
dev_size = ARG_UINT64(OPT_SIZE_ID);
+ if (ARG_SET(OPT_EXTERNAL_TOKENS_PATH_ID)) {
+ r = crypt_token_set_external_path(ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ if (r < 0) {
+ log_err(_("Failed to set external tokens path %s."),
+ ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ goto out;
+ }
+ }
+
if (cad.flags & CRYPT_ACTIVATE_KEYRING_KEY) {
if (ARG_SET(OPT_DISABLE_KEYRING_ID)) {
r = -EINVAL;
@@ -838,16 +904,9 @@ static int action_resize(void)
}
/* try load VK in kernel keyring using token */
- r = crypt_activate_by_token_pin(cd, NULL, ARG_STR(OPT_TOKEN_TYPE_ID),
- ARG_INT32(OPT_TOKEN_ID_ID), NULL, 0, NULL,
- CRYPT_ACTIVATE_KEYRING_KEY);
- tools_keyslot_msg(r, UNLOCKED);
- tools_token_error_msg(r, ARG_STR(OPT_TOKEN_TYPE_ID), ARG_INT32(OPT_TOKEN_ID_ID), false);
-
- /* Token requires PIN. Ask if there is evident preference for tokens */
- if (r == -ENOANO && (ARG_SET(OPT_TOKEN_ONLY_ID) || ARG_SET(OPT_TOKEN_TYPE_ID) ||
- ARG_SET(OPT_TOKEN_ID_ID)))
- r = _try_token_pin_unlock(cd, ARG_INT32(OPT_TOKEN_ID_ID), NULL, ARG_STR(OPT_TOKEN_TYPE_ID), CRYPT_ACTIVATE_KEYRING_KEY, 1, true);
+ r = _try_token_unlock(cd, ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_TOKEN_ID_ID),
+ NULL, ARG_STR(OPT_TOKEN_TYPE_ID), CRYPT_ACTIVATE_KEYRING_KEY,
+ 1, true, ARG_SET(OPT_TOKEN_ONLY_ID));
if (r >= 0 || quit || ARG_SET(OPT_TOKEN_ONLY_ID))
goto out;
@@ -883,7 +942,7 @@ static int action_status(void)
struct crypt_device *cd = NULL;
char *backing_file;
const char *device;
- int path = 0, r = 0;
+ int path = 0, r = 0, hw_enc;
/* perhaps a path, not a dm device name */
if (strchr(action_argv[0], '/'))
@@ -932,13 +991,33 @@ static int action_status(void)
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");
+ hw_enc = crypt_get_hw_encryption_type(cd);
+ if (hw_enc < 0) {
+ r = hw_enc;
+ goto out;
+ }
+
+ if (hw_enc == CRYPT_SW_ONLY) {
+ 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");
+ } else if (hw_enc == CRYPT_OPAL_HW_ONLY) {
+ log_std(" encryption: HW OPAL only\n");
+ log_std(" OPAL keysize: %d bits\n", crypt_get_hw_encryption_key_size(cd) * 8);
+ } else if (hw_enc == CRYPT_SW_AND_OPAL_HW) {
+ log_std(" encryption: dm-crypt over HW OPAL\n");
+ log_std(" OPAL keysize: %d bits\n", crypt_get_hw_encryption_key_size(cd) * 8);
+ 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) - crypt_get_hw_encryption_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);
+ if (ip.tag_size)
+ log_std(" integrity tag size: %u bytes\n", ip.tag_size);
device = crypt_get_device_name(cd);
log_std(" device: %s\n", device);
if ((backing_file = crypt_loop_backing_file(device))) {
@@ -1282,9 +1361,14 @@ static int action_luksRepair(void)
goto out;
}
- r = tools_detect_signatures(action_argv[0], PRB_FILTER_LUKS, NULL, ARG_SET(OPT_BATCH_MODE_ID));
- if (r < 0)
- goto out;
+ if (!ARG_SET(OPT_DISABLE_BLKID_ID)) {
+ r = tools_detect_signatures(action_argv[0], PRB_FILTER_LUKS, NULL, ARG_SET(OPT_BATCH_MODE_ID));
+ if (r < 0) {
+ if (r == -EIO)
+ log_err(_("Blkid scan failed for %s."), action_argv[0]);
+ goto out;
+ }
+ }
if (!ARG_SET(OPT_BATCH_MODE_ID) &&
!yesDialog(_("Really try to repair LUKS device header?"),
@@ -1353,12 +1437,13 @@ static int strcmp_or_null(const char *str, const char *expected)
int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_passwordLen)
{
- int r = -EINVAL, keysize, integrity_keysize = 0, fd, created = 0;
+ bool wipe_signatures = false;
+ int encrypt_type, r = -EINVAL, keysize, integrity_keysize = 0, fd, created = 0;
struct stat st;
const char *header_device, *type;
char *msg = NULL, *key = NULL, *password = NULL;
char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN], integrity[MAX_CIPHER_LEN];
- size_t passwordLen, signatures;
+ size_t passwordLen, signatures = 0;
struct crypt_device *cd = NULL;
struct crypt_params_luks1 params1 = {
.hash = ARG_STR(OPT_HASH_ID) ?: DEFAULT_LUKS1_HASH,
@@ -1372,6 +1457,9 @@ int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_password
.label = ARG_STR(OPT_LABEL_ID),
.subsystem = ARG_STR(OPT_SUBSYSTEM_ID)
};
+ struct crypt_params_hw_opal opal_params = {
+ .user_key_size = DEFAULT_LUKS1_KEYBITS / 8
+ };
void *params;
type = luksType(device_type);
@@ -1397,6 +1485,11 @@ int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_password
log_err(_("Unsupported LUKS2 metadata size options."));
return -EINVAL;
}
+
+ if (ARG_SET(OPT_HW_OPAL_ID) || ARG_SET(OPT_HW_OPAL_ONLY_ID)) {
+ log_err(_("OPAL is supported only for LUKS2 format."));
+ return -EINVAL;
+ }
} else
return -EINVAL;
@@ -1466,9 +1559,14 @@ int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_password
}
/* Print all present signatures in read-only mode */
- r = tools_detect_signatures(header_device, PRB_FILTER_NONE, &signatures, ARG_SET(OPT_BATCH_MODE_ID));
- if (r < 0)
- goto out;
+ if (!ARG_SET(OPT_DISABLE_BLKID_ID)) {
+ r = tools_detect_signatures(header_device, PRB_FILTER_NONE, &signatures, ARG_SET(OPT_BATCH_MODE_ID));
+ if (r < 0) {
+ if (r == -EIO)
+ log_err(_("Blkid scan failed for %s."), header_device);
+ goto out;
+ }
+ }
if (!created && !ARG_SET(OPT_BATCH_MODE_ID)) {
r = asprintf(&msg, _("This will overwrite data on %s irrevocably."), header_device);
@@ -1485,6 +1583,11 @@ int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_password
keysize = get_adjusted_key_size(cipher_mode, DEFAULT_LUKS1_KEYBITS, integrity_keysize);
+ if (ARG_SET(OPT_HW_OPAL_ONLY_ID))
+ keysize = opal_params.user_key_size;
+ else if (ARG_SET(OPT_HW_OPAL_ID))
+ keysize += opal_params.user_key_size;
+
if (ARG_SET(OPT_USE_RANDOM_ID))
crypt_set_rng_type(cd, CRYPT_RNG_RANDOM);
else if (ARG_SET(OPT_USE_URANDOM_ID))
@@ -1496,6 +1599,19 @@ int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_password
if (r < 0)
goto out;
+ if (ARG_SET(OPT_HW_OPAL_ID) || ARG_SET(OPT_HW_OPAL_ONLY_ID)) {
+ r = tools_get_key("Enter OPAL Admin password: ", CONST_CAST(char **)&opal_params.admin_key, &opal_params.admin_key_size,
+ 0, 0, NULL,
+ ARG_UINT32(OPT_TIMEOUT_ID), verify_passphrase(1), !ARG_SET(OPT_FORCE_PASSWORD_ID), cd);
+ if (r < 0)
+ goto out;
+ if (opal_params.admin_key_size == 0) {
+ log_err(_("OPAL Admin password cannot be empty."));
+ r = -EPERM;
+ goto out;
+ }
+ }
+
if (ARG_SET(OPT_VOLUME_KEY_FILE_ID)) {
r = tools_read_vk(ARG_STR(OPT_VOLUME_KEY_FILE_ID), &key, keysize);
if (r < 0)
@@ -1509,13 +1625,20 @@ int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_password
}
/* Signature candidates found */
- if (signatures && ((r = tools_wipe_all_signatures(header_device, true, false)) < 0))
+ if (!ARG_SET(OPT_DISABLE_BLKID_ID) && signatures &&
+ ((r = tools_wipe_all_signatures(header_device, true, false)) < 0))
goto out;
if (ARG_SET(OPT_INTEGRITY_LEGACY_PADDING_ID))
crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING);
- r = crypt_format(cd, type, cipher, cipher_mode,
+ if (ARG_SET(OPT_HW_OPAL_ID) || ARG_SET(OPT_HW_OPAL_ONLY_ID))
+ r = crypt_format_luks2_opal(cd,
+ ARG_SET(OPT_HW_OPAL_ONLY_ID) ? NULL : cipher,
+ ARG_SET(OPT_HW_OPAL_ONLY_ID) ? NULL : cipher_mode,
+ ARG_STR(OPT_UUID_ID), key, keysize, params, &opal_params);
+ else
+ r = crypt_format(cd, type, cipher, cipher_mode,
ARG_STR(OPT_UUID_ID), key, keysize, params);
check_signal(&r);
if (r < 0)
@@ -1529,25 +1652,44 @@ int luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_password
key, keysize,
password, passwordLen);
if (r < 0) {
- (void) tools_wipe_all_signatures(header_device, true, false);
+ wipe_signatures = true;
goto out;
}
tools_keyslot_msg(r, CREATED);
if (ARG_SET(OPT_INTEGRITY_ID) && !ARG_SET(OPT_INTEGRITY_NO_WIPE_ID) &&
- strcmp_or_null(params2.integrity, "none"))
+ strcmp_or_null(params2.integrity, "none")) {
r = _wipe_data_device(cd);
+ /* Interrupted wipe should not fail luksFormat action */
+ if (r == -EINTR)
+ r = 0;
+ }
out:
+ crypt_safe_free(key);
+
+ if (r < 0) {
+ encrypt_type = crypt_get_hw_encryption_type(cd);
+ if (encrypt_type == CRYPT_OPAL_HW_ONLY ||
+ encrypt_type == CRYPT_SW_AND_OPAL_HW) {
+ (void) crypt_wipe_hw_opal(cd, CRYPT_LUKS2_SEGMENT,
+ opal_params.admin_key, opal_params.admin_key_size,
+ 0);
+ }
+ if (wipe_signatures)
+ (void) tools_wipe_all_signatures(header_device, true, false);
+ }
+
+ crypt_safe_free(CONST_CAST(void *)opal_params.admin_key);
+
if (r >= 0 && r_cd && r_password && r_passwordLen) {
*r_cd = cd;
*r_password = password;
*r_passwordLen = passwordLen;
- } else {
- crypt_free(cd);
- crypt_safe_free(password);
+ return r;
}
- crypt_safe_free(key);
+ crypt_free(cd);
+ crypt_safe_free(password);
return r;
}
@@ -1557,17 +1699,166 @@ static int action_luksFormat(void)
return luksFormat(NULL, NULL, NULL);
}
+static int parse_vk_description(const char *key_description, char **ret_key_description)
+{
+ char *tmp;
+ int r;
+
+ assert(key_description);
+ assert(ret_key_description);
+
+ /* apply default key type */
+ if (*key_description != '%')
+ r = asprintf(&tmp, "%%user:%s", key_description) < 0 ? -EINVAL : 0;
+ else
+ r = (tmp = strdup(key_description)) ? 0 : -ENOMEM;
+ if (!r)
+ *ret_key_description = tmp;
+
+ return r;
+}
+
+static int parse_single_vk_and_keyring_description(
+ struct crypt_device *cd,
+ char *keyring_key_description, char **keyring_part_out, char
+ **key_part_out, char **type_part_out)
+{
+ int r = -EINVAL;
+ char *endp, *sep, *key_part, *type_part = NULL;
+ char *key_part_copy = NULL, *type_part_copy = NULL, *keyring_part = NULL;
+
+ if (!cd || !keyring_key_description)
+ return -EINVAL;
+
+ /* "::" is separator between keyring specification a key description */
+ key_part = strstr(keyring_key_description, "::");
+ if (!key_part)
+ goto out;
+
+ *key_part = '\0';
+ key_part = key_part + 2;
+
+ if (*key_part == '%') {
+ type_part = key_part + 1;
+ sep = strstr(type_part, ":");
+ if (!sep)
+ goto out;
+ *sep = '\0';
+
+ key_part = sep + 1;
+ }
+
+ if (*keyring_key_description == '%') {
+ keyring_key_description = strstr(keyring_key_description, ":");
+ if (!keyring_key_description)
+ goto out;
+ log_verbose(_("Type specification in --link-vk-to-keyring keyring specification is ignored."));
+ keyring_key_description++;
+ }
+
+ (void)strtol(keyring_key_description, &endp, 0);
+
+ r = 0;
+ if (*keyring_key_description == '@' || !*endp)
+ keyring_part = strdup(keyring_key_description);
+ else
+ r = asprintf(&keyring_part, "%%:%s", keyring_key_description);
+
+ if (!keyring_part || r < 0) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ if (!(key_part_copy = strdup(key_part))) {
+ r = -ENOMEM;
+ goto out;
+ }
+ if (type_part && !(type_part_copy = strdup(type_part)))
+ r = -ENOMEM;
+
+out:
+ if (r < 0) {
+ free(keyring_part);
+ free(key_part_copy);
+ free(type_part_copy);
+ } else {
+ *keyring_part_out = keyring_part;
+ *key_part_out = key_part_copy;
+ *type_part_out = type_part_copy;
+ }
+
+ return r;
+}
+
+static int parse_vk_and_keyring_description(
+ struct crypt_device *cd,
+ char **keyring_key_descriptions,
+ int keyring_key_links_count)
+{
+ int r = 0;
+
+ char *keyring_part_out1 = NULL, *key_part_out1 = NULL, *type_part_out1 = NULL;
+ char *keyring_part_out2 = NULL, *key_part_out2 = NULL, *type_part_out2 = NULL;
+
+ if (keyring_key_links_count > 0) {
+ r = parse_single_vk_and_keyring_description(cd,
+ keyring_key_descriptions[0],
+ &keyring_part_out1, &key_part_out1,
+ &type_part_out1);
+ if (r < 0)
+ goto out;
+ }
+ if (keyring_key_links_count > 1) {
+ r = parse_single_vk_and_keyring_description(cd,
+ keyring_key_descriptions[1],
+ &keyring_part_out2, &key_part_out2,
+ &type_part_out2);
+ if (r < 0)
+ goto out;
+
+ if ((type_part_out1 && type_part_out2) && strcmp(type_part_out1, type_part_out2)) {
+ log_err(_("Key types have to be the same for both volume keys."));
+ r = -EINVAL;
+ goto out;
+ }
+ if ((keyring_part_out1 && keyring_part_out2) && strcmp(keyring_part_out1, keyring_part_out2)) {
+ log_err(_("Both volume keys have to be linked to the same keyring."));
+ r = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (keyring_key_links_count > 0) {
+ r = crypt_set_keyring_to_link(cd, key_part_out1, key_part_out2,
+ type_part_out1, keyring_part_out1);
+ if (r == -EAGAIN)
+ log_err(_("You need to supply more key names."));
+ }
+out:
+ if (r == -EINVAL)
+ log_err(_("Invalid --link-vk-to-keyring value."));
+ free(keyring_part_out1);
+ free(key_part_out1);
+ free(type_part_out1);
+ free(keyring_part_out2);
+ free(key_part_out2);
+ free(type_part_out2);
+
+ return r;
+}
+
static int action_open_luks(void)
{
struct crypt_active_device cad;
struct crypt_device *cd = NULL;
const char *data_device, *header_device, *activated_name;
- char *key = NULL;
+ char *key = NULL, *vk_description_activation1 = NULL, *vk_description_activation2 = NULL;
uint32_t activate_flags = 0;
int r, keysize, tries;
char *password = NULL;
size_t passwordLen;
struct stat st;
+ struct crypt_keyslot_context *kc1 = NULL, *kc2 = NULL;
if (ARG_SET(OPT_REFRESH_ID)) {
activated_name = action_argc > 1 ? action_argv[1] : action_argv[0];
@@ -1606,6 +1897,21 @@ static int action_open_luks(void)
set_activation_flags(&activate_flags);
+ if (ARG_SET(OPT_EXTERNAL_TOKENS_PATH_ID)) {
+ r = crypt_token_set_external_path(ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ if (r < 0) {
+ log_err(_("Failed to set external tokens path %s."),
+ ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ goto out;
+ }
+ }
+
+ if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) {
+ r = parse_vk_and_keyring_description(cd, keyring_links, keyring_links_count);
+ if (r < 0)
+ goto out;
+ }
+
if (ARG_SET(OPT_VOLUME_KEY_FILE_ID)) {
keysize = crypt_get_volume_key_size(cd);
if (!keysize && !ARG_SET(OPT_KEY_SIZE_ID)) {
@@ -1620,16 +1926,37 @@ static int action_open_luks(void)
goto out;
r = crypt_activate_by_volume_key(cd, activated_name,
key, keysize, activate_flags);
+ } else if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
+ if (vks_in_keyring_count == 1) {
+ r = parse_vk_description(vks_in_keyring[0], &vk_description_activation1);
+ if (r < 0)
+ goto out;
+ r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation1, &kc1);
+ if (r)
+ goto out;
+ r = crypt_activate_by_keyslot_context(cd, activated_name, CRYPT_ANY_SLOT, kc1, CRYPT_ANY_SLOT, NULL, activate_flags);
+ } else if (vks_in_keyring_count == 2) {
+ r = parse_vk_description(vks_in_keyring[0], &vk_description_activation1);
+ if (r < 0)
+ goto out;
+ r = parse_vk_description(vks_in_keyring[1], &vk_description_activation2);
+ if (r < 0)
+ goto out;
+ r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation1, &kc1);
+ if (r)
+ goto out;
+ r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation2, &kc2);
+ if (r)
+ goto out;
+ r = crypt_activate_by_keyslot_context(cd, activated_name, CRYPT_ANY_SLOT, kc1, CRYPT_ANY_SLOT, kc2, activate_flags);
+ }
+ if (r)
+ goto out;
} else {
- r = crypt_activate_by_token_pin(cd, activated_name, ARG_STR(OPT_TOKEN_TYPE_ID),
- ARG_INT32(OPT_TOKEN_ID_ID), NULL, 0, NULL, activate_flags);
- tools_keyslot_msg(r, UNLOCKED);
- tools_token_error_msg(r, ARG_STR(OPT_TOKEN_TYPE_ID), ARG_INT32(OPT_TOKEN_ID_ID), false);
-
- /* Token requires PIN. Ask if there is evident preference for tokens */
- if (r == -ENOANO && (ARG_SET(OPT_TOKEN_ONLY_ID) || ARG_SET(OPT_TOKEN_TYPE_ID) ||
- ARG_SET(OPT_TOKEN_ID_ID)))
- r = _try_token_pin_unlock(cd, ARG_INT32(OPT_TOKEN_ID_ID), activated_name, ARG_STR(OPT_TOKEN_TYPE_ID), activate_flags, set_tries_tty(), true);
+ r = _try_token_unlock(cd, ARG_INT32(OPT_KEY_SLOT_ID),
+ ARG_INT32(OPT_TOKEN_ID_ID), activated_name,
+ ARG_STR(OPT_TOKEN_TYPE_ID), activate_flags,
+ set_tries_tty(), true, ARG_SET(OPT_TOKEN_ONLY_ID));
if (r >= 0 || r == -EEXIST || quit || ARG_SET(OPT_TOKEN_ONLY_ID))
goto out;
@@ -1657,9 +1984,14 @@ out:
crypt_persistent_flags_set(cd, CRYPT_FLAGS_ACTIVATION, cad.flags & activate_flags)))
log_err(_("Device activated but cannot make flags persistent."));
+ crypt_keyslot_context_free(kc1);
+ crypt_keyslot_context_free(kc2);
crypt_safe_free(key);
crypt_safe_free(password);
crypt_free(cd);
+ free(vk_description_activation1);
+ free(vk_description_activation2);
+
return r;
}
@@ -1839,6 +2171,15 @@ static int luksAddUnboundKey(void)
goto out;
}
+ if (ARG_SET(OPT_EXTERNAL_TOKENS_PATH_ID)) {
+ r = crypt_token_set_external_path(ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ if (r < 0) {
+ log_err(_("Failed to set external tokens path %s."),
+ ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ goto out;
+ }
+ }
+
r = _set_keyslot_encryption_params(cd);
if (r < 0)
goto out;
@@ -1943,7 +2284,8 @@ static int action_luksAddKey(void)
{
int keyslot_old, keyslot_new, keysize = 0, r = -EINVAL;
const char *new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
- char *key = NULL, *password = NULL, *password_new = NULL, *pin = NULL, *pin_new = NULL;
+ char *key = NULL, *password = NULL, *password_new = NULL, *pin = NULL, *pin_new = NULL,
+ *vk_description = NULL;
size_t pin_size, pin_size_new, password_size = 0, password_new_size = 0;
struct crypt_device *cd = NULL;
struct crypt_keyslot_context *p_kc_new = NULL, *kc = NULL, *kc_new = NULL;
@@ -1983,6 +2325,15 @@ static int action_luksAddKey(void)
if (r < 0)
goto out;
+ if (ARG_SET(OPT_EXTERNAL_TOKENS_PATH_ID)) {
+ r = crypt_token_set_external_path(ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ if (r < 0) {
+ log_err(_("Failed to set external tokens path %s."),
+ ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ goto out;
+ }
+ }
+
/* Never call pwquality if using null cipher */
if (crypt_is_cipher_null(crypt_get_cipher(cd)))
ARG_SET_TRUE(OPT_FORCE_PASSWORD_ID);
@@ -2019,7 +2370,11 @@ static int action_luksAddKey(void)
ARG_UINT32(OPT_KEYFILE_SIZE_ID),
ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
&kc);
- else if (ARG_SET(OPT_TOKEN_ID_ID) || ARG_SET(OPT_TOKEN_TYPE_ID) || ARG_SET(OPT_TOKEN_ONLY_ID)) {
+ else if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
+ r = parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description);
+ if (!r)
+ r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description, &kc);
+ } else if (ARG_SET(OPT_TOKEN_ID_ID) || ARG_SET(OPT_TOKEN_TYPE_ID) || ARG_SET(OPT_TOKEN_ONLY_ID)) {
r = crypt_keyslot_context_init_by_token(cd,
ARG_INT32(OPT_TOKEN_ID_ID),
ARG_STR(OPT_TOKEN_TYPE_ID),
@@ -2034,7 +2389,7 @@ static int action_luksAddKey(void)
goto out;
/* Check password before asking for new one */
- r = crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT,
+ r = crypt_activate_by_passphrase(cd, NULL, keyslot_old,
password, password_size, 0);
check_signal(&r);
tools_passphrase_msg(r);
@@ -2107,6 +2462,7 @@ static int action_luksAddKey(void)
}
out:
tools_keyslot_msg(r, CREATED);
+ free(vk_description);
crypt_keyslot_context_free(kc);
crypt_keyslot_context_free(kc_new);
crypt_safe_free(password);
@@ -2416,6 +2772,15 @@ static int action_luksDump(void)
goto out;
}
+ if (ARG_SET(OPT_EXTERNAL_TOKENS_PATH_ID)) {
+ r = crypt_token_set_external_path(ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ if (r < 0) {
+ log_err(_("Failed to set external tokens path %s."),
+ ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ goto out;
+ }
+ }
+
if (ARG_SET(OPT_DUMP_VOLUME_KEY_ID))
r = luksDump_with_volume_key(cd);
else if (ARG_SET(OPT_UNBOUND_ID))
@@ -2448,11 +2813,12 @@ static int action_luksSuspend(void)
static int action_luksResume(void)
{
struct crypt_device *cd = NULL;
- char *password = NULL;
+ char *password = NULL, *vk_description_activation = NULL;
size_t passwordLen;
int r, tries;
struct crypt_active_device cad;
const char *req_type = luksType(device_type);
+ struct crypt_keyslot_context *kc = NULL;
if (req_type && !isLUKS(req_type))
return -EINVAL;
@@ -2460,7 +2826,14 @@ static int action_luksResume(void)
if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(ARG_STR(OPT_HEADER_ID)))))
return r;
+ if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) {
+ r = parse_vk_and_keyring_description(cd, keyring_links, keyring_links_count);
+ if (r < 0)
+ goto out;
+ }
+
r = -EINVAL;
+
if (!isLUKS(crypt_get_type(cd))) {
log_err(_("%s is not active LUKS device name or header is missing."), action_argv[0]);
goto out;
@@ -2481,20 +2854,34 @@ static int action_luksResume(void)
goto out;
}
- /* try to resume LUKS2 device by token first */
- r = crypt_resume_by_token_pin(cd, action_argv[0], ARG_STR(OPT_TOKEN_TYPE_ID),
- ARG_INT32(OPT_TOKEN_ID_ID), NULL, 0, NULL);
- tools_keyslot_msg(r, UNLOCKED);
- tools_token_error_msg(r, ARG_STR(OPT_TOKEN_TYPE_ID), ARG_INT32(OPT_TOKEN_ID_ID), false);
+ if (ARG_SET(OPT_EXTERNAL_TOKENS_PATH_ID)) {
+ r = crypt_token_set_external_path(ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ if (r < 0) {
+ log_err(_("Failed to set external tokens path %s."),
+ ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ goto out;
+ }
+ }
- /* Token requires PIN. Ask if there is evident preference for tokens */
- if (r == -ENOANO && (ARG_SET(OPT_TOKEN_ONLY_ID) || ARG_SET(OPT_TOKEN_TYPE_ID) ||
- ARG_SET(OPT_TOKEN_ID_ID)))
- r = _try_token_pin_unlock(cd, ARG_INT32(OPT_TOKEN_ID_ID), action_argv[0], ARG_STR(OPT_TOKEN_TYPE_ID), 0, set_tries_tty(), false);
+ /* try to resume LUKS2 device by token first */
+ r = _try_token_unlock(cd, ARG_INT32(OPT_KEY_SLOT_ID), ARG_INT32(OPT_TOKEN_ID_ID),
+ action_argv[0], ARG_STR(OPT_TOKEN_TYPE_ID), 0,
+ set_tries_tty(), false, ARG_SET(OPT_TOKEN_ONLY_ID));
if (r >= 0 || quit || ARG_SET(OPT_TOKEN_ONLY_ID))
goto out;
+ if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
+ r = parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description_activation);
+ if (r < 0)
+ goto out;
+ r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation, &kc);
+ if (r)
+ goto out;
+ r = crypt_resume_by_keyslot_context(cd, action_argv[0], CRYPT_ANY_SLOT, kc);
+ goto out;
+ }
+
tries = set_tries_tty();
do {
r = tools_get_key(NULL, &password, &passwordLen,
@@ -2513,7 +2900,9 @@ static int action_luksResume(void)
password = NULL;
} while ((r == -EPERM || r == -ERANGE) && (--tries > 0));
out:
+ crypt_keyslot_context_free(kc);
crypt_safe_free(password);
+ free(vk_description_activation);
crypt_free(cd);
return r;
}
@@ -2642,15 +3031,48 @@ out:
return r;
}
+static int opal_erase(struct crypt_device *cd, bool factory_reset) {
+ char *password = NULL;
+ size_t password_size = 0;
+ int r;
+
+ r = tools_get_key(factory_reset ? _("Enter OPAL PSID: ") : _("Enter OPAL Admin password: "),
+ &password, &password_size, ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
+ ARG_UINT32(OPT_KEYFILE_SIZE_ID), ARG_STR(OPT_KEY_FILE_ID),
+ ARG_UINT32(OPT_TIMEOUT_ID), verify_passphrase(0),
+ !ARG_SET(OPT_FORCE_PASSWORD_ID), cd);
+ if (r < 0)
+ return r;
+
+ if (factory_reset && !ARG_SET(OPT_BATCH_MODE_ID) &&
+ !yesDialog(_("WARNING: WHOLE disk will be factory reset and all data will be lost! Continue?"),
+ _("Operation aborted.\n"))) {
+ crypt_safe_free(password);
+ return -EPERM;
+ }
+
+ r = crypt_wipe_hw_opal(cd, factory_reset ? CRYPT_NO_SEGMENT : CRYPT_LUKS2_SEGMENT,
+ password, password_size, 0);
+
+ crypt_safe_free(password);
+ return r;
+}
+
static int action_luksErase(void)
{
struct crypt_device *cd = NULL;
crypt_keyslot_info ki;
char *msg = NULL;
- int i, max, r;
+ int i, max, r, hw_enc;
- if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
+ if ((r = crypt_init_data_device(&cd, uuid_or_device(ARG_STR(OPT_HEADER_ID) ?: action_argv[0]), action_argv[0])))
+ return r;
+
+ /* Allow factory reset even if there's no LUKS header, as long as OPAL is enabled on the device */
+ if (ARG_SET(OPT_HW_OPAL_FACTORY_RESET_ID)) {
+ r = opal_erase(cd, true);
goto out;
+ }
if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
@@ -2658,7 +3080,15 @@ static int action_luksErase(void)
goto out;
}
- if(asprintf(&msg, _("This operation will erase all keyslots on device %s.\n"
+ hw_enc = crypt_get_hw_encryption_type(cd);
+ if (hw_enc < 0)
+ goto out;
+ if (hw_enc == CRYPT_OPAL_HW_ONLY || hw_enc == CRYPT_SW_AND_OPAL_HW) {
+ r = opal_erase(cd, false);
+ goto out;
+ }
+
+ if (asprintf(&msg, _("This operation will erase all keyslots on device %s.\n"
"Device will become unusable after this operation."),
uuid_or_device_header(NULL)) == -1) {
r = -ENOMEM;
@@ -2951,6 +3381,16 @@ static int action_token(void)
return r;
}
+ if (ARG_SET(OPT_EXTERNAL_TOKENS_PATH_ID)) {
+ r = crypt_token_set_external_path(ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ if (r < 0) {
+ log_err(_("Failed to set external tokens path %s."),
+ ARG_STR(OPT_EXTERNAL_TOKENS_PATH_ID));
+ crypt_free(cd);
+ return r;
+ }
+ }
+
r = -EINVAL;
if (!strcmp(action_argv[0], "add")) {
@@ -3063,7 +3503,7 @@ static const char *verify_resize(void)
static const char *verify_reencrypt(void)
{
if (ARG_SET(OPT_REDUCE_DEVICE_SIZE_ID) && ARG_SET(OPT_DEVICE_SIZE_ID))
- return _("Options --reduce-device-size and --data-size cannot be combined.");
+ return _("Options --reduce-device-size and --device-size cannot be combined.");
if (isLUKS1(luksType(device_type)) && ARG_SET(OPT_ACTIVE_NAME_ID))
return _("Option --active-name can be set only for LUKS2 device.");
@@ -3220,10 +3660,10 @@ static void help(poptContext popt_context,
path = crypt_token_external_path();
if (path) {
- log_std(_("\nLUKS2 external token plugin support is %s.\n"), _("compiled-in"));
+ log_std(_("\nLUKS2 external token plugin support is enabled.\n"));
log_std(_("LUKS2 external token plugin path: %s.\n"), path);
} else
- log_std(_("\nLUKS2 external token plugin support is %s.\n"), _("disabled"));
+ log_std(_("\nLUKS2 external token plugin support is disabled.\n"));
pbkdf_luks1 = crypt_get_pbkdf_default(CRYPT_LUKS1);
pbkdf_luks2 = crypt_get_pbkdf_default(CRYPT_LUKS2);
@@ -3315,6 +3755,7 @@ static void basic_options_cb(poptContext popt_context,
const char *arg,
void *data __attribute__((unused)))
{
+ char buf[128];
tools_parse_arg_value(popt_context, tool_core_args[key->val].type, tool_core_args + key->val, arg, key->val, needs_size_conversion);
/* special cases additional handling */
@@ -3366,6 +3807,29 @@ static void basic_options_cb(poptContext popt_context,
_("Key size must be a multiple of 8 bits"),
poptGetInvocationName(popt_context));
break;
+ case OPT_VOLUME_KEY_KEYRING_ID:
+ if (vks_in_keyring_count < MAX_VK_IN_KEYRING)
+ vks_in_keyring[vks_in_keyring_count++] = strdup(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID));
+ else {
+ if (snprintf(buf, sizeof(buf), _("At most %d volume key specifications can be supplied."), MAX_KEYRING_LINKS) < 0)
+ buf[0] = '\0';
+ usage(popt_context, EXIT_FAILURE,
+ buf,
+ poptGetInvocationName(popt_context));
+ }
+ break;
+ case OPT_LINK_VK_TO_KEYRING_ID:
+ if (keyring_links_count < MAX_KEYRING_LINKS)
+ keyring_links[keyring_links_count++] = strdup(ARG_STR(OPT_LINK_VK_TO_KEYRING_ID));
+ else {
+
+ if (snprintf(buf, sizeof(buf), _("At most %d keyring link specifications can be supplied."), MAX_KEYRING_LINKS) < 0)
+ buf[0] = '\0';
+ usage(popt_context, EXIT_FAILURE,
+ buf,
+ poptGetInvocationName(popt_context));
+ }
+ break;
case OPT_REDUCE_DEVICE_SIZE_ID:
if (ARG_UINT64(OPT_REDUCE_DEVICE_SIZE_ID) > 1024 * 1024 * 1024)
usage(popt_context, EXIT_FAILURE, _("Maximum device reduce size is 1 GiB."),
@@ -3439,6 +3903,9 @@ int main(int argc, const char **argv)
textdomain(PACKAGE);
popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
+ if (!popt_context)
+ exit(EXIT_FAILURE);
+
poptSetOtherOptionHelp(popt_context,
_("[OPTION...] <action> <action-specific>"));
@@ -3506,7 +3973,10 @@ int main(int argc, const char **argv)
aname = CLOSE_ACTION;
} else if (!strcmp(aname, "luksErase")) {
aname = ERASE_ACTION;
- device_type = "luks";
+ if (ARG_SET(OPT_TYPE_ID))
+ device_type = ARG_STR(OPT_TYPE_ID);
+ else
+ device_type = "luks";
} else if (!strcmp(aname, "luksConfig")) {
aname = CONFIG_ACTION;
device_type = "luks2";
@@ -3562,6 +4032,11 @@ int main(int argc, const char **argv)
_("PBKDF forced iterations cannot be combined with iteration time option."),
poptGetInvocationName(popt_context));
+ if (ARG_SET(OPT_DISABLE_KEYRING_ID) && ARG_SET(OPT_LINK_VK_TO_KEYRING_ID))
+ usage(popt_context, EXIT_FAILURE,
+ _("Cannot link volume key to a keyring when keyring is disabled."),
+ poptGetInvocationName(popt_context));
+
if (ARG_SET(OPT_DEBUG_ID) || ARG_SET(OPT_DEBUG_JSON_ID)) {
crypt_set_debug_level(ARG_SET(OPT_DEBUG_JSON_ID)? CRYPT_DEBUG_JSON : CRYPT_DEBUG_ALL);
dbg_version_and_cmd(argc, argv);