1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <libcryptsetup.h>
5 #include "cryptsetup-token-util.h"
8 #include "luks2-fido2.h"
9 #include "memory-util.h"
12 int acquire_luks2_key(
13 struct crypt_device
*cd
,
17 char **ret_keyslot_passphrase
,
18 size_t *ret_keyslot_passphrase_size
) {
21 Fido2EnrollFlags required
;
22 size_t cid_size
, salt_size
, decrypted_key_size
;
23 _cleanup_free_
void *cid
= NULL
, *salt
= NULL
;
24 _cleanup_free_
char *rp_id
= NULL
;
25 _cleanup_(erase_and_freep
) void *decrypted_key
= NULL
;
26 _cleanup_(erase_and_freep
) char *base64_encoded
= NULL
;
27 _cleanup_strv_free_erase_
char **pins
= NULL
;
28 ssize_t base64_encoded_size
;
30 assert(ret_keyslot_passphrase
);
31 assert(ret_keyslot_passphrase_size
);
33 r
= parse_luks2_fido2_data(cd
, json
, &rp_id
, &salt
, &salt_size
, &cid
, &cid_size
, &required
);
40 return crypt_log_oom(cd
);
43 /* configured to use pin but none was provided */
44 if ((required
& FIDO2ENROLL_PIN
) && strv_isempty(pins
))
47 r
= fido2_use_hmac_hash(
49 rp_id
?: "io.systemd.cryptsetup",
56 if (r
== -ENOLCK
) /* libcryptsetup returns -ENOANO also on wrong PIN */
61 /* Before using this key as passphrase we base64 encode it, for compat with homed */
62 base64_encoded_size
= base64mem(decrypted_key
, decrypted_key_size
, &base64_encoded
);
63 if (base64_encoded_size
< 0)
64 return crypt_log_error_errno(cd
, (int) base64_encoded_size
, "Failed to base64 encode key: %m");
66 *ret_keyslot_passphrase
= TAKE_PTR(base64_encoded
);
67 *ret_keyslot_passphrase_size
= base64_encoded_size
;
72 /* this function expects valid "systemd-fido2" in json */
73 int parse_luks2_fido2_data(
74 struct crypt_device
*cd
,
78 size_t *ret_salt_size
,
81 Fido2EnrollFlags
*ret_required
) {
83 _cleanup_free_
void *cid
= NULL
, *salt
= NULL
;
84 size_t cid_size
= 0, salt_size
= 0;
85 _cleanup_free_
char *rp
= NULL
;
87 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
89 Fido2EnrollFlags required
= 0;
94 assert(ret_salt_size
);
99 r
= json_parse(json
, 0, &v
, NULL
, NULL
);
101 return crypt_log_error_errno(cd
, r
, "Failed to parse JSON token data: %m");
103 w
= json_variant_by_key(v
, "fido2-credential");
107 r
= unbase64mem(json_variant_string(w
), &cid
, &cid_size
);
109 return crypt_log_error_errno(cd
, r
, "Failed to parse 'fido2-credentials' field: %m");
111 w
= json_variant_by_key(v
, "fido2-salt");
115 r
= unbase64mem(json_variant_string(w
), &salt
, &salt_size
);
117 return crypt_log_error_errno(cd
, r
, "Failed to parse 'fido2-salt' field: %m");
119 w
= json_variant_by_key(v
, "fido2-rp");
121 /* The "rp" field is optional. */
122 rp
= strdup(json_variant_string(w
));
124 crypt_log_error(cd
, "Not enough memory.");
129 w
= json_variant_by_key(v
, "fido2-clientPin-required");
131 /* The "fido2-clientPin-required" field is optional. */
132 SET_FLAG(required
, FIDO2ENROLL_PIN
, json_variant_boolean(w
));
134 required
|= FIDO2ENROLL_PIN_IF_NEEDED
; /* compat with 248, where the field was unset */
136 w
= json_variant_by_key(v
, "fido2-up-required");
138 /* The "fido2-up-required" field is optional. */
139 SET_FLAG(required
, FIDO2ENROLL_UP
, json_variant_boolean(w
));
141 required
|= FIDO2ENROLL_UP_IF_NEEDED
; /* compat with 248 */
143 w
= json_variant_by_key(v
, "fido2-uv-required");
145 /* The "fido2-uv-required" field is optional. */
146 SET_FLAG(required
, FIDO2ENROLL_UV
, json_variant_boolean(w
));
148 required
|= FIDO2ENROLL_UV_OMIT
; /* compat with 248 */
150 *ret_rp_id
= TAKE_PTR(rp
);
151 *ret_cid
= TAKE_PTR(cid
);
152 *ret_cid_size
= cid_size
;
153 *ret_salt
= TAKE_PTR(salt
);
154 *ret_salt_size
= salt_size
;
155 *ret_required
= required
;