summaryrefslogtreecommitdiffstats
path: root/src/shared/libfido2-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/libfido2-util.c')
-rw-r--r--src/shared/libfido2-util.c143
1 files changed, 89 insertions, 54 deletions
diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c
index 1cc3afe..37f6898 100644
--- a/src/shared/libfido2-util.c
+++ b/src/shared/libfido2-util.c
@@ -16,53 +16,54 @@
static void *libfido2_dl = NULL;
-int (*sym_fido_assert_allow_cred)(fido_assert_t *, const unsigned char *, size_t) = NULL;
-void (*sym_fido_assert_free)(fido_assert_t **) = NULL;
-size_t (*sym_fido_assert_hmac_secret_len)(const fido_assert_t *, size_t) = NULL;
-const unsigned char* (*sym_fido_assert_hmac_secret_ptr)(const fido_assert_t *, size_t) = NULL;
-fido_assert_t* (*sym_fido_assert_new)(void) = NULL;
-int (*sym_fido_assert_set_clientdata_hash)(fido_assert_t *, const unsigned char *, size_t) = NULL;
-int (*sym_fido_assert_set_extensions)(fido_assert_t *, int) = NULL;
-int (*sym_fido_assert_set_hmac_salt)(fido_assert_t *, const unsigned char *, size_t) = NULL;
-int (*sym_fido_assert_set_rp)(fido_assert_t *, const char *) = NULL;
-int (*sym_fido_assert_set_up)(fido_assert_t *, fido_opt_t) = NULL;
-int (*sym_fido_assert_set_uv)(fido_assert_t *, fido_opt_t) = NULL;
-size_t (*sym_fido_cbor_info_extensions_len)(const fido_cbor_info_t *) = NULL;
-char **(*sym_fido_cbor_info_extensions_ptr)(const fido_cbor_info_t *) = NULL;
-void (*sym_fido_cbor_info_free)(fido_cbor_info_t **) = NULL;
-fido_cbor_info_t* (*sym_fido_cbor_info_new)(void) = NULL;
-size_t (*sym_fido_cbor_info_options_len)(const fido_cbor_info_t *) = NULL;
-char** (*sym_fido_cbor_info_options_name_ptr)(const fido_cbor_info_t *) = NULL;
-const bool* (*sym_fido_cbor_info_options_value_ptr)(const fido_cbor_info_t *) = NULL;
-void (*sym_fido_cred_free)(fido_cred_t **) = NULL;
-size_t (*sym_fido_cred_id_len)(const fido_cred_t *) = NULL;
-const unsigned char* (*sym_fido_cred_id_ptr)(const fido_cred_t *) = NULL;
-fido_cred_t* (*sym_fido_cred_new)(void) = NULL;
-int (*sym_fido_cred_set_clientdata_hash)(fido_cred_t *, const unsigned char *, size_t) = NULL;
-int (*sym_fido_cred_set_extensions)(fido_cred_t *, int) = NULL;
-int (*sym_fido_cred_set_rk)(fido_cred_t *, fido_opt_t) = NULL;
-int (*sym_fido_cred_set_rp)(fido_cred_t *, const char *, const char *) = NULL;
-int (*sym_fido_cred_set_type)(fido_cred_t *, int) = NULL;
-int (*sym_fido_cred_set_user)(fido_cred_t *, const unsigned char *, size_t, const char *, const char *, const char *) = NULL;
-int (*sym_fido_cred_set_uv)(fido_cred_t *, fido_opt_t) = NULL;
-void (*sym_fido_dev_free)(fido_dev_t **) = NULL;
-int (*sym_fido_dev_get_assert)(fido_dev_t *, fido_assert_t *, const char *) = NULL;
-int (*sym_fido_dev_get_cbor_info)(fido_dev_t *, fido_cbor_info_t *) = NULL;
-void (*sym_fido_dev_info_free)(fido_dev_info_t **, size_t) = NULL;
-int (*sym_fido_dev_info_manifest)(fido_dev_info_t *, size_t, size_t *) = NULL;
-const char* (*sym_fido_dev_info_manufacturer_string)(const fido_dev_info_t *) = NULL;
-const char* (*sym_fido_dev_info_product_string)(const fido_dev_info_t *) = NULL;
-fido_dev_info_t* (*sym_fido_dev_info_new)(size_t) = NULL;
-const char* (*sym_fido_dev_info_path)(const fido_dev_info_t *) = NULL;
-const fido_dev_info_t* (*sym_fido_dev_info_ptr)(const fido_dev_info_t *, size_t) = NULL;
-bool (*sym_fido_dev_is_fido2)(const fido_dev_t *) = NULL;
-int (*sym_fido_dev_make_cred)(fido_dev_t *, fido_cred_t *, const char *) = NULL;
-fido_dev_t* (*sym_fido_dev_new)(void) = NULL;
-int (*sym_fido_dev_open)(fido_dev_t *, const char *) = NULL;
-int (*sym_fido_dev_close)(fido_dev_t *) = NULL;
-void (*sym_fido_init)(int) = NULL;
-void (*sym_fido_set_log_handler)(fido_log_handler_t *) = NULL;
-const char* (*sym_fido_strerr)(int) = NULL;
+DLSYM_FUNCTION(fido_assert_allow_cred);
+DLSYM_FUNCTION(fido_assert_free);
+DLSYM_FUNCTION(fido_assert_hmac_secret_len);
+DLSYM_FUNCTION(fido_assert_hmac_secret_ptr);
+DLSYM_FUNCTION(fido_assert_new);
+DLSYM_FUNCTION(fido_assert_set_clientdata_hash);
+DLSYM_FUNCTION(fido_assert_set_extensions);
+DLSYM_FUNCTION(fido_assert_set_hmac_salt);
+DLSYM_FUNCTION(fido_assert_set_rp);
+DLSYM_FUNCTION(fido_assert_set_up);
+DLSYM_FUNCTION(fido_assert_set_uv);
+DLSYM_FUNCTION(fido_cbor_info_extensions_len);
+DLSYM_FUNCTION(fido_cbor_info_extensions_ptr);
+DLSYM_FUNCTION(fido_cbor_info_free);
+DLSYM_FUNCTION(fido_cbor_info_new);
+DLSYM_FUNCTION(fido_cbor_info_options_len);
+DLSYM_FUNCTION(fido_cbor_info_options_name_ptr);
+DLSYM_FUNCTION(fido_cbor_info_options_value_ptr);
+DLSYM_FUNCTION(fido_cred_free);
+DLSYM_FUNCTION(fido_cred_id_len);
+DLSYM_FUNCTION(fido_cred_id_ptr);
+DLSYM_FUNCTION(fido_cred_new);
+DLSYM_FUNCTION(fido_cred_set_clientdata_hash);
+DLSYM_FUNCTION(fido_cred_set_extensions);
+DLSYM_FUNCTION(fido_cred_set_prot);
+DLSYM_FUNCTION(fido_cred_set_rk);
+DLSYM_FUNCTION(fido_cred_set_rp);
+DLSYM_FUNCTION(fido_cred_set_type);
+DLSYM_FUNCTION(fido_cred_set_user);
+DLSYM_FUNCTION(fido_cred_set_uv);
+DLSYM_FUNCTION(fido_dev_free);
+DLSYM_FUNCTION(fido_dev_get_assert);
+DLSYM_FUNCTION(fido_dev_get_cbor_info);
+DLSYM_FUNCTION(fido_dev_info_free);
+DLSYM_FUNCTION(fido_dev_info_manifest);
+DLSYM_FUNCTION(fido_dev_info_manufacturer_string);
+DLSYM_FUNCTION(fido_dev_info_product_string);
+DLSYM_FUNCTION(fido_dev_info_new);
+DLSYM_FUNCTION(fido_dev_info_path);
+DLSYM_FUNCTION(fido_dev_info_ptr);
+DLSYM_FUNCTION(fido_dev_is_fido2);
+DLSYM_FUNCTION(fido_dev_make_cred);
+DLSYM_FUNCTION(fido_dev_new);
+DLSYM_FUNCTION(fido_dev_open);
+DLSYM_FUNCTION(fido_dev_close);
+DLSYM_FUNCTION(fido_init);
+DLSYM_FUNCTION(fido_set_log_handler);
+DLSYM_FUNCTION(fido_strerr);
static void fido_log_propagate_handler(const char *s) {
log_debug("libfido2: %s", strempty(s));
@@ -71,6 +72,11 @@ static void fido_log_propagate_handler(const char *s) {
int dlopen_libfido2(void) {
int r;
+ ELF_NOTE_DLOPEN("fido2",
+ "Support fido2 for encryption and authentication",
+ ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+ "libfido2.so.1");
+
r = dlopen_many_sym_or_warn(
&libfido2_dl, "libfido2.so.1", LOG_DEBUG,
DLSYM_ARG(fido_assert_allow_cred),
@@ -97,6 +103,7 @@ int dlopen_libfido2(void) {
DLSYM_ARG(fido_cred_new),
DLSYM_ARG(fido_cred_set_clientdata_hash),
DLSYM_ARG(fido_cred_set_extensions),
+ DLSYM_ARG(fido_cred_set_prot),
DLSYM_ARG(fido_cred_set_rk),
DLSYM_ARG(fido_cred_set_rp),
DLSYM_ARG(fido_cred_set_type),
@@ -574,7 +581,7 @@ static int fido2_use_hmac_hash_specific_token(
/* COSE_ECDH_ES256 is not usable with fido_cred_set_type() thus it's not listed here. */
static const char *fido2_algorithm_to_string(int alg) {
- switch(alg) {
+ switch (alg) {
case COSE_ES256:
return "es256";
case COSE_RS256:
@@ -686,7 +693,8 @@ int fido2_generate_hmac_hash(
const char *user_name,
const char *user_display_name,
const char *user_icon,
- const char *askpw_icon_name,
+ const char *askpw_icon,
+ const char *askpw_credential,
Fido2EnrollFlags lock_with,
int cred_alg,
void **ret_cid, size_t *ret_cid_size,
@@ -775,10 +783,21 @@ int fido2_generate_hmac_hash(
if (!c)
return log_oom();
- r = sym_fido_cred_set_extensions(c, FIDO_EXT_HMAC_SECRET);
+ int extensions = FIDO_EXT_HMAC_SECRET;
+ if (FLAGS_SET(lock_with, FIDO2ENROLL_UV)) {
+ /* Attempt to use the "cred protect" extension, requiring user verification (UV) for this
+ * credential. If the authenticator doesn't support the extension, it will be ignored. */
+ extensions |= FIDO_EXT_CRED_PROTECT;
+
+ r = sym_fido_cred_set_prot(c, FIDO_CRED_PROT_UV_REQUIRED);
+ if (r != FIDO_OK)
+ log_warning("Failed to set protection level on FIDO2 credential, ignoring: %s", sym_fido_strerr(r));
+ }
+
+ r = sym_fido_cred_set_extensions(c, extensions);
if (r != FIDO_OK)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
- "Failed to enable HMAC-SECRET extension on FIDO2 credential: %s", sym_fido_strerr(r));
+ "Failed to enable extensions on FIDO2 credential: %s", sym_fido_strerr(r));
r = sym_fido_cred_set_rp(c, rp_id, rp_name);
if (r != FIDO_OK)
@@ -829,7 +848,17 @@ int fido2_generate_hmac_hash(
emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "",
emoji_enabled() ? " " : "");
- r = sym_fido_dev_make_cred(d, c, NULL);
+ /* If we are using the user PIN, then we must pass that PIN to the get_assertion call below, or
+ * the authenticator will use the non-user-verification HMAC secret (which differs from the one when
+ * the PIN is passed).
+ *
+ * Rather than potentially trying and failing to create the credential, just collect the PIN first
+ * and then pass it to both the make_credential and the get_assertion operations. */
+ if (FLAGS_SET(lock_with, FIDO2ENROLL_PIN))
+ r = FIDO_ERR_PIN_REQUIRED;
+ else
+ r = sym_fido_dev_make_cred(d, c, NULL);
+
if (r == FIDO_ERR_PIN_REQUIRED) {
if (!has_client_pin)
@@ -838,8 +867,14 @@ int fido2_generate_hmac_hash(
for (;;) {
_cleanup_strv_free_erase_ char **pin = NULL;
-
- r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", "fido2-pin", USEC_INFINITY, 0, &pin);
+ AskPasswordRequest req = {
+ .message = "Please enter security token PIN:",
+ .icon = askpw_icon,
+ .keyring = "fido2-pin",
+ .credential = askpw_credential,
+ };
+
+ r = ask_password_auto(&req, USEC_INFINITY, /* flags= */ 0, &pin);
if (r < 0)
return log_error_errno(r, "Failed to acquire user PIN: %m");