]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/libfido2-util.c
core,journald: use quoted commandlines
[thirdparty/systemd.git] / src / shared / libfido2-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "libfido2-util.h"
4
5 #if HAVE_LIBFIDO2
6 #include "alloc-util.h"
7 #include "ask-password-api.h"
8 #include "dlfcn-util.h"
9 #include "format-table.h"
10 #include "locale-util.h"
11 #include "log.h"
12 #include "memory-util.h"
13 #include "random-util.h"
14 #include "strv.h"
15
16 static void *libfido2_dl = NULL;
17
18 int (*sym_fido_assert_allow_cred)(fido_assert_t *, const unsigned char *, size_t) = NULL;
19 void (*sym_fido_assert_free)(fido_assert_t **) = NULL;
20 size_t (*sym_fido_assert_hmac_secret_len)(const fido_assert_t *, size_t) = NULL;
21 const unsigned char* (*sym_fido_assert_hmac_secret_ptr)(const fido_assert_t *, size_t) = NULL;
22 fido_assert_t* (*sym_fido_assert_new)(void) = NULL;
23 int (*sym_fido_assert_set_clientdata_hash)(fido_assert_t *, const unsigned char *, size_t) = NULL;
24 int (*sym_fido_assert_set_extensions)(fido_assert_t *, int) = NULL;
25 int (*sym_fido_assert_set_hmac_salt)(fido_assert_t *, const unsigned char *, size_t) = NULL;
26 int (*sym_fido_assert_set_rp)(fido_assert_t *, const char *) = NULL;
27 int (*sym_fido_assert_set_up)(fido_assert_t *, fido_opt_t) = NULL;
28 size_t (*sym_fido_cbor_info_extensions_len)(const fido_cbor_info_t *) = NULL;
29 char **(*sym_fido_cbor_info_extensions_ptr)(const fido_cbor_info_t *) = NULL;
30 void (*sym_fido_cbor_info_free)(fido_cbor_info_t **) = NULL;
31 fido_cbor_info_t* (*sym_fido_cbor_info_new)(void) = NULL;
32 size_t (*sym_fido_cbor_info_options_len)(const fido_cbor_info_t *) = NULL;
33 char** (*sym_fido_cbor_info_options_name_ptr)(const fido_cbor_info_t *) = NULL;
34 const bool* (*sym_fido_cbor_info_options_value_ptr)(const fido_cbor_info_t *) = NULL;
35 void (*sym_fido_cred_free)(fido_cred_t **) = NULL;
36 size_t (*sym_fido_cred_id_len)(const fido_cred_t *) = NULL;
37 const unsigned char* (*sym_fido_cred_id_ptr)(const fido_cred_t *) = NULL;
38 fido_cred_t* (*sym_fido_cred_new)(void) = NULL;
39 int (*sym_fido_cred_set_clientdata_hash)(fido_cred_t *, const unsigned char *, size_t) = NULL;
40 int (*sym_fido_cred_set_extensions)(fido_cred_t *, int) = NULL;
41 int (*sym_fido_cred_set_rk)(fido_cred_t *, fido_opt_t) = NULL;
42 int (*sym_fido_cred_set_rp)(fido_cred_t *, const char *, const char *) = NULL;
43 int (*sym_fido_cred_set_type)(fido_cred_t *, int) = NULL;
44 int (*sym_fido_cred_set_user)(fido_cred_t *, const unsigned char *, size_t, const char *, const char *, const char *) = NULL;
45 int (*sym_fido_cred_set_uv)(fido_cred_t *, fido_opt_t) = NULL;
46 void (*sym_fido_dev_free)(fido_dev_t **) = NULL;
47 int (*sym_fido_dev_get_assert)(fido_dev_t *, fido_assert_t *, const char *) = NULL;
48 int (*sym_fido_dev_get_cbor_info)(fido_dev_t *, fido_cbor_info_t *) = NULL;
49 void (*sym_fido_dev_info_free)(fido_dev_info_t **, size_t) = NULL;
50 int (*sym_fido_dev_info_manifest)(fido_dev_info_t *, size_t, size_t *) = NULL;
51 const char* (*sym_fido_dev_info_manufacturer_string)(const fido_dev_info_t *) = NULL;
52 const char* (*sym_fido_dev_info_product_string)(const fido_dev_info_t *) = NULL;
53 fido_dev_info_t* (*sym_fido_dev_info_new)(size_t) = NULL;
54 const char* (*sym_fido_dev_info_path)(const fido_dev_info_t *) = NULL;
55 const fido_dev_info_t* (*sym_fido_dev_info_ptr)(const fido_dev_info_t *, size_t) = NULL;
56 bool (*sym_fido_dev_is_fido2)(const fido_dev_t *) = NULL;
57 int (*sym_fido_dev_make_cred)(fido_dev_t *, fido_cred_t *, const char *) = NULL;
58 fido_dev_t* (*sym_fido_dev_new)(void) = NULL;
59 int (*sym_fido_dev_open)(fido_dev_t *, const char *) = NULL;
60 const char* (*sym_fido_strerr)(int) = NULL;
61
62 int dlopen_libfido2(void) {
63 _cleanup_(dlclosep) void *dl = NULL;
64 int r;
65
66 if (libfido2_dl)
67 return 0; /* Already loaded */
68
69 dl = dlopen("libfido2.so.1", RTLD_LAZY);
70 if (!dl)
71 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
72 "libfido2 support is not installed: %s", dlerror());
73
74 r = dlsym_many_and_warn(
75 dl,
76 LOG_DEBUG,
77 DLSYM_ARG(fido_assert_allow_cred),
78 DLSYM_ARG(fido_assert_free),
79 DLSYM_ARG(fido_assert_hmac_secret_len),
80 DLSYM_ARG(fido_assert_hmac_secret_ptr),
81 DLSYM_ARG(fido_assert_new),
82 DLSYM_ARG(fido_assert_set_clientdata_hash),
83 DLSYM_ARG(fido_assert_set_extensions),
84 DLSYM_ARG(fido_assert_set_hmac_salt),
85 DLSYM_ARG(fido_assert_set_rp),
86 DLSYM_ARG(fido_assert_set_up),
87 DLSYM_ARG(fido_cbor_info_extensions_len),
88 DLSYM_ARG(fido_cbor_info_extensions_ptr),
89 DLSYM_ARG(fido_cbor_info_free),
90 DLSYM_ARG(fido_cbor_info_new),
91 DLSYM_ARG(fido_cbor_info_options_len),
92 DLSYM_ARG(fido_cbor_info_options_name_ptr),
93 DLSYM_ARG(fido_cbor_info_options_value_ptr),
94 DLSYM_ARG(fido_cred_free),
95 DLSYM_ARG(fido_cred_id_len),
96 DLSYM_ARG(fido_cred_id_ptr),
97 DLSYM_ARG(fido_cred_new),
98 DLSYM_ARG(fido_cred_set_clientdata_hash),
99 DLSYM_ARG(fido_cred_set_extensions),
100 DLSYM_ARG(fido_cred_set_rk),
101 DLSYM_ARG(fido_cred_set_rp),
102 DLSYM_ARG(fido_cred_set_type),
103 DLSYM_ARG(fido_cred_set_user),
104 DLSYM_ARG(fido_cred_set_uv),
105 DLSYM_ARG(fido_dev_free),
106 DLSYM_ARG(fido_dev_get_assert),
107 DLSYM_ARG(fido_dev_get_cbor_info),
108 DLSYM_ARG(fido_dev_info_free),
109 DLSYM_ARG(fido_dev_info_manifest),
110 DLSYM_ARG(fido_dev_info_manufacturer_string),
111 DLSYM_ARG(fido_dev_info_new),
112 DLSYM_ARG(fido_dev_info_path),
113 DLSYM_ARG(fido_dev_info_product_string),
114 DLSYM_ARG(fido_dev_info_ptr),
115 DLSYM_ARG(fido_dev_is_fido2),
116 DLSYM_ARG(fido_dev_make_cred),
117 DLSYM_ARG(fido_dev_new),
118 DLSYM_ARG(fido_dev_open),
119 DLSYM_ARG(fido_strerr),
120 NULL);
121 if (r < 0)
122 return r;
123
124 /* Note that we never release the reference here, because there's no real reason to, after all this
125 * was traditionally a regular shared library dependency which lives forever too. */
126 libfido2_dl = TAKE_PTR(dl);
127 return 1;
128 }
129
130 static int verify_features(
131 fido_dev_t *d,
132 const char *path,
133 int log_level, /* the log level to use when device is not FIDO2 with hmac-secret */
134 bool *ret_has_rk,
135 bool *ret_has_client_pin,
136 bool *ret_has_up,
137 bool *ret_has_uv) {
138
139 _cleanup_(fido_cbor_info_free_wrapper) fido_cbor_info_t *di = NULL;
140 bool found_extension = false;
141 char **e, **o;
142 const bool *b;
143 bool has_rk = false, has_client_pin = false, has_up = true, has_uv = false; /* Defaults are per table in 5.4 in FIDO2 spec */
144 size_t n;
145 int r;
146
147 assert(d);
148 assert(path);
149
150 if (!sym_fido_dev_is_fido2(d))
151 return log_full_errno(log_level,
152 SYNTHETIC_ERRNO(ENODEV),
153 "Specified device %s is not a FIDO2 device.", path);
154
155 di = sym_fido_cbor_info_new();
156 if (!di)
157 return log_oom();
158
159 r = sym_fido_dev_get_cbor_info(d, di);
160 if (r != FIDO_OK)
161 return log_error_errno(SYNTHETIC_ERRNO(EIO),
162 "Failed to get CBOR device info for %s: %s", path, sym_fido_strerr(r));
163
164 e = sym_fido_cbor_info_extensions_ptr(di);
165 n = sym_fido_cbor_info_extensions_len(di);
166 for (size_t i = 0; i < n; i++) {
167 log_debug("FIDO2 device implements extension: %s", e[i]);
168 if (streq(e[i], "hmac-secret"))
169 found_extension = true;
170 }
171
172 o = sym_fido_cbor_info_options_name_ptr(di);
173 b = sym_fido_cbor_info_options_value_ptr(di);
174 n = sym_fido_cbor_info_options_len(di);
175 for (size_t i = 0; i < n; i++) {
176 log_debug("FIDO2 device implements option %s: %s", o[i], yes_no(b[i]));
177 if (streq(o[i], "rk"))
178 has_rk = b[i];
179 if (streq(o[i], "clientPin"))
180 has_client_pin = b[i];
181 if (streq(o[i], "up"))
182 has_up = b[i];
183 if (streq(o[i], "uv"))
184 has_uv = b[i];
185 }
186
187 if (!found_extension)
188 return log_full_errno(log_level,
189 SYNTHETIC_ERRNO(ENODEV),
190 "Specified device %s is a FIDO2 device, but does not support the required HMAC-SECRET extension.", path);
191
192 log_debug("Has rk ('Resident Key') support: %s\n"
193 "Has clientPin support: %s\n"
194 "Has up ('User Presence') support: %s\n"
195 "Has uv ('User Verification') support: %s\n",
196 yes_no(has_rk),
197 yes_no(has_client_pin),
198 yes_no(has_up),
199 yes_no(has_uv));
200
201 if (ret_has_rk)
202 *ret_has_rk = has_rk;
203 if (ret_has_client_pin)
204 *ret_has_client_pin = has_client_pin;
205 if (ret_has_up)
206 *ret_has_up = has_up;
207 if (ret_has_uv)
208 *ret_has_uv = has_uv;
209
210 return 0;
211 }
212
213 static int fido2_use_hmac_hash_specific_token(
214 const char *path,
215 const char *rp_id,
216 const void *salt,
217 size_t salt_size,
218 const void *cid,
219 size_t cid_size,
220 char **pins,
221 bool up, /* user presence permitted */
222 void **ret_hmac,
223 size_t *ret_hmac_size) {
224
225 _cleanup_(fido_assert_free_wrapper) fido_assert_t *a = NULL;
226 _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
227 _cleanup_(erase_and_freep) void *hmac_copy = NULL;
228 bool has_up, has_client_pin;
229 size_t hmac_size;
230 const void *hmac;
231 int r;
232
233 assert(path);
234 assert(rp_id);
235 assert(salt);
236 assert(cid);
237 assert(ret_hmac);
238 assert(ret_hmac_size);
239
240 d = sym_fido_dev_new();
241 if (!d)
242 return log_oom();
243
244 r = sym_fido_dev_open(d, path);
245 if (r != FIDO_OK)
246 return log_error_errno(SYNTHETIC_ERRNO(EIO),
247 "Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
248
249 r = verify_features(d, path, LOG_ERR, NULL, &has_client_pin, &has_up, NULL);
250 if (r < 0)
251 return r;
252
253 a = sym_fido_assert_new();
254 if (!a)
255 return log_oom();
256
257 r = sym_fido_assert_set_extensions(a, FIDO_EXT_HMAC_SECRET);
258 if (r != FIDO_OK)
259 return log_error_errno(SYNTHETIC_ERRNO(EIO),
260 "Failed to enable HMAC-SECRET extension on FIDO2 assertion: %s", sym_fido_strerr(r));
261
262 r = sym_fido_assert_set_hmac_salt(a, salt, salt_size);
263 if (r != FIDO_OK)
264 return log_error_errno(SYNTHETIC_ERRNO(EIO),
265 "Failed to set salt on FIDO2 assertion: %s", sym_fido_strerr(r));
266
267 r = sym_fido_assert_set_rp(a, rp_id);
268 if (r != FIDO_OK)
269 return log_error_errno(SYNTHETIC_ERRNO(EIO),
270 "Failed to set FIDO2 assertion ID: %s", sym_fido_strerr(r));
271
272 r = sym_fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32);
273 if (r != FIDO_OK)
274 return log_error_errno(SYNTHETIC_ERRNO(EIO),
275 "Failed to set FIDO2 assertion client data hash: %s", sym_fido_strerr(r));
276
277 r = sym_fido_assert_allow_cred(a, cid, cid_size);
278 if (r != FIDO_OK)
279 return log_error_errno(SYNTHETIC_ERRNO(EIO),
280 "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r));
281
282 if (has_up) {
283 r = sym_fido_assert_set_up(a, FIDO_OPT_FALSE);
284 if (r != FIDO_OK)
285 return log_error_errno(SYNTHETIC_ERRNO(EIO),
286 "Failed to set FIDO2 assertion user presence: %s", sym_fido_strerr(r));
287 }
288
289 log_info("Asking FIDO2 token for authentication.");
290
291 r = sym_fido_dev_get_assert(d, a, NULL); /* try without pin and without up first */
292 if (r == FIDO_ERR_UP_REQUIRED && up) {
293
294 if (!has_up)
295 log_warning("Weird, device asked for User Presence check, but does not advertise it as feature. Ignoring.");
296
297 r = sym_fido_assert_set_up(a, FIDO_OPT_TRUE);
298 if (r != FIDO_OK)
299 return log_error_errno(SYNTHETIC_ERRNO(EIO),
300 "Failed to set FIDO2 assertion user presence: %s", sym_fido_strerr(r));
301
302 log_info("Security token requires user presence.");
303
304 r = sym_fido_dev_get_assert(d, a, NULL); /* try without pin but with up now */
305 }
306 if (r == FIDO_ERR_PIN_REQUIRED) {
307 char **i;
308
309 if (!has_client_pin)
310 log_warning("Weird, device asked for client PIN, but does not advertise it as feature. Ignoring.");
311
312 /* OK, we needed a pin, try with all pins in turn */
313 STRV_FOREACH(i, pins) {
314 r = sym_fido_dev_get_assert(d, a, *i);
315 if (r != FIDO_ERR_PIN_INVALID)
316 break;
317 }
318 }
319
320 switch (r) {
321 case FIDO_OK:
322 break;
323 case FIDO_ERR_NO_CREDENTIALS:
324 return log_error_errno(SYNTHETIC_ERRNO(EBADSLT),
325 "Wrong security token; needed credentials not present on token.");
326 case FIDO_ERR_PIN_REQUIRED:
327 return log_error_errno(SYNTHETIC_ERRNO(ENOANO),
328 "Security token requires PIN.");
329 case FIDO_ERR_PIN_AUTH_BLOCKED:
330 return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD),
331 "PIN of security token is blocked, please remove/reinsert token.");
332 case FIDO_ERR_PIN_INVALID:
333 return log_error_errno(SYNTHETIC_ERRNO(ENOLCK),
334 "PIN of security token incorrect.");
335 case FIDO_ERR_UP_REQUIRED:
336 return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE),
337 "User presence required.");
338 case FIDO_ERR_ACTION_TIMEOUT:
339 return log_error_errno(SYNTHETIC_ERRNO(ENOSTR),
340 "Token action timeout. (User didn't interact with token quickly enough.)");
341 default:
342 return log_error_errno(SYNTHETIC_ERRNO(EIO),
343 "Failed to ask token for assertion: %s", sym_fido_strerr(r));
344 }
345
346 hmac = sym_fido_assert_hmac_secret_ptr(a, 0);
347 if (!hmac)
348 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve HMAC secret.");
349
350 hmac_size = sym_fido_assert_hmac_secret_len(a, 0);
351
352 hmac_copy = memdup(hmac, hmac_size);
353 if (!hmac_copy)
354 return log_oom();
355
356 *ret_hmac = TAKE_PTR(hmac_copy);
357 *ret_hmac_size = hmac_size;
358 return 0;
359 }
360
361 int fido2_use_hmac_hash(
362 const char *device,
363 const char *rp_id,
364 const void *salt,
365 size_t salt_size,
366 const void *cid,
367 size_t cid_size,
368 char **pins,
369 bool up, /* user presence permitted */
370 void **ret_hmac,
371 size_t *ret_hmac_size) {
372
373 size_t allocated = 64, found = 0;
374 fido_dev_info_t *di = NULL;
375 int r;
376
377 r = dlopen_libfido2();
378 if (r < 0)
379 return log_error_errno(r, "FIDO2 support is not installed.");
380
381 if (device)
382 return fido2_use_hmac_hash_specific_token(device, rp_id, salt, salt_size, cid, cid_size, pins, up, ret_hmac, ret_hmac_size);
383
384 di = sym_fido_dev_info_new(allocated);
385 if (!di)
386 return log_oom();
387
388 r = sym_fido_dev_info_manifest(di, allocated, &found);
389 if (r == FIDO_ERR_INTERNAL) {
390 /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */
391 r = log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "Got FIDO_ERR_INTERNAL, assuming no devices.");
392 goto finish;
393 }
394 if (r != FIDO_OK) {
395 r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r));
396 goto finish;
397 }
398
399 for (size_t i = 0; i < found; i++) {
400 const fido_dev_info_t *entry;
401 const char *path;
402
403 entry = sym_fido_dev_info_ptr(di, i);
404 if (!entry) {
405 r = log_error_errno(SYNTHETIC_ERRNO(EIO),
406 "Failed to get device information for FIDO device %zu.", i);
407 goto finish;
408 }
409
410 path = sym_fido_dev_info_path(entry);
411 if (!path) {
412 r = log_error_errno(SYNTHETIC_ERRNO(EIO),
413 "Failed to query FIDO device path.");
414 goto finish;
415 }
416
417 r = fido2_use_hmac_hash_specific_token(path, rp_id, salt, salt_size, cid, cid_size, pins, up, ret_hmac, ret_hmac_size);
418 if (!IN_SET(r,
419 -EBADSLT, /* device doesn't understand our credential hash */
420 -ENODEV /* device is not a FIDO2 device with HMAC-SECRET */))
421 goto finish;
422 }
423
424 r = -EAGAIN;
425
426 finish:
427 sym_fido_dev_info_free(&di, allocated);
428 return r;
429 }
430
431 #define FIDO2_SALT_SIZE 32
432
433 int fido2_generate_hmac_hash(
434 const char *device,
435 const char *rp_id,
436 const char *rp_name,
437 const void *user_id, size_t user_id_len,
438 const char *user_name,
439 const char *user_display_name,
440 const char *user_icon,
441 const char *askpw_icon_name,
442 void **ret_cid, size_t *ret_cid_size,
443 void **ret_salt, size_t *ret_salt_size,
444 void **ret_secret, size_t *ret_secret_size,
445 char **ret_usedpin) {
446
447 _cleanup_(erase_and_freep) void *salt = NULL, *secret_copy = NULL;
448 _cleanup_(fido_assert_free_wrapper) fido_assert_t *a = NULL;
449 _cleanup_(fido_cred_free_wrapper) fido_cred_t *c = NULL;
450 _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
451 _cleanup_(erase_and_freep) char *used_pin = NULL;
452 bool has_rk, has_client_pin, has_up, has_uv;
453 _cleanup_free_ char *cid_copy = NULL;
454 size_t cid_size, secret_size;
455 const void *cid, *secret;
456 int r;
457
458 assert(device);
459 assert(ret_cid);
460 assert(ret_cid_size);
461 assert(ret_salt);
462 assert(ret_salt_size);
463 assert(ret_secret);
464 assert(ret_secret_size);
465
466 /* Construction is like this: we generate a salt of 32 bytes. We then ask the FIDO2 device to
467 * HMAC-SHA256 it for us with its internal key. The result is the key used by LUKS and account
468 * authentication. LUKS and UNIX password auth all do their own salting before hashing, so that FIDO2
469 * device never sees the volume key.
470 *
471 * S = HMAC-SHA256(I, D)
472 *
473 * with: S → LUKS/account authentication key (never stored)
474 * I → internal key on FIDO2 device (stored in the FIDO2 device)
475 * D → salt we generate here (stored in the privileged part of the JSON record)
476 *
477 */
478
479 assert(device);
480
481 r = dlopen_libfido2();
482 if (r < 0)
483 return log_error_errno(r, "FIDO2 token support is not installed.");
484
485 salt = malloc(FIDO2_SALT_SIZE);
486 if (!salt)
487 return log_oom();
488
489 r = genuine_random_bytes(salt, FIDO2_SALT_SIZE, RANDOM_BLOCK);
490 if (r < 0)
491 return log_error_errno(r, "Failed to generate salt: %m");
492
493 d = sym_fido_dev_new();
494 if (!d)
495 return log_oom();
496
497 r = sym_fido_dev_open(d, device);
498 if (r != FIDO_OK)
499 return log_error_errno(SYNTHETIC_ERRNO(EIO),
500 "Failed to open FIDO2 device %s: %s", device, sym_fido_strerr(r));
501
502 r = verify_features(d, device, LOG_ERR, &has_rk, &has_client_pin, &has_up, &has_uv);
503 if (r < 0)
504 return r;
505
506 c = sym_fido_cred_new();
507 if (!c)
508 return log_oom();
509
510 r = sym_fido_cred_set_extensions(c, FIDO_EXT_HMAC_SECRET);
511 if (r != FIDO_OK)
512 return log_error_errno(SYNTHETIC_ERRNO(EIO),
513 "Failed to enable HMAC-SECRET extension on FIDO2 credential: %s", sym_fido_strerr(r));
514
515 r = sym_fido_cred_set_rp(c, rp_id, rp_name);
516 if (r != FIDO_OK)
517 return log_error_errno(SYNTHETIC_ERRNO(EIO),
518 "Failed to set FIDO2 credential relying party ID/name: %s", sym_fido_strerr(r));
519
520 r = sym_fido_cred_set_type(c, COSE_ES256);
521 if (r != FIDO_OK)
522 return log_error_errno(SYNTHETIC_ERRNO(EIO),
523 "Failed to set FIDO2 credential type to ES256: %s", sym_fido_strerr(r));
524
525 r = sym_fido_cred_set_user(
526 c,
527 user_id, user_id_len,
528 user_name,
529 user_display_name,
530 user_icon);
531 if (r != FIDO_OK)
532 return log_error_errno(SYNTHETIC_ERRNO(EIO),
533 "Failed to set FIDO2 credential user data: %s", sym_fido_strerr(r));
534
535 r = sym_fido_cred_set_clientdata_hash(c, (const unsigned char[32]) {}, 32);
536 if (r != FIDO_OK)
537 return log_error_errno(SYNTHETIC_ERRNO(EIO),
538 "Failed to set FIDO2 client data hash: %s", sym_fido_strerr(r));
539
540 if (has_rk) {
541 r = sym_fido_cred_set_rk(c, FIDO_OPT_FALSE);
542 if (r != FIDO_OK)
543 return log_error_errno(SYNTHETIC_ERRNO(EIO),
544 "Failed to turn off FIDO2 resident key option of credential: %s", sym_fido_strerr(r));
545 }
546
547 if (has_uv) {
548 r = sym_fido_cred_set_uv(c, FIDO_OPT_FALSE);
549 if (r != FIDO_OK)
550 return log_error_errno(SYNTHETIC_ERRNO(EIO),
551 "Failed to turn off FIDO2 user verification option of credential: %s", sym_fido_strerr(r));
552 }
553
554 log_info("Initializing FIDO2 credential on security token.");
555
556 log_notice("%s%s(Hint: This might require verification of user presence on security token.)",
557 emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "",
558 emoji_enabled() ? " " : "");
559
560 r = sym_fido_dev_make_cred(d, c, NULL);
561 if (r == FIDO_ERR_PIN_REQUIRED) {
562 for (;;) {
563 _cleanup_(strv_free_erasep) char **pin = NULL;
564 char **i;
565
566 if (!has_client_pin)
567 log_warning("Weird, device asked for client PIN, but does not advertise it as feature. Ignoring.");
568
569 r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", USEC_INFINITY, 0, &pin);
570 if (r < 0)
571 return log_error_errno(r, "Failed to acquire user PIN: %m");
572
573 r = FIDO_ERR_PIN_INVALID;
574 STRV_FOREACH(i, pin) {
575 if (isempty(*i)) {
576 log_info("PIN may not be empty.");
577 continue;
578 }
579
580 r = sym_fido_dev_make_cred(d, c, *i);
581 if (r == FIDO_OK) {
582 used_pin = strdup(*i);
583 if (!used_pin)
584 return log_oom();
585 break;
586 }
587 if (r != FIDO_ERR_PIN_INVALID)
588 break;
589 }
590
591 if (r != FIDO_ERR_PIN_INVALID)
592 break;
593
594 log_notice("PIN incorrect, please try again.");
595 }
596 }
597 if (r == FIDO_ERR_PIN_AUTH_BLOCKED)
598 return log_notice_errno(SYNTHETIC_ERRNO(EPERM),
599 "Token PIN is currently blocked, please remove and reinsert token.");
600 if (r == FIDO_ERR_ACTION_TIMEOUT)
601 return log_error_errno(SYNTHETIC_ERRNO(ENOSTR),
602 "Token action timeout. (User didn't interact with token quickly enough.)");
603 if (r != FIDO_OK)
604 return log_error_errno(SYNTHETIC_ERRNO(EIO),
605 "Failed to generate FIDO2 credential: %s", sym_fido_strerr(r));
606
607 cid = sym_fido_cred_id_ptr(c);
608 if (!cid)
609 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get FIDO2 credential ID.");
610
611 cid_size = sym_fido_cred_id_len(c);
612
613 a = sym_fido_assert_new();
614 if (!a)
615 return log_oom();
616
617 r = sym_fido_assert_set_extensions(a, FIDO_EXT_HMAC_SECRET);
618 if (r != FIDO_OK)
619 return log_error_errno(SYNTHETIC_ERRNO(EIO),
620 "Failed to enable HMAC-SECRET extension on FIDO2 assertion: %s", sym_fido_strerr(r));
621
622 r = sym_fido_assert_set_hmac_salt(a, salt, FIDO2_SALT_SIZE);
623 if (r != FIDO_OK)
624 return log_error_errno(SYNTHETIC_ERRNO(EIO),
625 "Failed to set salt on FIDO2 assertion: %s", sym_fido_strerr(r));
626
627 r = sym_fido_assert_set_rp(a, rp_id);
628 if (r != FIDO_OK)
629 return log_error_errno(SYNTHETIC_ERRNO(EIO),
630 "Failed to set FIDO2 assertion ID: %s", sym_fido_strerr(r));
631
632 r = sym_fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32);
633 if (r != FIDO_OK)
634 return log_error_errno(SYNTHETIC_ERRNO(EIO),
635 "Failed to set FIDO2 assertion client data hash: %s", sym_fido_strerr(r));
636
637 r = sym_fido_assert_allow_cred(a, cid, cid_size);
638 if (r != FIDO_OK)
639 return log_error_errno(SYNTHETIC_ERRNO(EIO),
640 "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r));
641
642 if (has_up) {
643 r = sym_fido_assert_set_up(a, FIDO_OPT_FALSE);
644 if (r != FIDO_OK)
645 return log_error_errno(SYNTHETIC_ERRNO(EIO),
646 "Failed to turn off FIDO2 assertion user presence: %s", sym_fido_strerr(r));
647 }
648
649 log_info("Generating secret key on FIDO2 security token.");
650
651 r = sym_fido_dev_get_assert(d, a, used_pin);
652 if (r == FIDO_ERR_UP_REQUIRED) {
653
654 if (!has_up)
655 log_warning("Weird, device asked for User Presence check, but does not advertise it as feature. Ignoring.");
656
657 r = sym_fido_assert_set_up(a, FIDO_OPT_TRUE);
658 if (r != FIDO_OK)
659 return log_error_errno(SYNTHETIC_ERRNO(EIO),
660 "Failed to turn on FIDO2 assertion user presence: %s", sym_fido_strerr(r));
661
662 log_notice("%s%sIn order to allow secret key generation, please verify presence on security token.",
663 emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "",
664 emoji_enabled() ? " " : "");
665
666 r = sym_fido_dev_get_assert(d, a, used_pin);
667 }
668 if (r == FIDO_ERR_ACTION_TIMEOUT)
669 return log_error_errno(SYNTHETIC_ERRNO(ENOSTR),
670 "Token action timeout. (User didn't interact with token quickly enough.)");
671 if (r != FIDO_OK)
672 return log_error_errno(SYNTHETIC_ERRNO(EIO),
673 "Failed to ask token for assertion: %s", sym_fido_strerr(r));
674
675 secret = sym_fido_assert_hmac_secret_ptr(a, 0);
676 if (!secret)
677 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve HMAC secret.");
678
679 secret_size = sym_fido_assert_hmac_secret_len(a, 0);
680
681 secret_copy = memdup(secret, secret_size);
682 if (!secret_copy)
683 return log_oom();
684
685 cid_copy = memdup(cid, cid_size);
686 if (!cid_copy)
687 return log_oom();
688
689 *ret_cid = TAKE_PTR(cid_copy);
690 *ret_cid_size = cid_size;
691 *ret_salt = TAKE_PTR(salt);
692 *ret_salt_size = FIDO2_SALT_SIZE;
693 *ret_secret = TAKE_PTR(secret_copy);
694 *ret_secret_size = secret_size;
695
696 if (ret_usedpin)
697 *ret_usedpin = TAKE_PTR(used_pin);
698
699 return 0;
700 }
701 #endif
702
703 #if HAVE_LIBFIDO2
704 static int check_device_is_fido2_with_hmac_secret(const char *path) {
705 _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
706 int r;
707
708 d = sym_fido_dev_new();
709 if (!d)
710 return log_oom();
711
712 r = sym_fido_dev_open(d, path);
713 if (r != FIDO_OK)
714 return log_error_errno(SYNTHETIC_ERRNO(EIO),
715 "Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
716
717 r = verify_features(d, path, LOG_DEBUG, NULL, NULL, NULL, NULL);
718 if (r == -ENODEV) /* Not a FIDO2 device, or not implementing 'hmac-secret' */
719 return false;
720 if (r < 0)
721 return r;
722
723 return true;
724 }
725 #endif
726
727 int fido2_list_devices(void) {
728 #if HAVE_LIBFIDO2
729 _cleanup_(table_unrefp) Table *t = NULL;
730 size_t allocated = 64, found = 0;
731 fido_dev_info_t *di = NULL;
732 int r;
733
734 r = dlopen_libfido2();
735 if (r < 0)
736 return log_error_errno(r, "FIDO2 token support is not installed.");
737
738 di = sym_fido_dev_info_new(allocated);
739 if (!di)
740 return log_oom();
741
742 r = sym_fido_dev_info_manifest(di, allocated, &found);
743 if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) {
744 /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */
745 log_info("No FIDO2 devices found.");
746 r = 0;
747 goto finish;
748 }
749 if (r != FIDO_OK) {
750 r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r));
751 goto finish;
752 }
753
754 t = table_new("path", "manufacturer", "product");
755 if (!t) {
756 r = log_oom();
757 goto finish;
758 }
759
760 for (size_t i = 0; i < found; i++) {
761 const fido_dev_info_t *entry;
762
763 entry = sym_fido_dev_info_ptr(di, i);
764 if (!entry) {
765 r = log_error_errno(SYNTHETIC_ERRNO(EIO),
766 "Failed to get device information for FIDO device %zu.", i);
767 goto finish;
768 }
769
770 r = check_device_is_fido2_with_hmac_secret(sym_fido_dev_info_path(entry));
771 if (r < 0)
772 goto finish;
773 if (!r)
774 continue;
775
776 r = table_add_many(
777 t,
778 TABLE_PATH, sym_fido_dev_info_path(entry),
779 TABLE_STRING, sym_fido_dev_info_manufacturer_string(entry),
780 TABLE_STRING, sym_fido_dev_info_product_string(entry));
781 if (r < 0) {
782 table_log_add_error(r);
783 goto finish;
784 }
785 }
786
787 r = table_print(t, stdout);
788 if (r < 0) {
789 log_error_errno(r, "Failed to show device table: %m");
790 goto finish;
791 }
792
793 r = 0;
794
795 finish:
796 sym_fido_dev_info_free(&di, allocated);
797 return r;
798 #else
799 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
800 "FIDO2 tokens not supported on this build.");
801 #endif
802 }
803
804 int fido2_find_device_auto(char **ret) {
805 #if HAVE_LIBFIDO2
806 _cleanup_free_ char *copy = NULL;
807 size_t di_size = 64, found = 0;
808 const fido_dev_info_t *entry;
809 fido_dev_info_t *di = NULL;
810 const char *path;
811 int r;
812
813 r = dlopen_libfido2();
814 if (r < 0)
815 return log_error_errno(r, "FIDO2 token support is not installed.");
816
817 di = sym_fido_dev_info_new(di_size);
818 if (!di)
819 return log_oom();
820
821 r = sym_fido_dev_info_manifest(di, di_size, &found);
822 if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) {
823 /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */
824 r = log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No FIDO devices found.");
825 goto finish;
826 }
827 if (r != FIDO_OK) {
828 r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO devices: %s", sym_fido_strerr(r));
829 goto finish;
830 }
831 if (found > 1) {
832 r = log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "More than one FIDO device found.");
833 goto finish;
834 }
835
836 entry = sym_fido_dev_info_ptr(di, 0);
837 if (!entry) {
838 r = log_error_errno(SYNTHETIC_ERRNO(EIO),
839 "Failed to get device information for FIDO device 0.");
840 goto finish;
841 }
842
843 r = check_device_is_fido2_with_hmac_secret(sym_fido_dev_info_path(entry));
844 if (r < 0)
845 goto finish;
846 if (!r) {
847 r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "FIDO device discovered does not implement FIDO2 with 'hmac-secret' extension.");
848 goto finish;
849 }
850
851 path = sym_fido_dev_info_path(entry);
852 if (!path) {
853 r = log_error_errno(SYNTHETIC_ERRNO(EIO),
854 "Failed to query FIDO device path.");
855 goto finish;
856 }
857
858 copy = strdup(path);
859 if (!copy) {
860 r = log_oom();
861 goto finish;
862 }
863
864 *ret = TAKE_PTR(copy);
865 r = 0;
866
867 finish:
868 sym_fido_dev_info_free(&di, di_size);
869 return r;
870 #else
871 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
872 "FIDO2 tokens not supported on this build.");
873 #endif
874 }