1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "homework-fido2.h"
9 static int fido2_use_specific_token(
13 const Fido2HmacSalt
*salt
,
16 _cleanup_(fido_cbor_info_free
) fido_cbor_info_t
*di
= NULL
;
17 _cleanup_(fido_assert_free
) fido_assert_t
*a
= NULL
;
18 _cleanup_(fido_dev_free
) fido_dev_t
*d
= NULL
;
19 bool found_extension
= false;
29 r
= fido_dev_open(d
, path
);
31 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
32 "Failed to open FIDO2 device %s: %s", path
, fido_strerr(r
));
34 if (!fido_dev_is_fido2(d
))
35 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
),
36 "Specified device %s is not a FIDO2 device.", path
);
38 di
= fido_cbor_info_new();
42 r
= fido_dev_get_cbor_info(d
, di
);
44 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
45 "Failed to get CBOR device info for %s: %s", path
, fido_strerr(r
));
47 e
= fido_cbor_info_extensions_ptr(di
);
48 n
= fido_cbor_info_extensions_len(di
);
50 for (size_t i
= 0; i
< n
; i
++)
51 if (streq(e
[i
], "hmac-secret")) {
52 found_extension
= true;
57 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
),
58 "Specified device %s is a FIDO2 device, but does not support the required HMAC-SECRET extension.", path
);
60 a
= fido_assert_new();
64 r
= fido_assert_set_extensions(a
, FIDO_EXT_HMAC_SECRET
);
66 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
67 "Failed to enable HMAC-SECRET extension on FIDO2 assertion: %s", fido_strerr(r
));
69 r
= fido_assert_set_hmac_salt(a
, salt
->salt
, salt
->salt_size
);
71 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
72 "Failed to set salt on FIDO2 assertion: %s", fido_strerr(r
));
74 r
= fido_assert_set_rp(a
, "io.systemd.home");
76 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
77 "Failed to set FIDO2 assertion ID: %s", fido_strerr(r
));
79 r
= fido_assert_set_clientdata_hash(a
, (const unsigned char[32]) {}, 32);
81 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
82 "Failed to set FIDO2 assertion client data hash: %s", fido_strerr(r
));
84 r
= fido_assert_allow_cred(a
, salt
->credential
.id
, salt
->credential
.size
);
86 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
87 "Failed to add FIDO2 assertion credential ID: %s", fido_strerr(r
));
89 r
= fido_assert_set_up(a
, h
->fido2_user_presence_permitted
<= 0 ? FIDO_OPT_FALSE
: FIDO_OPT_TRUE
);
91 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
92 "Failed to set FIDO2 assertion user presence: %s", fido_strerr(r
));
94 log_info("Asking FIDO2 token for authentication.");
96 r
= fido_dev_get_assert(d
, a
, NULL
); /* try without pin first */
97 if (r
== FIDO_ERR_PIN_REQUIRED
) {
100 /* OK, we needed a pin, try with all pins in turn */
101 STRV_FOREACH(i
, secret
->token_pin
) {
102 r
= fido_dev_get_assert(d
, a
, *i
);
103 if (r
!= FIDO_ERR_PIN_INVALID
)
111 case FIDO_ERR_NO_CREDENTIALS
:
112 return log_error_errno(SYNTHETIC_ERRNO(EBADSLT
),
113 "Wrong security token; needed credentials not present on token.");
114 case FIDO_ERR_PIN_REQUIRED
:
115 return log_error_errno(SYNTHETIC_ERRNO(ENOANO
),
116 "Security token requires PIN.");
117 case FIDO_ERR_PIN_AUTH_BLOCKED
:
118 return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD
),
119 "PIN of security token is blocked, please remove/reinsert token.");
120 case FIDO_ERR_PIN_INVALID
:
121 return log_error_errno(SYNTHETIC_ERRNO(ENOLCK
),
122 "PIN of security token incorrect.");
123 case FIDO_ERR_UP_REQUIRED
:
124 return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE
),
125 "User presence required.");
126 case FIDO_ERR_ACTION_TIMEOUT
:
127 return log_error_errno(SYNTHETIC_ERRNO(ENOSTR
),
128 "Token action timeout. (User didn't interact with token quickly enough.)");
130 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
131 "Failed to ask token for assertion: %s", fido_strerr(r
));
134 hmac
= fido_assert_hmac_secret_ptr(a
, 0);
136 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve HMAC secret.");
138 hmac_size
= fido_assert_hmac_secret_len(a
, 0);
140 r
= base64mem(hmac
, hmac_size
, ret
);
142 return log_error_errno(r
, "Failed to base64 encode HMAC secret: %m");
147 int fido2_use_token(UserRecord
*h
, UserRecord
*secret
, const Fido2HmacSalt
*salt
, char **ret
) {
148 size_t allocated
= 64, found
= 0;
149 fido_dev_info_t
*di
= NULL
;
152 di
= fido_dev_info_new(allocated
);
156 r
= fido_dev_info_manifest(di
, allocated
, &found
);
157 if (r
== FIDO_ERR_INTERNAL
) {
158 /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */
159 r
= log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
), "Got FIDO_ERR_INTERNAL, assuming no devices.");
163 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to enumerate FIDO2 devices: %s", fido_strerr(r
));
167 for (size_t i
= 0; i
< found
; i
++) {
168 const fido_dev_info_t
*entry
;
171 entry
= fido_dev_info_ptr(di
, i
);
173 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
),
174 "Failed to get device information for FIDO device %zu.", i
);
178 path
= fido_dev_info_path(entry
);
180 r
= log_error_errno(SYNTHETIC_ERRNO(EIO
),
181 "Failed to query FIDO device path.");
185 r
= fido2_use_specific_token(path
, h
, secret
, salt
, ret
);
187 -EBADSLT
, /* device doesn't understand our credential hash */
188 -ENODEV
/* device is not a FIDO2 device with HMAC-SECRET */))
195 fido_dev_info_free(&di
, allocated
);