install : true,
install_dir : libcryptsetup_plugins_dir)
endif
+
+ if conf.get('HAVE_LIBFIDO2') == 1
+ cryptsetup_token_systemd_fido2 = shared_library(
+ 'cryptsetup-token-systemd-fido2',
+ link_args : ['-shared',
+ '-Wl,--version-script=' + cryptsetup_token_sym_path],
+ dependencies : libshared_deps + [libcryptsetup, versiondep],
+ link_with : [libshared],
+ link_whole : [cryptsetup_token_systemd_fido2_static],
+ link_depends : cryptsetup_token_sym,
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : libcryptsetup_plugins_dir)
+ endif
endif
############################################################
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <errno.h>
+#include <libcryptsetup.h>
+#include <string.h>
+
+#include "cryptsetup-token.h"
+#include "cryptsetup-token-util.h"
+#include "hexdecoct.h"
+#include "json.h"
+#include "luks2-fido2.h"
+#include "memory-util.h"
+#include "version.h"
+
+#define TOKEN_NAME "systemd-fido2"
+#define TOKEN_VERSION_MAJOR "1"
+#define TOKEN_VERSION_MINOR "0"
+
+/* for libcryptsetup debug purpose */
+_public_ const char *cryptsetup_token_version(void) {
+ return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
+}
+
+_public_ int cryptsetup_token_open_pin(
+ struct crypt_device *cd, /* is always LUKS2 context */
+ int token /* is always >= 0 */,
+ const char *pin,
+ size_t pin_size,
+ char **password, /* freed by cryptsetup_token_buffer_free */
+ size_t *password_len,
+ void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
+
+ int r;
+ const char *json;
+ _cleanup_(erase_and_freep) char *pin_string = NULL;
+
+ assert(!pin || pin_size);
+ assert(token >= 0);
+
+ /* This must not fail at this moment (internal error) */
+ r = crypt_token_json_get(cd, token, &json);
+ assert(token == r);
+ assert(json);
+
+ if (pin && memchr(pin, 0, pin_size - 1))
+ return crypt_log_error_errno(cd, ENOANO, "PIN must be characters string.");
+
+ /* pin was passed as pin = pin, pin_size = strlen(pin). We need to add terminating
+ * NULL byte to addressable memory*/
+ if (pin && pin[pin_size-1] != '\0') {
+ pin_string = strndup(pin, pin_size);
+ if (!pin_string)
+ return crypt_log_oom(cd);
+ }
+
+ return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string ?: pin, password, password_len);
+}
+
+/*
+ * This function is called from within following libcryptsetup calls
+ * provided conditions further below are met:
+ *
+ * crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-fido2'):
+ *
+ * - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
+ * (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
+ * and token is assigned to at least single keyslot).
+ *
+ * - if plugin defines validate funtion (see cryptsetup_token_validate below) it must have
+ * passed the check (aka return 0)
+ */
+_public_ int cryptsetup_token_open(
+ struct crypt_device *cd, /* is always LUKS2 context */
+ int token /* is always >= 0 */,
+ char **password, /* freed by cryptsetup_token_buffer_free */
+ size_t *password_len,
+ void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
+
+ return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
+}
+
+/*
+ * libcryptsetup callback for memory deallocation of 'password' parameter passed in
+ * any crypt_token_open_* plugin function
+ */
+_public_ void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len) {
+ erase_and_free(buffer);
+}
+
+/*
+ * prints systemd-fido2 token content in crypt_dump().
+ * 'type' and 'keyslots' fields are printed by libcryptsetup
+ */
+_public_ void cryptsetup_token_dump(
+ struct crypt_device *cd /* is always LUKS2 context */,
+ const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) {
+
+ int r;
+ Fido2EnrollFlags required;
+ size_t cid_size, salt_size;
+ const char *client_pin_req_str, *up_req_str, *uv_req_str;
+ _cleanup_free_ void *cid = NULL, *salt = NULL;
+ _cleanup_free_ char *rp_id = NULL, *cid_str = NULL, *salt_str = NULL;
+
+ assert(json);
+
+ r = parse_luks2_fido2_data(cd, json, &rp_id, &salt, &salt_size, &cid, &cid_size, &required);
+ if (r < 0)
+ return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
+
+ r = crypt_dump_buffer_to_hex_string(cid, cid_size, &cid_str);
+ if (r < 0)
+ return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
+
+ r = crypt_dump_buffer_to_hex_string(salt, salt_size, &salt_str);
+ if (r < 0)
+ return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
+
+ if (required & FIDO2ENROLL_PIN)
+ client_pin_req_str = "true";
+ else if (required & FIDO2ENROLL_PIN_IF_NEEDED)
+ client_pin_req_str = NULL;
+ else
+ client_pin_req_str = "false";
+
+ if (required & FIDO2ENROLL_UP)
+ up_req_str = "true";
+ else if (required & FIDO2ENROLL_UP_IF_NEEDED)
+ up_req_str = NULL;
+ else
+ up_req_str = "false";
+
+ if (required & FIDO2ENROLL_UV)
+ uv_req_str = "true";
+ else if (required & FIDO2ENROLL_UV_OMIT)
+ uv_req_str = NULL;
+ else
+ uv_req_str = "false";
+
+ crypt_log(cd, "\tfido2-credential:" CRYPT_DUMP_LINE_SEP "%s\n", cid_str);
+ crypt_log(cd, "\tfido2-salt: %s\n", salt_str);
+
+ /* optional fields */
+ if (rp_id)
+ crypt_log(cd, "\tfido2-rp: %s\n", rp_id);
+ if (client_pin_req_str)
+ crypt_log(cd, "\tfido2-clientPin-required:" CRYPT_DUMP_LINE_SEP "%s\n",
+ client_pin_req_str);
+ if (up_req_str)
+ crypt_log(cd, "\tfido2-up-required:" CRYPT_DUMP_LINE_SEP "%s\n", up_req_str);
+ if (uv_req_str)
+ crypt_log(cd, "\tfido2-uv-required:" CRYPT_DUMP_LINE_SEP "%s\n", uv_req_str);
+}
+
+/*
+ * Note:
+ * If plugin is available in library path, it's called in before following libcryptsetup calls:
+ *
+ * crypt_token_json_set, crypt_dump, any crypt_activate_by_token_* flavour
+ */
+_public_ int cryptsetup_token_validate(
+ struct crypt_device *cd, /* is always LUKS2 context */
+ const char *json /* contains valid 'type' and 'keyslots' fields. 'type' is 'systemd-tpm2' */) {
+
+ int r;
+ JsonVariant *w;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+ assert(json);
+
+ r = json_parse(json, 0, &v, NULL, NULL);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m.");
+
+ w = json_variant_by_key(v, "fido2-credential");
+ if (!w || !json_variant_is_string(w)) {
+ crypt_log_debug(cd, "FIDO2 token data lacks 'fido2-credential' field.");
+ return 1;
+ }
+
+ r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'fido2-credential' field: %m");
+
+ w = json_variant_by_key(v, "fido2-salt");
+ if (!w || !json_variant_is_string(w)) {
+ crypt_log_debug(cd, "FIDO2 token data lacks 'fido2-salt' field.");
+ return 1;
+ }
+
+ r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
+ if (r < 0)
+ return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded salt: %m.");
+
+ /* The "rp" field is optional. */
+ w = json_variant_by_key(v, "fido2-rp");
+ if (w && !json_variant_is_string(w)) {
+ crypt_log_debug(cd, "FIDO2 token data's 'fido2-rp' field is not a string.");
+ return 1;
+ }
+
+ /* The "fido2-clientPin-required" field is optional. */
+ w = json_variant_by_key(v, "fido2-clientPin-required");
+ if (w && !json_variant_is_boolean(w)) {
+ crypt_log_debug(cd, "FIDO2 token data's 'fido2-clientPin-required' field is not a boolean.");
+ return 1;
+ }
+
+ /* The "fido2-up-required" field is optional. */
+ w = json_variant_by_key(v, "fido2-up-required");
+ if (w && !json_variant_is_boolean(w)) {
+ crypt_log_debug(cd, "FIDO2 token data's 'fido2-up-required' field is not a boolean.");
+ return 1;
+ }
+
+ /* The "fido2-uv-required" field is optional. */
+ w = json_variant_by_key(v, "fido2-uv-required");
+ if (w && !json_variant_is_boolean(w)) {
+ crypt_log_debug(cd, "FIDO2 token data's 'fido2-uv-required' field is not a boolean.");
+ return 1;
+ }
+
+ return 0;
+}
#pragma once
+#include <stdbool.h>
#include <stddef.h>
/* crypt_dump() internal indentation magic */
#define crypt_log_error(cd, ...) crypt_logf(cd, CRYPT_LOG_ERROR, __VA_ARGS__)
#define crypt_log(cd, ...) crypt_logf(cd, CRYPT_LOG_NORMAL, __VA_ARGS__)
-#define crypt_log_debug_errno(cd, e, ...) ({ \
+#define crypt_log_full_errno(cd, e, lvl, ...) ({ \
int _e = abs(e), _s = errno; \
errno = _e; \
- crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__); \
+ crypt_logf(cd, lvl, __VA_ARGS__); \
errno = _s; \
-_e; \
})
+#define crypt_log_debug_errno(cd, e, ...) \
+ crypt_log_full_errno(cd, e, CRYPT_LOG_DEBUG, __VA_ARGS__)
+
+#define crypt_log_error_errno(cd, e, ...) \
+ crypt_log_full_errno(cd, e, CRYPT_LOG_ERROR, __VA_ARGS__)
+
+#define crypt_log_oom(cd) crypt_log_error_errno(cd, ENOMEM, "Not enough memory.")
+
int crypt_dump_buffer_to_hex_string(
const char *buf,
size_t buf_size,
int cryptsetup_token_open(struct crypt_device *cd, int token,
char **password, size_t *password_len, void *usrptr);
+int cryptsetup_token_open_pin(struct crypt_device *cd, int token,
+ const char *pin, size_t pin_size,
+ char **password, size_t *password_len, void *usrptr);
+
void cryptsetup_token_dump(struct crypt_device *cd, const char *json);
int cryptsetup_token_validate(struct crypt_device *cd, const char *json);
CRYPTSETUP_TOKEN_1.0 {
global:
cryptsetup_token_open;
+ cryptsetup_token_open_pin;
cryptsetup_token_buffer_free;
cryptsetup_token_validate;
cryptsetup_token_dump;
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <libcryptsetup.h>
+
+#include "cryptsetup-token-util.h"
+#include "hexdecoct.h"
+#include "json.h"
+#include "luks2-fido2.h"
+#include "memory-util.h"
+#include "strv.h"
+
+int acquire_luks2_key(
+ struct crypt_device *cd,
+ const char *json,
+ const char *device,
+ const char *pin,
+ char **ret_keyslot_passphrase,
+ size_t *ret_keyslot_passphrase_size) {
+
+ int r;
+ Fido2EnrollFlags required;
+ size_t cid_size, salt_size, decrypted_key_size;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+ _cleanup_free_ void *cid = NULL, *salt = NULL;
+ _cleanup_free_ char *rp_id = NULL;
+ _cleanup_(erase_and_freep) void *decrypted_key = NULL;
+ _cleanup_(erase_and_freep) char *base64_encoded = NULL;
+ _cleanup_strv_free_erase_ char **pins = NULL;
+
+ assert(ret_keyslot_passphrase);
+ assert(ret_keyslot_passphrase_size);
+
+ r = parse_luks2_fido2_data(cd, json, &rp_id, &salt, &salt_size, &cid, &cid_size, &required);
+ if (r < 0)
+ return r;
+
+ if (pin) {
+ pins = strv_new(pin);
+ if (!pins)
+ return crypt_log_oom(cd);
+ }
+
+ /* configured to use pin but none was provided */
+ if ((required & FIDO2ENROLL_PIN) && strv_isempty(pins))
+ return -ENOANO;
+
+ r = fido2_use_hmac_hash(
+ device,
+ rp_id ?: "io.systemd.cryptsetup",
+ salt, salt_size,
+ cid, cid_size,
+ pins,
+ required,
+ &decrypted_key,
+ &decrypted_key_size);
+ if (r == -ENOLCK) /* libcryptsetup returns -ENOANO also on wrong pin */
+ r = -ENOANO;
+ if (r < 0)
+ return r;
+
+ /* Before using this key as passphrase we base64 encode it, for compat with homed */
+ r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
+ if (r < 0)
+ return crypt_log_error_errno(cd, r, "Can not base64 encode key: %m");
+
+ *ret_keyslot_passphrase = TAKE_PTR(base64_encoded);
+ *ret_keyslot_passphrase_size = strlen(*ret_keyslot_passphrase);
+
+ return 0;
+}
+
+/* this function expects valid "systemd-fido2" in json */
+int parse_luks2_fido2_data(
+ struct crypt_device *cd,
+ const char *json,
+ char **ret_rp_id,
+ void **ret_salt,
+ size_t *ret_salt_size,
+ void **ret_cid,
+ size_t *ret_cid_size,
+ Fido2EnrollFlags *ret_required) {
+
+ _cleanup_free_ void *cid = NULL, *salt = NULL;
+ size_t cid_size = 0, salt_size = 0;
+ _cleanup_free_ char *rp = NULL;
+ int r;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+ JsonVariant *w;
+ Fido2EnrollFlags required = 0;
+
+ assert(json);
+ assert(ret_rp_id);
+ assert(ret_salt);
+ assert(ret_salt_size);
+ assert(ret_cid);
+ assert(ret_cid_size);
+ assert(ret_required);
+
+ r = json_parse(json, 0, &v, NULL, NULL);
+ if (r < 0)
+ return crypt_log_error_errno(cd, r, "Failed to parse JSON token data: %m");
+
+ w = json_variant_by_key(v, "fido2-credential");
+ if (!w)
+ return -EINVAL;
+
+ r = unbase64mem(json_variant_string(w), SIZE_MAX, &cid, &cid_size);
+ if (r < 0)
+ return crypt_log_error_errno(cd, r, "Failed to parse 'fido2-credentials' field: %m");
+
+ w = json_variant_by_key(v, "fido2-salt");
+ if (!w)
+ return -EINVAL;
+
+ r = unbase64mem(json_variant_string(w), SIZE_MAX, &salt, &salt_size);
+ if (r < 0)
+ return crypt_log_error_errno(cd, r, "Failed to parse 'fido2-salt' field: %m");
+
+ w = json_variant_by_key(v, "fido2-rp");
+ if (w) {
+ /* The "rp" field is optional. */
+ rp = strdup(json_variant_string(w));
+ if (!rp) {
+ crypt_log_error(cd, "Not enough memory.");
+ return -ENOMEM;
+ }
+ }
+
+ w = json_variant_by_key(v, "fido2-clientPin-required");
+ if (w)
+ /* The "fido2-clientPin-required" field is optional. */
+ SET_FLAG(required, FIDO2ENROLL_PIN, json_variant_boolean(w));
+ else
+ required |= FIDO2ENROLL_PIN_IF_NEEDED; /* compat with 248, where the field was unset */
+
+ w = json_variant_by_key(v, "fido2-up-required");
+ if (w)
+ /* The "fido2-up-required" field is optional. */
+ SET_FLAG(required, FIDO2ENROLL_UP, json_variant_boolean(w));
+ else
+ required |= FIDO2ENROLL_UP_IF_NEEDED; /* compat with 248 */
+
+ w = json_variant_by_key(v, "fido2-uv-required");
+ if (w)
+ /* The "fido2-uv-required" field is optional. */
+ SET_FLAG(required, FIDO2ENROLL_UV, json_variant_boolean(w));
+ else
+ required |= FIDO2ENROLL_UV_OMIT; /* compat with 248 */
+
+ *ret_rp_id = TAKE_PTR(rp);
+ *ret_cid = TAKE_PTR(cid);
+ *ret_cid_size = cid_size;
+ *ret_salt = TAKE_PTR(salt);
+ *ret_salt_size = salt_size;
+ *ret_required = required;
+
+ return 0;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "libfido2-util.h"
+
+struct crypt_device;
+
+int acquire_luks2_key(
+ struct crypt_device *cd,
+ const char *json,
+ const char *device,
+ const char *pin,
+ char **ret_keyslot_passphrase,
+ size_t *ret_keyslot_passphrase_size);
+
+int parse_luks2_fido2_data(
+ struct crypt_device *cd,
+ const char *json,
+ char **ret_rp_id,
+ void **ret_salt,
+ size_t *ret_salt_size,
+ void **ret_cid,
+ size_t *ret_cid_size,
+ Fido2EnrollFlags *ret_required);
c_args : cryptsetup_token_c_args)
endif
+if conf.get('HAVE_LIBFIDO2') == 1
+ cryptsetup_token_systemd_fido2_sources = files('''
+ cryptsetup-token-systemd-fido2.c
+ cryptsetup-token.h
+ cryptsetup-token-util.h
+ cryptsetup-token-util.c
+ luks2-fido2.c
+ luks2-fido2.h
+ '''.split())
+
+ cryptsetup_token_systemd_fido2_static = static_library(
+ 'cryptsetup-token-systemd-fido2_static',
+ cryptsetup_token_systemd_fido2_sources,
+ include_directories : includes,
+ dependencies : libshared_deps + [libcryptsetup, versiondep],
+ c_args : cryptsetup_token_c_args)
+endif
+
endif
return 0;
}
+static bool libcryptsetup_plugins_support(void) {
+#if HAVE_LIBCRYPTSETUP_PLUGINS
+ return crypt_token_external_path() != NULL;
+#else
+ return false;
+#endif
+}
+
+#if HAVE_LIBCRYPTSETUP_PLUGINS
+static int acquire_pins_from_env_variable(char ***ret_pins) {
+ char *e;
+ _cleanup_strv_free_erase_ char **pins = NULL;
+
+ assert(ret_pins);
+
+ e = getenv("PIN");
+ if (e) {
+ pins = strv_new(e);
+ if (!pins)
+ return log_oom();
+
+ string_erase(e);
+ if (unsetenv("PIN") < 0)
+ return log_error_errno(errno, "Failed to unset $PIN: %m");
+ }
+
+ *ret_pins = TAKE_PTR(pins);
+
+ return 0;
+}
+#endif
+
+static int attach_luks2_by_fido2(
+ struct crypt_device *cd,
+ const char *name,
+ usec_t until,
+ bool headless,
+ void *usrptr,
+ uint32_t activation_flags) {
+
+ int r = -EOPNOTSUPP;
+#if HAVE_LIBCRYPTSETUP_PLUGINS
+ char **p;
+ _cleanup_strv_free_erase_ char **pins = NULL;
+ AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
+
+ r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
+ if (r > 0) /* returns unlocked keyslot id on success */
+ r = 0;
+ if (r != -ENOANO) /* needs pin or pin is wrong */
+ return r;
+
+ r = acquire_pins_from_env_variable(&pins);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, pins) {
+ r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
+ if (r > 0) /* returns unlocked keyslot id on success */
+ r = 0;
+ if (r != -ENOANO) /* needs pin or pin is wrong */
+ return r;
+ }
+
+ if (headless)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
+
+ pins = strv_free_erase(pins);
+ r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, pins) {
+ r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
+ if (r > 0) /* returns unlocked keyslot id on success */
+ r = 0;
+ if (r != -ENOANO) /* needs pin or pin is wrong */
+ return r;
+ }
+
+ flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
+ for (;;) {
+ pins = strv_free_erase(pins);
+ r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, pins) {
+ r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
+ if (r > 0) /* returns unlocked keyslot id on success */
+ r = 0;
+ if (r != -ENOANO) /* needs pin or pin is wrong */
+ return r;
+ }
+ }
+#endif
+ return r;
+}
+
static int attach_luks_or_plain_or_bitlk_by_fido2(
struct crypt_device *cd,
const char *name,
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_free_ void *discovered_salt = NULL, *discovered_cid = NULL;
- size_t discovered_salt_size, discovered_cid_size, cid_size, decrypted_key_size;
+ size_t discovered_salt_size, discovered_cid_size, decrypted_key_size, cid_size = 0;
_cleanup_free_ char *friendly = NULL, *discovered_rp_id = NULL;
int keyslot = arg_key_slot, r;
- const char *rp_id;
- const void *cid;
+ const char *rp_id = NULL;
+ const void *cid = NULL;
Fido2EnrollFlags required;
+ bool use_libcryptsetup_plugin = libcryptsetup_plugins_support();
assert(cd);
assert(name);
* use PIN + UP when needed, and do not configure UV at all. Eventually, we should make this
* explicitly configurable. */
required = FIDO2ENROLL_PIN_IF_NEEDED | FIDO2ENROLL_UP_IF_NEEDED | FIDO2ENROLL_UV_OMIT;
- } else {
+ } else if (!use_libcryptsetup_plugin) {
r = find_fido2_auto_data(
cd,
&discovered_rp_id,
for (;;) {
bool processed = false;
- r = acquire_fido2_key(
- name,
- friendly,
- arg_fido2_device,
- rp_id,
- cid, cid_size,
- key_file, arg_keyfile_size, arg_keyfile_offset,
- key_data, key_data_size,
- until,
- arg_headless,
- required,
- &decrypted_key, &decrypted_key_size,
- arg_ask_password_flags);
- if (r >= 0)
- break;
+ if (use_libcryptsetup_plugin && !arg_fido2_cid) {
+ r = attach_luks2_by_fido2(cd, name, until, arg_headless, arg_fido2_device, flags);
+ if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT))
+ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
+ "Automatic FIDO2 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking.");
+
+ } else {
+ r = acquire_fido2_key(
+ name,
+ friendly,
+ arg_fido2_device,
+ rp_id,
+ cid, cid_size,
+ key_file, arg_keyfile_size, arg_keyfile_offset,
+ key_data, key_data_size,
+ until,
+ arg_headless,
+ required,
+ &decrypted_key, &decrypted_key_size,
+ arg_ask_password_flags);
+ if (r >= 0)
+ break;
+ }
+
if (r != -EAGAIN) /* EAGAIN means: token not found */
return r;