]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cryptsetup-util.c
shared/cryptsetup-util: build problematic code only in developer mode
[thirdparty/systemd.git] / src / shared / cryptsetup-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
691c2e2e 2
0d12936d 3#include "alloc-util.h"
1e2f3230 4#include "cryptsetup-util.h"
0d12936d 5#include "dlfcn-util.h"
691c2e2e 6#include "log.h"
4098bc13 7#include "parse-util.h"
691c2e2e 8
fdf6c27c 9#if HAVE_LIBCRYPTSETUP
0d12936d
LP
10static void *cryptsetup_dl = NULL;
11
12int (*sym_crypt_activate_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size, uint32_t flags);
13#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
14int (*sym_crypt_activate_by_signed_key)(struct crypt_device *cd, const char *name, const char *volume_key, size_t volume_key_size, const char *signature, size_t signature_size, uint32_t flags);
15#endif
16int (*sym_crypt_activate_by_volume_key)(struct crypt_device *cd, const char *name, const char *volume_key, size_t volume_key_size, uint32_t flags);
17int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags);
18int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params);
19void (*sym_crypt_free)(struct crypt_device *cd);
71eceff6
LP
20const char *(*sym_crypt_get_cipher)(struct crypt_device *cd);
21const char *(*sym_crypt_get_cipher_mode)(struct crypt_device *cd);
22uint64_t (*sym_crypt_get_data_offset)(struct crypt_device *cd);
23const char *(*sym_crypt_get_device_name)(struct crypt_device *cd);
0d12936d 24const char *(*sym_crypt_get_dir)(void);
71eceff6
LP
25const char *(*sym_crypt_get_type)(struct crypt_device *cd);
26const char *(*sym_crypt_get_uuid)(struct crypt_device *cd);
0d12936d 27int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp);
71eceff6 28int (*sym_crypt_get_volume_key_size)(struct crypt_device *cd);
0d12936d
LP
29int (*sym_crypt_init)(struct crypt_device **cd, const char *device);
30int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name);
31int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size);
71eceff6
LP
32int (*sym_crypt_keyslot_destroy)(struct crypt_device *cd, int keyslot);
33int (*sym_crypt_keyslot_max)(const char *type);
0d12936d
LP
34int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params);
35int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size);
71eceff6 36int (*sym_crypt_resume_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size);
0d12936d
LP
37int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device);
38void (*sym_crypt_set_debug_level)(int level);
39void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr);
71eceff6
LP
40#if HAVE_CRYPT_SET_METADATA_SIZE
41int (*sym_crypt_set_metadata_size)(struct crypt_device *cd, uint64_t metadata_size, uint64_t keyslots_size);
42#endif
43int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf);
44int (*sym_crypt_suspend)(struct crypt_device *cd, const char *name);
45int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json);
46int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json);
3c2c8e62
LB
47#if HAVE_CRYPT_TOKEN_MAX
48int (*sym_crypt_token_max)(const char *type);
49#endif
71eceff6
LP
50crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type);
51int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
48a09a8f
DDM
52#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
53int (*sym_crypt_reencrypt_init_by_passphrase)(struct crypt_device *cd, const char *name, const char *passphrase, size_t passphrase_size, int keyslot_old, int keyslot_new, const char *cipher, const char *cipher_mode, const struct crypt_params_reencrypt *params);
54#endif
55#if HAVE_CRYPT_REENCRYPT
56int (*sym_crypt_reencrypt)(struct crypt_device *cd, int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
57#endif
58int (*sym_crypt_metadata_locking)(struct crypt_device *cd, int enable);
59#if HAVE_CRYPT_SET_DATA_OFFSET
60int (*sym_crypt_set_data_offset)(struct crypt_device *cd, uint64_t data_offset);
61#endif
62int (*sym_crypt_header_restore)(struct crypt_device *cd, const char *requested_type, const char *backup_file);
63int (*sym_crypt_volume_key_keyring)(struct crypt_device *cd, int enable);
0d12936d 64
0631eac9
LP
65/* Unfortunately libcryptsetup provides neither an environment variable to redirect where to look for token
66 * modules, nor does it have an API to change the token lookup path at runtime. The maintainers suggest using
67 * ELF interposition instead (see https://gitlab.com/cryptsetup/cryptsetup/-/issues/846). Hence let's do
68 * that: let's interpose libcryptsetup's crypt_token_external_path() function with our own, that *does*
69 * honour an environment variable where to look for tokens. This is tremendously useful for debugging
70 * libcryptsetup tokens: set the environment variable to your build dir and you can easily test token modules
71 * without jumping through various hoops. */
72
73/* Do this only on new enough compilers that actually support the "symver" attribute. Given this is a debug
74 * feature, let's simply not bother on older compilers */
25757715 75#if BUILD_MODE_DEVELOPER && defined(__has_attribute) && __has_attribute(symver)
0631eac9
LP
76const char *my_crypt_token_external_path(void); /* prototype for our own implementation */
77
78/* We use the "symver" attribute to mark this implementation as the default implementation, and drop the
79 * SD_SHARED namespace we by default attach to our symbols via a version script. */
80__attribute__((symver("crypt_token_external_path@@")))
81_public_ const char *my_crypt_token_external_path(void) {
82 const char *e;
83
84 e = secure_getenv("SYSTEMD_CRYPTSETUP_TOKEN_PATH");
85 if (e)
86 return e;
87
88 /* Now chain invoke the original implementation. */
89 if (cryptsetup_dl) {
90 typeof(crypt_token_external_path) *func;
91 func = (typeof(crypt_token_external_path)*) dlsym(cryptsetup_dl, "crypt_token_external_path");
92 if (func)
93 return func();
94 }
95
96 return NULL;
97}
98#endif
0631eac9 99
efc3b12f 100static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
0d12936d 101
aa2cc005
JJ
102 switch (level) {
103 case CRYPT_LOG_NORMAL:
104 level = LOG_NOTICE;
105 break;
106 case CRYPT_LOG_ERROR:
107 level = LOG_ERR;
108 break;
109 case CRYPT_LOG_VERBOSE:
110 level = LOG_INFO;
111 break;
112 case CRYPT_LOG_DEBUG:
113 level = LOG_DEBUG;
114 break;
115 default:
116 log_error("Unknown libcryptsetup log level: %d", level);
117 level = LOG_ERR;
118 }
119
120 log_full(level, "%s", msg);
691c2e2e 121}
efc3b12f
LB
122
123void cryptsetup_enable_logging(struct crypt_device *cd) {
7bbcaee3 124 /* It's OK to call this with a NULL parameter, in which case libcryptsetup will set the default log
e9252fae
LP
125 * function.
126 *
127 * Note that this is also called from dlopen_cryptsetup(), which we call here too. Sounds like an
128 * endless loop, but isn't because we break it via the check for 'cryptsetup_dl' early in
129 * dlopen_cryptsetup(). */
130
131 if (dlopen_cryptsetup() < 0)
132 return; /* If this fails, let's gracefully ignore the issue, this is just debug logging after
133 * all, and if this failed we already generated a debug log message that should help
134 * to track things down. */
0d12936d
LP
135
136 sym_crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
137 sym_crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE);
efc3b12f
LB
138}
139
4760384d
LP
140int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd) {
141
358b1f68
OK
142 /* With CRYPT_PBKDF_NO_BENCHMARK flag set .time_ms member is ignored
143 * while .iterations must be set at least to recommended minimum value. */
144
4760384d
LP
145 static const struct crypt_pbkdf_type minimal_pbkdf = {
146 .hash = "sha512",
147 .type = CRYPT_KDF_PBKDF2,
358b1f68
OK
148 .iterations = 1000, /* recommended minimum count for pbkdf2
149 * according to NIST SP 800-132, ch. 5.2 */
150 .flags = CRYPT_PBKDF_NO_BENCHMARK
4760384d
LP
151 };
152
153 int r;
154
155 /* Sets a minimal PKBDF in case we already have a high entropy key. */
156
157 r = dlopen_cryptsetup();
158 if (r < 0)
159 return r;
160
161 r = sym_crypt_set_pbkdf_type(cd, &minimal_pbkdf);
162 if (r < 0)
163 return r;
164
165 return 0;
166}
167
4098bc13
LP
168int cryptsetup_get_token_as_json(
169 struct crypt_device *cd,
170 int idx,
171 const char *verify_type,
172 JsonVariant **ret) {
173
174 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
175 const char *text;
176 int r;
177
178 assert(cd);
179
180 /* Extracts and parses the LUKS2 JSON token data from a LUKS2 device. Optionally verifies the type of
181 * the token. Returns:
182 *
183 * -EINVAL → token index out of range or "type" field missing
184 * -ENOENT → token doesn't exist
185 * -EMEDIUMTYPE → "verify_type" specified and doesn't match token's type
186 */
187
188 r = dlopen_cryptsetup();
189 if (r < 0)
190 return r;
191
192 r = sym_crypt_token_json_get(cd, idx, &text);
193 if (r < 0)
194 return r;
195
196 r = json_parse(text, 0, &v, NULL, NULL);
197 if (r < 0)
198 return r;
199
200 if (verify_type) {
201 JsonVariant *w;
202
203 w = json_variant_by_key(v, "type");
204 if (!w)
205 return -EINVAL;
206
207 if (!streq_ptr(json_variant_string(w), verify_type))
208 return -EMEDIUMTYPE;
209 }
210
211 if (ret)
212 *ret = TAKE_PTR(v);
213
214 return 0;
215}
216
fdf6c27c
LP
217int cryptsetup_add_token_json(struct crypt_device *cd, JsonVariant *v) {
218 _cleanup_free_ char *text = NULL;
219 int r;
220
221 r = dlopen_cryptsetup();
222 if (r < 0)
223 return r;
224
225 r = json_variant_format(v, 0, &text);
226 if (r < 0)
227 return log_debug_errno(r, "Failed to format token data for LUKS: %m");
228
229 log_debug("Adding token text <%s>", text);
230
231 r = sym_crypt_token_json_set(cd, CRYPT_ANY_TOKEN, text);
232 if (r < 0)
233 return log_debug_errno(r, "Failed to write token data to LUKS: %m");
234
235 return 0;
236}
237#endif
238
bbf73b00
DDM
239int dlopen_cryptsetup(void) {
240#if HAVE_LIBCRYPTSETUP
241 int r;
242
7736a71f
LP
243 /* libcryptsetup added crypt_reencrypt() in 2.2.0, and marked it obsolete in 2.4.0, replacing it with
244 * crypt_reencrypt_run(), which takes one extra argument but is otherwise identical. The old call is
245 * still available though, and given we want to support 2.2.0 for a while longer, we'll stick to the
6c2d70ce 246 * old symbol. However, the old symbols now has a GCC deprecation decorator, hence let's turn off
7736a71f
LP
247 * warnings about this for now. */
248
249 DISABLE_WARNING_DEPRECATED_DECLARATIONS;
250
bbf73b00
DDM
251 r = dlopen_many_sym_or_warn(
252 &cryptsetup_dl, "libcryptsetup.so.12", LOG_DEBUG,
253 DLSYM_ARG(crypt_activate_by_passphrase),
254#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
255 DLSYM_ARG(crypt_activate_by_signed_key),
256#endif
257 DLSYM_ARG(crypt_activate_by_volume_key),
258 DLSYM_ARG(crypt_deactivate_by_name),
259 DLSYM_ARG(crypt_format),
260 DLSYM_ARG(crypt_free),
261 DLSYM_ARG(crypt_get_cipher),
262 DLSYM_ARG(crypt_get_cipher_mode),
263 DLSYM_ARG(crypt_get_data_offset),
264 DLSYM_ARG(crypt_get_device_name),
265 DLSYM_ARG(crypt_get_dir),
266 DLSYM_ARG(crypt_get_type),
267 DLSYM_ARG(crypt_get_uuid),
268 DLSYM_ARG(crypt_get_verity_info),
269 DLSYM_ARG(crypt_get_volume_key_size),
270 DLSYM_ARG(crypt_init),
271 DLSYM_ARG(crypt_init_by_name),
272 DLSYM_ARG(crypt_keyslot_add_by_volume_key),
273 DLSYM_ARG(crypt_keyslot_destroy),
274 DLSYM_ARG(crypt_keyslot_max),
275 DLSYM_ARG(crypt_load),
276 DLSYM_ARG(crypt_resize),
277 DLSYM_ARG(crypt_resume_by_passphrase),
278 DLSYM_ARG(crypt_set_data_device),
279 DLSYM_ARG(crypt_set_debug_level),
280 DLSYM_ARG(crypt_set_log_callback),
281#if HAVE_CRYPT_SET_METADATA_SIZE
282 DLSYM_ARG(crypt_set_metadata_size),
283#endif
284 DLSYM_ARG(crypt_set_pbkdf_type),
285 DLSYM_ARG(crypt_suspend),
286 DLSYM_ARG(crypt_token_json_get),
287 DLSYM_ARG(crypt_token_json_set),
288#if HAVE_CRYPT_TOKEN_MAX
289 DLSYM_ARG(crypt_token_max),
290#endif
291 DLSYM_ARG(crypt_token_status),
48a09a8f
DDM
292 DLSYM_ARG(crypt_volume_key_get),
293#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
294 DLSYM_ARG(crypt_reencrypt_init_by_passphrase),
295#endif
296#if HAVE_CRYPT_REENCRYPT
297 DLSYM_ARG(crypt_reencrypt),
298#endif
299 DLSYM_ARG(crypt_metadata_locking),
300#if HAVE_CRYPT_SET_DATA_OFFSET
301 DLSYM_ARG(crypt_set_data_offset),
302#endif
303 DLSYM_ARG(crypt_header_restore),
304 DLSYM_ARG(crypt_volume_key_keyring));
bbf73b00
DDM
305 if (r <= 0)
306 return r;
307
7736a71f
LP
308 REENABLE_WARNING;
309
bbf73b00
DDM
310 /* Redirect the default logging calls of libcryptsetup to our own logging infra. (Note that
311 * libcryptsetup also maintains per-"struct crypt_device" log functions, which we'll also set
312 * whenever allocating a "struct crypt_device" context. Why set both? To be defensive: maybe some
313 * other code loaded into this process also changes the global log functions of libcryptsetup, who
314 * knows? And if so, we still want our own objects to log via our own infra, at the very least.) */
315 cryptsetup_enable_logging(NULL);
316 return 1;
317#else
318 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "cryptsetup support is not compiled in.");
319#endif
320}
321
4098bc13
LP
322int cryptsetup_get_keyslot_from_token(JsonVariant *v) {
323 int keyslot, r;
324 JsonVariant *w;
325
326 /* Parses the "keyslots" field of a LUKS2 token object. The field can be an array, but here we assume
327 * that it contains a single element only, since that's the only way we ever generate it
328 * ourselves. */
329
330 w = json_variant_by_key(v, "keyslots");
331 if (!w)
332 return -ENOENT;
333 if (!json_variant_is_array(w) || json_variant_elements(w) != 1)
334 return -EMEDIUMTYPE;
335
336 w = json_variant_by_index(w, 0);
337 if (!w)
338 return -ENOENT;
339 if (!json_variant_is_string(w))
340 return -EMEDIUMTYPE;
341
342 r = safe_atoi(json_variant_string(w), &keyslot);
343 if (r < 0)
344 return r;
345 if (keyslot < 0)
346 return -EINVAL;
347
348 return keyslot;
349}