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