]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/pkcs11-util.c
tree-wide: add dlopen ELF notes to all dlopen() deps of ours
[thirdparty/systemd.git] / src / shared / pkcs11-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
839fddbe
LP
2
3#include <fcntl.h>
4
5#include "ask-password-api.h"
da035a3a 6#include "dlfcn-util.h"
7a6abbe9 7#include "env-util.h"
839fddbe
LP
8#include "escape.h"
9#include "fd-util.h"
f240cbb6 10#include "format-table.h"
839fddbe
LP
11#include "io-util.h"
12#include "memory-util.h"
13#if HAVE_OPENSSL
14#include "openssl-util.h"
15#endif
16#include "pkcs11-util.h"
17#include "random-util.h"
18#include "string-util.h"
19#include "strv.h"
20
21bool pkcs11_uri_valid(const char *uri) {
22 const char *p;
23
24 /* A very superficial checker for RFC7512 PKCS#11 URI syntax */
25
26 if (isempty(uri))
27 return false;
28
29 p = startswith(uri, "pkcs11:");
30 if (!p)
31 return false;
32
33 if (isempty(p))
34 return false;
35
b204bdd4 36 if (!in_charset(p, ALPHANUMERICAL ".~/-_?;&%="))
839fddbe
LP
37 return false;
38
39 return true;
40}
41
42#if HAVE_P11KIT
43
da035a3a
LB
44static void *p11kit_dl = NULL;
45
9dbabd0a
LP
46DLSYM_FUNCTION(p11_kit_module_get_name);
47DLSYM_FUNCTION(p11_kit_modules_finalize_and_release);
48DLSYM_FUNCTION(p11_kit_modules_load_and_initialize);
49DLSYM_FUNCTION(p11_kit_strerror);
50DLSYM_FUNCTION(p11_kit_uri_format);
51DLSYM_FUNCTION(p11_kit_uri_free);
52DLSYM_FUNCTION(p11_kit_uri_get_attributes);
53DLSYM_FUNCTION(p11_kit_uri_get_attribute);
54DLSYM_FUNCTION(p11_kit_uri_set_attribute);
55DLSYM_FUNCTION(p11_kit_uri_get_module_info);
56DLSYM_FUNCTION(p11_kit_uri_get_slot_info);
57DLSYM_FUNCTION(p11_kit_uri_get_token_info);
58DLSYM_FUNCTION(p11_kit_uri_match_token_info);
59DLSYM_FUNCTION(p11_kit_uri_message);
60DLSYM_FUNCTION(p11_kit_uri_new);
61DLSYM_FUNCTION(p11_kit_uri_parse);
da035a3a
LB
62
63int dlopen_p11kit(void) {
cd7c2077
LP
64 ELF_NOTE_DLOPEN("p11-kit",
65 "Support for PKCS11 hardware tokens",
66 ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
67 "libp11-kit.so.0");
68
da035a3a
LB
69 return dlopen_many_sym_or_warn(
70 &p11kit_dl,
71 "libp11-kit.so.0", LOG_DEBUG,
72 DLSYM_ARG(p11_kit_module_get_name),
73 DLSYM_ARG(p11_kit_modules_finalize_and_release),
74 DLSYM_ARG(p11_kit_modules_load_and_initialize),
75 DLSYM_ARG(p11_kit_strerror),
76 DLSYM_ARG(p11_kit_uri_format),
77 DLSYM_ARG(p11_kit_uri_free),
78 DLSYM_ARG(p11_kit_uri_get_attributes),
85828ef9
VS
79 DLSYM_ARG(p11_kit_uri_get_attribute),
80 DLSYM_ARG(p11_kit_uri_set_attribute),
da035a3a
LB
81 DLSYM_ARG(p11_kit_uri_get_module_info),
82 DLSYM_ARG(p11_kit_uri_get_slot_info),
83 DLSYM_ARG(p11_kit_uri_get_token_info),
84 DLSYM_ARG(p11_kit_uri_match_token_info),
85 DLSYM_ARG(p11_kit_uri_message),
86 DLSYM_ARG(p11_kit_uri_new),
87 DLSYM_ARG(p11_kit_uri_parse));
88}
89
839fddbe 90int uri_from_string(const char *p, P11KitUri **ret) {
da035a3a
LB
91 _cleanup_(sym_p11_kit_uri_freep) P11KitUri *uri = NULL;
92 int r;
839fddbe
LP
93
94 assert(p);
95 assert(ret);
96
da035a3a
LB
97 r = dlopen_p11kit();
98 if (r < 0)
99 return r;
100
101 uri = sym_p11_kit_uri_new();
839fddbe
LP
102 if (!uri)
103 return -ENOMEM;
104
da035a3a 105 if (sym_p11_kit_uri_parse(p, P11_KIT_URI_FOR_ANY, uri) != P11_KIT_URI_OK)
839fddbe
LP
106 return -EINVAL;
107
108 *ret = TAKE_PTR(uri);
109 return 0;
110}
111
112P11KitUri *uri_from_module_info(const CK_INFO *info) {
113 P11KitUri *uri;
114
115 assert(info);
116
da035a3a
LB
117 if (dlopen_p11kit() < 0)
118 return NULL;
119
120 uri = sym_p11_kit_uri_new();
839fddbe
LP
121 if (!uri)
122 return NULL;
123
da035a3a 124 *sym_p11_kit_uri_get_module_info(uri) = *info;
839fddbe
LP
125 return uri;
126}
127
128P11KitUri *uri_from_slot_info(const CK_SLOT_INFO *slot_info) {
129 P11KitUri *uri;
130
131 assert(slot_info);
132
da035a3a
LB
133 if (dlopen_p11kit() < 0)
134 return NULL;
135
136 uri = sym_p11_kit_uri_new();
839fddbe
LP
137 if (!uri)
138 return NULL;
139
da035a3a 140 *sym_p11_kit_uri_get_slot_info(uri) = *slot_info;
839fddbe
LP
141 return uri;
142}
143
144P11KitUri *uri_from_token_info(const CK_TOKEN_INFO *token_info) {
145 P11KitUri *uri;
146
147 assert(token_info);
148
da035a3a
LB
149 if (dlopen_p11kit() < 0)
150 return NULL;
151
152 uri = sym_p11_kit_uri_new();
839fddbe
LP
153 if (!uri)
154 return NULL;
155
da035a3a 156 *sym_p11_kit_uri_get_token_info(uri) = *token_info;
839fddbe
LP
157 return uri;
158}
159
160CK_RV pkcs11_get_slot_list_malloc(
161 CK_FUNCTION_LIST *m,
162 CK_SLOT_ID **ret_slotids,
163 CK_ULONG *ret_n_slotids) {
164
165 CK_RV rv;
166
167 assert(m);
168 assert(ret_slotids);
169 assert(ret_n_slotids);
170
171 for (unsigned tries = 0; tries < 16; tries++) {
172 _cleanup_free_ CK_SLOT_ID *slotids = NULL;
173 CK_ULONG n_slotids = 0;
174
175 rv = m->C_GetSlotList(0, NULL, &n_slotids);
176 if (rv != CKR_OK)
177 return rv;
178 if (n_slotids == 0) {
179 *ret_slotids = NULL;
180 *ret_n_slotids = 0;
181 return CKR_OK;
182 }
183
184 slotids = new(CK_SLOT_ID, n_slotids);
185 if (!slotids)
186 return CKR_HOST_MEMORY;
187
188 rv = m->C_GetSlotList(0, slotids, &n_slotids);
189 if (rv == CKR_OK) {
190 *ret_slotids = TAKE_PTR(slotids);
191 *ret_n_slotids = n_slotids;
192 return CKR_OK;
193 }
194
195 if (rv != CKR_BUFFER_TOO_SMALL)
196 return rv;
197
198 /* Hu? Maybe somebody plugged something in and things changed? Let's try again */
199 }
200
201 return CKR_BUFFER_TOO_SMALL;
202}
203
204char *pkcs11_token_label(const CK_TOKEN_INFO *token_info) {
205 char *t;
206
207 /* The label is not NUL terminated and likely padded with spaces, let's make a copy here, so that we
208 * can strip that. */
209 t = strndup((char*) token_info->label, sizeof(token_info->label));
210 if (!t)
211 return NULL;
212
213 strstrip(t);
214 return t;
215}
216
0eb3be46
LP
217char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info) {
218 char *t;
219
220 t = strndup((char*) token_info->manufacturerID, sizeof(token_info->manufacturerID));
221 if (!t)
222 return NULL;
223
224 strstrip(t);
225 return t;
226}
227
228char *pkcs11_token_model(const CK_TOKEN_INFO *token_info) {
229 char *t;
230
231 t = strndup((char*) token_info->model, sizeof(token_info->model));
232 if (!t)
233 return NULL;
234
235 strstrip(t);
236 return t;
237}
238
0ff60566
OK
239int pkcs11_token_login_by_pin(
240 CK_FUNCTION_LIST *m,
241 CK_SESSION_HANDLE session,
242 const CK_TOKEN_INFO *token_info,
243 const char *token_label,
244 const void *pin,
245 size_t pin_size) {
246
247 CK_RV rv;
da035a3a 248 int r;
0ff60566
OK
249
250 assert(m);
251 assert(token_info);
252
da035a3a
LB
253 r = dlopen_p11kit();
254 if (r < 0)
255 return r;
256
0ff60566
OK
257 if (FLAGS_SET(token_info->flags, CKF_PROTECTED_AUTHENTICATION_PATH)) {
258 rv = m->C_Login(session, CKU_USER, NULL, 0);
259 if (rv != CKR_OK)
260 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 261 "Failed to log into security token '%s': %s", token_label, sym_p11_kit_strerror(rv));
0ff60566
OK
262
263 log_info("Successfully logged into security token '%s' via protected authentication path.", token_label);
264 return 0;
265 }
266
267 if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
268 log_info("No login into security token '%s' required.", token_label);
269 return 0;
270 }
271
272 if (!pin)
273 return -ENOANO;
274
275 rv = m->C_Login(session, CKU_USER, (CK_UTF8CHAR*) pin, pin_size);
276 if (rv == CKR_OK) {
277 log_info("Successfully logged into security token '%s'.", token_label);
278 return 0;
279 }
280
281 if (rv == CKR_PIN_LOCKED)
282 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
283 "PIN has been locked, please reset PIN of security token '%s'.", token_label);
284 if (!IN_SET(rv, CKR_PIN_INCORRECT, CKR_PIN_LEN_RANGE))
285 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 286 "Failed to log into security token '%s': %s", token_label, sym_p11_kit_strerror(rv));
0ff60566 287
b98416e1
FS
288 return log_notice_errno(SYNTHETIC_ERRNO(ENOLCK),
289 "PIN for token '%s' is incorrect, please try again.",
290 token_label);
0ff60566
OK
291}
292
839fddbe
LP
293int pkcs11_token_login(
294 CK_FUNCTION_LIST *m,
295 CK_SESSION_HANDLE session,
296 CK_SLOT_ID slotid,
297 const CK_TOKEN_INFO *token_info,
298 const char *friendly_name,
a96c284f
LP
299 const char *askpw_icon,
300 const char *askpw_keyring,
301 const char *askpw_credential,
839fddbe 302 usec_t until,
b2ac9280 303 AskPasswordFlags askpw_flags,
839fddbe
LP
304 char **ret_used_pin) {
305
306 _cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL;
da035a3a 307 _cleanup_(sym_p11_kit_uri_freep) P11KitUri *token_uri = NULL;
839fddbe 308 CK_TOKEN_INFO updated_token_info;
0eb3be46 309 int uri_result, r;
839fddbe 310 CK_RV rv;
839fddbe
LP
311
312 assert(m);
313 assert(token_info);
314
da035a3a
LB
315 r = dlopen_p11kit();
316 if (r < 0)
317 return r;
318
839fddbe
LP
319 token_label = pkcs11_token_label(token_info);
320 if (!token_label)
321 return log_oom();
322
323 token_uri = uri_from_token_info(token_info);
324 if (!token_uri)
325 return log_oom();
326
da035a3a 327 uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
839fddbe 328 if (uri_result != P11_KIT_URI_OK)
da035a3a 329 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
839fddbe 330
0ff60566
OK
331 r = pkcs11_token_login_by_pin(m, session, token_info, token_label, /* pin= */ NULL, 0);
332 if (r == 0 && ret_used_pin)
333 *ret_used_pin = NULL;
839fddbe 334
0ff60566
OK
335 if (r != -ENOANO) /* pin required */
336 return r;
839fddbe
LP
337
338 token_uri_escaped = cescape(token_uri_string);
339 if (!token_uri_escaped)
340 return log_oom();
341
342 id = strjoin("pkcs11:", token_uri_escaped);
343 if (!id)
344 return log_oom();
345
346 for (unsigned tries = 0; tries < 3; tries++) {
347 _cleanup_strv_free_erase_ char **passwords = NULL;
e99ca147 348 _cleanup_(erase_and_freep) char *envpin = NULL;
e99ca147
LP
349
350 r = getenv_steal_erase("PIN", &envpin);
351 if (r < 0)
352 return log_error_errno(r, "Failed to acquire PIN from environment: %m");
353 if (r > 0) {
354 passwords = strv_new(envpin);
839fddbe
LP
355 if (!passwords)
356 return log_oom();
357
b2ac9280 358 } else if (FLAGS_SET(askpw_flags, ASK_PASSWORD_HEADLESS))
cd5f57bd
LB
359 return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable.");
360 else {
c63ec11b
LP
361 _cleanup_free_ char *text = NULL;
362
363 if (FLAGS_SET(token_info->flags, CKF_USER_PIN_FINAL_TRY))
364 r = asprintf(&text,
365 "Please enter correct PIN for security token '%s' in order to unlock %s (final try):",
366 token_label, friendly_name);
367 else if (FLAGS_SET(token_info->flags, CKF_USER_PIN_COUNT_LOW))
368 r = asprintf(&text,
369 "PIN has been entered incorrectly previously, please enter correct PIN for security token '%s' in order to unlock %s:",
370 token_label, friendly_name);
371 else if (tries == 0)
372 r = asprintf(&text,
373 "Please enter PIN for security token '%s' in order to unlock %s:",
374 token_label, friendly_name);
375 else
376 r = asprintf(&text,
377 "Please enter PIN for security token '%s' in order to unlock %s (try #%u):",
378 token_label, friendly_name, tries+1);
379 if (r < 0)
380 return log_oom();
381
d08fd4c3
LP
382 AskPasswordRequest req = {
383 .message = text,
a96c284f 384 .icon = askpw_icon,
d08fd4c3 385 .id = id,
a96c284f
LP
386 .keyring = askpw_keyring,
387 .credential = askpw_credential,
d08fd4c3
LP
388 };
389
839fddbe 390 /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */
b2ac9280 391 r = ask_password_auto(&req, until, askpw_flags, &passwords);
839fddbe
LP
392 if (r < 0)
393 return log_error_errno(r, "Failed to query PIN for security token '%s': %m", token_label);
394 }
395
396 STRV_FOREACH(i, passwords) {
0ff60566
OK
397 r = pkcs11_token_login_by_pin(m, session, token_info, token_label, *i, strlen(*i));
398 if (r == 0 && ret_used_pin) {
399 char *c;
839fddbe 400
0ff60566
OK
401 c = strdup(*i);
402 if (!c)
403 return log_oom();
839fddbe 404
0ff60566 405 *ret_used_pin = c;
839fddbe 406 }
0ff60566
OK
407
408 if (r != -ENOLCK)
409 return r;
839fddbe 410
fcdd21ec 411 /* Refresh the token info, so that we can prompt knowing the new flags if they changed. */
839fddbe
LP
412 rv = m->C_GetTokenInfo(slotid, &updated_token_info);
413 if (rv != CKR_OK)
414 return log_error_errno(SYNTHETIC_ERRNO(EIO),
415 "Failed to acquire updated security token information for slot %lu: %s",
da035a3a 416 slotid, sym_p11_kit_strerror(rv));
839fddbe
LP
417
418 token_info = &updated_token_info;
839fddbe
LP
419 }
420 }
421
422 return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Too many attempts to log into token '%s'.", token_label);
423}
424
425int pkcs11_token_find_x509_certificate(
426 CK_FUNCTION_LIST *m,
427 CK_SESSION_HANDLE session,
428 P11KitUri *search_uri,
429 CK_OBJECT_HANDLE *ret_object) {
430
431 bool found_class = false, found_certificate_type = false;
432 _cleanup_free_ CK_ATTRIBUTE *attributes_buffer = NULL;
433 CK_ULONG n_attributes, a, n_objects;
434 CK_ATTRIBUTE *attributes = NULL;
435 CK_OBJECT_HANDLE objects[2];
436 CK_RV rv, rv2;
da035a3a 437 int r;
839fddbe
LP
438
439 assert(m);
440 assert(search_uri);
441 assert(ret_object);
442
da035a3a
LB
443 r = dlopen_p11kit();
444 if (r < 0)
445 return r;
446
447 attributes = sym_p11_kit_uri_get_attributes(search_uri, &n_attributes);
839fddbe
LP
448 for (a = 0; a < n_attributes; a++) {
449
450 /* We use the URI's included match attributes, but make them more strict. This allows users
451 * to specify a token URL instead of an object URL and the right thing should happen if
452 * there's only one suitable key on the token. */
453
454 switch (attributes[a].type) {
455
456 case CKA_CLASS: {
457 CK_OBJECT_CLASS c;
458
459 if (attributes[a].ulValueLen != sizeof(c))
460 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CLASS attribute size.");
461
462 memcpy(&c, attributes[a].pValue, sizeof(c));
463 if (c != CKO_CERTIFICATE)
464 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
465
466 found_class = true;
467 break;
468 }
469
470 case CKA_CERTIFICATE_TYPE: {
471 CK_CERTIFICATE_TYPE t;
472
473 if (attributes[a].ulValueLen != sizeof(t))
474 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CERTIFICATE_TYPE attribute size.");
475
476 memcpy(&t, attributes[a].pValue, sizeof(t));
477 if (t != CKC_X_509)
478 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
479
480 found_certificate_type = true;
481 break;
482 }}
483 }
484
485 if (!found_class || !found_certificate_type) {
486 /* Hmm, let's slightly extend the attribute list we search for */
487
488 attributes_buffer = new(CK_ATTRIBUTE, n_attributes + !found_class + !found_certificate_type);
489 if (!attributes_buffer)
490 return log_oom();
491
492 memcpy(attributes_buffer, attributes, sizeof(CK_ATTRIBUTE) * n_attributes);
493
494 if (!found_class) {
495 static const CK_OBJECT_CLASS class = CKO_CERTIFICATE;
496
497 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
498 .type = CKA_CLASS,
499 .pValue = (CK_OBJECT_CLASS*) &class,
500 .ulValueLen = sizeof(class),
501 };
502 }
503
504 if (!found_certificate_type) {
505 static const CK_CERTIFICATE_TYPE type = CKC_X_509;
506
507 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
508 .type = CKA_CERTIFICATE_TYPE,
509 .pValue = (CK_CERTIFICATE_TYPE*) &type,
510 .ulValueLen = sizeof(type),
511 };
512 }
513
514 attributes = attributes_buffer;
515 }
516
517 rv = m->C_FindObjectsInit(session, attributes, n_attributes);
518 if (rv != CKR_OK)
519 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 520 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
521
522 rv = m->C_FindObjects(session, objects, ELEMENTSOF(objects), &n_objects);
523 rv2 = m->C_FindObjectsFinal(session);
524 if (rv != CKR_OK)
525 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 526 "Failed to find objects: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
527 if (rv2 != CKR_OK)
528 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 529 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
530 if (n_objects == 0)
531 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
532 "Failed to find selected X509 certificate on token.");
533 if (n_objects > 1)
534 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
535 "Configured URI matches multiple certificates, refusing.");
536
537 *ret_object = objects[0];
538 return 0;
539}
540
541#if HAVE_OPENSSL
85686b37
VS
542static int read_public_key_info(
543 CK_FUNCTION_LIST *m,
544 CK_SESSION_HANDLE session,
545 CK_OBJECT_HANDLE object,
546 EVP_PKEY **ret_pkey) {
547
548 CK_ATTRIBUTE attribute = { CKA_PUBLIC_KEY_INFO, NULL_PTR, 0 };
549 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
550 CK_RV rv;
551
552 rv = m->C_GetAttributeValue(session, object, &attribute, 1);
553 if (rv != CKR_OK)
554 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
555 "Failed to get size of CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv));
556
557 if (attribute.ulValueLen == 0)
558 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "CKA_PUBLIC_KEY_INFO is empty");
559
560 _cleanup_free_ void *buffer = malloc(attribute.ulValueLen);
561 if (!buffer)
562 return log_oom_debug();
563
564 attribute.pValue = buffer;
565
566 rv = m->C_GetAttributeValue(session, object, &attribute, 1);
567 if (rv != CKR_OK)
568 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
569 "Failed to read CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv));
570
571 const unsigned char *value = attribute.pValue;
572 pkey = d2i_PUBKEY(NULL, &value, attribute.ulValueLen);
573 if (!pkey)
574 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse CKA_PUBLIC_KEY_INFO");
575
576 *ret_pkey = TAKE_PTR(pkey);
577 return 0;
578}
579
580int pkcs11_token_read_public_key(
581 CK_FUNCTION_LIST *m,
582 CK_SESSION_HANDLE session,
583 CK_OBJECT_HANDLE object,
584 EVP_PKEY **ret_pkey) {
585
586 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
587 CK_RV rv;
588 int r;
589
590 r = read_public_key_info(m, session, object, &pkey);
591 if (r >= 0) {
592 *ret_pkey = TAKE_PTR(pkey);
593 return 0;
594 }
595
596 CK_KEY_TYPE key_type;
597 CK_ATTRIBUTE attribute = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
598
599 rv = m->C_GetAttributeValue(session, object, &attribute, 1);
600 if (rv != CKR_OK)
601 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
602 "Failed to get CKA_KEY_TYPE of a public key: %s", sym_p11_kit_strerror(rv));
603
604 switch (key_type) {
605 case CKK_RSA: {
606 CK_ATTRIBUTE rsa_attributes[] = {
607 { CKA_MODULUS, NULL_PTR, 0 },
608 { CKA_PUBLIC_EXPONENT, NULL_PTR, 0 },
609 };
610
611 rv = m->C_GetAttributeValue(session, object, rsa_attributes, ELEMENTSOF(rsa_attributes));
612 if (rv != CKR_OK)
613 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
614 "Failed to get size of attributes of an RSA public key: %s", sym_p11_kit_strerror(rv));
615
616 if (rsa_attributes[0].ulValueLen == 0)
617 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "An RSA public key has empty CKA_MODULUS.");
618
619 _cleanup_free_ void *modulus = malloc(rsa_attributes[0].ulValueLen);
620 if (!modulus)
621 return log_oom_debug();
622
623 rsa_attributes[0].pValue = modulus;
624
625 if (rsa_attributes[1].ulValueLen == 0)
626 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "An RSA public key has empty CKA_PUBLIC_EXPONENT.");
627
628 _cleanup_free_ void *public_exponent = malloc(rsa_attributes[1].ulValueLen);
629 if (!public_exponent)
630 return log_oom_debug();
631
632 rsa_attributes[1].pValue = public_exponent;
633
634 rv = m->C_GetAttributeValue(session, object, rsa_attributes, ELEMENTSOF(rsa_attributes));
635 if (rv != CKR_OK)
636 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
637 "Failed to get attributes of an RSA public key: %s", sym_p11_kit_strerror(rv));
638
639 size_t n_size = rsa_attributes[0].ulValueLen, e_size = rsa_attributes[1].ulValueLen;
640 r = rsa_pkey_from_n_e(rsa_attributes[0].pValue, n_size, rsa_attributes[1].pValue, e_size, &pkey);
641 if (r < 0)
642 return log_debug_errno(r, "Failed to create an EVP_PKEY from RSA parameters.");
643
644 break;
645 }
646 case CKK_EC: {
647 CK_ATTRIBUTE ec_attributes[] = {
648 { CKA_EC_PARAMS, NULL_PTR, 0 },
649 { CKA_EC_POINT, NULL_PTR, 0 },
650 };
651
652 rv = m->C_GetAttributeValue(session, object, ec_attributes, ELEMENTSOF(ec_attributes));
653 if (rv != CKR_OK)
654 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
655 "Failed to get size of attributes of an EC public key: %s", sym_p11_kit_strerror(rv));
656
657 if (ec_attributes[0].ulValueLen == 0)
658 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "An EC public key has empty CKA_EC_PARAMS.");
659
660 _cleanup_free_ void *ec_group = malloc(ec_attributes[0].ulValueLen);
661 if (!ec_group)
662 return log_oom_debug();
663
664 ec_attributes[0].pValue = ec_group;
665
666 if (ec_attributes[1].ulValueLen == 0)
667 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "An EC public key has empty CKA_EC_POINT.");
668
669 _cleanup_free_ void *ec_point = malloc(ec_attributes[1].ulValueLen);
670 if (!ec_point)
671 return log_oom_debug();
672
673 ec_attributes[1].pValue = ec_point;
674
675 rv = m->C_GetAttributeValue(session, object, ec_attributes, ELEMENTSOF(ec_attributes));
676 if (rv != CKR_OK)
677 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
678 "Failed to get attributes of an EC public key: %s", sym_p11_kit_strerror(rv));
679
680 _cleanup_(EC_GROUP_freep) EC_GROUP *group = NULL;
681 _cleanup_(ASN1_OCTET_STRING_freep) ASN1_OCTET_STRING *os = NULL;
682
683 const unsigned char *ec_params_value = ec_attributes[0].pValue;
684 group = d2i_ECPKParameters(NULL, &ec_params_value, ec_attributes[0].ulValueLen);
685 if (!group)
686 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unable to decode CKA_EC_PARAMS.");
687
688 const unsigned char *ec_point_value = ec_attributes[1].pValue;
689 os = d2i_ASN1_OCTET_STRING(NULL, &ec_point_value, ec_attributes[1].ulValueLen);
690 if (!os)
691 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unable to decode CKA_EC_POINT.");
692
693#if OPENSSL_VERSION_MAJOR >= 3
694 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
695 if (!ctx)
696 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to create an EVP_PKEY_CTX for EC.");
697
698 if (EVP_PKEY_fromdata_init(ctx) != 1)
699 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to init an EVP_PKEY_CTX for EC.");
700
701 OSSL_PARAM ec_params[8] = {
702 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, os->data, os->length)
703 };
704
705 _cleanup_free_ void *order = NULL, *p = NULL, *a = NULL, *b = NULL, *generator = NULL;
706 size_t order_size, p_size, a_size, b_size, generator_size;
707
708 int nid = EC_GROUP_get_curve_name(group);
709 if (nid != NID_undef) {
710 const char* name = OSSL_EC_curve_nid2name(nid);
711 ec_params[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, (char*)name, strlen(name));
712 ec_params[2] = OSSL_PARAM_construct_end();
713 } else {
714 const char *field_type = EC_GROUP_get_field_type(group) == NID_X9_62_prime_field ?
715 "prime-field" : "characteristic-two-field";
716
717 const BIGNUM *bn_order = EC_GROUP_get0_order(group);
718
719 _cleanup_(BN_CTX_freep) BN_CTX *bnctx = BN_CTX_new();
720 if (!bnctx)
721 return log_oom_debug();
722
723 _cleanup_(BN_freep) BIGNUM *bn_p = BN_new();
724 if (!bn_p)
725 return log_oom_debug();
726
727 _cleanup_(BN_freep) BIGNUM *bn_a = BN_new();
728 if (!bn_a)
729 return log_oom_debug();
730
731 _cleanup_(BN_freep) BIGNUM *bn_b = BN_new();
732 if (!bn_b)
733 return log_oom_debug();
734
735 if (EC_GROUP_get_curve(group, bn_p, bn_a, bn_b, bnctx) != 1)
736 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to extract EC parameters from EC_GROUP.");
737
738 order_size = BN_num_bytes(bn_order);
739 p_size = BN_num_bytes(bn_p);
740 a_size = BN_num_bytes(bn_a);
741 b_size = BN_num_bytes(bn_b);
742
743 order = malloc(order_size);
744 if (!order)
745 return log_oom_debug();
746
747 p = malloc(p_size);
748 if (!p)
749 return log_oom_debug();
750
751 a = malloc(a_size);
752 if (!a)
753 return log_oom_debug();
754
755 b = malloc(b_size);
756 if (!b)
757 return log_oom_debug();
758
759 if (BN_bn2nativepad(bn_order, order, order_size) <= 0 ||
760 BN_bn2nativepad(bn_p, p, p_size) <= 0 ||
761 BN_bn2nativepad(bn_a, a, a_size) <= 0 ||
762 BN_bn2nativepad(bn_b, b, b_size) <= 0 )
763 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to store EC parameters in native byte order.");
764
765 const EC_POINT *point_gen = EC_GROUP_get0_generator(group);
766 generator_size = EC_POINT_point2oct(group, point_gen, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bnctx);
767 if (generator_size == 0)
768 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine size of a EC generator.");
769
770 generator = malloc(generator_size);
771 if (!generator)
772 return log_oom_debug();
773
774 generator_size = EC_POINT_point2oct(group, point_gen, POINT_CONVERSION_UNCOMPRESSED, generator, generator_size, bnctx);
775 if (generator_size == 0)
776 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert a EC generator to octet string.");
777
778 ec_params[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_FIELD_TYPE, (char*)field_type, strlen(field_type));
779 ec_params[2] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_EC_GENERATOR, generator, generator_size);
780 ec_params[3] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_ORDER, order, order_size);
781 ec_params[4] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_P, p, p_size);
782 ec_params[5] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_A, a, a_size);
783 ec_params[6] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_B, b, b_size);
784 ec_params[7] = OSSL_PARAM_construct_end();
785 }
786
787 if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, ec_params) != 1)
788 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to create EVP_PKEY from EC parameters.");
789#else
790 _cleanup_(EC_POINT_freep) EC_POINT *point = EC_POINT_new(group);
791 if (!point)
792 return log_oom_debug();
793
794 if (EC_POINT_oct2point(group, point, os->data, os->length, NULL) != 1)
795 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unable to decode CKA_EC_POINT.");
796
797 _cleanup_(EC_KEY_freep) EC_KEY *ec_key = EC_KEY_new();
798 if (!ec_key)
799 return log_oom_debug();
800
801 if (EC_KEY_set_group(ec_key, group) != 1)
802 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set group for EC_KEY.");
803
804 if (EC_KEY_set_public_key(ec_key, point) != 1)
805 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set public key for EC_KEY.");
806
807 pkey = EVP_PKEY_new();
808 if (!pkey)
809 return log_oom_debug();
810
811 if (EVP_PKEY_set1_EC_KEY(pkey, ec_key) != 1)
812 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to assign EC_KEY to EVP_PKEY.");
813#endif
814 break;
815 }
816 default:
817 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported type of public key: %lu", key_type);
818 }
819
820 *ret_pkey = TAKE_PTR(pkey);
821 return 0;
822}
823
839fddbe
LP
824int pkcs11_token_read_x509_certificate(
825 CK_FUNCTION_LIST *m,
826 CK_SESSION_HANDLE session,
827 CK_OBJECT_HANDLE object,
828 X509 **ret_cert) {
829
839fddbe
LP
830 _cleanup_free_ char *t = NULL;
831 CK_ATTRIBUTE attribute = {
832 .type = CKA_VALUE
833 };
834 CK_RV rv;
835 _cleanup_(X509_freep) X509 *x509 = NULL;
836 X509_NAME *name = NULL;
da035a3a
LB
837 int r;
838
839 r = dlopen_p11kit();
840 if (r < 0)
841 return r;
839fddbe
LP
842
843 rv = m->C_GetAttributeValue(session, object, &attribute, 1);
844 if (rv != CKR_OK)
85686b37 845 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 846 "Failed to read X.509 certificate size off token: %s", sym_p11_kit_strerror(rv));
839fddbe 847
85686b37 848 _cleanup_free_ void *buffer = malloc(attribute.ulValueLen);
839fddbe 849 if (!buffer)
85686b37 850 return log_oom_debug();
839fddbe
LP
851
852 attribute.pValue = buffer;
853
854 rv = m->C_GetAttributeValue(session, object, &attribute, 1);
855 if (rv != CKR_OK)
85686b37 856 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 857 "Failed to read X.509 certificate data off token: %s", sym_p11_kit_strerror(rv));
839fddbe 858
85686b37 859 const unsigned char *p = attribute.pValue;
839fddbe
LP
860 x509 = d2i_X509(NULL, &p, attribute.ulValueLen);
861 if (!x509)
85686b37 862 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate.");
839fddbe
LP
863
864 name = X509_get_subject_name(x509);
865 if (!name)
85686b37 866 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to acquire X.509 subject name.");
839fddbe
LP
867
868 t = X509_NAME_oneline(name, NULL, 0);
869 if (!t)
85686b37 870 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to format X.509 subject name as string.");
839fddbe
LP
871
872 log_debug("Using X.509 certificate issued for '%s'.", t);
873
874 *ret_cert = TAKE_PTR(x509);
875 return 0;
876}
877#endif
878
879int pkcs11_token_find_private_key(
880 CK_FUNCTION_LIST *m,
881 CK_SESSION_HANDLE session,
882 P11KitUri *search_uri,
883 CK_OBJECT_HANDLE *ret_object) {
884
3d05c058 885 bool found_class = false;
839fddbe 886 _cleanup_free_ CK_ATTRIBUTE *attributes_buffer = NULL;
ca6cb9c0 887 CK_KEY_TYPE key_type;
3d05c058
VS
888 CK_BBOOL decrypt_value, derive_value;
889 CK_ATTRIBUTE optional_attributes[] = {
ca6cb9c0
VS
890 { CKA_KEY_TYPE, &key_type, sizeof(key_type) },
891 { CKA_DECRYPT, &decrypt_value, sizeof(decrypt_value) },
892 { CKA_DERIVE, &derive_value, sizeof(derive_value) },
3d05c058 893 };
ca6cb9c0
VS
894 uint8_t n_private_keys = 0;
895 CK_OBJECT_HANDLE private_key = CK_INVALID_HANDLE;
3d05c058 896 CK_RV rv;
839fddbe
LP
897
898 assert(m);
899 assert(search_uri);
900 assert(ret_object);
901
3d05c058
VS
902 CK_ULONG n_attributes;
903 CK_ATTRIBUTE *attributes = sym_p11_kit_uri_get_attributes(search_uri, &n_attributes);
904 for (CK_ULONG i = 0; i < n_attributes; i++) {
839fddbe
LP
905
906 /* We use the URI's included match attributes, but make them more strict. This allows users
907 * to specify a token URL instead of an object URL and the right thing should happen if
908 * there's only one suitable key on the token. */
909
3d05c058 910 switch (attributes[i].type) {
839fddbe 911 case CKA_CLASS: {
ca6cb9c0 912 if (attributes[i].ulValueLen != sizeof(CK_OBJECT_CLASS))
839fddbe
LP
913 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CLASS attribute size.");
914
ca6cb9c0
VS
915 CK_OBJECT_CLASS *class = (CK_OBJECT_CLASS*) attributes[i].pValue;
916 if (*class != CKO_PRIVATE_KEY)
839fddbe
LP
917 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
918 "Selected PKCS#11 object is not a private key, refusing.");
919
920 found_class = true;
921 break;
839fddbe
LP
922 }}
923 }
924
3d05c058 925 if (!found_class) {
839fddbe 926 /* Hmm, let's slightly extend the attribute list we search for */
ca6cb9c0 927 static const CK_OBJECT_CLASS required_class = CKO_PRIVATE_KEY;
839fddbe 928
3d05c058 929 attributes_buffer = new(CK_ATTRIBUTE, n_attributes + 1);
839fddbe
LP
930 if (!attributes_buffer)
931 return log_oom();
932
933 memcpy(attributes_buffer, attributes, sizeof(CK_ATTRIBUTE) * n_attributes);
934
3d05c058
VS
935 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
936 .type = CKA_CLASS,
ca6cb9c0
VS
937 .pValue = (CK_OBJECT_CLASS*) &required_class,
938 .ulValueLen = sizeof(required_class),
3d05c058 939 };
839fddbe
LP
940
941 attributes = attributes_buffer;
942 }
943
944 rv = m->C_FindObjectsInit(session, attributes, n_attributes);
945 if (rv != CKR_OK)
946 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 947 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv));
839fddbe 948
3d05c058
VS
949 for (;;) {
950 CK_ULONG b;
ca6cb9c0 951 CK_OBJECT_HANDLE candidate;
3d05c058
VS
952 rv = m->C_FindObjects(session, &candidate, 1, &b);
953 if (rv != CKR_OK)
954 return log_error_errno(SYNTHETIC_ERRNO(EIO),
955 "Failed to find objects: %s", sym_p11_kit_strerror(rv));
956
957 if (b == 0)
958 break;
959
ca6cb9c0
VS
960 optional_attributes[0].ulValueLen = sizeof(key_type);
961 optional_attributes[1].ulValueLen = sizeof(decrypt_value);
962 optional_attributes[2].ulValueLen = sizeof(derive_value);
3d05c058
VS
963
964 rv = m->C_GetAttributeValue(session, candidate, optional_attributes, ELEMENTSOF(optional_attributes));
c83f4220 965 if (!IN_SET(rv, CKR_OK, CKR_ATTRIBUTE_TYPE_INVALID))
3d05c058 966 return log_error_errno(SYNTHETIC_ERRNO(EIO),
ca6cb9c0 967 "Failed to get attributes of a found private key: %s", sym_p11_kit_strerror(rv));
3d05c058 968
ca6cb9c0
VS
969 if (optional_attributes[0].ulValueLen == CK_UNAVAILABLE_INFORMATION) {
970 log_debug("A found private key does not have CKA_KEY_TYPE, rejecting the key.");
971 continue;
972 }
3d05c058 973
ca6cb9c0
VS
974 if (key_type == CKK_RSA)
975 if (optional_attributes[1].ulValueLen == CK_UNAVAILABLE_INFORMATION || decrypt_value == CK_FALSE) {
976 log_debug("A found private RSA key can't decrypt, rejecting the key.");
977 continue;
978 }
3d05c058 979
ca6cb9c0
VS
980 if (key_type == CKK_EC)
981 if (optional_attributes[2].ulValueLen == CK_UNAVAILABLE_INFORMATION || derive_value == CK_FALSE) {
982 log_debug("A found private EC key can't derive, rejecting the key.");
983 continue;
984 }
985
986 n_private_keys++;
987 if (n_private_keys > 1)
988 break;
989 private_key = candidate;
3d05c058
VS
990 }
991
992 rv = m->C_FindObjectsFinal(session);
839fddbe
LP
993 if (rv != CKR_OK)
994 return log_error_errno(SYNTHETIC_ERRNO(EIO),
3d05c058
VS
995 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
996
ca6cb9c0 997 if (n_private_keys == 0)
839fddbe 998 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
3d05c058
VS
999 "Failed to find selected private key suitable for decryption or derivation on token.");
1000
ca6cb9c0 1001 if (n_private_keys > 1)
839fddbe 1002 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
3d05c058 1003 "Configured private key URI matches multiple keys, refusing.");
839fddbe 1004
ca6cb9c0 1005 *ret_object = private_key;
839fddbe
LP
1006 return 0;
1007}
1008
06b77382
VS
1009static const char* object_class_to_string(CK_OBJECT_CLASS class) {
1010 switch (class) {
1011 case CKO_CERTIFICATE:
1012 return "CKO_CERTIFICATE";
1013 case CKO_PUBLIC_KEY:
1014 return "CKO_PUBLIC_KEY";
1015 case CKO_PRIVATE_KEY:
1016 return "CKO_PRIVATE_KEY";
1017 case CKO_SECRET_KEY:
1018 return "CKO_SECRET_KEY";
1019 default:
1020 return NULL;
1021 }
1022}
1023
1024/* Returns an object with the given class and the same CKA_ID or CKA_LABEL as prototype */
1025int pkcs11_token_find_related_object(
1026 CK_FUNCTION_LIST *m,
1027 CK_SESSION_HANDLE session,
1028 CK_OBJECT_HANDLE prototype,
1029 CK_OBJECT_CLASS class,
1030 CK_OBJECT_HANDLE *ret_object ) {
1031
1032 _cleanup_free_ void *buffer = NULL;
1033 CK_ATTRIBUTE attributes[] = {
1034 { CKA_ID, NULL_PTR, 0 },
1035 { CKA_LABEL, NULL_PTR, 0 }
1036 };
1037 CK_OBJECT_CLASS search_class = class;
1038 CK_ATTRIBUTE search_attributes[2] = {
1039 { CKA_CLASS, &search_class, sizeof(search_class) }
1040 };
1041 CK_ULONG n_objects;
1042 CK_OBJECT_HANDLE objects[2];
1043 CK_RV rv;
1044
1045 rv = m->C_GetAttributeValue(session, prototype, attributes, ELEMENTSOF(attributes));
c83f4220 1046 if (!IN_SET(rv, CKR_OK, CKR_ATTRIBUTE_TYPE_INVALID))
06b77382
VS
1047 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve length of attributes: %s", sym_p11_kit_strerror(rv));
1048
1049 if (attributes[0].ulValueLen != CK_UNAVAILABLE_INFORMATION) {
1050 buffer = malloc(attributes[0].ulValueLen);
1051 if (!buffer)
1052 return log_oom();
1053
1054 attributes[0].pValue = buffer;
1055 rv = m->C_GetAttributeValue(session, prototype, &attributes[0], 1);
1056 if (rv != CKR_OK)
1057 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
1058 "Failed to retrieve CKA_ID: %s", sym_p11_kit_strerror(rv));
1059
1060 search_attributes[1] = attributes[0];
1061
1062 } else if (attributes[1].ulValueLen != CK_UNAVAILABLE_INFORMATION) {
1063 buffer = malloc(attributes[1].ulValueLen);
1064 if (!buffer)
1065 return log_oom();
1066
1067 attributes[1].pValue = buffer;
1068 rv = m->C_GetAttributeValue(session, prototype, &attributes[1], 1);
1069 if (rv != CKR_OK)
1070 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
1071 "Failed to retrieve CKA_LABEL: %s", sym_p11_kit_strerror(rv));
1072
1073 search_attributes[1] = attributes[1];
1074
1075 } else
1076 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "The prototype does not have CKA_ID or CKA_LABEL");
1077
1078 rv = m->C_FindObjectsInit(session, search_attributes, 2);
1079 if (rv != CKR_OK)
1080 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
1081 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv));
1082
1083 rv = m->C_FindObjects(session, objects, 2, &n_objects);
1084 if (rv != CKR_OK)
1085 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
1086 "Failed to find objects: %s", sym_p11_kit_strerror(rv));
1087
1088 rv = m->C_FindObjectsFinal(session);
1089 if (rv != CKR_OK)
1090 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
1091 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
1092
1093 if (n_objects == 0)
1094 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
1095 "Failed to find a related object with class %s", object_class_to_string(class));
1096
1097 if (n_objects > 1)
1098 log_warning("Found multiple related objects with class %s, using the first object.",
1099 object_class_to_string(class));
1100
1101 *ret_object = objects[0];
1102 return 0;
1103}
1104
1105#if HAVE_OPENSSL
1106static int ecc_convert_to_compressed(
1107 CK_FUNCTION_LIST *m,
1108 CK_SESSION_HANDLE session,
1109 CK_OBJECT_HANDLE object,
1110 const void *uncompressed_point,
1111 size_t uncompressed_point_size,
1112 void **ret_compressed_point,
1113 size_t *ret_compressed_point_size) {
1114
1115 _cleanup_free_ void *ec_params_buffer = NULL;
1116 CK_ATTRIBUTE ec_params_attr = { CKA_EC_PARAMS, NULL_PTR, 0 };
1117 CK_RV rv;
1118 int r;
1119
1120 rv = m->C_GetAttributeValue(session, object, &ec_params_attr, 1);
c83f4220 1121 if (!IN_SET(rv, CKR_OK, CKR_ATTRIBUTE_TYPE_INVALID))
06b77382
VS
1122 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1123 "Failed to retrieve length of CKA_EC_PARAMS: %s", sym_p11_kit_strerror(rv));
1124
1125 if (ec_params_attr.ulValueLen != CK_UNAVAILABLE_INFORMATION) {
1126 ec_params_buffer = malloc(ec_params_attr.ulValueLen);
1127 if (!ec_params_buffer)
1128 return log_oom();
1129
1130 ec_params_attr.pValue = ec_params_buffer;
1131 rv = m->C_GetAttributeValue(session, object, &ec_params_attr, 1);
1132 if (rv != CKR_OK)
1133 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1134 "Failed to retrieve CKA_EC_PARAMS from a private key: %s", sym_p11_kit_strerror(rv));
1135 } else {
1136 CK_OBJECT_HANDLE public_key;
1137 r = pkcs11_token_find_related_object(m, session, object, CKO_PUBLIC_KEY, &public_key);
1138 if (r < 0)
1139 return log_error_errno(r, "Failed to find a public key for compressing a EC point");
1140
1141 ec_params_attr.ulValueLen = 0;
1142 rv = m->C_GetAttributeValue(session, public_key, &ec_params_attr, 1);
c83f4220 1143 if (!IN_SET(rv, CKR_OK, CKR_ATTRIBUTE_TYPE_INVALID))
06b77382
VS
1144 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1145 "Failed to retrieve length of CKA_EC_PARAMS: %s", sym_p11_kit_strerror(rv));
1146
1147 if (ec_params_attr.ulValueLen == CK_UNAVAILABLE_INFORMATION)
1148 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1149 "The public key does not have CKA_EC_PARAMS");
1150
1151 ec_params_buffer = malloc(ec_params_attr.ulValueLen);
1152 if (!ec_params_buffer)
1153 return log_oom();
1154
1155 ec_params_attr.pValue = ec_params_buffer;
1156 rv = m->C_GetAttributeValue(session, public_key, &ec_params_attr, 1);
1157 if (rv != CKR_OK)
1158 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1159 "Failed to retrieve CKA_EC_PARAMS from a public key: %s", sym_p11_kit_strerror(rv));
1160 }
1161
1162 _cleanup_(EC_GROUP_freep) EC_GROUP *group = NULL;
1163 _cleanup_(EC_POINT_freep) EC_POINT *point = NULL;
1164 _cleanup_(BN_CTX_freep) BN_CTX *bnctx = NULL;
1165 _cleanup_free_ void *compressed_point = NULL;
1166 size_t compressed_point_size;
1167
1168 const unsigned char *ec_params_value = ec_params_attr.pValue;
1169 group = d2i_ECPKParameters(NULL, &ec_params_value, ec_params_attr.ulValueLen);
1170 if (!group)
1171 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unable to decode CKA_EC_PARAMS");
1172
1173 point = EC_POINT_new(group);
1174 if (!point)
1175 return log_oom();
1176
1177 bnctx = BN_CTX_new();
1178 if (!bnctx)
1179 return log_oom();
1180
1181 if (EC_POINT_oct2point(group, point, uncompressed_point, uncompressed_point_size, bnctx) != 1)
1182 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unable to decode an uncompressed EC point");
1183
1184 compressed_point_size = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, NULL, 0, bnctx);
1185 if (compressed_point_size == 0)
1186 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine size of a compressed EC point");
1187
1188 compressed_point = malloc(compressed_point_size);
1189 if (!compressed_point)
1190 return log_oom();
1191
1192 compressed_point_size = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, compressed_point, compressed_point_size, bnctx);
1193 if (compressed_point_size == 0)
1194 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert a EC point to compressed format");
1195
1196 *ret_compressed_point = TAKE_PTR(compressed_point);
1197 *ret_compressed_point_size = compressed_point_size;
1198 return 0;
1199}
1200#endif
1201
3d05c058
VS
1202/* Since EC keys doesn't support encryption directly, we use ECDH protocol to derive shared secret here.
1203 * We use PKCS#11 C_DeriveKey function to derive a shared secret with a private key stored in the token and
1204 * a public key saved on enrollment. */
1205static int pkcs11_token_decrypt_data_ecc(
1206 CK_FUNCTION_LIST *m,
1207 CK_SESSION_HANDLE session,
1208 CK_OBJECT_HANDLE object,
1209 const void *encrypted_data,
1210 size_t encrypted_data_size,
1211 void **ret_decrypted_data,
1212 size_t *ret_decrypted_data_size) {
1213
1214 static const CK_BBOOL yes = CK_TRUE, no = CK_FALSE;
1215 static const CK_OBJECT_CLASS shared_secret_class = CKO_SECRET_KEY;
1216 static const CK_KEY_TYPE shared_secret_type = CKK_GENERIC_SECRET;
1217 static const CK_ATTRIBUTE shared_secret_template[] = {
1218 { CKA_TOKEN, (void*) &no, sizeof(no) },
1219 { CKA_CLASS, (void*) &shared_secret_class, sizeof(shared_secret_class) },
1220 { CKA_KEY_TYPE, (void*) &shared_secret_type, sizeof(shared_secret_type) },
1221 { CKA_SENSITIVE, (void*) &no, sizeof(no) },
1222 { CKA_EXTRACTABLE, (void*) &yes, sizeof(yes) }
1223 };
1224 CK_ECDH1_DERIVE_PARAMS params = {
1225 .kdf = CKD_NULL,
1226 .pPublicData = (void*) encrypted_data,
1227 .ulPublicDataLen = encrypted_data_size
1228 };
1229 CK_MECHANISM mechanism = {
1230 .mechanism = CKM_ECDH1_DERIVE,
1231 .pParameter = &params,
1232 .ulParameterLen = sizeof(params)
1233 };
1234 CK_OBJECT_HANDLE shared_secret_handle;
06b77382
VS
1235 CK_SESSION_INFO session_info;
1236 CK_MECHANISM_INFO mechanism_info;
3d05c058 1237 CK_RV rv, rv2;
06b77382
VS
1238#if HAVE_OPENSSL
1239 _cleanup_free_ void *compressed_point = NULL;
1240 int r;
1241#endif
1242
1243 rv = m->C_GetSessionInfo(session, &session_info);
1244 if (rv != CKR_OK)
1245 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1246 "Failed to get information about the PKCS#11 session: %s", sym_p11_kit_strerror(rv));
1247
1248 rv = m->C_GetMechanismInfo(session_info.slotID, CKM_ECDH1_DERIVE, &mechanism_info);
1249 if (rv != CKR_OK)
1250 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1251 "Failed to get information about CKM_ECDH1_DERIVE: %s", sym_p11_kit_strerror(rv));
1252
1253 if (!(mechanism_info.flags & CKF_EC_UNCOMPRESS)) {
1254 if (mechanism_info.flags & CKF_EC_COMPRESS) {
1255#if HAVE_OPENSSL
1256 log_debug("CKM_ECDH1_DERIVE accepts compressed EC points only, trying to convert.");
0a87b834 1257 size_t compressed_point_size = 0; /* Explicit initialization to appease gcc */
06b77382
VS
1258 r = ecc_convert_to_compressed(m, session, object, encrypted_data, encrypted_data_size, &compressed_point, &compressed_point_size);
1259 if (r < 0)
1260 return r;
1261
1262 params.pPublicData = compressed_point;
1263 params.ulPublicDataLen = compressed_point_size;
1264#else
1265 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1266 "CKM_ECDH1_DERIVE does not support uncompressed format of EC points");
1267#endif
1268 } else
1269 log_debug("Both CKF_EC_UNCOMPRESS and CKF_EC_COMPRESS are false for CKM_ECDH1_DERIVE, ignoring.");
1270 }
3d05c058
VS
1271
1272 rv = m->C_DeriveKey(session, &mechanism, object, (CK_ATTRIBUTE*) shared_secret_template, ELEMENTSOF(shared_secret_template), &shared_secret_handle);
1273 if (rv != CKR_OK)
1274 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to derive a shared secret: %s", sym_p11_kit_strerror(rv));
1275
1276 CK_ATTRIBUTE shared_secret_attr = { CKA_VALUE, NULL_PTR, 0};
1277
1278 rv = m->C_GetAttributeValue(session, shared_secret_handle, &shared_secret_attr, 1);
1279 if (rv != CKR_OK) {
1280 rv2 = m->C_DestroyObject(session, shared_secret_handle);
1281 if (rv2 != CKR_OK)
1282 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2));
1283 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve shared secret length: %s", sym_p11_kit_strerror(rv));
1284 }
1285
1286 shared_secret_attr.pValue = malloc(shared_secret_attr.ulValueLen);
1287 if (!shared_secret_attr.pValue)
1288 return log_oom();
1289
1290 rv = m->C_GetAttributeValue(session, shared_secret_handle, &shared_secret_attr, 1);
1291 rv2 = m->C_DestroyObject(session, shared_secret_handle);
1292 if (rv2 != CKR_OK)
1293 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2));
1294
1295 if (rv != CKR_OK) {
1296 erase_and_free(shared_secret_attr.pValue);
1297 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve a shared secret: %s", sym_p11_kit_strerror(rv));
1298 }
1299
1300 log_info("Successfully derived key with security token.");
1301
1302 *ret_decrypted_data = shared_secret_attr.pValue;
1303 *ret_decrypted_data_size = shared_secret_attr.ulValueLen;
1304 return 0;
1305}
1306
1307static int pkcs11_token_decrypt_data_rsa(
839fddbe
LP
1308 CK_FUNCTION_LIST *m,
1309 CK_SESSION_HANDLE session,
1310 CK_OBJECT_HANDLE object,
1311 const void *encrypted_data,
1312 size_t encrypted_data_size,
1313 void **ret_decrypted_data,
1314 size_t *ret_decrypted_data_size) {
1315
1316 static const CK_MECHANISM mechanism = {
1317 .mechanism = CKM_RSA_PKCS
1318 };
1319 _cleanup_(erase_and_freep) CK_BYTE *dbuffer = NULL;
1320 CK_ULONG dbuffer_size = 0;
1321 CK_RV rv;
da035a3a 1322
839fddbe
LP
1323 rv = m->C_DecryptInit(session, (CK_MECHANISM*) &mechanism, object);
1324 if (rv != CKR_OK)
1325 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 1326 "Failed to initialize decryption on security token: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
1327
1328 dbuffer_size = encrypted_data_size; /* Start with something reasonable */
1329 dbuffer = malloc(dbuffer_size);
1330 if (!dbuffer)
1331 return log_oom();
1332
1333 rv = m->C_Decrypt(session, (CK_BYTE*) encrypted_data, encrypted_data_size, dbuffer, &dbuffer_size);
1334 if (rv == CKR_BUFFER_TOO_SMALL) {
1335 erase_and_free(dbuffer);
1336
1337 dbuffer = malloc(dbuffer_size);
1338 if (!dbuffer)
1339 return log_oom();
1340
1341 rv = m->C_Decrypt(session, (CK_BYTE*) encrypted_data, encrypted_data_size, dbuffer, &dbuffer_size);
1342 }
1343 if (rv != CKR_OK)
1344 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 1345 "Failed to decrypt key on security token: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
1346
1347 log_info("Successfully decrypted key with security token.");
1348
1349 *ret_decrypted_data = TAKE_PTR(dbuffer);
1350 *ret_decrypted_data_size = dbuffer_size;
1351 return 0;
1352}
1353
3d05c058
VS
1354int pkcs11_token_decrypt_data(
1355 CK_FUNCTION_LIST *m,
1356 CK_SESSION_HANDLE session,
1357 CK_OBJECT_HANDLE object,
1358 const void *encrypted_data,
1359 size_t encrypted_data_size,
1360 void **ret_decrypted_data,
1361 size_t *ret_decrypted_data_size) {
1362
1363 CK_KEY_TYPE key_type;
1364 CK_ATTRIBUTE key_type_template = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
1365 CK_RV rv;
1366
1367 assert(m);
1368 assert(encrypted_data);
1369 assert(encrypted_data_size > 0);
1370 assert(ret_decrypted_data);
1371 assert(ret_decrypted_data_size);
1372
1373 rv = m->C_GetAttributeValue(session, object, &key_type_template, 1);
1374 if (rv != CKR_OK)
1375 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve private key type");
1376
1377 switch (key_type) {
1378
1379 case CKK_RSA:
1380 return pkcs11_token_decrypt_data_rsa(m, session, object, encrypted_data, encrypted_data_size, ret_decrypted_data, ret_decrypted_data_size);
1381
1382 case CKK_EC:
1383 return pkcs11_token_decrypt_data_ecc(m, session, object, encrypted_data, encrypted_data_size, ret_decrypted_data, ret_decrypted_data_size);
1384
1385 default:
1386 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported private key type: %lu", key_type);
1387 }
1388}
1389
839fddbe
LP
1390int pkcs11_token_acquire_rng(
1391 CK_FUNCTION_LIST *m,
1392 CK_SESSION_HANDLE session) {
1393
1394 _cleanup_free_ void *buffer = NULL;
839fddbe
LP
1395 size_t rps;
1396 CK_RV rv;
1397 int r;
1398
1399 assert(m);
1400
da035a3a
LB
1401 r = dlopen_p11kit();
1402 if (r < 0)
1403 return r;
1404
839fddbe
LP
1405 /* While we are at it, let's read some RNG data from the PKCS#11 token and pass it to the kernel
1406 * random pool. This should be cheap if we are talking to the device already. Note that we don't
1407 * credit any entropy, since we don't know about the quality of the pkcs#11 token's RNG. Why bother
1408 * at all? There are two sides to the argument whether to generate private keys on tokens or on the
1409 * host. By crediting some data from the token RNG to the host's pool we at least can say that any
1410 * key generated from it is at least as good as both sources individually. */
1411
1412 rps = random_pool_size();
1413
1414 buffer = malloc(rps);
1415 if (!buffer)
1416 return log_oom();
1417
1418 rv = m->C_GenerateRandom(session, buffer, rps);
1419 if (rv != CKR_OK)
1420 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
da035a3a 1421 "Failed to generate RNG data on security token: %s", sym_p11_kit_strerror(rv));
839fddbe 1422
61bd7d1e 1423 r = random_write_entropy(-1, buffer, rps, false);
839fddbe
LP
1424 if (r < 0)
1425 return log_debug_errno(r, "Failed to write PKCS#11 acquired random data to /dev/urandom: %m");
1426
1427 log_debug("Successfully written %zu bytes random data acquired via PKCS#11 to kernel random pool.", rps);
1428
1429 return 0;
1430}
1431
1432static int token_process(
1433 CK_FUNCTION_LIST *m,
1434 CK_SLOT_ID slotid,
1435 const CK_SLOT_INFO *slot_info,
1436 const CK_TOKEN_INFO *token_info,
1437 P11KitUri *search_uri,
1438 pkcs11_find_token_callback_t callback,
1439 void *userdata) {
1440
1441 _cleanup_free_ char *token_label = NULL;
1442 CK_SESSION_HANDLE session;
1443 CK_RV rv;
1444 int r;
1445
1446 assert(m);
1447 assert(slot_info);
1448 assert(token_info);
839fddbe
LP
1449
1450 token_label = pkcs11_token_label(token_info);
1451 if (!token_label)
1452 return log_oom();
1453
1454 rv = m->C_OpenSession(slotid, CKF_SERIAL_SESSION, NULL, NULL, &session);
1455 if (rv != CKR_OK)
1456 return log_error_errno(SYNTHETIC_ERRNO(EIO),
da035a3a 1457 "Failed to create session for security token '%s': %s", token_label, sym_p11_kit_strerror(rv));
839fddbe
LP
1458
1459 if (callback)
1460 r = callback(m, session, slotid, slot_info, token_info, search_uri, userdata);
1461 else
1462 r = 1; /* if not callback was specified, just say we found what we were looking for */
1463
1464 rv = m->C_CloseSession(session);
1465 if (rv != CKR_OK)
da035a3a 1466 log_warning("Failed to close session on PKCS#11 token, ignoring: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
1467
1468 return r;
1469}
1470
1471static int slot_process(
1472 CK_FUNCTION_LIST *m,
1473 CK_SLOT_ID slotid,
1474 P11KitUri *search_uri,
1475 pkcs11_find_token_callback_t callback,
1476 void *userdata) {
1477
da035a3a 1478 _cleanup_(sym_p11_kit_uri_freep) P11KitUri* slot_uri = NULL, *token_uri = NULL;
839fddbe
LP
1479 _cleanup_free_ char *token_uri_string = NULL;
1480 CK_TOKEN_INFO token_info;
1481 CK_SLOT_INFO slot_info;
da035a3a 1482 int uri_result, r;
839fddbe
LP
1483 CK_RV rv;
1484
1485 assert(m);
839fddbe 1486
da035a3a
LB
1487 r = dlopen_p11kit();
1488 if (r < 0)
1489 return r;
1490
839fddbe
LP
1491 /* We return -EAGAIN for all failures we can attribute to a specific slot in some way, so that the
1492 * caller might try other slots before giving up. */
1493
1494 rv = m->C_GetSlotInfo(slotid, &slot_info);
1495 if (rv != CKR_OK) {
da035a3a 1496 log_warning("Failed to acquire slot info for slot %lu, ignoring slot: %s", slotid, sym_p11_kit_strerror(rv));
839fddbe
LP
1497 return -EAGAIN;
1498 }
1499
1500 slot_uri = uri_from_slot_info(&slot_info);
1501 if (!slot_uri)
1502 return log_oom();
1503
1504 if (DEBUG_LOGGING) {
1505 _cleanup_free_ char *slot_uri_string = NULL;
1506
da035a3a 1507 uri_result = sym_p11_kit_uri_format(slot_uri, P11_KIT_URI_FOR_ANY, &slot_uri_string);
839fddbe 1508 if (uri_result != P11_KIT_URI_OK) {
da035a3a 1509 log_warning("Failed to format slot URI, ignoring slot: %s", sym_p11_kit_uri_message(uri_result));
839fddbe
LP
1510 return -EAGAIN;
1511 }
1512
1513 log_debug("Found slot with URI %s", slot_uri_string);
1514 }
1515
1516 rv = m->C_GetTokenInfo(slotid, &token_info);
1517 if (rv == CKR_TOKEN_NOT_PRESENT) {
d7a0f1f4
FS
1518 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
1519 "Token not present in slot, ignoring.");
839fddbe 1520 } else if (rv != CKR_OK) {
da035a3a 1521 log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid, sym_p11_kit_strerror(rv));
839fddbe
LP
1522 return -EAGAIN;
1523 }
1524
1525 token_uri = uri_from_token_info(&token_info);
1526 if (!token_uri)
1527 return log_oom();
1528
da035a3a 1529 uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
839fddbe 1530 if (uri_result != P11_KIT_URI_OK) {
da035a3a 1531 log_warning("Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
839fddbe
LP
1532 return -EAGAIN;
1533 }
1534
da035a3a 1535 if (search_uri && !sym_p11_kit_uri_match_token_info(search_uri, &token_info))
d7a0f1f4
FS
1536 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
1537 "Found non-matching token with URI %s.",
1538 token_uri_string);
839fddbe
LP
1539
1540 log_debug("Found matching token with URI %s.", token_uri_string);
1541
1542 return token_process(
1543 m,
1544 slotid,
1545 &slot_info,
1546 &token_info,
1547 search_uri,
1548 callback,
1549 userdata);
1550}
1551
1552static int module_process(
1553 CK_FUNCTION_LIST *m,
1554 P11KitUri *search_uri,
1555 pkcs11_find_token_callback_t callback,
1556 void *userdata) {
1557
da035a3a 1558 _cleanup_(sym_p11_kit_uri_freep) P11KitUri* module_uri = NULL;
839fddbe 1559 _cleanup_free_ char *name = NULL, *module_uri_string = NULL;
839fddbe
LP
1560 _cleanup_free_ CK_SLOT_ID *slotids = NULL;
1561 CK_ULONG n_slotids = 0;
1562 int uri_result;
1563 CK_INFO info;
1564 size_t k;
1565 CK_RV rv;
1566 int r;
1567
1568 assert(m);
839fddbe 1569
da035a3a
LB
1570 r = dlopen_p11kit();
1571 if (r < 0)
1572 return r;
1573
839fddbe
LP
1574 /* We ignore most errors from modules here, in order to skip over faulty modules: one faulty module
1575 * should not have the effect that we don't try the others anymore. We indicate such per-module
1576 * failures with -EAGAIN, which let's the caller try the next module. */
1577
da035a3a 1578 name = sym_p11_kit_module_get_name(m);
839fddbe
LP
1579 if (!name)
1580 return log_oom();
1581
1582 log_debug("Trying PKCS#11 module %s.", name);
1583
1584 rv = m->C_GetInfo(&info);
1585 if (rv != CKR_OK) {
da035a3a 1586 log_warning("Failed to get info on PKCS#11 module, ignoring module: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
1587 return -EAGAIN;
1588 }
1589
1590 module_uri = uri_from_module_info(&info);
1591 if (!module_uri)
1592 return log_oom();
1593
da035a3a 1594 uri_result = sym_p11_kit_uri_format(module_uri, P11_KIT_URI_FOR_ANY, &module_uri_string);
839fddbe 1595 if (uri_result != P11_KIT_URI_OK) {
da035a3a 1596 log_warning("Failed to format module URI, ignoring module: %s", sym_p11_kit_uri_message(uri_result));
839fddbe
LP
1597 return -EAGAIN;
1598 }
1599
1600 log_debug("Found module with URI %s", module_uri_string);
1601
1602 rv = pkcs11_get_slot_list_malloc(m, &slotids, &n_slotids);
1603 if (rv != CKR_OK) {
da035a3a 1604 log_warning("Failed to get slot list, ignoring module: %s", sym_p11_kit_strerror(rv));
839fddbe
LP
1605 return -EAGAIN;
1606 }
d7a0f1f4
FS
1607 if (n_slotids == 0)
1608 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
1609 "This module has no slots? Ignoring module.");
839fddbe
LP
1610
1611 for (k = 0; k < n_slotids; k++) {
1612 r = slot_process(
1613 m,
1614 slotids[k],
1615 search_uri,
1616 callback,
1617 userdata);
1618 if (r != -EAGAIN)
1619 return r;
1620 }
1621
1622 return -EAGAIN;
1623}
1624
1625int pkcs11_find_token(
1626 const char *pkcs11_uri,
1627 pkcs11_find_token_callback_t callback,
1628 void *userdata) {
1629
da035a3a
LB
1630 _cleanup_(sym_p11_kit_modules_finalize_and_releasep) CK_FUNCTION_LIST **modules = NULL;
1631 _cleanup_(sym_p11_kit_uri_freep) P11KitUri *search_uri = NULL;
839fddbe
LP
1632 int r;
1633
da035a3a
LB
1634 r = dlopen_p11kit();
1635 if (r < 0)
1636 return r;
1637
839fddbe
LP
1638 /* Execute the specified callback for each matching token found. If nothing is found returns
1639 * -EAGAIN. Logs about all errors, except for EAGAIN, which the caller has to log about. */
1640
0eb3be46
LP
1641 if (pkcs11_uri) {
1642 r = uri_from_string(pkcs11_uri, &search_uri);
1643 if (r < 0)
1644 return log_error_errno(r, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri);
1645 }
839fddbe 1646
da035a3a 1647 modules = sym_p11_kit_modules_load_and_initialize(0);
839fddbe
LP
1648 if (!modules)
1649 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize pkcs11 modules");
1650
1651 for (CK_FUNCTION_LIST **i = modules; *i; i++) {
1652 r = module_process(
1653 *i,
1654 search_uri,
1655 callback,
1656 userdata);
1657 if (r != -EAGAIN)
1658 return r;
1659 }
1660
1661 return -EAGAIN;
1662}
1663
2289a784 1664#if HAVE_OPENSSL
85686b37 1665struct pkcs11_acquire_public_key_callback_data {
2289a784 1666 char *pin_used;
85686b37 1667 EVP_PKEY *pkey;
a96c284f 1668 const char *askpw_friendly_name, *askpw_icon, *askpw_credential;
a758a128 1669 AskPasswordFlags askpw_flags;
2289a784
LP
1670};
1671
85686b37 1672static void pkcs11_acquire_public_key_callback_data_release(struct pkcs11_acquire_public_key_callback_data *data) {
2289a784 1673 erase_and_free(data->pin_used);
85686b37 1674 EVP_PKEY_free(data->pkey);
2289a784
LP
1675}
1676
85686b37 1677static int pkcs11_acquire_public_key_callback(
2289a784
LP
1678 CK_FUNCTION_LIST *m,
1679 CK_SESSION_HANDLE session,
1680 CK_SLOT_ID slot_id,
1681 const CK_SLOT_INFO *slot_info,
1682 const CK_TOKEN_INFO *token_info,
1683 P11KitUri *uri,
1684 void *userdata) {
1685
1686 _cleanup_(erase_and_freep) char *pin_used = NULL;
85686b37
VS
1687 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
1688 CK_OBJECT_CLASS class;
1689 CK_CERTIFICATE_TYPE type;
1690 CK_ATTRIBUTE candidate_attributes[] = {
1691 { CKA_CLASS, &class, sizeof(class) },
1692 { CKA_CERTIFICATE_TYPE, &type, sizeof(type) },
1693 };
1694 CK_OBJECT_HANDLE candidate, public_key = CK_INVALID_HANDLE, certificate = CK_INVALID_HANDLE;
1695 uint8_t n_public_keys = 0, n_certificates = 0;
1696 CK_RV rv;
2289a784
LP
1697 int r;
1698
1699 assert(m);
1700 assert(slot_info);
1701 assert(token_info);
1702 assert(uri);
2289a784 1703
85686b37
VS
1704 struct pkcs11_acquire_public_key_callback_data *data = ASSERT_PTR(userdata);
1705
2289a784
LP
1706 /* Called for every token matching our URI */
1707
a758a128
LP
1708 r = pkcs11_token_login(
1709 m,
1710 session,
1711 slot_id,
1712 token_info,
1713 data->askpw_friendly_name,
a96c284f 1714 data->askpw_icon,
a758a128 1715 "pkcs11-pin",
a96c284f 1716 data->askpw_credential,
a758a128
LP
1717 UINT64_MAX,
1718 data->askpw_flags,
a758a128 1719 &pin_used);
2289a784
LP
1720 if (r < 0)
1721 return r;
1722
85686b37
VS
1723 CK_ULONG n_attributes;
1724 CK_ATTRIBUTE *attributes = sym_p11_kit_uri_get_attributes(uri, &n_attributes);
1725 for (CK_ULONG i = 0; i < n_attributes; i++) {
1726 switch (attributes[i].type) {
1727 case CKA_CLASS: {
1728 CK_OBJECT_CLASS requested_class = *((CK_OBJECT_CLASS*) attributes[i].pValue);
a30fdf85 1729 if (!IN_SET(requested_class, CKO_PUBLIC_KEY, CKO_CERTIFICATE))
85686b37
VS
1730 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1731 "Selected PKCS#11 object is not a public key or certificate, refusing.");
1732 break;
1733 }
2289a784 1734
85686b37
VS
1735 case CKA_CERTIFICATE_TYPE: {
1736 CK_CERTIFICATE_TYPE requested_type = *((CK_CERTIFICATE_TYPE*) attributes[i].pValue);
1737 if (requested_type != CKC_X_509)
1738 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
1739 break;
1740 }}
1741 }
1742
1743 rv = m->C_FindObjectsInit(session, attributes, n_attributes);
1744 if (rv != CKR_OK)
1745 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1746 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv));
2289a784 1747
85686b37
VS
1748 for (;;) {
1749 CK_ULONG n;
1750 rv = m->C_FindObjects(session, &candidate, 1, &n);
1751 if (rv != CKR_OK)
1752 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1753 "Failed to find objects: %s", sym_p11_kit_strerror(rv));
1754
1755 if (n == 0)
1756 break;
1757
1758 candidate_attributes[0].ulValueLen = sizeof(class);
1759 candidate_attributes[1].ulValueLen = sizeof(type);
1760 rv = m->C_GetAttributeValue(session, candidate, candidate_attributes, ELEMENTSOF(candidate_attributes));
a30fdf85 1761 if (!IN_SET(rv, CKR_OK, CKR_ATTRIBUTE_TYPE_INVALID))
85686b37
VS
1762 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1763 "Failed to get attributes of a selected candidate: %s", sym_p11_kit_strerror(rv));
1764
1765 if (candidate_attributes[0].ulValueLen == CK_UNAVAILABLE_INFORMATION) {
1766 log_debug("Failed to get CKA_CLASS of a selected candidate");
1767 continue;
1768 }
1769
1770 if (class == CKO_PUBLIC_KEY) {
1771 n_public_keys++;
1772 if (n_public_keys > 1)
1773 break;
1774 public_key = candidate;
1775 continue;
1776 }
1777
1778 if (class == CKO_CERTIFICATE) {
1779 if (candidate_attributes[1].ulValueLen == CK_UNAVAILABLE_INFORMATION) {
1780 log_debug("Failed to get CKA_CERTIFICATE_TYPE of a selected candidate");
1781 continue;
1782 }
1783 if (type != CKC_X_509)
1784 continue;
1785 n_certificates++;
1786 if (n_certificates > 1)
1787 break;
1788 certificate = candidate;
1789 continue;
1790 }
1791 }
1792
1793 rv = m->C_FindObjectsFinal(session);
1794 if (rv != CKR_OK)
1795 return log_error_errno(SYNTHETIC_ERRNO(EIO),
1796 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
1797
1798 if (n_public_keys == 0 && n_certificates == 0)
1799 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
1800 "Failed to find selected public key or X.509 certificate.");
1801
1802 if (n_public_keys > 1)
1803 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
1804 "Provided URI matches multiple public keys, refusing.");
1805
1806 if (n_certificates > 1)
1807 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
1808 "Provided URI matches multiple certificates, refusing.");
1809
1810 if (n_public_keys != 0) {
1811 r = pkcs11_token_read_public_key(m, session, public_key, &pkey);
1812 if (r >= 0)
1813 goto success;
1814 }
1815
1816 if (n_certificates == 0)
1817 return log_error_errno(r, "Failed to read a found public key.");
1818
1819 {
1820 _cleanup_(X509_freep) X509 *cert = NULL;
1821
1822 r = pkcs11_token_read_x509_certificate(m, session, certificate, &cert);
1823 if (r < 0)
1824 return log_error_errno(r, "Failed to read a found X.509 certificate.");
1825
1826 pkey = X509_get_pubkey(cert);
1827 if (!pkey)
1828 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to extract public key from X.509 certificate.");
1829 }
1830success:
2289a784
LP
1831 /* Let's read some random data off the token and write it to the kernel pool before we generate our
1832 * random key from it. This way we can claim the quality of the RNG is at least as good as the
1833 * kernel's and the token's pool */
1834 (void) pkcs11_token_acquire_rng(m, session);
1835
1836 data->pin_used = TAKE_PTR(pin_used);
85686b37
VS
1837 data->pkey = TAKE_PTR(pkey);
1838 return 0;
2289a784
LP
1839}
1840
85686b37 1841int pkcs11_acquire_public_key(
2289a784
LP
1842 const char *uri,
1843 const char *askpw_friendly_name,
a96c284f
LP
1844 const char *askpw_icon,
1845 const char *askpw_credential,
b2ac9280 1846 AskPasswordFlags askpw_flags,
85686b37 1847 EVP_PKEY **ret_pkey,
2289a784
LP
1848 char **ret_pin_used) {
1849
85686b37 1850 _cleanup_(pkcs11_acquire_public_key_callback_data_release) struct pkcs11_acquire_public_key_callback_data data = {
2289a784 1851 .askpw_friendly_name = askpw_friendly_name,
a96c284f
LP
1852 .askpw_icon = askpw_icon,
1853 .askpw_credential = askpw_credential,
b2ac9280 1854 .askpw_flags = askpw_flags,
2289a784
LP
1855 };
1856 int r;
1857
1858 assert(uri);
85686b37 1859 assert(ret_pkey);
2289a784 1860
85686b37 1861 r = pkcs11_find_token(uri, pkcs11_acquire_public_key_callback, &data);
2289a784
LP
1862 if (r == -EAGAIN) /* pkcs11_find_token() doesn't log about this error, but all others */
1863 return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
1864 "Specified PKCS#11 token with URI '%s' not found.",
1865 uri);
1866 if (r < 0)
1867 return r;
1868
85686b37 1869 *ret_pkey = TAKE_PTR(data.pkey);
2289a784
LP
1870 if (ret_pin_used)
1871 *ret_pin_used = TAKE_PTR(data.pin_used);
2289a784
LP
1872 return 0;
1873}
f240cbb6
LP
1874#endif
1875
1876static int list_callback(
1877 CK_FUNCTION_LIST *m,
1878 CK_SESSION_HANDLE session,
1879 CK_SLOT_ID slot_id,
1880 const CK_SLOT_INFO *slot_info,
1881 const CK_TOKEN_INFO *token_info,
1882 P11KitUri *uri,
1883 void *userdata) {
1884
1885 _cleanup_free_ char *token_uri_string = NULL, *token_label = NULL, *token_manufacturer_id = NULL, *token_model = NULL;
da035a3a 1886 _cleanup_(sym_p11_kit_uri_freep) P11KitUri *token_uri = NULL;
f240cbb6
LP
1887 Table *t = userdata;
1888 int uri_result, r;
1889
1890 assert(slot_info);
1891 assert(token_info);
1892
da035a3a
LB
1893 r = dlopen_p11kit();
1894 if (r < 0)
1895 return r;
1896
f240cbb6
LP
1897 /* We only care about hardware devices here with a token inserted. Let's filter everything else
1898 * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during
1899 * enumeration we'll filter those, since software tokens are typically the system certificate store
1900 * and such, and it's typically not what people want to bind their home directories to.) */
50079424 1901 if (!FLAGS_SET(slot_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT))
f240cbb6
LP
1902 return -EAGAIN;
1903
1904 token_label = pkcs11_token_label(token_info);
1905 if (!token_label)
1906 return log_oom();
1907
1908 token_manufacturer_id = pkcs11_token_manufacturer_id(token_info);
1909 if (!token_manufacturer_id)
1910 return log_oom();
1911
1912 token_model = pkcs11_token_model(token_info);
1913 if (!token_model)
1914 return log_oom();
1915
1916 token_uri = uri_from_token_info(token_info);
1917 if (!token_uri)
1918 return log_oom();
1919
da035a3a 1920 uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
f240cbb6 1921 if (uri_result != P11_KIT_URI_OK)
da035a3a 1922 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
f240cbb6
LP
1923
1924 r = table_add_many(
1925 t,
1926 TABLE_STRING, token_uri_string,
1927 TABLE_STRING, token_label,
1928 TABLE_STRING, token_manufacturer_id,
1929 TABLE_STRING, token_model);
1930 if (r < 0)
1931 return table_log_add_error(r);
1932
1933 return -EAGAIN; /* keep scanning */
1934}
1935#endif
1936
1937int pkcs11_list_tokens(void) {
1938#if HAVE_P11KIT
1939 _cleanup_(table_unrefp) Table *t = NULL;
1940 int r;
1941
1942 t = table_new("uri", "label", "manufacturer", "model");
1943 if (!t)
1944 return log_oom();
1945
1946 r = pkcs11_find_token(NULL, list_callback, t);
1947 if (r < 0 && r != -EAGAIN)
1948 return r;
2289a784 1949
2413a0fa 1950 if (table_isempty(t)) {
f240cbb6
LP
1951 log_info("No suitable PKCS#11 tokens found.");
1952 return 0;
1953 }
1954
1955 r = table_print(t, stdout);
1956 if (r < 0)
1957 return log_error_errno(r, "Failed to show device table: %m");
1958
1959 return 0;
1960#else
1961 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1962 "PKCS#11 tokens not supported on this build.");
1963#endif
1964}
1965
1966#if HAVE_P11KIT
1967static int auto_callback(
1968 CK_FUNCTION_LIST *m,
1969 CK_SESSION_HANDLE session,
1970 CK_SLOT_ID slot_id,
1971 const CK_SLOT_INFO *slot_info,
1972 const CK_TOKEN_INFO *token_info,
1973 P11KitUri *uri,
1974 void *userdata) {
1975
da035a3a 1976 _cleanup_(sym_p11_kit_uri_freep) P11KitUri *token_uri = NULL;
f240cbb6 1977 char **t = userdata;
da035a3a 1978 int uri_result, r;
f240cbb6
LP
1979
1980 assert(slot_info);
1981 assert(token_info);
1982
da035a3a
LB
1983 r = dlopen_p11kit();
1984 if (r < 0)
1985 return r;
1986
f240cbb6
LP
1987 if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT))
1988 return -EAGAIN;
1989
1990 if (*t)
1991 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
1992 "More than one suitable PKCS#11 token found.");
1993
1994 token_uri = uri_from_token_info(token_info);
1995 if (!token_uri)
1996 return log_oom();
1997
da035a3a 1998 uri_result = sym_p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, t);
f240cbb6 1999 if (uri_result != P11_KIT_URI_OK)
da035a3a 2000 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result));
f240cbb6
LP
2001
2002 return 0;
2003}
2289a784 2004#endif
f240cbb6
LP
2005
2006int pkcs11_find_token_auto(char **ret) {
2007#if HAVE_P11KIT
2008 int r;
2009
2010 r = pkcs11_find_token(NULL, auto_callback, ret);
2011 if (r == -EAGAIN)
2012 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No suitable PKCS#11 tokens found.");
2013 if (r < 0)
2014 return r;
2015
2016 return 0;
2017#else
2018 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
2019 "PKCS#11 tokens not supported on this build.");
839fddbe 2020#endif
f240cbb6 2021}
ed3d3af1
OK
2022
2023#if HAVE_P11KIT
2024void pkcs11_crypt_device_callback_data_release(pkcs11_crypt_device_callback_data *data) {
2025 erase_and_free(data->decrypted_key);
2026
2027 if (data->free_encrypted_key)
2028 free(data->encrypted_key);
2029}
2030
2031int pkcs11_crypt_device_callback(
2032 CK_FUNCTION_LIST *m,
2033 CK_SESSION_HANDLE session,
2034 CK_SLOT_ID slot_id,
2035 const CK_SLOT_INFO *slot_info,
2036 const CK_TOKEN_INFO *token_info,
2037 P11KitUri *uri,
2038 void *userdata) {
2039
99534007 2040 pkcs11_crypt_device_callback_data *data = ASSERT_PTR(userdata);
ed3d3af1
OK
2041 CK_OBJECT_HANDLE object;
2042 int r;
2043
2044 assert(m);
2045 assert(slot_info);
2046 assert(token_info);
2047 assert(uri);
ed3d3af1
OK
2048
2049 /* Called for every token matching our URI */
2050
2051 r = pkcs11_token_login(
2052 m,
2053 session,
2054 slot_id,
2055 token_info,
2056 data->friendly_name,
2057 "drive-harddisk",
2058 "pkcs11-pin",
a96c284f 2059 data->askpw_credential,
ed3d3af1 2060 data->until,
a758a128 2061 data->askpw_flags,
ed3d3af1
OK
2062 NULL);
2063 if (r < 0)
2064 return r;
2065
2066 /* We are likely called during early boot, where entropy is scarce. Mix some data from the PKCS#11
2067 * token, if it supports that. It should be cheap, given that we already are talking to it anyway and
2068 * shouldn't hurt. */
2069 (void) pkcs11_token_acquire_rng(m, session);
2070
2071 r = pkcs11_token_find_private_key(m, session, uri, &object);
2072 if (r < 0)
2073 return r;
2074
2075 r = pkcs11_token_decrypt_data(
2076 m,
2077 session,
2078 object,
2079 data->encrypted_key,
2080 data->encrypted_key_size,
2081 &data->decrypted_key,
2082 &data->decrypted_key_size);
2083 if (r < 0)
2084 return r;
2085
2086 return 0;
2087}
2088#endif