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