/src/cryptsetup/lib/luks2/luks2_token.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * LUKS - Linux Unified Key Setup v2, token handling |
4 | | * |
5 | | * Copyright (C) 2016-2025 Red Hat, Inc. All rights reserved. |
6 | | * Copyright (C) 2016-2025 Milan Broz |
7 | | */ |
8 | | |
9 | | #include <ctype.h> |
10 | | |
11 | | #include "luks2_internal.h" |
12 | | |
13 | | #if USE_EXTERNAL_TOKENS |
14 | | #include <dlfcn.h> |
15 | | #define TOKENS_PATH_MAX PATH_MAX |
16 | | static bool external_tokens_enabled = true; |
17 | | static char external_tokens_path[TOKENS_PATH_MAX] = EXTERNAL_LUKS2_TOKENS_PATH; |
18 | | #else |
19 | | static bool external_tokens_enabled = false; |
20 | | #endif |
21 | | |
22 | | static struct crypt_token_handler_internal token_handlers[LUKS2_TOKENS_MAX] = { |
23 | | /* keyring builtin token */ |
24 | | { |
25 | | .version = 1, |
26 | | .u = { |
27 | | .v1 = { .name = LUKS2_TOKEN_KEYRING, |
28 | | .open = keyring_open, |
29 | | .buffer_free = keyring_buffer_free, |
30 | | .validate = keyring_validate, |
31 | | .dump = keyring_dump } |
32 | | } |
33 | | } |
34 | | }; |
35 | | |
36 | | void crypt_token_external_disable(void) |
37 | 0 | { |
38 | 0 | external_tokens_enabled = false; |
39 | 0 | } |
40 | | |
41 | | const char *crypt_token_external_path(void) |
42 | 0 | { |
43 | 0 | #if USE_EXTERNAL_TOKENS |
44 | 0 | return external_tokens_enabled ? external_tokens_path : NULL; |
45 | | #else |
46 | | return NULL; |
47 | | #endif |
48 | 0 | } |
49 | | |
50 | | #if USE_EXTERNAL_TOKENS |
51 | | int crypt_token_set_external_path(const char *path) |
52 | 0 | { |
53 | 0 | int r; |
54 | 0 | char tokens_path[TOKENS_PATH_MAX]; |
55 | |
|
56 | 0 | if (!path) |
57 | 0 | path = EXTERNAL_LUKS2_TOKENS_PATH; |
58 | 0 | else if (*path != '/') |
59 | 0 | return -EINVAL; |
60 | | |
61 | 0 | r = snprintf(tokens_path, sizeof(tokens_path), "%s", path); |
62 | 0 | if (r < 0 || (size_t)r >= sizeof(tokens_path)) |
63 | 0 | return -EINVAL; |
64 | | |
65 | 0 | (void)strcpy(external_tokens_path, tokens_path); |
66 | |
|
67 | 0 | return 0; |
68 | 0 | } |
69 | | #else |
70 | | #pragma GCC diagnostic ignored "-Wunused-parameter" |
71 | | int crypt_token_set_external_path(const char *path) |
72 | | { |
73 | | return -ENOTSUP; |
74 | | } |
75 | | #endif |
76 | | |
77 | | static bool token_validate_v1(struct crypt_device *cd, const crypt_token_handler *h) |
78 | 0 | { |
79 | 0 | if (!h) |
80 | 0 | return false; |
81 | | |
82 | 0 | if (!h->name) { |
83 | 0 | log_dbg(cd, "Error: token handler does not provide name attribute."); |
84 | 0 | return false; |
85 | 0 | } |
86 | | |
87 | 0 | if (!h->open) { |
88 | 0 | log_dbg(cd, "Error: token handler does not provide open function."); |
89 | 0 | return false; |
90 | 0 | } |
91 | | |
92 | 0 | return true; |
93 | 0 | } |
94 | | |
95 | | #if USE_EXTERNAL_TOKENS |
96 | | static void *token_dlvsym(struct crypt_device *cd, |
97 | | void *handle, |
98 | | const char *symbol, |
99 | | const char *version) |
100 | 0 | { |
101 | 0 | char *error; |
102 | 0 | void *sym; |
103 | |
|
104 | 0 | #if HAVE_DLVSYM |
105 | 0 | log_dbg(cd, "Loading symbol %s@%s.", symbol, version); |
106 | 0 | sym = dlvsym(handle, symbol, version); |
107 | | #else |
108 | | UNUSED(version); |
109 | | log_dbg(cd, "Loading default version of symbol %s.", symbol); |
110 | | sym = dlsym(handle, symbol); |
111 | | #endif |
112 | 0 | error = dlerror(); |
113 | |
|
114 | 0 | if (error) |
115 | 0 | log_dbg(cd, "%s", error); |
116 | |
|
117 | 0 | return sym; |
118 | 0 | } |
119 | | |
120 | | static bool token_validate_v2(struct crypt_device *cd, const struct crypt_token_handler_internal *h) |
121 | 0 | { |
122 | 0 | if (!h) |
123 | 0 | return false; |
124 | | |
125 | 0 | if (!token_validate_v1(cd, &h->u.v1)) |
126 | 0 | return false; |
127 | | |
128 | 0 | if (!h->u.v2.version) { |
129 | 0 | log_dbg(cd, "Error: token handler does not provide " CRYPT_TOKEN_ABI_VERSION " function."); |
130 | 0 | return false; |
131 | 0 | } |
132 | | |
133 | 0 | return true; |
134 | 0 | } |
135 | | |
136 | | static bool external_token_name_valid(const char *name) |
137 | 0 | { |
138 | 0 | if (!*name || strlen(name) > LUKS2_TOKEN_NAME_MAX) |
139 | 0 | return false; |
140 | | |
141 | 0 | while (*name) { |
142 | 0 | if (!isalnum(*name) && *name != '-' && *name != '_') |
143 | 0 | return false; |
144 | 0 | name++; |
145 | 0 | } |
146 | | |
147 | 0 | return true; |
148 | 0 | } |
149 | | |
150 | | static int |
151 | | crypt_token_load_external(struct crypt_device *cd, const char *name, struct crypt_token_handler_internal *ret) |
152 | 0 | { |
153 | 0 | struct crypt_token_handler_v2 *token; |
154 | 0 | void *h; |
155 | 0 | char buf[PATH_MAX]; |
156 | 0 | int r; |
157 | |
|
158 | 0 | if (!external_tokens_enabled) |
159 | 0 | return -ENOTSUP; |
160 | | |
161 | 0 | if (!ret || !name) |
162 | 0 | return -EINVAL; |
163 | | |
164 | 0 | if (!external_token_name_valid(name)) { |
165 | 0 | log_dbg(cd, "External token name (%.*s) invalid.", LUKS2_TOKEN_NAME_MAX, name); |
166 | 0 | return -EINVAL; |
167 | 0 | } |
168 | | |
169 | 0 | token = &ret->u.v2; |
170 | |
|
171 | 0 | r = snprintf(buf, sizeof(buf), "%s/libcryptsetup-token-%s.so", crypt_token_external_path(), name); |
172 | 0 | if (r < 0 || (size_t)r >= sizeof(buf)) |
173 | 0 | return -EINVAL; |
174 | | |
175 | 0 | assert(*buf == '/'); |
176 | |
|
177 | 0 | log_dbg(cd, "Trying to load %s.", buf); |
178 | |
|
179 | 0 | h = dlopen(buf, RTLD_LAZY); |
180 | 0 | if (!h) { |
181 | 0 | log_dbg(cd, "%s", dlerror()); |
182 | 0 | return -EINVAL; |
183 | 0 | } |
184 | 0 | dlerror(); |
185 | |
|
186 | 0 | token->name = strdup(name); |
187 | 0 | if (!token->name) { |
188 | 0 | dlclose(h); |
189 | 0 | memset(token, 0, sizeof(*token)); |
190 | 0 | return -ENOMEM; |
191 | 0 | } |
192 | | |
193 | 0 | token->open = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_OPEN, CRYPT_TOKEN_ABI_VERSION1); |
194 | 0 | token->buffer_free = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_BUFFER_FREE, CRYPT_TOKEN_ABI_VERSION1); |
195 | 0 | token->validate = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_VALIDATE, CRYPT_TOKEN_ABI_VERSION1); |
196 | 0 | token->dump = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_DUMP, CRYPT_TOKEN_ABI_VERSION1); |
197 | 0 | token->open_pin = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_OPEN_PIN, CRYPT_TOKEN_ABI_VERSION1); |
198 | 0 | token->version = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_VERSION, CRYPT_TOKEN_ABI_VERSION1); |
199 | |
|
200 | 0 | if (!token_validate_v2(cd, ret)) { |
201 | 0 | free(CONST_CAST(void *)token->name); |
202 | 0 | dlclose(h); |
203 | 0 | memset(token, 0, sizeof(*token)); |
204 | 0 | return -EINVAL; |
205 | 0 | } |
206 | | |
207 | | /* Token loaded, possible error here means only debug message fail and can be ignored */ |
208 | 0 | r = snprintf(buf, sizeof(buf), "%s", token->version() ?: ""); |
209 | 0 | if (r < 0 || (size_t)r >= sizeof(buf)) |
210 | 0 | *buf = '\0'; |
211 | |
|
212 | 0 | log_dbg(cd, "Token handler %s-%s loaded successfully.", token->name, buf); |
213 | |
|
214 | 0 | token->dlhandle = h; |
215 | 0 | ret->version = 2; |
216 | |
|
217 | 0 | return 0; |
218 | 0 | } |
219 | | |
220 | | void crypt_token_unload_external_all(struct crypt_device *cd) |
221 | 0 | { |
222 | 0 | struct crypt_token_handler_v2 *token; |
223 | 0 | int i; |
224 | |
|
225 | 0 | for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) { |
226 | 0 | if (token_handlers[i].version < 2) |
227 | 0 | continue; |
228 | | |
229 | 0 | token = &token_handlers[i].u.v2; |
230 | |
|
231 | 0 | log_dbg(cd, "Unloading %s token handler.", token->name); |
232 | |
|
233 | 0 | free(CONST_CAST(void *)token->name); |
234 | |
|
235 | 0 | if (dlclose(token->dlhandle)) |
236 | 0 | log_dbg(cd, "%s", dlerror()); |
237 | |
|
238 | 0 | memset(token, 0, sizeof(*token)); |
239 | 0 | token_handlers[i].version = 0; |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | | #else /* USE_EXTERNAL_TOKENS */ |
244 | | |
245 | | static int crypt_token_load_external(struct crypt_device *cd __attribute__((unused)), |
246 | | const char *name __attribute__((unused)), |
247 | | struct crypt_token_handler_internal *ret __attribute__((unused))) |
248 | | { |
249 | | return -ENOTSUP; |
250 | | } |
251 | | |
252 | | void crypt_token_unload_external_all(struct crypt_device *cd __attribute__((unused))) |
253 | | { |
254 | | } |
255 | | |
256 | | #endif |
257 | | |
258 | | static int is_builtin_candidate(const char *type) |
259 | 0 | { |
260 | 0 | return !strncmp(type, LUKS2_BUILTIN_TOKEN_PREFIX, LUKS2_BUILTIN_TOKEN_PREFIX_LEN); |
261 | 0 | } |
262 | | |
263 | | static int crypt_token_find_free(struct crypt_device *cd, const char *name, int *index) |
264 | 0 | { |
265 | 0 | int i; |
266 | |
|
267 | 0 | if (is_builtin_candidate(name)) { |
268 | 0 | log_dbg(cd, "'" LUKS2_BUILTIN_TOKEN_PREFIX "' is reserved prefix for builtin tokens."); |
269 | 0 | return -EINVAL; |
270 | 0 | } |
271 | | |
272 | 0 | for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++) { |
273 | 0 | if (!strcmp(token_handlers[i].u.v1.name, name)) { |
274 | 0 | log_dbg(cd, "Keyslot handler %s is already registered.", name); |
275 | 0 | return -EINVAL; |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | if (i == LUKS2_TOKENS_MAX) |
280 | 0 | return -EINVAL; |
281 | | |
282 | 0 | if (index) |
283 | 0 | *index = i; |
284 | |
|
285 | 0 | return 0; |
286 | 0 | } |
287 | | |
288 | | int crypt_token_register(const crypt_token_handler *handler) |
289 | 0 | { |
290 | 0 | int i, r; |
291 | |
|
292 | 0 | if (!token_validate_v1(NULL, handler)) |
293 | 0 | return -EINVAL; |
294 | | |
295 | 0 | r = crypt_token_find_free(NULL, handler->name, &i); |
296 | 0 | if (r < 0) |
297 | 0 | return r; |
298 | | |
299 | 0 | token_handlers[i].version = 1; |
300 | 0 | token_handlers[i].u.v1 = *handler; |
301 | 0 | return 0; |
302 | 0 | } |
303 | | |
304 | | static const void |
305 | | *LUKS2_token_handler_type(struct crypt_device *cd, const char *type) |
306 | 0 | { |
307 | 0 | int i; |
308 | |
|
309 | 0 | for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++) |
310 | 0 | if (!strcmp(token_handlers[i].u.v1.name, type)) |
311 | 0 | return &token_handlers[i].u; |
312 | | |
313 | 0 | if (i >= LUKS2_TOKENS_MAX) |
314 | 0 | return NULL; |
315 | | |
316 | 0 | if (is_builtin_candidate(type)) |
317 | 0 | return NULL; |
318 | | |
319 | 0 | if (crypt_token_load_external(cd, type, &token_handlers[i])) |
320 | 0 | return NULL; |
321 | | |
322 | 0 | return &token_handlers[i].u; |
323 | 0 | } |
324 | | |
325 | | static const void |
326 | | *LUKS2_token_handler(struct crypt_device *cd, int token) |
327 | 0 | { |
328 | 0 | struct luks2_hdr *hdr; |
329 | 0 | json_object *jobj1, *jobj2; |
330 | |
|
331 | 0 | if (token < 0) |
332 | 0 | return NULL; |
333 | | |
334 | 0 | if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2))) |
335 | 0 | return NULL; |
336 | | |
337 | 0 | if (!(jobj1 = LUKS2_get_token_jobj(hdr, token))) |
338 | 0 | return NULL; |
339 | | |
340 | 0 | if (!json_object_object_get_ex(jobj1, "type", &jobj2)) |
341 | 0 | return NULL; |
342 | | |
343 | 0 | return LUKS2_token_handler_type(cd, json_object_get_string(jobj2)); |
344 | 0 | } |
345 | | |
346 | | static int LUKS2_token_find_free(struct luks2_hdr *hdr) |
347 | 0 | { |
348 | 0 | int i; |
349 | |
|
350 | 0 | for (i = 0; i < LUKS2_TOKENS_MAX; i++) |
351 | 0 | if (!LUKS2_get_token_jobj(hdr, i)) |
352 | 0 | return i; |
353 | | |
354 | 0 | return -EINVAL; |
355 | 0 | } |
356 | | |
357 | | int LUKS2_token_create(struct crypt_device *cd, |
358 | | struct luks2_hdr *hdr, |
359 | | int token, |
360 | | const char *json, |
361 | | int commit) |
362 | 0 | { |
363 | 0 | const crypt_token_handler *h; |
364 | 0 | json_object *jobj_tokens, *jobj_type, *jobj; |
365 | 0 | enum json_tokener_error jerr; |
366 | 0 | char num[16]; |
367 | |
|
368 | 0 | if (token == CRYPT_ANY_TOKEN) { |
369 | 0 | if (!json) |
370 | 0 | return -EINVAL; |
371 | 0 | token = LUKS2_token_find_free(hdr); |
372 | 0 | } |
373 | | |
374 | 0 | if (token < 0 || token >= LUKS2_TOKENS_MAX) |
375 | 0 | return -EINVAL; |
376 | | |
377 | 0 | if (!json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens)) |
378 | 0 | return -EINVAL; |
379 | | |
380 | 0 | if (snprintf(num, sizeof(num), "%d", token) < 0) |
381 | 0 | return -EINVAL; |
382 | | |
383 | | /* Remove token */ |
384 | 0 | if (!json) |
385 | 0 | json_object_object_del(jobj_tokens, num); |
386 | 0 | else { |
387 | |
|
388 | 0 | jobj = json_tokener_parse_verbose(json, &jerr); |
389 | 0 | if (!jobj) { |
390 | 0 | log_dbg(cd, "Token JSON parse failed."); |
391 | 0 | return -EINVAL; |
392 | 0 | } |
393 | | |
394 | 0 | if (LUKS2_token_validate(cd, hdr->jobj, jobj, num)) { |
395 | 0 | json_object_put(jobj); |
396 | 0 | return -EINVAL; |
397 | 0 | } |
398 | | |
399 | 0 | json_object_object_get_ex(jobj, "type", &jobj_type); |
400 | 0 | h = LUKS2_token_handler_type(cd, json_object_get_string(jobj_type)); |
401 | |
|
402 | 0 | if (is_builtin_candidate(json_object_get_string(jobj_type)) && !h) { |
403 | 0 | log_dbg(cd, "%s is builtin token candidate with missing handler", |
404 | 0 | json_object_get_string(jobj_type)); |
405 | 0 | json_object_put(jobj); |
406 | 0 | return -EINVAL; |
407 | 0 | } |
408 | | |
409 | 0 | if (h && h->validate && h->validate(cd, json)) { |
410 | 0 | json_object_put(jobj); |
411 | 0 | log_dbg(cd, "Token type %s validation failed.", h->name); |
412 | 0 | return -EINVAL; |
413 | 0 | } |
414 | | |
415 | 0 | json_object_object_add(jobj_tokens, num, jobj); |
416 | 0 | if (LUKS2_check_json_size(cd, hdr)) { |
417 | 0 | log_dbg(cd, "Not enough space in header json area for new token."); |
418 | 0 | json_object_object_del(jobj_tokens, num); |
419 | 0 | return -ENOSPC; |
420 | 0 | } |
421 | 0 | } |
422 | | |
423 | 0 | if (commit) |
424 | 0 | return LUKS2_hdr_write(cd, hdr) ?: token; |
425 | | |
426 | 0 | return token; |
427 | 0 | } |
428 | | |
429 | | crypt_token_info LUKS2_token_status(struct crypt_device *cd, |
430 | | struct luks2_hdr *hdr, |
431 | | int token, |
432 | | const char **type) |
433 | 0 | { |
434 | 0 | const char *tmp; |
435 | 0 | const crypt_token_handler *th; |
436 | 0 | json_object *jobj_type, *jobj_token; |
437 | |
|
438 | 0 | if (token < 0 || token >= LUKS2_TOKENS_MAX) |
439 | 0 | return CRYPT_TOKEN_INVALID; |
440 | | |
441 | 0 | if (!(jobj_token = LUKS2_get_token_jobj(hdr, token))) |
442 | 0 | return CRYPT_TOKEN_INACTIVE; |
443 | | |
444 | 0 | json_object_object_get_ex(jobj_token, "type", &jobj_type); |
445 | 0 | tmp = json_object_get_string(jobj_type); |
446 | |
|
447 | 0 | if ((th = LUKS2_token_handler_type(cd, tmp))) { |
448 | 0 | if (type) |
449 | 0 | *type = th->name; |
450 | 0 | return is_builtin_candidate(tmp) ? CRYPT_TOKEN_INTERNAL : CRYPT_TOKEN_EXTERNAL; |
451 | 0 | } |
452 | | |
453 | 0 | if (type) |
454 | 0 | *type = tmp; |
455 | |
|
456 | 0 | return is_builtin_candidate(tmp) ? CRYPT_TOKEN_INTERNAL_UNKNOWN : CRYPT_TOKEN_EXTERNAL_UNKNOWN; |
457 | 0 | } |
458 | | |
459 | | static int token_is_usable(struct luks2_hdr *hdr, json_object *jobj_token, int keyslot, int segment, |
460 | | crypt_keyslot_priority minimal_priority, bool requires_keyslot) |
461 | 0 | { |
462 | 0 | crypt_keyslot_priority keyslot_priority; |
463 | 0 | json_object *jobj_array; |
464 | 0 | int i, slot, len, r = -ENOENT; |
465 | |
|
466 | 0 | if (!jobj_token) |
467 | 0 | return -EINVAL; |
468 | | |
469 | 0 | if (!json_object_object_get_ex(jobj_token, "keyslots", &jobj_array)) |
470 | 0 | return -EINVAL; |
471 | | |
472 | 0 | if (segment < 0 && segment != CRYPT_ANY_SEGMENT) |
473 | 0 | return -EINVAL; |
474 | | |
475 | | /* no assigned keyslot returns -ENOENT even for CRYPT_ANY_SEGMENT */ |
476 | 0 | len = json_object_array_length(jobj_array); |
477 | 0 | if (len < 0) |
478 | 0 | return -ENOENT; |
479 | | |
480 | 0 | if (!requires_keyslot) |
481 | 0 | return 0; |
482 | | |
483 | 0 | if (!len) |
484 | 0 | return -ENOENT; |
485 | | |
486 | 0 | for (i = 0; i < len; i++) { |
487 | 0 | slot = atoi(json_object_get_string(json_object_array_get_idx(jobj_array, i))); |
488 | |
|
489 | 0 | if (keyslot != CRYPT_ANY_SLOT && slot != keyslot) |
490 | 0 | continue; |
491 | | |
492 | 0 | keyslot_priority = LUKS2_keyslot_priority_get(hdr, slot); |
493 | 0 | if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID) |
494 | 0 | return -EINVAL; |
495 | | |
496 | 0 | if (keyslot_priority < minimal_priority) |
497 | 0 | continue; |
498 | | |
499 | 0 | r = LUKS2_keyslot_for_segment(hdr, slot, segment); |
500 | 0 | if (r != -ENOENT) |
501 | 0 | return r; |
502 | 0 | } |
503 | | |
504 | 0 | return r; |
505 | 0 | } |
506 | | |
507 | | static int translate_errno(struct crypt_device *cd, int ret_val, const char *type) |
508 | 0 | { |
509 | 0 | if ((ret_val > 0 || ret_val == -EINVAL || ret_val == -EPERM) && !is_builtin_candidate(type)) { |
510 | 0 | log_dbg(cd, "%s token handler returned %d. Changing to %d.", type, ret_val, -ENOENT); |
511 | 0 | ret_val = -ENOENT; |
512 | 0 | } |
513 | |
|
514 | 0 | return ret_val; |
515 | 0 | } |
516 | | |
517 | | static int token_open(struct crypt_device *cd, |
518 | | struct luks2_hdr *hdr, |
519 | | int keyslot, |
520 | | int token, |
521 | | json_object *jobj_token, |
522 | | const char *type, |
523 | | int segment, |
524 | | crypt_keyslot_priority priority, |
525 | | const char *pin, |
526 | | size_t pin_size, |
527 | | char **buffer, |
528 | | size_t *buffer_len, |
529 | | void *usrptr, |
530 | | bool requires_keyslot) |
531 | 0 | { |
532 | 0 | const struct crypt_token_handler_v2 *h; |
533 | 0 | json_object *jobj_type; |
534 | 0 | int r; |
535 | |
|
536 | 0 | assert(token >= 0); |
537 | 0 | assert(jobj_token); |
538 | 0 | assert(priority >= 0); |
539 | |
|
540 | 0 | if (type) { |
541 | 0 | if (!json_object_object_get_ex(jobj_token, "type", &jobj_type)) |
542 | 0 | return -EINVAL; |
543 | 0 | if (strcmp(type, json_object_get_string(jobj_type))) |
544 | 0 | return -ENOENT; |
545 | 0 | } |
546 | | |
547 | 0 | r = token_is_usable(hdr, jobj_token, keyslot, segment, priority, requires_keyslot); |
548 | 0 | if (r < 0) { |
549 | 0 | if (r == -ENOENT) |
550 | 0 | log_dbg(cd, "Token %d unusable for segment %d with desired keyslot priority %d.", |
551 | 0 | token, segment, priority); |
552 | 0 | return r; |
553 | 0 | } |
554 | | |
555 | 0 | if (!(h = LUKS2_token_handler(cd, token))) |
556 | 0 | return -ENOENT; |
557 | | |
558 | 0 | if (h->validate && h->validate(cd, crypt_jobj_to_string_on_disk(jobj_token))) { |
559 | 0 | log_dbg(cd, "Token %d (%s) validation failed.", token, h->name); |
560 | 0 | return -ENOENT; |
561 | 0 | } |
562 | | |
563 | 0 | if (pin && !h->open_pin) |
564 | 0 | r = -ENOENT; |
565 | 0 | else if (pin) |
566 | 0 | r = translate_errno(cd, h->open_pin(cd, token, pin, pin_size, buffer, buffer_len, usrptr), h->name); |
567 | 0 | else |
568 | 0 | r = translate_errno(cd, h->open(cd, token, buffer, buffer_len, usrptr), h->name); |
569 | 0 | if (r < 0) |
570 | 0 | log_dbg(cd, "Token %d (%s) open failed with %d.", token, h->name, r); |
571 | |
|
572 | 0 | return r; |
573 | 0 | } |
574 | | |
575 | | static void LUKS2_token_buffer_free(struct crypt_device *cd, |
576 | | int token, |
577 | | void *buffer, |
578 | | size_t buffer_len) |
579 | 0 | { |
580 | 0 | const crypt_token_handler *h = LUKS2_token_handler(cd, token); |
581 | |
|
582 | 0 | if (h && h->buffer_free) |
583 | 0 | h->buffer_free(buffer, buffer_len); |
584 | 0 | else { |
585 | 0 | crypt_safe_memzero(buffer, buffer_len); |
586 | 0 | free(buffer); |
587 | 0 | } |
588 | 0 | } |
589 | | |
590 | | static bool break_loop_retval(int r) |
591 | 0 | { |
592 | 0 | if (r == -ENOENT || r == -EPERM || r == -EAGAIN || r == -ENOANO) |
593 | 0 | return false; |
594 | 0 | return true; |
595 | 0 | } |
596 | | |
597 | | static void update_return_errno(int r, int *stored) |
598 | 0 | { |
599 | 0 | if (*stored == -ENOANO) |
600 | 0 | return; |
601 | 0 | else if (r == -ENOANO) |
602 | 0 | *stored = r; |
603 | 0 | else if (r == -EAGAIN && *stored != -ENOANO) |
604 | 0 | *stored = r; |
605 | 0 | else if (r == -EPERM && (*stored != -ENOANO && *stored != -EAGAIN)) |
606 | 0 | *stored = r; |
607 | 0 | } |
608 | | |
609 | | static int try_token_keyslot_unlock(struct crypt_device *cd, |
610 | | struct luks2_hdr *hdr, |
611 | | const char *type, |
612 | | json_object *jobj_token_keyslots, |
613 | | int token, |
614 | | int segment, |
615 | | crypt_keyslot_priority priority, |
616 | | const char *buffer, |
617 | | size_t buffer_len, |
618 | | struct volume_key **r_vk) |
619 | 0 | { |
620 | 0 | json_object *jobj; |
621 | 0 | crypt_keyslot_priority keyslot_priority; |
622 | 0 | int i, r = -ENOENT, stored_retval = -ENOENT; |
623 | 0 | unsigned int num = 0; |
624 | |
|
625 | 0 | for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots) && r < 0; i++) { |
626 | 0 | jobj = json_object_array_get_idx(jobj_token_keyslots, i); |
627 | 0 | num = atoi(json_object_get_string(jobj)); |
628 | 0 | keyslot_priority = LUKS2_keyslot_priority_get(hdr, num); |
629 | 0 | if (keyslot_priority == CRYPT_SLOT_PRIORITY_INVALID) |
630 | 0 | return -EINVAL; |
631 | 0 | if (keyslot_priority < priority) |
632 | 0 | continue; |
633 | 0 | log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", |
634 | 0 | num, token, type); |
635 | 0 | r = LUKS2_keyslot_open(cd, num, segment, buffer, buffer_len, r_vk); |
636 | | /* short circuit on fatal error */ |
637 | 0 | if (r < 0 && r != -EPERM && r != -ENOENT) |
638 | 0 | return r; |
639 | | /* save -EPERM in case no other keyslot is usable */ |
640 | 0 | if (r == -EPERM) |
641 | 0 | stored_retval = r; |
642 | 0 | } |
643 | | |
644 | 0 | if (r < 0) |
645 | 0 | return stored_retval; |
646 | | |
647 | 0 | return num; |
648 | 0 | } |
649 | | |
650 | | static int LUKS2_keyslot_open_by_token(struct crypt_device *cd, |
651 | | struct luks2_hdr *hdr, |
652 | | int keyslot, |
653 | | int token, |
654 | | int segment, |
655 | | crypt_keyslot_priority min_priority, |
656 | | const char *buffer, |
657 | | size_t buffer_len, |
658 | | struct volume_key **vk) |
659 | 0 | { |
660 | 0 | json_object *jobj_token, *jobj_token_keyslots, *jobj_type; |
661 | 0 | crypt_keyslot_priority priority = CRYPT_SLOT_PRIORITY_PREFER; |
662 | 0 | int r = -ENOENT, stored_retval = -ENOENT; |
663 | |
|
664 | 0 | jobj_token = LUKS2_get_token_jobj(hdr, token); |
665 | 0 | if (!jobj_token) |
666 | 0 | return -EINVAL; |
667 | | |
668 | 0 | if (!json_object_object_get_ex(jobj_token, "type", &jobj_type)) |
669 | 0 | return -EINVAL; |
670 | | |
671 | 0 | json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots); |
672 | 0 | if (!jobj_token_keyslots) |
673 | 0 | return -EINVAL; |
674 | | |
675 | | /* with specific keyslot just ignore priorities and unlock */ |
676 | 0 | if (keyslot != CRYPT_ANY_SLOT) { |
677 | 0 | log_dbg(cd, "Trying to open keyslot %u with token %d (type %s).", |
678 | 0 | keyslot, token, json_object_get_string(jobj_type)); |
679 | 0 | return LUKS2_keyslot_open(cd, keyslot, segment, buffer, buffer_len, vk); |
680 | 0 | } |
681 | | |
682 | | /* Try to open keyslot referenced in token */ |
683 | 0 | while (priority >= min_priority) { |
684 | 0 | r = try_token_keyslot_unlock(cd, hdr, json_object_get_string(jobj_type), |
685 | 0 | jobj_token_keyslots, token, segment, |
686 | 0 | priority, buffer, buffer_len, vk); |
687 | 0 | if (r == -EINVAL || r >= 0) |
688 | 0 | return r; |
689 | 0 | if (r == -EPERM) |
690 | 0 | stored_retval = r; |
691 | 0 | priority--; |
692 | 0 | } |
693 | | |
694 | 0 | return stored_retval; |
695 | 0 | } |
696 | | |
697 | | static bool token_is_blocked(int token, uint32_t *block_list) |
698 | 0 | { |
699 | | /* it is safe now, but have assert in case LUKS2_TOKENS_MAX grows */ |
700 | 0 | assert(token >= 0 && (size_t)token < BITFIELD_SIZE(block_list)); |
701 | |
|
702 | 0 | return (*block_list & (UINT32_C(1) << token)); |
703 | 0 | } |
704 | | |
705 | | static void token_block(int token, uint32_t *block_list) |
706 | 0 | { |
707 | | /* it is safe now, but have assert in case LUKS2_TOKENS_MAX grows */ |
708 | 0 | assert(token >= 0 && (size_t)token < BITFIELD_SIZE(block_list)); |
709 | |
|
710 | 0 | *block_list |= (UINT32_C(1) << token); |
711 | 0 | } |
712 | | |
713 | | static int token_open_priority(struct crypt_device *cd, |
714 | | struct luks2_hdr *hdr, |
715 | | json_object *jobj_tokens, |
716 | | const char *type, |
717 | | int keyslot, |
718 | | int segment, |
719 | | crypt_keyslot_priority priority, |
720 | | const char *pin, |
721 | | size_t pin_size, |
722 | | void *usrptr, |
723 | | int *stored_retval, |
724 | | uint32_t *block_list, |
725 | | struct volume_key **vk) |
726 | 0 | { |
727 | 0 | char *buffer; |
728 | 0 | size_t buffer_size; |
729 | 0 | int token, r; |
730 | |
|
731 | 0 | assert(stored_retval); |
732 | 0 | assert(block_list); |
733 | |
|
734 | 0 | json_object_object_foreach(jobj_tokens, slot, val) { |
735 | 0 | token = atoi(slot); |
736 | 0 | if (token_is_blocked(token, block_list)) |
737 | 0 | continue; |
738 | 0 | r = token_open(cd, hdr, keyslot, token, val, type, segment, priority, pin, pin_size, |
739 | 0 | &buffer, &buffer_size, usrptr, true); |
740 | 0 | if (!r) { |
741 | 0 | r = LUKS2_keyslot_open_by_token(cd, hdr, keyslot, token, segment, priority, |
742 | 0 | buffer, buffer_size, vk); |
743 | 0 | LUKS2_token_buffer_free(cd, token, buffer, buffer_size); |
744 | 0 | } |
745 | |
|
746 | 0 | if (r == -ENOANO) |
747 | 0 | token_block(token, block_list); |
748 | |
|
749 | 0 | if (break_loop_retval(r)) |
750 | 0 | return r; |
751 | | |
752 | 0 | update_return_errno(r, stored_retval); |
753 | 0 | } |
754 | | |
755 | 0 | return *stored_retval; |
756 | 0 | } |
757 | | |
758 | | static int token_open_any(struct crypt_device *cd, struct luks2_hdr *hdr, const char *type, |
759 | | int keyslot, int segment, const char *pin, size_t pin_size, void *usrptr, |
760 | | struct volume_key **vk) |
761 | 0 | { |
762 | 0 | json_object *jobj_tokens; |
763 | 0 | int r, retval = -ENOENT; |
764 | 0 | uint32_t blocked = 0; /* bitmap with tokens blocked from loop by returning -ENOANO (wrong/missing pin) */ |
765 | |
|
766 | 0 | json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens); |
767 | | |
768 | | /* passing usrptr for CRYPT_ANY_TOKEN does not make sense without specific type */ |
769 | 0 | if (!type) |
770 | 0 | usrptr = NULL; |
771 | |
|
772 | 0 | if (keyslot != CRYPT_ANY_SLOT) |
773 | 0 | return token_open_priority(cd, hdr, jobj_tokens, type, keyslot, segment, CRYPT_SLOT_PRIORITY_IGNORE, |
774 | 0 | pin, pin_size, usrptr, &retval, &blocked, vk); |
775 | | |
776 | 0 | r = token_open_priority(cd, hdr, jobj_tokens, type, keyslot, segment, CRYPT_SLOT_PRIORITY_PREFER, |
777 | 0 | pin, pin_size, usrptr, &retval, &blocked, vk); |
778 | 0 | if (break_loop_retval(r)) |
779 | 0 | return r; |
780 | | |
781 | 0 | return token_open_priority(cd, hdr, jobj_tokens, type, keyslot, segment, CRYPT_SLOT_PRIORITY_NORMAL, |
782 | 0 | pin, pin_size, usrptr, &retval, &blocked, vk); |
783 | 0 | } |
784 | | |
785 | | int LUKS2_token_unlock_key(struct crypt_device *cd, |
786 | | struct luks2_hdr *hdr, |
787 | | int keyslot, |
788 | | int token, |
789 | | const char *type, |
790 | | const char *pin, |
791 | | size_t pin_size, |
792 | | int segment, |
793 | | void *usrptr, |
794 | | struct volume_key **vk) |
795 | 0 | { |
796 | 0 | char *buffer; |
797 | 0 | size_t buffer_size; |
798 | 0 | json_object *jobj_token; |
799 | 0 | crypt_keyslot_priority min_priority; |
800 | 0 | int r = -ENOENT; |
801 | |
|
802 | 0 | assert(vk); |
803 | |
|
804 | 0 | if (segment == CRYPT_DEFAULT_SEGMENT) |
805 | 0 | segment = LUKS2_get_default_segment(hdr); |
806 | |
|
807 | 0 | if (segment < 0 && segment != CRYPT_ANY_SEGMENT) |
808 | 0 | return -EINVAL; |
809 | | |
810 | 0 | if (keyslot != CRYPT_ANY_SLOT || token != CRYPT_ANY_TOKEN) |
811 | 0 | min_priority = CRYPT_SLOT_PRIORITY_IGNORE; |
812 | 0 | else |
813 | 0 | min_priority = CRYPT_SLOT_PRIORITY_NORMAL; |
814 | |
|
815 | 0 | if (keyslot != CRYPT_ANY_SLOT) { |
816 | 0 | r = LUKS2_keyslot_for_segment(hdr, keyslot, segment); |
817 | 0 | if (r < 0) { |
818 | 0 | if (r == -ENOENT) |
819 | 0 | log_dbg(cd, "Keyslot %d unusable for segment %d.", keyslot, segment); |
820 | 0 | return r; |
821 | 0 | } |
822 | 0 | } |
823 | | |
824 | 0 | if (token >= 0 && token < LUKS2_TOKENS_MAX) { |
825 | 0 | if ((jobj_token = LUKS2_get_token_jobj(hdr, token))) { |
826 | 0 | r = token_open(cd, hdr, keyslot, token, jobj_token, type, segment, min_priority, |
827 | 0 | pin, pin_size, &buffer, &buffer_size, usrptr, true); |
828 | 0 | if (!r) { |
829 | 0 | r = LUKS2_keyslot_open_by_token(cd, hdr, keyslot, token, segment, |
830 | 0 | min_priority, buffer, buffer_size, vk); |
831 | 0 | LUKS2_token_buffer_free(cd, token, buffer, buffer_size); |
832 | 0 | } |
833 | 0 | } |
834 | 0 | } else if (token == CRYPT_ANY_TOKEN) |
835 | | /* |
836 | | * return priorities (ordered form least to most significant): |
837 | | * ENOENT - unusable for activation (no token handler, invalid token metadata, not assigned to volume segment, etc) |
838 | | * EPERM - usable but token provided passphrase did not unlock any assigned keyslot |
839 | | * EAGAIN - usable but not ready (token HW is missing) |
840 | | * ENOANO - ready, but token pin is wrong or missing |
841 | | * |
842 | | * success (>= 0) or any other negative errno short-circuits token activation loop |
843 | | * immediately |
844 | | */ |
845 | 0 | r = token_open_any(cd, hdr, type, keyslot, segment, pin, pin_size, usrptr, vk); |
846 | 0 | else |
847 | 0 | r = -EINVAL; |
848 | |
|
849 | 0 | return r; |
850 | 0 | } |
851 | | |
852 | | void LUKS2_token_dump(struct crypt_device *cd, int token) |
853 | 0 | { |
854 | 0 | const crypt_token_handler *h; |
855 | 0 | json_object *jobj_token; |
856 | |
|
857 | 0 | h = LUKS2_token_handler(cd, token); |
858 | 0 | if (h && h->dump) { |
859 | 0 | jobj_token = LUKS2_get_token_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), token); |
860 | 0 | if (jobj_token) |
861 | 0 | h->dump(cd, crypt_jobj_to_string_on_disk(jobj_token)); |
862 | 0 | } |
863 | 0 | } |
864 | | |
865 | | int LUKS2_token_json_get(struct luks2_hdr *hdr, int token, const char **json) |
866 | 0 | { |
867 | 0 | json_object *jobj_token; |
868 | |
|
869 | 0 | jobj_token = LUKS2_get_token_jobj(hdr, token); |
870 | 0 | if (!jobj_token) |
871 | 0 | return -EINVAL; |
872 | | |
873 | 0 | *json = crypt_jobj_to_string_on_disk(jobj_token); |
874 | 0 | return 0; |
875 | 0 | } |
876 | | |
877 | | static int assign_one_keyslot(struct crypt_device *cd, struct luks2_hdr *hdr, |
878 | | int token, int keyslot, int assign) |
879 | 0 | { |
880 | 0 | json_object *jobj1, *jobj_token, *jobj_token_keyslots; |
881 | 0 | char num[16]; |
882 | |
|
883 | 0 | log_dbg(cd, "Keyslot %i %s token %i.", keyslot, assign ? "assigned to" : "unassigned from", token); |
884 | |
|
885 | 0 | jobj_token = LUKS2_get_token_jobj(hdr, token); |
886 | 0 | if (!jobj_token) |
887 | 0 | return -EINVAL; |
888 | | |
889 | 0 | json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots); |
890 | 0 | if (!jobj_token_keyslots) |
891 | 0 | return -EINVAL; |
892 | | |
893 | 0 | if (snprintf(num, sizeof(num), "%d", keyslot) < 0) |
894 | 0 | return -EINVAL; |
895 | | |
896 | 0 | if (assign) { |
897 | 0 | jobj1 = LUKS2_array_jobj(jobj_token_keyslots, num); |
898 | 0 | if (!jobj1) |
899 | 0 | json_object_array_add(jobj_token_keyslots, json_object_new_string(num)); |
900 | 0 | } else { |
901 | 0 | jobj1 = LUKS2_array_remove(jobj_token_keyslots, num); |
902 | 0 | if (jobj1) |
903 | 0 | json_object_object_add(jobj_token, "keyslots", jobj1); |
904 | 0 | } |
905 | |
|
906 | 0 | return 0; |
907 | 0 | } |
908 | | |
909 | | static int assign_one_token(struct crypt_device *cd, struct luks2_hdr *hdr, |
910 | | int keyslot, int token, int assign) |
911 | 0 | { |
912 | 0 | json_object *jobj_keyslots; |
913 | 0 | int r = 0; |
914 | |
|
915 | 0 | if (!LUKS2_get_token_jobj(hdr, token)) |
916 | 0 | return -EINVAL; |
917 | | |
918 | 0 | if (keyslot == CRYPT_ANY_SLOT) { |
919 | 0 | json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots); |
920 | |
|
921 | 0 | json_object_object_foreach(jobj_keyslots, key, val) { |
922 | 0 | UNUSED(val); |
923 | 0 | r = assign_one_keyslot(cd, hdr, token, atoi(key), assign); |
924 | 0 | if (r < 0) |
925 | 0 | break; |
926 | 0 | } |
927 | 0 | } else |
928 | 0 | r = assign_one_keyslot(cd, hdr, token, keyslot, assign); |
929 | |
|
930 | 0 | return r; |
931 | 0 | } |
932 | | |
933 | | int LUKS2_token_assign(struct crypt_device *cd, struct luks2_hdr *hdr, |
934 | | int keyslot, int token, int assign, int commit) |
935 | 0 | { |
936 | 0 | json_object *jobj_tokens; |
937 | 0 | int r = 0; |
938 | |
|
939 | 0 | if ((keyslot < 0 && keyslot != CRYPT_ANY_SLOT) || keyslot >= LUKS2_KEYSLOTS_MAX || |
940 | 0 | (token < 0 && token != CRYPT_ANY_TOKEN) || token >= LUKS2_TOKENS_MAX) |
941 | 0 | return -EINVAL; |
942 | | |
943 | 0 | if (token == CRYPT_ANY_TOKEN) { |
944 | 0 | json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens); |
945 | |
|
946 | 0 | json_object_object_foreach(jobj_tokens, key, val) { |
947 | 0 | UNUSED(val); |
948 | 0 | r = assign_one_token(cd, hdr, keyslot, atoi(key), assign); |
949 | 0 | if (r < 0) |
950 | 0 | break; |
951 | 0 | } |
952 | 0 | } else |
953 | 0 | r = assign_one_token(cd, hdr, keyslot, token, assign); |
954 | |
|
955 | 0 | if (r < 0) |
956 | 0 | return r; |
957 | | |
958 | 0 | if (commit) |
959 | 0 | return LUKS2_hdr_write(cd, hdr) ?: token; |
960 | | |
961 | 0 | return token; |
962 | 0 | } |
963 | | |
964 | | static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token) |
965 | 0 | { |
966 | 0 | int i; |
967 | 0 | json_object *jobj, *jobj_token_keyslots, |
968 | 0 | *jobj_token = LUKS2_get_token_jobj(hdr, token); |
969 | |
|
970 | 0 | if (!jobj_token) |
971 | 0 | return -ENOENT; |
972 | | |
973 | 0 | json_object_object_get_ex(jobj_token, "keyslots", &jobj_token_keyslots); |
974 | |
|
975 | 0 | for (i = 0; i < (int) json_object_array_length(jobj_token_keyslots); i++) { |
976 | 0 | jobj = json_object_array_get_idx(jobj_token_keyslots, i); |
977 | 0 | if (keyslot == atoi(json_object_get_string(jobj))) |
978 | 0 | return 0; |
979 | 0 | } |
980 | | |
981 | 0 | return -ENOENT; |
982 | 0 | } |
983 | | |
984 | | int LUKS2_token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token) |
985 | 0 | { |
986 | 0 | if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX) |
987 | 0 | return -EINVAL; |
988 | | |
989 | 0 | return token_is_assigned(hdr, keyslot, token); |
990 | 0 | } |
991 | | |
992 | | int LUKS2_tokens_count(struct luks2_hdr *hdr) |
993 | 0 | { |
994 | 0 | json_object *jobj_tokens = LUKS2_get_tokens_jobj(hdr); |
995 | 0 | if (!jobj_tokens) |
996 | 0 | return -EINVAL; |
997 | | |
998 | 0 | return json_object_object_length(jobj_tokens); |
999 | 0 | } |
1000 | | |
1001 | | int LUKS2_token_assignment_copy(struct crypt_device *cd, |
1002 | | struct luks2_hdr *hdr, |
1003 | | int keyslot_from, |
1004 | | int keyslot_to, |
1005 | | int commit) |
1006 | 0 | { |
1007 | 0 | int i, r; |
1008 | |
|
1009 | 0 | if (keyslot_from < 0 || keyslot_from >= LUKS2_KEYSLOTS_MAX || keyslot_to < 0 || keyslot_to >= LUKS2_KEYSLOTS_MAX) |
1010 | 0 | return -EINVAL; |
1011 | | |
1012 | 0 | r = LUKS2_tokens_count(hdr); |
1013 | 0 | if (r <= 0) |
1014 | 0 | return r; |
1015 | | |
1016 | 0 | for (i = 0; i < LUKS2_TOKENS_MAX; i++) { |
1017 | 0 | if (!token_is_assigned(hdr, keyslot_from, i)) { |
1018 | 0 | if ((r = assign_one_token(cd, hdr, keyslot_to, i, 1))) |
1019 | 0 | return r; |
1020 | 0 | } |
1021 | 0 | } |
1022 | | |
1023 | 0 | return commit ? LUKS2_hdr_write(cd, hdr) : 0; |
1024 | 0 | } |
1025 | | |
1026 | | int LUKS2_token_unlock_passphrase(struct crypt_device *cd, |
1027 | | struct luks2_hdr *hdr, |
1028 | | int token, |
1029 | | const char *type, |
1030 | | const char *pin, |
1031 | | size_t pin_size, |
1032 | | void *usrptr, |
1033 | | char **passphrase, |
1034 | | size_t *passphrase_size) |
1035 | 0 | { |
1036 | 0 | char *buffer; |
1037 | 0 | size_t buffer_size; |
1038 | 0 | json_object *jobj_token, *jobj_tokens; |
1039 | 0 | int r = -ENOENT, retval = -ENOENT; |
1040 | |
|
1041 | 0 | if (!hdr) |
1042 | 0 | return -EINVAL; |
1043 | | |
1044 | 0 | if (token >= 0 && token < LUKS2_TOKENS_MAX) { |
1045 | 0 | if ((jobj_token = LUKS2_get_token_jobj(hdr, token))) |
1046 | 0 | r = token_open(cd, hdr, CRYPT_ANY_SLOT, token, jobj_token, type, |
1047 | 0 | CRYPT_ANY_SEGMENT, CRYPT_SLOT_PRIORITY_IGNORE, pin, pin_size, |
1048 | 0 | &buffer, &buffer_size, usrptr, false); |
1049 | 0 | } else if (token == CRYPT_ANY_TOKEN) { |
1050 | 0 | json_object_object_get_ex(hdr->jobj, "tokens", &jobj_tokens); |
1051 | |
|
1052 | 0 | if (!type) |
1053 | 0 | usrptr = NULL; |
1054 | |
|
1055 | 0 | json_object_object_foreach(jobj_tokens, slot, val) { |
1056 | 0 | token = atoi(slot); |
1057 | 0 | r = token_open(cd, hdr, CRYPT_ANY_SLOT, token, val, type, CRYPT_ANY_SEGMENT, CRYPT_SLOT_PRIORITY_IGNORE, |
1058 | 0 | pin, pin_size, &buffer, &buffer_size, usrptr, false); |
1059 | | |
1060 | | /* |
1061 | | * return priorities (ordered form least to most significant): |
1062 | | * ENOENT - unusable for activation (no token handler, invalid token metadata, etc) |
1063 | | * EAGAIN - usable but not ready (token HW is missing) |
1064 | | * ENOANO - ready, but token pin is wrong or missing |
1065 | | * |
1066 | | * success (>= 0) or any other negative errno short-circuits token activation loop |
1067 | | * immediately |
1068 | | */ |
1069 | 0 | if (break_loop_retval(r)) |
1070 | 0 | goto out; |
1071 | | |
1072 | 0 | update_return_errno(r, &retval); |
1073 | 0 | } |
1074 | 0 | r = retval; |
1075 | 0 | } else |
1076 | 0 | r = -EINVAL; |
1077 | 0 | out: |
1078 | 0 | if (!r) { |
1079 | 0 | *passphrase = crypt_safe_alloc(buffer_size); |
1080 | 0 | if (*passphrase) { |
1081 | 0 | crypt_safe_memcpy(*passphrase, buffer, buffer_size); |
1082 | 0 | *passphrase_size = buffer_size; |
1083 | 0 | } else |
1084 | 0 | r = -ENOMEM; |
1085 | 0 | LUKS2_token_buffer_free(cd, token, buffer, buffer_size); |
1086 | 0 | } |
1087 | |
|
1088 | 0 | if (!r) |
1089 | 0 | return token; |
1090 | | |
1091 | 0 | return r; |
1092 | 0 | } |