]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptenroll/cryptenroll-fido2.c
tree-wide: fix return value handling of base64mem()
[thirdparty/systemd.git] / src / cryptenroll / cryptenroll-fido2.c
CommitLineData
8710a681
LP
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
48765191 3#include "ask-password-api.h"
8710a681 4#include "cryptenroll-fido2.h"
48765191 5#include "cryptsetup-fido2.h"
8710a681
LP
6#include "hexdecoct.h"
7#include "json.h"
8#include "libfido2-util.h"
9#include "memory-util.h"
10#include "random-util.h"
11
48765191
PC
12int load_volume_key_fido2(
13 struct crypt_device *cd,
14 const char *cd_node,
15 const char *device,
16 void *ret_vk,
17 size_t *ret_vks) {
18
19 _cleanup_(erase_and_freep) void *decrypted_key = NULL;
20 _cleanup_(erase_and_freep) char *passphrase = NULL;
21 size_t decrypted_key_size;
5e476b85 22 ssize_t passphrase_size;
48765191
PC
23 int r;
24
25 assert_se(cd);
26 assert_se(cd_node);
27 assert_se(ret_vk);
28 assert_se(ret_vks);
29
30 r = acquire_fido2_key_auto(
31 cd,
32 cd_node,
33 cd_node,
34 device,
35 /* until= */ 0,
36 /* headless= */ false,
37 &decrypted_key,
38 &decrypted_key_size,
39 ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED);
40 if (r == -EAGAIN)
41 return log_error_errno(r, "FIDO2 token does not exist, or UV is blocked. Please try again.");
42 if (r < 0)
43 return r;
44
45 /* Because cryptenroll requires a LUKS header, we can assume that this device is not
46 * a PLAIN device. In this case, we need to base64 encode the secret to use as the passphrase */
5e476b85
LP
47 passphrase_size = base64mem(decrypted_key, decrypted_key_size, &passphrase);
48 if (passphrase_size < 0)
48765191
PC
49 return log_oom();
50
51 r = crypt_volume_key_get(
52 cd,
53 CRYPT_ANY_SLOT,
54 ret_vk,
55 ret_vks,
56 passphrase,
5e476b85 57 passphrase_size);
48765191
PC
58 if (r < 0)
59 return log_error_errno(r, "Unlocking via FIDO2 device failed: %m");
60
61 return r;
62}
63
8710a681
LP
64int enroll_fido2(
65 struct crypt_device *cd,
66 const void *volume_key,
67 size_t volume_key_size,
cde2f860 68 const char *device,
70e723c0
M
69 Fido2EnrollFlags lock_with,
70 int cred_alg) {
8710a681
LP
71
72 _cleanup_(erase_and_freep) void *salt = NULL, *secret = NULL;
73 _cleanup_(erase_and_freep) char *base64_encoded = NULL;
74 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
75 _cleanup_free_ char *keyslot_as_string = NULL;
76 size_t cid_size, salt_size, secret_size;
77 _cleanup_free_ void *cid = NULL;
5e476b85 78 ssize_t base64_encoded_size;
8710a681
LP
79 const char *node, *un;
80 int r, keyslot;
81
82 assert_se(cd);
83 assert_se(volume_key);
84 assert_se(volume_key_size > 0);
85 assert_se(device);
86
87 assert_se(node = crypt_get_device_name(cd));
88
89 un = strempty(crypt_get_uuid(cd));
90
91 r = fido2_generate_hmac_hash(
92 device,
93 /* rp_id= */ "io.systemd.cryptsetup",
94 /* rp_name= */ "Encrypted Volume",
95 /* user_id= */ un, strlen(un), /* We pass the user ID and name as the same: the disk's UUID if we have it */
96 /* user_name= */ un,
97 /* user_display_name= */ node,
98 /* user_icon_name= */ NULL,
99 /* askpw_icon_name= */ "drive-harddisk",
cde2f860 100 lock_with,
70e723c0 101 cred_alg,
8710a681
LP
102 &cid, &cid_size,
103 &salt, &salt_size,
104 &secret, &secret_size,
0735ed95
LP
105 NULL,
106 &lock_with);
8710a681
LP
107 if (r < 0)
108 return r;
109
110 /* Before we use the secret, we base64 encode it, for compat with homed, and to make it easier to type in manually */
5e476b85
LP
111 base64_encoded_size = base64mem(secret, secret_size, &base64_encoded);
112 if (base64_encoded_size < 0)
113 return log_error_errno(base64_encoded_size, "Failed to base64 encode secret key: %m");
8710a681
LP
114
115 r = cryptsetup_set_minimal_pbkdf(cd);
116 if (r < 0)
117 return log_error_errno(r, "Failed to set minimal PBKDF: %m");
118
119 keyslot = crypt_keyslot_add_by_volume_key(
120 cd,
121 CRYPT_ANY_SLOT,
122 volume_key,
123 volume_key_size,
124 base64_encoded,
5e476b85 125 base64_encoded_size);
8710a681 126 if (keyslot < 0)
4b9aa29b 127 return log_error_errno(keyslot, "Failed to add new FIDO2 key to %s: %m", node);
8710a681
LP
128
129 if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
130 return log_oom();
131
132 r = json_build(&v,
133 JSON_BUILD_OBJECT(
0cdf6b14 134 JSON_BUILD_PAIR("type", JSON_BUILD_CONST_STRING("systemd-fido2")),
8710a681
LP
135 JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
136 JSON_BUILD_PAIR("fido2-credential", JSON_BUILD_BASE64(cid, cid_size)),
137 JSON_BUILD_PAIR("fido2-salt", JSON_BUILD_BASE64(salt, salt_size)),
0cdf6b14 138 JSON_BUILD_PAIR("fido2-rp", JSON_BUILD_CONST_STRING("io.systemd.cryptsetup")),
06f08719 139 JSON_BUILD_PAIR("fido2-clientPin-required", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_PIN))),
896cc0da
LB
140 JSON_BUILD_PAIR("fido2-up-required", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_UP))),
141 JSON_BUILD_PAIR("fido2-uv-required", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_UV)))));
8710a681 142 if (r < 0)
4b9aa29b 143 return log_error_errno(r, "Failed to prepare FIDO2 JSON token object: %m");
8710a681
LP
144
145 r = cryptsetup_add_token_json(cd, v);
146 if (r < 0)
147 return log_error_errno(r, "Failed to add FIDO2 JSON token to LUKS2 header: %m");
148
149 log_info("New FIDO2 token enrolled as key slot %i.", keyslot);
150 return keyslot;
151}