]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/pkcs11-util.c
Merge pull request #17741 from poettering/cryptsetup-fido2
[thirdparty/systemd.git] / src / shared / pkcs11-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <fcntl.h>
4
5 #include "ask-password-api.h"
6 #include "escape.h"
7 #include "fd-util.h"
8 #include "format-table.h"
9 #include "io-util.h"
10 #include "memory-util.h"
11 #if HAVE_OPENSSL
12 #include "openssl-util.h"
13 #endif
14 #include "pkcs11-util.h"
15 #include "random-util.h"
16 #include "string-util.h"
17 #include "strv.h"
18
19 bool pkcs11_uri_valid(const char *uri) {
20 const char *p;
21
22 /* A very superficial checker for RFC7512 PKCS#11 URI syntax */
23
24 if (isempty(uri))
25 return false;
26
27 p = startswith(uri, "pkcs11:");
28 if (!p)
29 return false;
30
31 if (isempty(p))
32 return false;
33
34 if (!in_charset(p, ALPHANUMERICAL "-_?;&%="))
35 return false;
36
37 return true;
38 }
39
40 #if HAVE_P11KIT
41
42 int uri_from_string(const char *p, P11KitUri **ret) {
43 _cleanup_(p11_kit_uri_freep) P11KitUri *uri = NULL;
44
45 assert(p);
46 assert(ret);
47
48 uri = p11_kit_uri_new();
49 if (!uri)
50 return -ENOMEM;
51
52 if (p11_kit_uri_parse(p, P11_KIT_URI_FOR_ANY, uri) != P11_KIT_URI_OK)
53 return -EINVAL;
54
55 *ret = TAKE_PTR(uri);
56 return 0;
57 }
58
59 P11KitUri *uri_from_module_info(const CK_INFO *info) {
60 P11KitUri *uri;
61
62 assert(info);
63
64 uri = p11_kit_uri_new();
65 if (!uri)
66 return NULL;
67
68 *p11_kit_uri_get_module_info(uri) = *info;
69 return uri;
70 }
71
72 P11KitUri *uri_from_slot_info(const CK_SLOT_INFO *slot_info) {
73 P11KitUri *uri;
74
75 assert(slot_info);
76
77 uri = p11_kit_uri_new();
78 if (!uri)
79 return NULL;
80
81 *p11_kit_uri_get_slot_info(uri) = *slot_info;
82 return uri;
83 }
84
85 P11KitUri *uri_from_token_info(const CK_TOKEN_INFO *token_info) {
86 P11KitUri *uri;
87
88 assert(token_info);
89
90 uri = p11_kit_uri_new();
91 if (!uri)
92 return NULL;
93
94 *p11_kit_uri_get_token_info(uri) = *token_info;
95 return uri;
96 }
97
98 CK_RV pkcs11_get_slot_list_malloc(
99 CK_FUNCTION_LIST *m,
100 CK_SLOT_ID **ret_slotids,
101 CK_ULONG *ret_n_slotids) {
102
103 CK_RV rv;
104
105 assert(m);
106 assert(ret_slotids);
107 assert(ret_n_slotids);
108
109 for (unsigned tries = 0; tries < 16; tries++) {
110 _cleanup_free_ CK_SLOT_ID *slotids = NULL;
111 CK_ULONG n_slotids = 0;
112
113 rv = m->C_GetSlotList(0, NULL, &n_slotids);
114 if (rv != CKR_OK)
115 return rv;
116 if (n_slotids == 0) {
117 *ret_slotids = NULL;
118 *ret_n_slotids = 0;
119 return CKR_OK;
120 }
121
122 slotids = new(CK_SLOT_ID, n_slotids);
123 if (!slotids)
124 return CKR_HOST_MEMORY;
125
126 rv = m->C_GetSlotList(0, slotids, &n_slotids);
127 if (rv == CKR_OK) {
128 *ret_slotids = TAKE_PTR(slotids);
129 *ret_n_slotids = n_slotids;
130 return CKR_OK;
131 }
132
133 if (rv != CKR_BUFFER_TOO_SMALL)
134 return rv;
135
136 /* Hu? Maybe somebody plugged something in and things changed? Let's try again */
137 }
138
139 return CKR_BUFFER_TOO_SMALL;
140 }
141
142 char *pkcs11_token_label(const CK_TOKEN_INFO *token_info) {
143 char *t;
144
145 /* The label is not NUL terminated and likely padded with spaces, let's make a copy here, so that we
146 * can strip that. */
147 t = strndup((char*) token_info->label, sizeof(token_info->label));
148 if (!t)
149 return NULL;
150
151 strstrip(t);
152 return t;
153 }
154
155 char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info) {
156 char *t;
157
158 t = strndup((char*) token_info->manufacturerID, sizeof(token_info->manufacturerID));
159 if (!t)
160 return NULL;
161
162 strstrip(t);
163 return t;
164 }
165
166 char *pkcs11_token_model(const CK_TOKEN_INFO *token_info) {
167 char *t;
168
169 t = strndup((char*) token_info->model, sizeof(token_info->model));
170 if (!t)
171 return NULL;
172
173 strstrip(t);
174 return t;
175 }
176
177 int pkcs11_token_login(
178 CK_FUNCTION_LIST *m,
179 CK_SESSION_HANDLE session,
180 CK_SLOT_ID slotid,
181 const CK_TOKEN_INFO *token_info,
182 const char *friendly_name,
183 const char *icon_name,
184 const char *keyname,
185 usec_t until,
186 char **ret_used_pin) {
187
188 _cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL;
189 _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL;
190 CK_TOKEN_INFO updated_token_info;
191 int uri_result, r;
192 CK_RV rv;
193
194 assert(m);
195 assert(token_info);
196
197 token_label = pkcs11_token_label(token_info);
198 if (!token_label)
199 return log_oom();
200
201 token_uri = uri_from_token_info(token_info);
202 if (!token_uri)
203 return log_oom();
204
205 uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
206 if (uri_result != P11_KIT_URI_OK)
207 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
208
209 if (FLAGS_SET(token_info->flags, CKF_PROTECTED_AUTHENTICATION_PATH)) {
210 rv = m->C_Login(session, CKU_USER, NULL, 0);
211 if (rv != CKR_OK)
212 return log_error_errno(SYNTHETIC_ERRNO(EIO),
213 "Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
214
215 log_info("Successfully logged into security token '%s' via protected authentication path.", token_label);
216 if (ret_used_pin)
217 *ret_used_pin = NULL;
218 return 0;
219 }
220
221 if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
222 log_info("No login into security token '%s' required.", token_label);
223 if (ret_used_pin)
224 *ret_used_pin = NULL;
225 return 0;
226 }
227
228 token_uri_escaped = cescape(token_uri_string);
229 if (!token_uri_escaped)
230 return log_oom();
231
232 id = strjoin("pkcs11:", token_uri_escaped);
233 if (!id)
234 return log_oom();
235
236 for (unsigned tries = 0; tries < 3; tries++) {
237 _cleanup_strv_free_erase_ char **passwords = NULL;
238 char **i, *e;
239
240 e = getenv("PIN");
241 if (e) {
242 passwords = strv_new(e);
243 if (!passwords)
244 return log_oom();
245
246 string_erase(e);
247 if (unsetenv("PIN") < 0)
248 return log_error_errno(errno, "Failed to unset $PIN: %m");
249 } else {
250 _cleanup_free_ char *text = NULL;
251
252 if (FLAGS_SET(token_info->flags, CKF_USER_PIN_FINAL_TRY))
253 r = asprintf(&text,
254 "Please enter correct PIN for security token '%s' in order to unlock %s (final try):",
255 token_label, friendly_name);
256 else if (FLAGS_SET(token_info->flags, CKF_USER_PIN_COUNT_LOW))
257 r = asprintf(&text,
258 "PIN has been entered incorrectly previously, please enter correct PIN for security token '%s' in order to unlock %s:",
259 token_label, friendly_name);
260 else if (tries == 0)
261 r = asprintf(&text,
262 "Please enter PIN for security token '%s' in order to unlock %s:",
263 token_label, friendly_name);
264 else
265 r = asprintf(&text,
266 "Please enter PIN for security token '%s' in order to unlock %s (try #%u):",
267 token_label, friendly_name, tries+1);
268 if (r < 0)
269 return log_oom();
270
271 /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */
272 r = ask_password_auto(text, icon_name, id, keyname, until, 0, &passwords);
273 if (r < 0)
274 return log_error_errno(r, "Failed to query PIN for security token '%s': %m", token_label);
275 }
276
277 STRV_FOREACH(i, passwords) {
278 rv = m->C_Login(session, CKU_USER, (CK_UTF8CHAR*) *i, strlen(*i));
279 if (rv == CKR_OK) {
280
281 if (ret_used_pin) {
282 char *c;
283
284 c = strdup(*i);
285 if (!c)
286 return log_oom();
287
288 *ret_used_pin = c;
289 }
290
291 log_info("Successfully logged into security token '%s'.", token_label);
292 return 0;
293 }
294 if (rv == CKR_PIN_LOCKED)
295 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
296 "PIN has been locked, please reset PIN of security token '%s'.", token_label);
297 if (!IN_SET(rv, CKR_PIN_INCORRECT, CKR_PIN_LEN_RANGE))
298 return log_error_errno(SYNTHETIC_ERRNO(EIO),
299 "Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
300
301 /* Referesh the token info, so that we can prompt knowing the new flags if they changed. */
302 rv = m->C_GetTokenInfo(slotid, &updated_token_info);
303 if (rv != CKR_OK)
304 return log_error_errno(SYNTHETIC_ERRNO(EIO),
305 "Failed to acquire updated security token information for slot %lu: %s",
306 slotid, p11_kit_strerror(rv));
307
308 token_info = &updated_token_info;
309 log_notice("PIN for token '%s' is incorrect, please try again.", token_label);
310 }
311 }
312
313 return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Too many attempts to log into token '%s'.", token_label);
314 }
315
316 int pkcs11_token_find_x509_certificate(
317 CK_FUNCTION_LIST *m,
318 CK_SESSION_HANDLE session,
319 P11KitUri *search_uri,
320 CK_OBJECT_HANDLE *ret_object) {
321
322 bool found_class = false, found_certificate_type = false;
323 _cleanup_free_ CK_ATTRIBUTE *attributes_buffer = NULL;
324 CK_ULONG n_attributes, a, n_objects;
325 CK_ATTRIBUTE *attributes = NULL;
326 CK_OBJECT_HANDLE objects[2];
327 CK_RV rv, rv2;
328
329 assert(m);
330 assert(search_uri);
331 assert(ret_object);
332
333 attributes = p11_kit_uri_get_attributes(search_uri, &n_attributes);
334 for (a = 0; a < n_attributes; a++) {
335
336 /* We use the URI's included match attributes, but make them more strict. This allows users
337 * to specify a token URL instead of an object URL and the right thing should happen if
338 * there's only one suitable key on the token. */
339
340 switch (attributes[a].type) {
341
342 case CKA_CLASS: {
343 CK_OBJECT_CLASS c;
344
345 if (attributes[a].ulValueLen != sizeof(c))
346 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CLASS attribute size.");
347
348 memcpy(&c, attributes[a].pValue, sizeof(c));
349 if (c != CKO_CERTIFICATE)
350 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
351
352 found_class = true;
353 break;
354 }
355
356 case CKA_CERTIFICATE_TYPE: {
357 CK_CERTIFICATE_TYPE t;
358
359 if (attributes[a].ulValueLen != sizeof(t))
360 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CERTIFICATE_TYPE attribute size.");
361
362 memcpy(&t, attributes[a].pValue, sizeof(t));
363 if (t != CKC_X_509)
364 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
365
366 found_certificate_type = true;
367 break;
368 }}
369 }
370
371 if (!found_class || !found_certificate_type) {
372 /* Hmm, let's slightly extend the attribute list we search for */
373
374 attributes_buffer = new(CK_ATTRIBUTE, n_attributes + !found_class + !found_certificate_type);
375 if (!attributes_buffer)
376 return log_oom();
377
378 memcpy(attributes_buffer, attributes, sizeof(CK_ATTRIBUTE) * n_attributes);
379
380 if (!found_class) {
381 static const CK_OBJECT_CLASS class = CKO_CERTIFICATE;
382
383 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
384 .type = CKA_CLASS,
385 .pValue = (CK_OBJECT_CLASS*) &class,
386 .ulValueLen = sizeof(class),
387 };
388 }
389
390 if (!found_certificate_type) {
391 static const CK_CERTIFICATE_TYPE type = CKC_X_509;
392
393 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
394 .type = CKA_CERTIFICATE_TYPE,
395 .pValue = (CK_CERTIFICATE_TYPE*) &type,
396 .ulValueLen = sizeof(type),
397 };
398 }
399
400 attributes = attributes_buffer;
401 }
402
403 rv = m->C_FindObjectsInit(session, attributes, n_attributes);
404 if (rv != CKR_OK)
405 return log_error_errno(SYNTHETIC_ERRNO(EIO),
406 "Failed to initialize object find call: %s", p11_kit_strerror(rv));
407
408 rv = m->C_FindObjects(session, objects, ELEMENTSOF(objects), &n_objects);
409 rv2 = m->C_FindObjectsFinal(session);
410 if (rv != CKR_OK)
411 return log_error_errno(SYNTHETIC_ERRNO(EIO),
412 "Failed to find objects: %s", p11_kit_strerror(rv));
413 if (rv2 != CKR_OK)
414 return log_error_errno(SYNTHETIC_ERRNO(EIO),
415 "Failed to finalize object find call: %s", p11_kit_strerror(rv));
416 if (n_objects == 0)
417 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
418 "Failed to find selected X509 certificate on token.");
419 if (n_objects > 1)
420 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
421 "Configured URI matches multiple certificates, refusing.");
422
423 *ret_object = objects[0];
424 return 0;
425 }
426
427 #if HAVE_OPENSSL
428 int pkcs11_token_read_x509_certificate(
429 CK_FUNCTION_LIST *m,
430 CK_SESSION_HANDLE session,
431 CK_OBJECT_HANDLE object,
432 X509 **ret_cert) {
433
434 _cleanup_free_ void *buffer = NULL;
435 _cleanup_free_ char *t = NULL;
436 CK_ATTRIBUTE attribute = {
437 .type = CKA_VALUE
438 };
439 CK_RV rv;
440 _cleanup_(X509_freep) X509 *x509 = NULL;
441 X509_NAME *name = NULL;
442 const unsigned char *p;
443
444 rv = m->C_GetAttributeValue(session, object, &attribute, 1);
445 if (rv != CKR_OK)
446 return log_error_errno(SYNTHETIC_ERRNO(EIO),
447 "Failed to read X.509 certificate size off token: %s", p11_kit_strerror(rv));
448
449 buffer = malloc(attribute.ulValueLen);
450 if (!buffer)
451 return log_oom();
452
453 attribute.pValue = buffer;
454
455 rv = m->C_GetAttributeValue(session, object, &attribute, 1);
456 if (rv != CKR_OK)
457 return log_error_errno(SYNTHETIC_ERRNO(EIO),
458 "Failed to read X.509 certificate data off token: %s", p11_kit_strerror(rv));
459
460 p = attribute.pValue;
461 x509 = d2i_X509(NULL, &p, attribute.ulValueLen);
462 if (!x509)
463 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed parse X.509 certificate.");
464
465 name = X509_get_subject_name(x509);
466 if (!name)
467 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to acquire X.509 subject name.");
468
469 t = X509_NAME_oneline(name, NULL, 0);
470 if (!t)
471 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to format X.509 subject name as string.");
472
473 log_debug("Using X.509 certificate issued for '%s'.", t);
474
475 *ret_cert = TAKE_PTR(x509);
476 return 0;
477 }
478 #endif
479
480 int pkcs11_token_find_private_key(
481 CK_FUNCTION_LIST *m,
482 CK_SESSION_HANDLE session,
483 P11KitUri *search_uri,
484 CK_OBJECT_HANDLE *ret_object) {
485
486 bool found_decrypt = false, found_class = false, found_key_type = false;
487 _cleanup_free_ CK_ATTRIBUTE *attributes_buffer = NULL;
488 CK_ULONG n_attributes, a, n_objects;
489 CK_ATTRIBUTE *attributes = NULL;
490 CK_OBJECT_HANDLE objects[2];
491 CK_RV rv, rv2;
492
493 assert(m);
494 assert(search_uri);
495 assert(ret_object);
496
497 attributes = p11_kit_uri_get_attributes(search_uri, &n_attributes);
498 for (a = 0; a < n_attributes; a++) {
499
500 /* We use the URI's included match attributes, but make them more strict. This allows users
501 * to specify a token URL instead of an object URL and the right thing should happen if
502 * there's only one suitable key on the token. */
503
504 switch (attributes[a].type) {
505
506 case CKA_CLASS: {
507 CK_OBJECT_CLASS c;
508
509 if (attributes[a].ulValueLen != sizeof(c))
510 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CLASS attribute size.");
511
512 memcpy(&c, attributes[a].pValue, sizeof(c));
513 if (c != CKO_PRIVATE_KEY)
514 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
515 "Selected PKCS#11 object is not a private key, refusing.");
516
517 found_class = true;
518 break;
519 }
520
521 case CKA_DECRYPT: {
522 CK_BBOOL b;
523
524 if (attributes[a].ulValueLen != sizeof(b))
525 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_DECRYPT attribute size.");
526
527 memcpy(&b, attributes[a].pValue, sizeof(b));
528 if (!b)
529 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
530 "Selected PKCS#11 object is not suitable for decryption, refusing.");
531
532 found_decrypt = true;
533 break;
534 }
535
536 case CKA_KEY_TYPE: {
537 CK_KEY_TYPE t;
538
539 if (attributes[a].ulValueLen != sizeof(t))
540 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_KEY_TYPE attribute size.");
541
542 memcpy(&t, attributes[a].pValue, sizeof(t));
543 if (t != CKK_RSA)
544 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected PKCS#11 object is not an RSA key, refusing.");
545
546 found_key_type = true;
547 break;
548 }}
549 }
550
551 if (!found_decrypt || !found_class || !found_key_type) {
552 /* Hmm, let's slightly extend the attribute list we search for */
553
554 attributes_buffer = new(CK_ATTRIBUTE, n_attributes + !found_decrypt + !found_class + !found_key_type);
555 if (!attributes_buffer)
556 return log_oom();
557
558 memcpy(attributes_buffer, attributes, sizeof(CK_ATTRIBUTE) * n_attributes);
559
560 if (!found_decrypt) {
561 static const CK_BBOOL yes = true;
562
563 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
564 .type = CKA_DECRYPT,
565 .pValue = (CK_BBOOL*) &yes,
566 .ulValueLen = sizeof(yes),
567 };
568 }
569
570 if (!found_class) {
571 static const CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
572
573 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
574 .type = CKA_CLASS,
575 .pValue = (CK_OBJECT_CLASS*) &class,
576 .ulValueLen = sizeof(class),
577 };
578 }
579
580 if (!found_key_type) {
581 static const CK_KEY_TYPE type = CKK_RSA;
582
583 attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
584 .type = CKA_KEY_TYPE,
585 .pValue = (CK_KEY_TYPE*) &type,
586 .ulValueLen = sizeof(type),
587 };
588 }
589
590 attributes = attributes_buffer;
591 }
592
593 rv = m->C_FindObjectsInit(session, attributes, n_attributes);
594 if (rv != CKR_OK)
595 return log_error_errno(SYNTHETIC_ERRNO(EIO),
596 "Failed to initialize object find call: %s", p11_kit_strerror(rv));
597
598 rv = m->C_FindObjects(session, objects, ELEMENTSOF(objects), &n_objects);
599 rv2 = m->C_FindObjectsFinal(session);
600 if (rv != CKR_OK)
601 return log_error_errno(SYNTHETIC_ERRNO(EIO),
602 "Failed to find objects: %s", p11_kit_strerror(rv));
603 if (rv2 != CKR_OK)
604 return log_error_errno(SYNTHETIC_ERRNO(EIO),
605 "Failed to finalize object find call: %s", p11_kit_strerror(rv));
606 if (n_objects == 0)
607 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
608 "Failed to find selected private key suitable for decryption on token.");
609 if (n_objects > 1)
610 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
611 "Configured private key URI matches multiple keys, refusing.");
612
613 *ret_object = objects[0];
614 return 0;
615 }
616
617 int pkcs11_token_decrypt_data(
618 CK_FUNCTION_LIST *m,
619 CK_SESSION_HANDLE session,
620 CK_OBJECT_HANDLE object,
621 const void *encrypted_data,
622 size_t encrypted_data_size,
623 void **ret_decrypted_data,
624 size_t *ret_decrypted_data_size) {
625
626 static const CK_MECHANISM mechanism = {
627 .mechanism = CKM_RSA_PKCS
628 };
629 _cleanup_(erase_and_freep) CK_BYTE *dbuffer = NULL;
630 CK_ULONG dbuffer_size = 0;
631 CK_RV rv;
632
633 assert(m);
634 assert(encrypted_data);
635 assert(encrypted_data_size > 0);
636 assert(ret_decrypted_data);
637 assert(ret_decrypted_data_size);
638
639 rv = m->C_DecryptInit(session, (CK_MECHANISM*) &mechanism, object);
640 if (rv != CKR_OK)
641 return log_error_errno(SYNTHETIC_ERRNO(EIO),
642 "Failed to initialize decryption on security token: %s", p11_kit_strerror(rv));
643
644 dbuffer_size = encrypted_data_size; /* Start with something reasonable */
645 dbuffer = malloc(dbuffer_size);
646 if (!dbuffer)
647 return log_oom();
648
649 rv = m->C_Decrypt(session, (CK_BYTE*) encrypted_data, encrypted_data_size, dbuffer, &dbuffer_size);
650 if (rv == CKR_BUFFER_TOO_SMALL) {
651 erase_and_free(dbuffer);
652
653 dbuffer = malloc(dbuffer_size);
654 if (!dbuffer)
655 return log_oom();
656
657 rv = m->C_Decrypt(session, (CK_BYTE*) encrypted_data, encrypted_data_size, dbuffer, &dbuffer_size);
658 }
659 if (rv != CKR_OK)
660 return log_error_errno(SYNTHETIC_ERRNO(EIO),
661 "Failed to decrypt key on security token: %s", p11_kit_strerror(rv));
662
663 log_info("Successfully decrypted key with security token.");
664
665 *ret_decrypted_data = TAKE_PTR(dbuffer);
666 *ret_decrypted_data_size = dbuffer_size;
667 return 0;
668 }
669
670 int pkcs11_token_acquire_rng(
671 CK_FUNCTION_LIST *m,
672 CK_SESSION_HANDLE session) {
673
674 _cleanup_free_ void *buffer = NULL;
675 size_t rps;
676 CK_RV rv;
677 int r;
678
679 assert(m);
680
681 /* While we are at it, let's read some RNG data from the PKCS#11 token and pass it to the kernel
682 * random pool. This should be cheap if we are talking to the device already. Note that we don't
683 * credit any entropy, since we don't know about the quality of the pkcs#11 token's RNG. Why bother
684 * at all? There are two sides to the argument whether to generate private keys on tokens or on the
685 * host. By crediting some data from the token RNG to the host's pool we at least can say that any
686 * key generated from it is at least as good as both sources individually. */
687
688 rps = random_pool_size();
689
690 buffer = malloc(rps);
691 if (!buffer)
692 return log_oom();
693
694 rv = m->C_GenerateRandom(session, buffer, rps);
695 if (rv != CKR_OK)
696 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
697 "Failed to generate RNG data on security token: %s", p11_kit_strerror(rv));
698
699 r = random_write_entropy(-1, buffer, rps, false);
700 if (r < 0)
701 return log_debug_errno(r, "Failed to write PKCS#11 acquired random data to /dev/urandom: %m");
702
703 log_debug("Successfully written %zu bytes random data acquired via PKCS#11 to kernel random pool.", rps);
704
705 return 0;
706 }
707
708 static int token_process(
709 CK_FUNCTION_LIST *m,
710 CK_SLOT_ID slotid,
711 const CK_SLOT_INFO *slot_info,
712 const CK_TOKEN_INFO *token_info,
713 P11KitUri *search_uri,
714 pkcs11_find_token_callback_t callback,
715 void *userdata) {
716
717 _cleanup_free_ char *token_label = NULL;
718 CK_SESSION_HANDLE session;
719 CK_RV rv;
720 int r;
721
722 assert(m);
723 assert(slot_info);
724 assert(token_info);
725
726 token_label = pkcs11_token_label(token_info);
727 if (!token_label)
728 return log_oom();
729
730 rv = m->C_OpenSession(slotid, CKF_SERIAL_SESSION, NULL, NULL, &session);
731 if (rv != CKR_OK)
732 return log_error_errno(SYNTHETIC_ERRNO(EIO),
733 "Failed to create session for security token '%s': %s", token_label, p11_kit_strerror(rv));
734
735 if (callback)
736 r = callback(m, session, slotid, slot_info, token_info, search_uri, userdata);
737 else
738 r = 1; /* if not callback was specified, just say we found what we were looking for */
739
740 rv = m->C_CloseSession(session);
741 if (rv != CKR_OK)
742 log_warning("Failed to close session on PKCS#11 token, ignoring: %s", p11_kit_strerror(rv));
743
744 return r;
745 }
746
747 static int slot_process(
748 CK_FUNCTION_LIST *m,
749 CK_SLOT_ID slotid,
750 P11KitUri *search_uri,
751 pkcs11_find_token_callback_t callback,
752 void *userdata) {
753
754 _cleanup_(p11_kit_uri_freep) P11KitUri* slot_uri = NULL, *token_uri = NULL;
755 _cleanup_free_ char *token_uri_string = NULL;
756 CK_TOKEN_INFO token_info;
757 CK_SLOT_INFO slot_info;
758 int uri_result;
759 CK_RV rv;
760
761 assert(m);
762
763 /* We return -EAGAIN for all failures we can attribute to a specific slot in some way, so that the
764 * caller might try other slots before giving up. */
765
766 rv = m->C_GetSlotInfo(slotid, &slot_info);
767 if (rv != CKR_OK) {
768 log_warning("Failed to acquire slot info for slot %lu, ignoring slot: %s", slotid, p11_kit_strerror(rv));
769 return -EAGAIN;
770 }
771
772 slot_uri = uri_from_slot_info(&slot_info);
773 if (!slot_uri)
774 return log_oom();
775
776 if (DEBUG_LOGGING) {
777 _cleanup_free_ char *slot_uri_string = NULL;
778
779 uri_result = p11_kit_uri_format(slot_uri, P11_KIT_URI_FOR_ANY, &slot_uri_string);
780 if (uri_result != P11_KIT_URI_OK) {
781 log_warning("Failed to format slot URI, ignoring slot: %s", p11_kit_uri_message(uri_result));
782 return -EAGAIN;
783 }
784
785 log_debug("Found slot with URI %s", slot_uri_string);
786 }
787
788 rv = m->C_GetTokenInfo(slotid, &token_info);
789 if (rv == CKR_TOKEN_NOT_PRESENT) {
790 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
791 "Token not present in slot, ignoring.");
792 } else if (rv != CKR_OK) {
793 log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid, p11_kit_strerror(rv));
794 return -EAGAIN;
795 }
796
797 token_uri = uri_from_token_info(&token_info);
798 if (!token_uri)
799 return log_oom();
800
801 uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
802 if (uri_result != P11_KIT_URI_OK) {
803 log_warning("Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
804 return -EAGAIN;
805 }
806
807 if (search_uri && !p11_kit_uri_match_token_info(search_uri, &token_info))
808 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
809 "Found non-matching token with URI %s.",
810 token_uri_string);
811
812 log_debug("Found matching token with URI %s.", token_uri_string);
813
814 return token_process(
815 m,
816 slotid,
817 &slot_info,
818 &token_info,
819 search_uri,
820 callback,
821 userdata);
822 }
823
824 static int module_process(
825 CK_FUNCTION_LIST *m,
826 P11KitUri *search_uri,
827 pkcs11_find_token_callback_t callback,
828 void *userdata) {
829
830 _cleanup_free_ char *name = NULL, *module_uri_string = NULL;
831 _cleanup_(p11_kit_uri_freep) P11KitUri* module_uri = NULL;
832 _cleanup_free_ CK_SLOT_ID *slotids = NULL;
833 CK_ULONG n_slotids = 0;
834 int uri_result;
835 CK_INFO info;
836 size_t k;
837 CK_RV rv;
838 int r;
839
840 assert(m);
841
842 /* We ignore most errors from modules here, in order to skip over faulty modules: one faulty module
843 * should not have the effect that we don't try the others anymore. We indicate such per-module
844 * failures with -EAGAIN, which let's the caller try the next module. */
845
846 name = p11_kit_module_get_name(m);
847 if (!name)
848 return log_oom();
849
850 log_debug("Trying PKCS#11 module %s.", name);
851
852 rv = m->C_GetInfo(&info);
853 if (rv != CKR_OK) {
854 log_warning("Failed to get info on PKCS#11 module, ignoring module: %s", p11_kit_strerror(rv));
855 return -EAGAIN;
856 }
857
858 module_uri = uri_from_module_info(&info);
859 if (!module_uri)
860 return log_oom();
861
862 uri_result = p11_kit_uri_format(module_uri, P11_KIT_URI_FOR_ANY, &module_uri_string);
863 if (uri_result != P11_KIT_URI_OK) {
864 log_warning("Failed to format module URI, ignoring module: %s", p11_kit_uri_message(uri_result));
865 return -EAGAIN;
866 }
867
868 log_debug("Found module with URI %s", module_uri_string);
869
870 rv = pkcs11_get_slot_list_malloc(m, &slotids, &n_slotids);
871 if (rv != CKR_OK) {
872 log_warning("Failed to get slot list, ignoring module: %s", p11_kit_strerror(rv));
873 return -EAGAIN;
874 }
875 if (n_slotids == 0)
876 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
877 "This module has no slots? Ignoring module.");
878
879 for (k = 0; k < n_slotids; k++) {
880 r = slot_process(
881 m,
882 slotids[k],
883 search_uri,
884 callback,
885 userdata);
886 if (r != -EAGAIN)
887 return r;
888 }
889
890 return -EAGAIN;
891 }
892
893 int pkcs11_find_token(
894 const char *pkcs11_uri,
895 pkcs11_find_token_callback_t callback,
896 void *userdata) {
897
898 _cleanup_(p11_kit_modules_finalize_and_releasep) CK_FUNCTION_LIST **modules = NULL;
899 _cleanup_(p11_kit_uri_freep) P11KitUri *search_uri = NULL;
900 int r;
901
902 /* Execute the specified callback for each matching token found. If nothing is found returns
903 * -EAGAIN. Logs about all errors, except for EAGAIN, which the caller has to log about. */
904
905 if (pkcs11_uri) {
906 r = uri_from_string(pkcs11_uri, &search_uri);
907 if (r < 0)
908 return log_error_errno(r, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri);
909 }
910
911 modules = p11_kit_modules_load_and_initialize(0);
912 if (!modules)
913 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize pkcs11 modules");
914
915 for (CK_FUNCTION_LIST **i = modules; *i; i++) {
916 r = module_process(
917 *i,
918 search_uri,
919 callback,
920 userdata);
921 if (r != -EAGAIN)
922 return r;
923 }
924
925 return -EAGAIN;
926 }
927
928 #if HAVE_OPENSSL
929 struct pkcs11_acquire_certificate_callback_data {
930 char *pin_used;
931 X509 *cert;
932 const char *askpw_friendly_name, *askpw_icon_name;
933 };
934
935 static void pkcs11_acquire_certificate_callback_data_release(struct pkcs11_acquire_certificate_callback_data *data) {
936 erase_and_free(data->pin_used);
937 X509_free(data->cert);
938 }
939
940 static int pkcs11_acquire_certificate_callback(
941 CK_FUNCTION_LIST *m,
942 CK_SESSION_HANDLE session,
943 CK_SLOT_ID slot_id,
944 const CK_SLOT_INFO *slot_info,
945 const CK_TOKEN_INFO *token_info,
946 P11KitUri *uri,
947 void *userdata) {
948
949 _cleanup_(erase_and_freep) char *pin_used = NULL;
950 struct pkcs11_acquire_certificate_callback_data *data = userdata;
951 CK_OBJECT_HANDLE object;
952 int r;
953
954 assert(m);
955 assert(slot_info);
956 assert(token_info);
957 assert(uri);
958 assert(data);
959
960 /* Called for every token matching our URI */
961
962 r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", UINT64_MAX, &pin_used);
963 if (r < 0)
964 return r;
965
966 r = pkcs11_token_find_x509_certificate(m, session, uri, &object);
967 if (r < 0)
968 return r;
969
970 r = pkcs11_token_read_x509_certificate(m, session, object, &data->cert);
971 if (r < 0)
972 return r;
973
974 /* Let's read some random data off the token and write it to the kernel pool before we generate our
975 * random key from it. This way we can claim the quality of the RNG is at least as good as the
976 * kernel's and the token's pool */
977 (void) pkcs11_token_acquire_rng(m, session);
978
979 data->pin_used = TAKE_PTR(pin_used);
980 return 1;
981 }
982
983 int pkcs11_acquire_certificate(
984 const char *uri,
985 const char *askpw_friendly_name,
986 const char *askpw_icon_name,
987 X509 **ret_cert,
988 char **ret_pin_used) {
989
990 _cleanup_(pkcs11_acquire_certificate_callback_data_release) struct pkcs11_acquire_certificate_callback_data data = {
991 .askpw_friendly_name = askpw_friendly_name,
992 .askpw_icon_name = askpw_icon_name,
993 };
994 int r;
995
996 assert(uri);
997 assert(ret_cert);
998
999 r = pkcs11_find_token(uri, pkcs11_acquire_certificate_callback, &data);
1000 if (r == -EAGAIN) /* pkcs11_find_token() doesn't log about this error, but all others */
1001 return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
1002 "Specified PKCS#11 token with URI '%s' not found.",
1003 uri);
1004 if (r < 0)
1005 return r;
1006
1007 *ret_cert = TAKE_PTR(data.cert);
1008
1009 if (ret_pin_used)
1010 *ret_pin_used = TAKE_PTR(data.pin_used);
1011
1012 return 0;
1013 }
1014 #endif
1015
1016 static int list_callback(
1017 CK_FUNCTION_LIST *m,
1018 CK_SESSION_HANDLE session,
1019 CK_SLOT_ID slot_id,
1020 const CK_SLOT_INFO *slot_info,
1021 const CK_TOKEN_INFO *token_info,
1022 P11KitUri *uri,
1023 void *userdata) {
1024
1025 _cleanup_free_ char *token_uri_string = NULL, *token_label = NULL, *token_manufacturer_id = NULL, *token_model = NULL;
1026 _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL;
1027 Table *t = userdata;
1028 int uri_result, r;
1029
1030 assert(slot_info);
1031 assert(token_info);
1032
1033 /* We only care about hardware devices here with a token inserted. Let's filter everything else
1034 * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during
1035 * enumeration we'll filter those, since software tokens are typically the system certificate store
1036 * and such, and it's typically not what people want to bind their home directories to.) */
1037 if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT))
1038 return -EAGAIN;
1039
1040 token_label = pkcs11_token_label(token_info);
1041 if (!token_label)
1042 return log_oom();
1043
1044 token_manufacturer_id = pkcs11_token_manufacturer_id(token_info);
1045 if (!token_manufacturer_id)
1046 return log_oom();
1047
1048 token_model = pkcs11_token_model(token_info);
1049 if (!token_model)
1050 return log_oom();
1051
1052 token_uri = uri_from_token_info(token_info);
1053 if (!token_uri)
1054 return log_oom();
1055
1056 uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string);
1057 if (uri_result != P11_KIT_URI_OK)
1058 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
1059
1060 r = table_add_many(
1061 t,
1062 TABLE_STRING, token_uri_string,
1063 TABLE_STRING, token_label,
1064 TABLE_STRING, token_manufacturer_id,
1065 TABLE_STRING, token_model);
1066 if (r < 0)
1067 return table_log_add_error(r);
1068
1069 return -EAGAIN; /* keep scanning */
1070 }
1071 #endif
1072
1073 int pkcs11_list_tokens(void) {
1074 #if HAVE_P11KIT
1075 _cleanup_(table_unrefp) Table *t = NULL;
1076 int r;
1077
1078 t = table_new("uri", "label", "manufacturer", "model");
1079 if (!t)
1080 return log_oom();
1081
1082 r = pkcs11_find_token(NULL, list_callback, t);
1083 if (r < 0 && r != -EAGAIN)
1084 return r;
1085
1086 if (table_get_rows(t) <= 1) {
1087 log_info("No suitable PKCS#11 tokens found.");
1088 return 0;
1089 }
1090
1091 r = table_print(t, stdout);
1092 if (r < 0)
1093 return log_error_errno(r, "Failed to show device table: %m");
1094
1095 return 0;
1096 #else
1097 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1098 "PKCS#11 tokens not supported on this build.");
1099 #endif
1100 }
1101
1102 #if HAVE_P11KIT
1103 static int auto_callback(
1104 CK_FUNCTION_LIST *m,
1105 CK_SESSION_HANDLE session,
1106 CK_SLOT_ID slot_id,
1107 const CK_SLOT_INFO *slot_info,
1108 const CK_TOKEN_INFO *token_info,
1109 P11KitUri *uri,
1110 void *userdata) {
1111
1112 _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL;
1113 char **t = userdata;
1114 int uri_result;
1115
1116 assert(slot_info);
1117 assert(token_info);
1118
1119 if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT))
1120 return -EAGAIN;
1121
1122 if (*t)
1123 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
1124 "More than one suitable PKCS#11 token found.");
1125
1126 token_uri = uri_from_token_info(token_info);
1127 if (!token_uri)
1128 return log_oom();
1129
1130 uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, t);
1131 if (uri_result != P11_KIT_URI_OK)
1132 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
1133
1134 return 0;
1135 }
1136 #endif
1137
1138 int pkcs11_find_token_auto(char **ret) {
1139 #if HAVE_P11KIT
1140 int r;
1141
1142 r = pkcs11_find_token(NULL, auto_callback, ret);
1143 if (r == -EAGAIN)
1144 return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No suitable PKCS#11 tokens found.");
1145 if (r < 0)
1146 return r;
1147
1148 return 0;
1149 #else
1150 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
1151 "PKCS#11 tokens not supported on this build.");
1152 #endif
1153 }