1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "libfido2-util.h"
6 #include "alloc-util.h"
7 #include "dlfcn-util.h"
8 #include "format-table.h"
9 #include "locale-util.h"
12 static void *libfido2_dl
= NULL
;
14 int (*sym_fido_assert_allow_cred
)(fido_assert_t
*, const unsigned char *, size_t) = NULL
;
15 void (*sym_fido_assert_free
)(fido_assert_t
**) = NULL
;
16 size_t (*sym_fido_assert_hmac_secret_len
)(const fido_assert_t
*, size_t) = NULL
;
17 const unsigned char* (*sym_fido_assert_hmac_secret_ptr
)(const fido_assert_t
*, size_t) = NULL
;
18 fido_assert_t
* (*sym_fido_assert_new
)(void) = NULL
;
19 int (*sym_fido_assert_set_clientdata_hash
)(fido_assert_t
*, const unsigned char *, size_t) = NULL
;
20 int (*sym_fido_assert_set_extensions
)(fido_assert_t
*, int) = NULL
;
21 int (*sym_fido_assert_set_hmac_salt
)(fido_assert_t
*, const unsigned char *, size_t) = NULL
;
22 int (*sym_fido_assert_set_rp
)(fido_assert_t
*, const char *) = NULL
;
23 int (*sym_fido_assert_set_up
)(fido_assert_t
*, fido_opt_t
) = NULL
;
24 size_t (*sym_fido_cbor_info_extensions_len
)(const fido_cbor_info_t
*) = NULL
;
25 char **(*sym_fido_cbor_info_extensions_ptr
)(const fido_cbor_info_t
*) = NULL
;
26 void (*sym_fido_cbor_info_free
)(fido_cbor_info_t
**) = NULL
;
27 fido_cbor_info_t
* (*sym_fido_cbor_info_new
)(void) = NULL
;
28 void (*sym_fido_cred_free
)(fido_cred_t
**) = NULL
;
29 size_t (*sym_fido_cred_id_len
)(const fido_cred_t
*) = NULL
;
30 const unsigned char* (*sym_fido_cred_id_ptr
)(const fido_cred_t
*) = NULL
;
31 fido_cred_t
* (*sym_fido_cred_new
)(void) = NULL
;
32 int (*sym_fido_cred_set_clientdata_hash
)(fido_cred_t
*, const unsigned char *, size_t) = NULL
;
33 int (*sym_fido_cred_set_extensions
)(fido_cred_t
*, int) = NULL
;
34 int (*sym_fido_cred_set_rk
)(fido_cred_t
*, fido_opt_t
) = NULL
;
35 int (*sym_fido_cred_set_rp
)(fido_cred_t
*, const char *, const char *) = NULL
;
36 int (*sym_fido_cred_set_type
)(fido_cred_t
*, int) = NULL
;
37 int (*sym_fido_cred_set_user
)(fido_cred_t
*, const unsigned char *, size_t, const char *, const char *, const char *) = NULL
;
38 int (*sym_fido_cred_set_uv
)(fido_cred_t
*, fido_opt_t
) = NULL
;
39 void (*sym_fido_dev_free
)(fido_dev_t
**) = NULL
;
40 int (*sym_fido_dev_get_assert
)(fido_dev_t
*, fido_assert_t
*, const char *) = NULL
;
41 int (*sym_fido_dev_get_cbor_info
)(fido_dev_t
*, fido_cbor_info_t
*) = NULL
;
42 void (*sym_fido_dev_info_free
)(fido_dev_info_t
**, size_t) = NULL
;
43 int (*sym_fido_dev_info_manifest
)(fido_dev_info_t
*, size_t, size_t *) = NULL
;
44 const char* (*sym_fido_dev_info_manufacturer_string
)(const fido_dev_info_t
*) = NULL
;
45 const char* (*sym_fido_dev_info_product_string
)(const fido_dev_info_t
*) = NULL
;
46 fido_dev_info_t
* (*sym_fido_dev_info_new
)(size_t) = NULL
;
47 const char* (*sym_fido_dev_info_path
)(const fido_dev_info_t
*) = NULL
;
48 const fido_dev_info_t
* (*sym_fido_dev_info_ptr
)(const fido_dev_info_t
*, size_t) = NULL
;
49 bool (*sym_fido_dev_is_fido2
)(const fido_dev_t
*) = NULL
;
50 int (*sym_fido_dev_make_cred
)(fido_dev_t
*, fido_cred_t
*, const char *) = NULL
;
51 fido_dev_t
* (*sym_fido_dev_new
)(void) = NULL
;
52 int (*sym_fido_dev_open
)(fido_dev_t
*, const char *) = NULL
;
53 const char* (*sym_fido_strerr
)(int) = NULL
;
55 int dlopen_libfido2(void) {
56 _cleanup_(dlclosep
) void *dl
= NULL
;
60 return 0; /* Already loaded */
62 dl
= dlopen("libfido2.so.1", RTLD_LAZY
);
64 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
65 "libfido2 support is not installed: %s", dlerror());
67 r
= dlsym_many_and_warn(
70 DLSYM_ARG(fido_assert_allow_cred
),
71 DLSYM_ARG(fido_assert_free
),
72 DLSYM_ARG(fido_assert_hmac_secret_len
),
73 DLSYM_ARG(fido_assert_hmac_secret_ptr
),
74 DLSYM_ARG(fido_assert_new
),
75 DLSYM_ARG(fido_assert_set_clientdata_hash
),
76 DLSYM_ARG(fido_assert_set_extensions
),
77 DLSYM_ARG(fido_assert_set_hmac_salt
),
78 DLSYM_ARG(fido_assert_set_rp
),
79 DLSYM_ARG(fido_assert_set_up
),
80 DLSYM_ARG(fido_cbor_info_extensions_len
),
81 DLSYM_ARG(fido_cbor_info_extensions_ptr
),
82 DLSYM_ARG(fido_cbor_info_free
),
83 DLSYM_ARG(fido_cbor_info_new
),
84 DLSYM_ARG(fido_cred_free
),
85 DLSYM_ARG(fido_cred_id_len
),
86 DLSYM_ARG(fido_cred_id_ptr
),
87 DLSYM_ARG(fido_cred_new
),
88 DLSYM_ARG(fido_cred_set_clientdata_hash
),
89 DLSYM_ARG(fido_cred_set_extensions
),
90 DLSYM_ARG(fido_cred_set_rk
),
91 DLSYM_ARG(fido_cred_set_rp
),
92 DLSYM_ARG(fido_cred_set_type
),
93 DLSYM_ARG(fido_cred_set_user
),
94 DLSYM_ARG(fido_cred_set_uv
),
95 DLSYM_ARG(fido_dev_free
),
96 DLSYM_ARG(fido_dev_get_assert
),
97 DLSYM_ARG(fido_dev_get_cbor_info
),
98 DLSYM_ARG(fido_dev_info_free
),
99 DLSYM_ARG(fido_dev_info_manifest
),
100 DLSYM_ARG(fido_dev_info_manufacturer_string
),
101 DLSYM_ARG(fido_dev_info_new
),
102 DLSYM_ARG(fido_dev_info_path
),
103 DLSYM_ARG(fido_dev_info_product_string
),
104 DLSYM_ARG(fido_dev_info_ptr
),
105 DLSYM_ARG(fido_dev_is_fido2
),
106 DLSYM_ARG(fido_dev_make_cred
),
107 DLSYM_ARG(fido_dev_new
),
108 DLSYM_ARG(fido_dev_open
),
109 DLSYM_ARG(fido_strerr
),
114 /* Note that we never release the reference here, because there's no real reason to, after all this
115 * was traditionally a regular shared library dependency which lives forever too. */
116 libfido2_dl
= TAKE_PTR(dl
);
121 int fido2_list_devices(void) {
123 _cleanup_(table_unrefp
) Table
*t
= NULL
;
124 size_t allocated
= 64, found
= 0;
125 fido_dev_info_t
*di
= NULL
;
128 r
= dlopen_libfido2();
130 return log_error_errno(r
, "FIDO2 token support is not installed.");
132 di
= sym_fido_dev_info_new(allocated
);
136 r
= sym_fido_dev_info_manifest(di
, allocated
, &found
);
137 if (r
== FIDO_ERR_INTERNAL
|| (r
== FIDO_OK
&& found
== 0)) {
138 /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */
139 log_info("No FIDO2 devices found.");
144 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r
));
148 t
= table_new("path", "manufacturer", "product");
154 for (size_t i
= 0; i
< found
; i
++) {
155 const fido_dev_info_t
*entry
;
157 entry
= sym_fido_dev_info_ptr(di
, i
);
159 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
),
160 "Failed to get device information for FIDO device %zu.", i
);
166 TABLE_PATH
, sym_fido_dev_info_path(entry
),
167 TABLE_STRING
, sym_fido_dev_info_manufacturer_string(entry
),
168 TABLE_STRING
, sym_fido_dev_info_product_string(entry
));
170 table_log_add_error(r
);
175 r
= table_print(t
, stdout
);
177 log_error_errno(r
, "Failed to show device table: %m");
184 sym_fido_dev_info_free(&di
, allocated
);
187 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
188 "FIDO2 tokens not supported on this build.");
192 int fido2_find_device_auto(char **ret
) {
194 _cleanup_free_
char *copy
= NULL
;
195 size_t di_size
= 64, found
= 0;
196 const fido_dev_info_t
*entry
;
197 fido_dev_info_t
*di
= NULL
;
201 r
= dlopen_libfido2();
203 return log_error_errno(r
, "FIDO2 token support is not installed.");
205 di
= sym_fido_dev_info_new(di_size
);
209 r
= sym_fido_dev_info_manifest(di
, di_size
, &found
);
210 if (r
== FIDO_ERR_INTERNAL
|| (r
== FIDO_OK
&& found
== 0)) {
211 /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */
212 r
= log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "No FIDO devices found.");
216 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to enumerate FIDO devices: %s", sym_fido_strerr(r
));
220 r
= log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
), "More than one FIDO device found.");
224 entry
= sym_fido_dev_info_ptr(di
, 0);
226 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
),
227 "Failed to get device information for FIDO device 0.");
231 path
= sym_fido_dev_info_path(entry
);
233 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
),
234 "Failed to query FIDO device path.");
244 *ret
= TAKE_PTR(copy
);
248 sym_fido_dev_info_free(&di
, di_size
);
251 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
252 "FIDO2 tokens not supported on this build.");