cryptenroll: add new "systemd-cryptenroll" tool for enrolling FIDO2+PKCS#11 security tokens

This commit is contained in:
Lennart Poettering 2020-11-24 13:41:47 +01:00
parent 2bc5c425e6
commit 8710a6818e
10 changed files with 829 additions and 0 deletions

View File

@ -2420,6 +2420,36 @@ if conf.get('HAVE_LIBCRYPTSETUP') == 1
install_rpath : rootlibexecdir,
install : true,
install_dir : systemgeneratordir)
systemd_cryptenroll_sources = files('''
src/cryptenroll/cryptenroll-fido2.h
src/cryptenroll/cryptenroll-password.c
src/cryptenroll/cryptenroll-password.h
src/cryptenroll/cryptenroll-pkcs11.h
src/cryptenroll/cryptenroll-recovery.c
src/cryptenroll/cryptenroll-recovery.h
src/cryptenroll/cryptenroll.c
'''.split())
if conf.get('HAVE_P11KIT') == 1 and conf.get('HAVE_OPENSSL') == 1
systemd_cryptenroll_sources += files('src/cryptenroll/cryptenroll-pkcs11.c')
endif
if conf.get('HAVE_LIBFIDO2') == 1
systemd_cryptenroll_sources += files('src/cryptenroll/cryptenroll-fido2.c')
endif
executable(
'systemd-cryptenroll',
systemd_cryptenroll_sources,
include_directories : includes,
link_with : [libshared],
dependencies : [libcryptsetup,
libopenssl,
libp11kit],
install_rpath : rootlibexecdir,
install : true,
install_dir : bindir)
endif
if conf.get('HAVE_SYSV_COMPAT') == 1

View File

@ -0,0 +1,88 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "cryptenroll-fido2.h"
#include "hexdecoct.h"
#include "json.h"
#include "libfido2-util.h"
#include "memory-util.h"
#include "random-util.h"
int enroll_fido2(
struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size,
const char *device) {
_cleanup_(erase_and_freep) void *salt = NULL, *secret = NULL;
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_free_ char *keyslot_as_string = NULL;
size_t cid_size, salt_size, secret_size;
_cleanup_free_ void *cid = NULL;
const char *node, *un;
int r, keyslot;
assert_se(cd);
assert_se(volume_key);
assert_se(volume_key_size > 0);
assert_se(device);
assert_se(node = crypt_get_device_name(cd));
un = strempty(crypt_get_uuid(cd));
r = fido2_generate_hmac_hash(
device,
/* rp_id= */ "io.systemd.cryptsetup",
/* rp_name= */ "Encrypted Volume",
/* user_id= */ un, strlen(un), /* We pass the user ID and name as the same: the disk's UUID if we have it */
/* user_name= */ un,
/* user_display_name= */ node,
/* user_icon_name= */ NULL,
/* askpw_icon_name= */ "drive-harddisk",
&cid, &cid_size,
&salt, &salt_size,
&secret, &secret_size,
NULL);
if (r < 0)
return r;
/* Before we use the secret, we base64 encode it, for compat with homed, and to make it easier to type in manually */
r = base64mem(secret, secret_size, &base64_encoded);
if (r < 0)
return log_error_errno(r, "Failed to base64 encode secret key: %m");
r = cryptsetup_set_minimal_pbkdf(cd);
if (r < 0)
return log_error_errno(r, "Failed to set minimal PBKDF: %m");
keyslot = crypt_keyslot_add_by_volume_key(
cd,
CRYPT_ANY_SLOT,
volume_key,
volume_key_size,
base64_encoded,
strlen(base64_encoded));
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new PKCS#11 key to %s: %m", node);
if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
return log_oom();
r = json_build(&v,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-fido2")),
JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
JSON_BUILD_PAIR("fido2-credential", JSON_BUILD_BASE64(cid, cid_size)),
JSON_BUILD_PAIR("fido2-salt", JSON_BUILD_BASE64(salt, salt_size)),
JSON_BUILD_PAIR("fido2-rp", JSON_BUILD_STRING("io.systemd.cryptsetup"))));
if (r < 0)
return log_error_errno(r, "Failed to prepare PKCS#11 JSON token object: %m");
r = cryptsetup_add_token_json(cd, v);
if (r < 0)
return log_error_errno(r, "Failed to add FIDO2 JSON token to LUKS2 header: %m");
log_info("New FIDO2 token enrolled as key slot %i.", keyslot);
return keyslot;
}

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/types.h>
#include "cryptsetup-util.h"
#include "log.h"
#if HAVE_LIBFIDO2
int enroll_fido2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device);
#else
static inline int enroll_fido2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"FIDO2 key enrollment not supported.");
}
#endif

View File

@ -0,0 +1,105 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "ask-password-api.h"
#include "cryptenroll-password.h"
#include "escape.h"
#include "memory-util.h"
#include "pwquality-util.h"
#include "strv.h"
int enroll_password(
struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size) {
_cleanup_(erase_and_freep) char *new_password = NULL;
_cleanup_free_ char *error = NULL;
const char *node;
int r, keyslot;
char *e;
assert_se(node = crypt_get_device_name(cd));
e = getenv("NEWPASSWORD");
if (e) {
new_password = strdup(e);
if (!new_password)
return log_oom();
string_erase(e);
assert_se(unsetenv("NEWPASSWORD") == 0);
} else {
_cleanup_free_ char *disk_path = NULL;
unsigned i = 5;
const char *id;
assert_se(node = crypt_get_device_name(cd));
(void) suggest_passwords();
disk_path = cescape(node);
if (!disk_path)
return log_oom();
id = strjoina("cryptsetup:", disk_path);
for (;;) {
_cleanup_strv_free_erase_ char **passwords = NULL, **passwords2 = NULL;
_cleanup_free_ char *question = NULL;
if (--i == 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
"Too many attempts, giving up:");
question = strjoin("Please enter new passphrase for disk ", node, ":");
if (!question)
return log_oom();
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
assert(strv_length(passwords) == 1);
free(question);
question = strjoin("Please enter new passphrase for disk ", node, " (repeat):");
if (!question)
return log_oom();
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
assert(strv_length(passwords2) == 1);
if (strv_equal(passwords, passwords2)) {
new_password = passwords2[0];
passwords2 = mfree(passwords2);
break;
}
log_error("Password didn't match, try again.");
}
}
r = quality_check_password(new_password, NULL, &error);
if (r < 0)
return log_error_errno(r, "Failed to check password for quality: %m");
if (r == 0)
log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", error);
keyslot = crypt_keyslot_add_by_volume_key(
cd,
CRYPT_ANY_SLOT,
volume_key,
volume_key_size,
new_password,
strlen(new_password));
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new password to %s: %m", node);
log_info("New password enrolled as key slot %i.", keyslot);
return keyslot;
}

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/types.h>
#include "cryptsetup-util.h"
int enroll_password(struct crypt_device *cd, const void *volume_key, size_t volume_key_size);

View File

@ -0,0 +1,99 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "cryptenroll-pkcs11.h"
#include "hexdecoct.h"
#include "json.h"
#include "memory-util.h"
#include "openssl-util.h"
#include "pkcs11-util.h"
#include "random-util.h"
int enroll_pkcs11(
struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size,
const char *uri) {
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_free_ char *keyslot_as_string = NULL;
size_t decrypted_key_size, encrypted_key_size;
_cleanup_free_ void *encrypted_key = NULL;
_cleanup_(X509_freep) X509 *cert = NULL;
const char *node;
EVP_PKEY *pkey;
int keyslot, r;
assert_se(cd);
assert_se(volume_key);
assert_se(volume_key_size > 0);
assert_se(uri);
assert_se(node = crypt_get_device_name(cd));
r = pkcs11_acquire_certificate(uri, "volume enrollment operation", "drive-harddisk", &cert, NULL);
if (r < 0)
return r;
pkey = X509_get0_pubkey(cert);
if (!pkey)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to extract public key from X.509 certificate.");
r = rsa_pkey_to_suitable_key_size(pkey, &decrypted_key_size);
if (r < 0)
return log_error_errno(r, "Failed to determine RSA public key size.");
log_debug("Generating %zu bytes random key.", decrypted_key_size);
decrypted_key = malloc(decrypted_key_size);
if (!decrypted_key)
return log_oom();
r = genuine_random_bytes(decrypted_key, decrypted_key_size, RANDOM_BLOCK);
if (r < 0)
return log_error_errno(r, "Failed to generate random key: %m");
r = rsa_encrypt_bytes(pkey, decrypted_key, decrypted_key_size, &encrypted_key, &encrypted_key_size);
if (r < 0)
return log_error_errno(r, "Failed to encrypt key: %m");
/* Let's base64 encode the key to use, for compat with homed (and it's easier to type it in by
* keyboard, if that might ever end up being necessary.) */
r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
if (r < 0)
return log_error_errno(r, "Failed to base64 encode secret key: %m");
r = cryptsetup_set_minimal_pbkdf(cd);
if (r < 0)
return log_error_errno(r, "Failed to set minimal PBKDF: %m");
keyslot = crypt_keyslot_add_by_volume_key(
cd,
CRYPT_ANY_SLOT,
volume_key,
volume_key_size,
base64_encoded,
strlen(base64_encoded));
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new PKCS#11 key to %s: %m", node);
if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
return log_oom();
r = json_build(&v,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-pkcs11")),
JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
JSON_BUILD_PAIR("pkcs11-uri", JSON_BUILD_STRING(uri)),
JSON_BUILD_PAIR("pkcs11-key", JSON_BUILD_BASE64(encrypted_key, encrypted_key_size))));
if (r < 0)
return log_error_errno(r, "Failed to prepare PKCS#11 JSON token object: %m");
r = cryptsetup_add_token_json(cd, v);
if (r < 0)
return log_error_errno(r, "Failed to add PKCS#11 JSON token to LUKS2 header: %m");
log_info("New PKCS#11 token enrolled as key slot %i.", keyslot);
return keyslot;
}

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/types.h>
#include "cryptsetup-util.h"
#include "log.h"
#if HAVE_P11KIT && HAVE_OPENSSL
int enroll_pkcs11(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *uri);
#else
static inline int enroll_pkcs11(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *uri) {
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"PKCS#11 key enrollment not supported.");
}
#endif

View File

@ -0,0 +1,101 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "cryptenroll-recovery.h"
#include "json.h"
#include "locale-util.h"
#include "memory-util.h"
#include "qrcode-util.h"
#include "recovery-key.h"
#include "terminal-util.h"
int enroll_recovery(
struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(erase_and_freep) char *password = NULL;
_cleanup_free_ char *keyslot_as_string = NULL;
int keyslot, r, q;
const char *node;
assert_se(cd);
assert_se(volume_key);
assert_se(volume_key_size > 0);
assert_se(node = crypt_get_device_name(cd));
r = make_recovery_key(&password);
if (r < 0)
return log_error_errno(r, "Failed to generate recovery key: %m");
r = cryptsetup_set_minimal_pbkdf(cd);
if (r < 0)
return log_error_errno(r, "Failed to set minimal PBKDF: %m");
keyslot = crypt_keyslot_add_by_volume_key(
cd,
CRYPT_ANY_SLOT,
volume_key,
volume_key_size,
password,
strlen(password));
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new recovery key to %s: %m", node);
fflush(stdout);
fprintf(stderr,
"A secret recovery key has been generated for this volume:\n\n"
" %s%s%s",
emoji_enabled() ? special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY) : "",
emoji_enabled() ? " " : "",
ansi_highlight());
fflush(stderr);
fputs(password, stdout);
fflush(stdout);
fputs(ansi_normal(), stderr);
fflush(stderr);
fputc('\n', stdout);
fflush(stdout);
fputs("\nPlease save this secret recovery key at a secure location. It may be used to\n"
"regain access to the volume if the other configured access credentials have\n"
"been lost or forgotten. The recovery key may be entered in place of a password\n"
"whenever authentication is requested.\n", stderr);
fflush(stderr);
(void) print_qrcode(stderr, "You may optionally scan the recovery key off screen", password);
if (asprintf(&keyslot_as_string, "%i", keyslot) < 0) {
r = log_oom();
goto rollback;
}
r = json_build(&v,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-recovery")),
JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string)))));
if (r < 0) {
log_error_errno(r, "Failed to prepare recovery key JSON token object: %m");
goto rollback;
}
r = cryptsetup_add_token_json(cd, v);
if (r < 0) {
log_error_errno(r, "Failed to add recovery JSON token to LUKS2 header: %m");
goto rollback;
}
log_info("New recovery key enrolled as key slot %i.", keyslot);
return keyslot;
rollback:
q = crypt_keyslot_destroy(cd, keyslot);
if (q < 0)
log_debug_errno(q, "Unable to remove key slot we just added again, can't rollback, sorry: %m");
return r;
}

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/types.h>
#include "cryptsetup-util.h"
int enroll_recovery(struct crypt_device *cd, const void *volume_key, size_t volume_key_size);

View File

@ -0,0 +1,358 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include "ask-password-api.h"
#include "cryptenroll-fido2.h"
#include "cryptenroll-password.h"
#include "cryptenroll-pkcs11.h"
#include "cryptenroll-recovery.h"
#include "cryptsetup-util.h"
#include "escape.h"
#include "libfido2-util.h"
#include "main-func.h"
#include "memory-util.h"
#include "path-util.h"
#include "pkcs11-util.h"
#include "pretty-print.h"
#include "strv.h"
#include "terminal-util.h"
typedef enum EnrollType {
ENROLL_PASSWORD,
ENROLL_RECOVERY,
ENROLL_PKCS11,
ENROLL_FIDO2,
_ENROLL_TYPE_MAX,
_ENROLL_TYPE_INVALID = -1,
} EnrollType;
static EnrollType arg_enroll_type = _ENROLL_TYPE_INVALID;
static char *arg_pkcs11_token_uri = NULL;
static char *arg_fido2_device = NULL;
static char *arg_tpm2_device = NULL;
static char *arg_node = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, freep);
STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_node, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("systemd-cryptenroll", "1", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] BLOCK-DEVICE\n"
"\n%sEnroll a security token or authentication credential to a LUKS volume.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --password Enroll a user-supplied password\n"
" --recovery-key Enroll a recovery key\n"
" --pkcs11-token-uri=URI\n"
" Specify PKCS#11 security token URI\n"
" --fido2-device=PATH\n"
" Enroll a FIDO2-HMAC security token\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
, ansi_highlight(), ansi_normal()
, link
);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_PASSWORD,
ARG_RECOVERY_KEY,
ARG_PKCS11_TOKEN_URI,
ARG_FIDO2_DEVICE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "password", no_argument, NULL, ARG_PASSWORD },
{ "recovery-key", no_argument, NULL, ARG_RECOVERY_KEY },
{ "pkcs11-token-uri", required_argument, NULL, ARG_PKCS11_TOKEN_URI },
{ "fido2-device", required_argument, NULL, ARG_FIDO2_DEVICE },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
switch (c) {
case 'h':
return help();
case ARG_VERSION:
return version();
case ARG_PASSWORD:
if (arg_enroll_type >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Multiple operations specified at once, refusing.");
arg_enroll_type = ENROLL_PASSWORD;
break;
case ARG_RECOVERY_KEY:
if (arg_enroll_type >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Multiple operations specified at once, refusing.");
arg_enroll_type = ENROLL_RECOVERY;
break;
case ARG_PKCS11_TOKEN_URI: {
_cleanup_free_ char *uri = NULL;
if (streq(optarg, "list"))
return pkcs11_list_tokens();
if (arg_enroll_type >= 0 || arg_pkcs11_token_uri)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Multiple operations specified at once, refusing.");
if (streq(optarg, "auto")) {
r = pkcs11_find_token_auto(&uri);
if (r < 0)
return r;
} else {
if (!pkcs11_uri_valid(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid PKCS#11 URI: %s", optarg);
uri = strdup(optarg);
if (!uri)
return log_oom();
}
arg_enroll_type = ENROLL_PKCS11;
arg_pkcs11_token_uri = TAKE_PTR(uri);
break;
}
case ARG_FIDO2_DEVICE: {
_cleanup_free_ char *device = NULL;
if (streq(optarg, "list"))
return fido2_list_devices();
if (arg_enroll_type >= 0 || arg_fido2_device)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Multiple operations specified at once, refusing.");
if (streq(optarg, "auto")) {
r = fido2_find_device_auto(&device);
if (r < 0)
return r;
} else {
device = strdup(optarg);
if (!device)
return log_oom();
}
arg_enroll_type = ENROLL_FIDO2;
arg_fido2_device = TAKE_PTR(device);
break;
}
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
}
if (arg_enroll_type < 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No operation specified, refusing.");
if (optind >= argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"No block device node specified, refusing.");
if (argc > optind+1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Too many arguments, refusing.");
r = parse_path_argument_and_warn(argv[optind], false, &arg_node);
if (r < 0)
return r;
return 1;
}
static int prepare_luks(
struct crypt_device **ret_cd,
void **ret_volume_key,
size_t *ret_volume_key_size) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *vk = NULL;
char *e = NULL;
size_t vks;
int r;
assert(ret_cd);
assert(!ret_volume_key == !ret_volume_key_size);
r = crypt_init(&cd, arg_node);
if (r < 0)
return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
cryptsetup_enable_logging(cd);
r = crypt_load(cd, CRYPT_LUKS2, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load LUKS2 superblock: %m");
if (!ret_volume_key) {
*ret_cd = TAKE_PTR(cd);
return 0;
}
r = crypt_get_volume_key_size(cd);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
vks = (size_t) r;
vk = malloc(vks);
if (!vk)
return log_oom();
e = getenv("PASSWORD");
if (e) {
_cleanup_(erase_and_freep) char *password = NULL;
password = strdup(e);
if (!password)
return log_oom();
string_erase(e);
assert_se(unsetenv("PASSWORD") >= 0);
r = crypt_volume_key_get(
cd,
CRYPT_ANY_SLOT,
vk,
&vks,
password,
strlen(password));
if (r < 0)
return log_error_errno(r, "Password from environent variable $PASSWORD did not work.");
} else {
AskPasswordFlags ask_password_flags = ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED;
_cleanup_free_ char *question = NULL, *disk_path = NULL;
unsigned i = 5;
const char *id;
question = strjoin("Please enter current passphrase for disk ", arg_node, ":");
if (!question)
return log_oom();
disk_path = cescape(arg_node);
if (!disk_path)
return log_oom();
id = strjoina("cryptsetup:", disk_path);
for (;;) {
_cleanup_strv_free_erase_ char **passwords = NULL;
char **p;
if (--i == 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
"Too many attempts, giving up:");
r = ask_password_auto(
question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY,
ask_password_flags,
&passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
r = -EPERM;
STRV_FOREACH(p, passwords) {
r = crypt_volume_key_get(
cd,
CRYPT_ANY_SLOT,
vk,
&vks,
*p,
strlen(*p));
if (r >= 0)
break;
}
if (r >= 0)
break;
log_error_errno(r, "Password not correct, please try again.");
ask_password_flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
}
}
*ret_cd = TAKE_PTR(cd);
*ret_volume_key = TAKE_PTR(vk);
*ret_volume_key_size = vks;
return 0;
}
static int run(int argc, char *argv[]) {
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *vk = NULL;
size_t vks;
int r;
log_show_color(true);
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
r = prepare_luks(&cd, &vk, &vks);
if (r < 0)
return r;
switch (arg_enroll_type) {
case ENROLL_PASSWORD:
r = enroll_password(cd, vk, vks);
break;
case ENROLL_RECOVERY:
r = enroll_recovery(cd, vk, vks);
break;
case ENROLL_PKCS11:
r = enroll_pkcs11(cd, vk, vks, arg_pkcs11_token_uri);
break;
case ENROLL_FIDO2:
r = enroll_fido2(cd, vk, vks, arg_fido2_device);
break;
default:
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Operation not implemented yet.");
}
return r;
}
DEFINE_MAIN_FUNCTION(run);