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