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